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
_activatedand_activatedAt(three slots). - Bounded sparkle particle pool
_sparkles(capped atMAX_SPARKLES). - The exported
weaponChestModuleCinematicModuledefinition 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
CinematicContextandCinematicModuletypes from./registry.playCinematicTonefrom./audio(plays'cheer'and'sparkle'tones).setSlotIntroDurationfrom../hud(shrinks the slot intro window so the reveal does not over-hold).SampleSfx.playWeaponChestOpenfrom../../audio/sample-sfx(chest-open stinger on reveal start).isSkipRewardAnimationsfrom../../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
CanvasRenderingContext2Dpassed viadrawBackdrop,drawCardOverride, anddrawOverlay— paints blackout wash, horizon gradient, vignette, silhouette card placeholders, radial spotlight cones (using'lighter'composite), lens flare streaks, and sparkle particles. setSlotIntroDurationto retune theslot_introstate budget at reveal start.- Audio via
SampleSfx.playWeaponChestOpenandplayCinematicTone('cheer' | 'sparkle')on each activation. drawCardOverridereturnstruewhile a slot is still in silhouette to suppress hud.ts’s default card paint, andfalseonce 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
_cardCenteronly to seed particle bursts, and uses thex/y/w/hargs hud.ts passes intodrawCardOverridefor the silhouette path. - Does not run during the
announcestate’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.timefrom a captured start timestamp — game time freezes during level-up, so timing accumulates fromctx.dt. - Does not drive activations from
ctx.stateTimer— the three cues spanslot_introthroughshineand are timed against the module-local_elapsedclock instead. - Does not exceed the 60-particle budget —
_spawnSparkleBurstand_spawnIdleShimmerboth check_sparkles.lengthagainstMAX_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, retunesslot_introto 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 duringshowing.weaponChestModule.drawBackdrop— paints fullscreen blackout, horizon gradient, and vignette on every non-announce frame.weaponChestModule.drawCardOverride— returnstrueto paint a silhouette rounded-rect while a slot is unactivated,falseonce 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
_clockArmedflag 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 forSPOTLIGHT_HOLD_S, linear fade to 0 overSPOTLIGHT_FADE_S, then skipped. - Spotlight cones use radial gradients with
'lighter'compositing and a radius ofmax(cardW, cardH) * 0.58so 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
showinguses 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 —
onStartpre-activates all slots, andonUpdate/drawBackdrop/drawCardOverride/drawOverlayearly-return so hud.ts paints unmodified cards immediately. - The
_cardCenterhelper duplicates hud.ts’s three-card layout math (gap =cardW * 0.12) for particle spawns outside the per-card loop; insidedrawCardOverridethe hud-providedx/y/w/hare used directly to avoid drift. playCinematicTone('cheer')andplayCinematicTone('sparkle')are layered on each activation so the chime has a sharper attack stacked on the cheer.