Within a clearing round the matched gems no longer all explode at once: each
gem's pop (and its burst) START is offset by a bounded per-gem delay so the
cells detonate as a ripple.
- board_anim.sx: clear_ripple_t(t,u) mirrors fall_stagger_t's (t-delay)/window,
delaying a gem's pop START by CLEAR_STAGGER_MAX*u (0.45 of the clear window).
Bounded: every gem still reaches local 1 (scale 0) by t==1, so none is left
mid-pop at the seam to the fall. clear_diag_span/clear_rank rank each matched
gem 0..1 by diagonal (col+row) PER ROUND, so even a 3-match ripples across the
full budget.
- board_view.sx render_clear: feed each matched gem's ranked, staggered local t
through the P18.1 clear_pop_scale (locked endpoints unchanged).
- board_fx.sx: bursts carry the same per-gem delay so they ripple in lockstep
with the pops. Per-round audio cue (P10.10) still fires once at t0, not per gem.
- Model untouched (same cells cleared, same final board); CLEAR_ANIM_DUR fixed,
so cascade-cue snapshots don't churn and M3TE_ANIM_TIME=0 still rests.
- tests/easing.sx: pin clear_ripple_t endpoints, bounded completion by t==1,
monotonicity, ripple ordering, and the diagonal rank.
- goldens: add p18_stagger (M3TE_FX=3 @ 0.22); refresh p18_pop, p6_fx_match,
p11_combo_deep (all pinned mid-clear, now showing the ripple).
Integration-only (no logic changes). Validated the full candy vibe in the booted
iPhone sim and brought every artifact in line with the shipped candy palette +
Triple Treat SFX bank.
Goldens — swept all 23:
- Refreshed 15 that predated the candy palette (P12): p6_idle_t0, p6_idle_mid,
p6_select, p7_restart, p5_swap_before/after, p6_anim_swap/clear/fall/after,
p6_fx, p6_fx_after, p6_fx_match, p6_inputlock_board, p11_combo_deep — re-captured
via the documented M3TE_* hooks.
- Left 5 unchanged (board+HUD region byte-identical to the current build, verified
by cropped-region hash): p4_board, p4_hud, p9_polish, p7_win, p7_lose.
- Removed 3 obsolete pre-board orange-quad goldens (app no longer renders them):
p0_quad, p0_input_before, p0_input_after.
Docs — README.md:
- Section 2 now describes the candy board (not the old orange quad) and points at
goldens/p6_idle_t0.png; dropped the removed p0_* references.
- Added the final audio model: Triple Treat SFX provenance + per-cue mapping, the
per-round ascending cascade (one combo cue per round, clamped at combo5), the
WAVE/mono/44100/Int16 @ -15 dBFS format spec, and the cue-log capture commands.
- Added image-art asset regeneration (codex imagegen via codex exec + sips
normalize to exact per-asset dims/format).
Gate: ios-sim build links (exit 0); 21/21 pure-sx logic tests pass. Playthrough
evidence (cue NSLog ascending combo1..combo5 + win/lose stingers, screenshots)
captured in the worker report.
Scale the combo FX with cascade depth (mv.rounds.len) — the same depth the
cascade SFX (play_cascade) steps up on — so deeper cascades read as more
exciting and land in lockstep with the audio escalation. Purely visual and
self-pruning: no board / score / move state changes, and input stays gated by
BoardAnim.active alone.
- board_fx.sx: add fx_combo_level (mirrors audio's cascade_cue_index clamp:
depth<=1 -> floor, depth>=5 -> ceiling). The +points popup now carries the
cascade depth and grows one font step + lerps gold -> hot-gold per level
(fx_popup_font / fx_popup_color). Every burst of a deep cascade gets a
whole-move depth boost (FX_BURST_DEPTH) on top of the existing per-round bump.
- board_view.sx: render_fx_popups derives styling from depth and tops a combo
with a "COMBO xN" label naming the true cascade depth.
- tests/fx_combo.sx: headless snapshot locking the depth->level/font table and
asserting fx_combo_level matches the cascade-cue index column entry-for-entry.
- goldens/p11_combo_deep.png + README: deterministic depth-5 capture (M3TE_FX=11)
vs the depth-1 single clear (M3TE_FX=3); FX gone after settle at a later phase.