Skip to content

Add a 'task complete' chime on entering celebrate state#15

Open
SnowWarri0r wants to merge 1 commit into
anthropics:mainfrom
SnowWarri0r:feat/celebrate-chime
Open

Add a 'task complete' chime on entering celebrate state#15
SnowWarri0r wants to merge 1 commit into
anthropics:mainfrom
SnowWarri0r:feat/celebrate-chime

Conversation

@SnowWarri0r
Copy link
Copy Markdown

@SnowWarri0r SnowWarri0r commented May 9, 2026

Why

The P_CELEBRATE state drives the GIF animation when a turn completes (or on level-up via triggerOneShot), but it's silent. If you're looking at another screen when the buddy starts dancing, you miss it entirely — the visual cue is the only signal.

What

Two-note ascending chime on the transition into P_CELEBRATE, gated by an edge-triggered check on activeState. Note 2 is scheduled via millis() because M5.Beep.tone() is one-at-a-time — calling it twice in the same tick stomps the first note.

static PersonaState prevActiveState = P_SLEEP;
static uint32_t chimeNote2At = 0;
if (activeState == P_CELEBRATE && prevActiveState != P_CELEBRATE) {
  beep(2000, 100);
  chimeNote2At = now + 130;
}
if (chimeNote2At && (int32_t)(now - chimeNote2At) >= 0) {
  beep(2800, 150);
  chimeNote2At = 0;
}
prevActiveState = activeState;

Inserted right after activeState resolves for this tick, so it covers both code paths into celebrate:

  1. baseState == P_CELEBRATE driven by recentlyCompleted from the heartbeat (bridge / desktop app)
  2. triggerOneShot(P_CELEBRATE, 3000) from statsPollLevelUp()

Design choices

Two notes, not one The existing single-tone palette (600 Hz deny / 1200 prompt / 1800 cycle / 2400 approve) is dense; a single tone risks sounding like button feedback. An ascending two-note chime is the universal "ta-da" cue for "task complete".
2000 Hz → 2800 Hz Both new — neither collides with the existing palette. 1.4× ratio reads as "lift" rather than melodic, fitting a short success cue.
100 ms + 130 ms gap + 150 ms Total ~380 ms, brief enough to not feel intrusive, long enough that the second note registers as distinct rather than a glitch on the first.
Edge-triggered on activeState One chime per celebrate session (5 s default), not one per loop tick. Catches the level-up triggerOneShot path and the bridge recentlyCompleted path uniformly.
Routes through beep() Existing settings().sound toggle gates the entire chime (both notes). No new opt-out machinery.

Testing

Flashed on M5StickC Plus (pio run -t upload) and verified live via the Claude Code CLI bridge:

  • ✅ Two-note chime fires on every turn-complete heartbeat from the bridge
  • ✅ Audibly distinct from the existing 2400 Hz approve confirm — no sonic conflation
  • ✅ Animation and chime fire together as a paired audio+visual cue

Edge cases not exercised in this session but covered by the structure:

  • Silent operation when Settings → Sound = off (both notes route through beep() which gates on this)
  • No re-trigger if triggerOneShot lands while recentlyCompleted is already setting baseState = P_CELEBRATE (single edge transition per celebrate window)

🤖 Generated with Claude Code

P_CELEBRATE drives the GIF animation (turn-complete from the desktop
app / CLI bridge, plus level-up via triggerOneShot), but is silent —
miss the screen, miss the cue.

Two-note ascending chime (2000 Hz → 2800 Hz, the universal "ta-da" of
completion sounds) on the activeState edge into P_CELEBRATE. Picked
this over a single-tone beep because the existing palette (600 deny /
1200 prompt / 1800 cycle / 2400 approve) is dense — any single tone
risks sounding like a button confirmation rather than a state event.

Note 2 is scheduled via millis() because M5.Beep.tone() is
one-at-a-time: calling it twice in the same tick stomps the first
note. Routes through beep() so settings().sound still gates everything.

Edge-triggered (`prev != cur`) so we get one chime per celebrate
session, not one per loop tick.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant