my-sea voice: voice-btn glow/pulse state machine (sea-precedence, pulse-while-alone, 2x on 2nd party) — TDD

Phase 3 of the my-sea voice batch (user-spec 2026-05-29). A --quaUser/--ninUser
glow + pulse machine for the burger btn + its voice sub-btn, driven by the
voice sub-btn availability (voice_active) + the live mesh state.

- voice-mesh.js: VoiceRoom gains a state-change hook — setOnStateChange(cb) +
  peerCount() + _notify({inCall, peerCount, muted}), fired on join, every peer
  add/drop, mute toggle, and teardown. No behaviour change without a subscriber
  (VoiceMeshSpec stays green).
- voice-glow.js (new): the glow machine. PRE-JOIN nudge — burger glows when the
  fan is closed (sea draw-nudge keeps burger precedence; voice reclaims it once
  the sea glow clears), voice sub-btn glows when the fan opens. LIVE — the glow
  PULSES on whichever surface shows (voice sub-btn fan-open, burger fan-closed):
  base 2s cadence while alone, doubled (.voice-pulse--fast) once a 2nd party
  connects (equalizer stand-in; a true volume-reactive equalizer is a live-only
  enhancement). Class writes are reconciled (idempotent) so the burger-class
  MutationObserver doesn't feed back on itself.
- _burger.scss: .voice-glow + @keyframes voice-pulse + .voice-pulse(--fast).
- loaded on my_sea.html + my_sea_visit.html (after burger-btn.js).
- VoiceGlowSpec.js (18 specs) + registered in SpecRunner; MySeaSeatsSpec flare
  window updated 1.5s → 2s (Phase 2 bump). 428 Jasmine specs green.

Live-verify on staging: the actual glow colours/cadence + the equalizer
upgrade (item 5) and disconnect states (item 7) land in later phases.

Code architected by Disco DeDisco <discodedisco@outlook.com>
Git commit message Co-Authored-By:
Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Disco DeDisco
2026-05-29 21:06:02 -04:00
parent 7bd8e3256a
commit b021d8017c
11 changed files with 519 additions and 2 deletions

View File

@@ -43,11 +43,14 @@ describe('my-sea-seats one-shot seated glow', function () {
expect(seat.classList.contains('seat-just-seated')).toBe(true);
});
it('removes the flare class after the ~1.5s glow window', function () {
it('removes the flare class after the 2s glow window', function () {
jasmine.clock().install();
window.playSeatGlow(seat);
expect(seat.classList.contains('seat-just-seated')).toBe(true);
// Still flaring mid-window (bumped 1.5s → 2s, user-spec 2026-05-29).
jasmine.clock().tick(1600);
expect(seat.classList.contains('seat-just-seated')).toBe(true);
jasmine.clock().tick(500);
expect(seat.classList.contains('seat-just-seated')).toBe(false);
jasmine.clock().uninstall();
});