3 Commits

Author SHA1 Message Date
ranger 0675c9f7d8 fix: wink is now a real CSS animation, no longer sticks (v0.1.3)
The v0.1.1 wink was rendered as a static SVG (left eye drawn as a
closed curve). Once the 5% random gate picked the wink tone, the
left eye stayed closed until the next page render — if the
dashboard sat idle, Buddy was stuck mid-wink indefinitely. David's
report: "the eye does not unblink."

v0.1.2's lower probability (30% → 5%) reduced how often you'd see
the stuck state, but didn't fix the underlying issue.

This release makes the wink a real transient animation:

- sprite.php no longer swaps the left eye for a closed path when
  tone is wink — both eyes are always open circles in the SVG
- buddy.css adds @keyframes buddyWink that briefly closes the
  left eye (scaleY 0.1) for ~250ms every 2.5s, applied only when
  the parent has the .buddy-sprite--wink class
- right eye keeps its normal 5s blink — the asymmetry is what
  makes it read as a wink rather than a synchronised blink
- mouth/cheeks/label still differ for wink tone (those are valid
  static state changes); only the eye behaviour moved to animation

Net effect: when the 5% chance fires, Buddy now actually winks
(closes, opens, closes, opens) instead of freezing one-eye-shut.
2026-05-26 08:08:56 +01:00
ranger c7d49b383a chore: release v0.1.2 — wink tuning entry
Documents the wink-probability tune-down (f661eab) as a proper
patch release. No code behaviour change in this commit — purely
version metadata, changelog, and user-facing about-page history.

CHANGES
- buddy.php: Version header + BUDDY_VERSION constant 0.1.1 → 0.1.2
- CHANGELOG.md: new [0.1.2] entry above [0.1.1], explains the
  tuning rationale + what's intentionally unchanged (wink visuals,
  trigger threshold mood >= 75)
- inc/about.php: version-history card leads with v0.1.2 (latest
  badge), v0.1.1 demoted to second slot

Why a patch release: the wink fires far less often now than it
did in v0.1.1. From a user's point of view that IS a behaviour
change worth a version. Following SemVer: PATCH bump because the
public API and feature set are unchanged; only the tuning of an
existing behaviour was adjusted.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 07:20:25 +01:00
ranger f661eabba1 tune: lower wink probability from 30% to 5%
The original 30% per-render rate felt disturbing in practice. Default
mood is 80, so most admin/dashboard renders cleared the >=75 gate, and
~30% of those flipped to wink. Stacked across the main admin page +
dashboard widget visible on the same screen, the visible wink rate
felt closer to "stuck" than "playful" — buddy looked like he had one
eye closed all the time instead of occasionally cheeking out.

5% is true Easter-egg territory: rare enough to feel magical when it
lands, frequent enough you'll catch it after a few admin sessions.
Refresh ~20 times before expecting to see one.

CHANGES
- inc/state.php: mt_rand probability gate 30 -> 5
- inc/state.php: docstring updated to match new ~5% probability

NOT CHANGED
- Wink visuals (sprite.php) unchanged — still the same closed-eye arc,
  asymmetric smirk, rosier cheeks. Just rarer.
- Version constant + CHANGELOG entry left at v0.1.1 — this is a tuning
  hotfix, not new behavior worth a version bump. If we want a v0.1.2
  bump for hygiene, that's a separate commit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 07:16:32 +01:00
