PURPOSE

Implements the “car show” weapon-chest reveal cinematic. Three weapon-choice cards are revealed one at a time under sweeping stage spotlights against a full blackout backdrop, with silhouettes crossfading to fully-rendered cards as each spotlight fires. Drives sparkle bursts, lens flares, cone lighting, and audio cues across the reveal opening window.

OWNS

  • Module-local elapsed clock (_elapsed) and arming flag (_clockArmed) that drives activation cue timing independent of game time (which freezes during level-up).
  • Per-card activation state arrays _activated and _activatedAt (three slots).
  • Bounded sparkle particle pool _sparkles (capped at MAX_SPARKLES).
  • The exported weaponChestModule CinematicModule definition with id 'weapon-chest'.
  • Tunables for activation timing, flash/hold/fade durations, sparkle counts, silhouette colors, blackout alpha, and idle shimmer rate.
  • Helpers for sparkle bursts, idle shimmer spawn, particle simulation, rounded-rect path, spotlight cone rendering, and lens flare rendering.

READS FROM

  • CinematicContext and CinematicModule types from ./registry.
  • playCinematicTone from ./audio (plays 'cheer' and 'sparkle' tones).
  • setSlotIntroDuration from ../hud (shrinks the slot intro window so the reveal does not over-hold).
  • SampleSfx.playWeaponChestOpen from ../../audio/sample-sfx (chest-open stinger on reveal start).
  • isSkipRewardAnimations from ../../core/config/_accessibility (gates the entire animation; skip mode pre-activates all three slots and shrinks slot intro to 0.05s).
  • Per-frame ctx.dt, ctx.state, ctx.choices.length, ctx.W, ctx.H, ctx.cardW, ctx.cardH.

PUSHES TO

  • The canvas CanvasRenderingContext2D passed via drawBackdrop, drawCardOverride, and drawOverlay — paints blackout wash, horizon gradient, vignette, silhouette card placeholders, radial spotlight cones (using 'lighter' composite), lens flare streaks, and sparkle particles.
  • setSlotIntroDuration to retune the slot_intro state budget at reveal start.
  • Audio via SampleSfx.playWeaponChestOpen and playCinematicTone('cheer' | 'sparkle') on each activation.
  • drawCardOverride returns true while a slot is still in silhouette to suppress hud.ts’s default card paint, and false once activated to hand painting back.

DOES NOT

  • Does not own the choice-card layout math — it mirrors hud.ts’s three-card-centered formula in _cardCenter only to seed particle bursts, and uses the x/y/w/h args hud.ts passes into drawCardOverride for the silhouette path.
  • Does not run during the announce state’s backdrop pass — the placeholder pop-ins sit under only the hud’s default dim so all four cinematics share the same intro look.
  • Does not subtract ctx.time from a captured start timestamp — game time freezes during level-up, so timing accumulates from ctx.dt.
  • Does not drive activations from ctx.stateTimer — the three cues span slot_intro through shine and are timed against the module-local _elapsed clock instead.
  • Does not exceed the 60-particle budget — _spawnSparkleBurst and _spawnIdleShimmer both check _sparkles.length against MAX_SPARKLES.
  • Does not keep spotlights lit forever — each cone runs flash → hold → fade then is skipped, so the revealed weapon stands on its own.

Signals

  • weaponChestModule.id — string identifier 'weapon-chest' consumed by the cinematics registry.
  • weaponChestModule.onStart — resets module-local state, plays the chest-open stinger, retunes slot_intro to 1.3s (or 0.05s in skip mode).
  • weaponChestModule.onUpdate — arms the clock after the announce state, accumulates _elapsed, fires pending activations when their cue time is reached, spawns idle shimmer during showing.
  • weaponChestModule.drawBackdrop — paints fullscreen blackout, horizon gradient, and vignette on every non-announce frame.
  • weaponChestModule.drawCardOverride — returns true to paint a silhouette rounded-rect while a slot is unactivated, false once activated to hand painting back to hud.ts.
  • weaponChestModule.drawOverlay — paints per-activated-card spotlight cones with flash/hold/fade strength curve, lens flare during the flash window, and the sparkle particle layer on top.
  • weaponChestModule.onEnd — resets module-local state.

Entry points

  • weaponChestModule (named export) — consumed by the cinematics registry; not invoked directly by other modules.
  • The six lifecycle hooks attached to the module (onStart, onUpdate, drawBackdrop, drawCardOverride, drawOverlay, onEnd) are invoked by the cinematics dispatcher driven from hud.ts.

Pattern notes

  • All visible numeric tunables sit at the top of the file in a single block (activation cue times, flash/hold/fade durations, sparkle counts, lifetime, blackout alpha, silhouette colors, shimmer rate).
  • Activations are anchored to reveal-start rather than per-state timers so retuning individual hud.ts state budgets does not desync the cue sequence, provided cues fall within the ~1.35s opening window.
  • The clock is gated by an _clockArmed flag that flips on the first non-announce frame; this keeps activation timing aligned with when cards first become visible.
  • Spotlight strength uses a piecewise curve: ease-out flash pulse (1.8 → 1.0 over FLASH_DURATION_S), steady hold at 1.0 for SPOTLIGHT_HOLD_S, linear fade to 0 over SPOTLIGHT_FADE_S, then skipped.
  • Spotlight cones use radial gradients with 'lighter' compositing and a radius of max(cardW, cardH) * 0.58 so each card gets a contained spotlight that does not bleed into neighbors (a prior cone-rect version overlapped adjacent cards).
  • Sparkle bursts mix warm-yellow and cool-white particles (~65% warm), use a slight upward bias for stage-light fall feel, and apply gravity plus per-axis air drag during simulation.
  • Bigger sparkles render a four-point star with cross strokes; all sparkles draw under globalCompositeOperation = 'lighter' for additive glow.
  • Idle shimmer during showing uses a Poisson-style per-frame probability (SHIMMER_SPAWN_CHANCE_PER_SEC * ctx.dt) on already-activated slots.
  • Skip-rewards accessibility mode short-circuits every hook — onStart pre-activates all slots, and onUpdate/drawBackdrop/drawCardOverride/drawOverlay early-return so hud.ts paints unmodified cards immediately.
  • The _cardCenter helper duplicates hud.ts’s three-card layout math (gap = cardW * 0.12) for particle spawns outside the per-card loop; inside drawCardOverride the hud-provided x/y/w/h are used directly to avoid drift.
  • playCinematicTone('cheer') and playCinematicTone('sparkle') are layered on each activation so the chime has a sharper attack stacked on the cheer.