6 changed files with 88 additions and 19 deletions
+49
View File
@@ -9,6 +9,55 @@ Format: [Keep a Changelog 1.1.0](https://keepachangelog.com/en/1.1.0/) — versi
---
## [0.1.3] — 2026-05-27
### Fixed — Wink no longer gets stuck
The v0.1.1 wink was implemented as a static SVG render (left eye drawn as a closed curved line). Once the random 5% chance picked the `wink` tone, the page rendered with one eye closed and stayed that way until the next page reload — and 95% of subsequent reloads went back to a non-wink tone, but if the dashboard sat idle, Buddy was stuck mid-wink indefinitely. David reported it as *"buddy has the wink face but the eye does not unblink."*
v0.1.2's lower probability (30% → 5%) reduced how often you'd see the stuck state but did not fix the underlying issue.
v0.1.3 makes the wink a real CSS animation:
- **sprite.php** no longer renders the left eye as a closed path when tone is `wink` — both eyes are always open circles in the SVG.
- **buddy.css** has a new `@keyframes buddyWink` that briefly closes the left eye (`scaleY(0.1)`) for ~250 ms every 2.5 s. The right eye keeps its normal 5 s blink. That asymmetric pattern is what makes it read as a wink rather than a synchronised blink.
- The wink animation only runs when the parent has the `buddy-sprite--wink` class, which is still controlled by the same 5% probability gate from v0.1.2.
- The mouth (asymmetric smirk), cheek opacity (rosier), and mood label (`Cheeky 😉`) all still differ for the wink tone — those are valid static state changes. Only the eye behaviour moved from static-state to transient-animation.
Net effect: when the 5% chance fires, Buddy now actually winks (closes left eye, opens it, closes it, opens it, etc., every 2.5 s) instead of freezing one-eye-shut.
---
## [0.1.2] — 2026-05-26
### Tuned — Wink probability lowered from 30% to 5%
The wink Easter-egg added in v0.1.1 fired at 30% per page render
when Buddy's mood was ≥ 75. Default mood is 80, so most admin
visits hit the gate and ~30% of those flipped to wink. Stacked
across the main admin page + dashboard widget visible on the same
screen, Buddy ended up looking like he had one eye closed all the
time — "stuck" rather than "playful".
Dropped to 5%. Same wink visuals when it fires; just rare enough
to feel magical instead of constant. Refresh ~20 times when mood
is high and you'll catch one.
### Changed
- **`inc/state.php`**: `buddy_mood_label()` probability gate
`mt_rand( 1, 100 ) <= 30` changed to `<= 5`. Docstring updated
to reflect new ~5% rate.
- **Plugin version bumped**: header + `BUDDY_VERSION` constant
0.1.1 → 0.1.2.
- **About page** version-history card leads with v0.1.2; v0.1.1
demoted.
### Not changed
- Wink visuals (`inc/sprite.php`) — same closed-eye arc, smirk,
rosy cheeks when it fires. Just rarer.
- All other behavior identical to v0.1.1.
---
## [0.1.1] — 2026-05-25
### Added — Wink expression 😉
+15
View File
@@ -24,6 +24,17 @@
animation-duration: 7s; /* sadder Buddy blinks slower */
}
/* Cheeky wink: when the mood-label picks the 'wink' tone, the LEFT eye
runs a faster, more dramatic keyframe that closes for ~250ms every
2.5s. The right eye keeps its normal 5s blink — that asymmetry is
what makes it read as a wink rather than a synchronised blink.
v0.1.3 fix: previously the wink was a static SVG render (left eye
drawn as a closed curve), which got stuck on the page until the next
render. Now it's a real transient animation, so Buddy unblinks. */
.buddy-sprite--wink .buddy-sprite__eye--left {
animation: buddyWink 2.5s infinite;
}
@keyframes buddyBob {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-4px); }
@@ -32,6 +43,10 @@
0%, 92%, 100% { transform: scaleY(1); }
94%, 98% { transform: scaleY(0.1); }
}
@keyframes buddyWink {
0%, 80%, 100% { transform: scaleY(1); } /* eye open most of the cycle */
85%, 95% { transform: scaleY(0.1); } /* closes briefly = the wink */
}
/* ── Dashboard widget ───────────────────────────────────────────── */
+2 -2
View File
@@ -5,7 +5,7 @@
* Plugin Name: Buddy
* Plugin URI: https://icanhelp.ie/buddy
* Description: Adopt a small companion that lives in your WordPress dashboard. Its mood reflects your site's health — published posts feed it, outdated plugins make it sick, clearing spam makes it happy. Gamifies WordPress maintenance with a bit of charm.
* Version: 0.1.1
* Version: 0.1.3
* Requires at least: 5.0
* Requires PHP: 7.4
* Author: David Keane
@@ -20,7 +20,7 @@
if ( ! defined( 'ABSPATH' ) ) { exit; }
// Plugin coordinates.
if ( ! defined( 'BUDDY_VERSION' ) ) { define( 'BUDDY_VERSION', '0.1.1' ); }
if ( ! defined( 'BUDDY_VERSION' ) ) { define( 'BUDDY_VERSION', '0.1.3' ); }
if ( ! defined( 'BUDDY_FILE' ) ) { define( 'BUDDY_FILE', __FILE__ ); }
if ( ! defined( 'BUDDY_PATH' ) ) { define( 'BUDDY_PATH', plugin_dir_path( __FILE__ ) ); }
if ( ! defined( 'BUDDY_URL' ) ) { define( 'BUDDY_URL', plugin_dir_url( __FILE__ ) ); }
+5 -1
View File
@@ -98,7 +98,11 @@ function buddy_render_about_page() {
<h2><?php esc_html_e( 'Version history', 'buddy' ); ?></h2>
<ul>
<li>
<span class="ver">v0.1.1</span> &mdash; 25 May 2026 <span class="latest">latest</span><br>
<span class="ver">v0.1.2</span> &mdash; 26 May 2026 <span class="latest">latest</span><br>
<?php esc_html_e( 'Wink, tuned. The Easter-egg wink from v0.1.1 was firing at 30% per render — felt closer to "stuck" than "playful". Dropped to 5%: same cheeky face when it lands, just rare enough to feel like a treat.', 'buddy' ); ?>
</li>
<li>
<span class="ver">v0.1.1</span> &mdash; 25 May 2026<br>
<?php esc_html_e( 'Cheeky face! New wink expression that occasionally appears when Buddy is in a good mood — one eye closed, asymmetric smirk, rosier cheeks. Pure SVG, no image files. Proof that the expression engine is properly extensible.', 'buddy' ); ?>
</li>
<li>
+10 -10
View File
@@ -8,8 +8,10 @@
* dog / dragon / sprite / etc.
*
* Mood tone changes the expression: 'happy' = open smile, 'neutral'
* = flat mouth, 'sad' = downturned. Eyes blink via CSS keyframes
* regardless of tone (it's always alive).
* = flat mouth, 'sad' = downturned, 'wink' = asymmetric smirk + rosier
* cheeks + CSS-driven left-eye wink animation. Eyes blink via CSS
* keyframes regardless of tone (it's always alive); the wink keyframe
* lives in buddy.css alongside the regular blink.
*/
if ( ! defined( 'ABSPATH' ) ) { exit; }
@@ -45,18 +47,16 @@ function buddy_render_sprite( $species = 'default', $tone = 'happy', $size = 'md
aria-label="<?php echo esc_attr( sprintf( __( 'Buddy is %s', 'buddy' ), $tone ) ); ?>">
<!-- body -->
<circle cx="50" cy="55" r="32" fill="<?php echo esc_attr( $body_fill ); ?>" stroke="#c9941d" stroke-width="2" />
<!-- left eye -->
<!-- left eye — always an open circle in the SVG. When the
tone is 'wink', the buddy-sprite--wink class on the parent
triggers a CSS keyframe animation (buddyWink in buddy.css)
that briefly closes this eye every couple of seconds.
That way the wink is a transient action, not a stuck state. -->
<g class="buddy-sprite__eye buddy-sprite__eye--left">
<?php if ( $tone === 'wink' ) : ?>
<!-- Closed left eye for a wink: a downward curved line below the eye-circle's normal y. -->
<path d="M 35 46 Q 40 50 45 46"
stroke="#2c3338" stroke-width="2.4" fill="none" stroke-linecap="round" />
<?php else : ?>
<circle cx="40" cy="46" r="5" fill="#2c3338" />
<circle cx="41.2" cy="45" r="1.5" fill="#fff" />
<?php endif; ?>
</g>
<!-- right eye (always open, even during wink) -->
<!-- right eye always open, normal slow blink even during wink -->
<g class="buddy-sprite__eye buddy-sprite__eye--right">
<circle cx="60" cy="46" r="5" fill="#2c3338" />
<circle cx="61.2" cy="45" r="1.5" fill="#fff" />
+5 -4
View File
@@ -106,12 +106,13 @@ function buddy_overall_mood( array $state ) {
* admin page.
*
* Easter-egg: when Buddy is genuinely happy (mood >= 75) there's a
* ~30% chance per page-render of returning the "Cheeky" wink tone
* instead of the standard happy face. Gives the pet a touch of
* personality — refresh the page enough and you'll catch the wink.
* ~5% chance per page-render of returning the "Cheeky" wink tone
* instead of the standard happy face. Rare enough to feel magical
* rather than disturbing — refresh the page a few dozen times and
* you'll catch it.
*/
function buddy_mood_label( $mood_score ) {
if ( $mood_score >= 75 && mt_rand( 1, 100 ) <= 30 ) {
if ( $mood_score >= 75 && mt_rand( 1, 100 ) <= 5 ) {
return array( 'label' => __( 'Cheeky 😉', 'buddy' ), 'tone' => 'wink' );
}
if ( $mood_score >= 80 ) { return array( 'label' => __( 'Thriving', 'buddy' ), 'tone' => 'happy' ); }