P18.2: organic combine — staggered clear ripple (sx, iOS sim)

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).
This commit is contained in:
swipelab
2026-06-06 13:20:52 +03:00
parent 70a69864c1
commit 5eaf91b22d
10 changed files with 161 additions and 8 deletions

View File

@@ -413,10 +413,52 @@ env SIMCTL_CHILD_M3TE_FX=3 SIMCTL_CHILD_M3TE_ANIM_TIME=0 \
```
`goldens/p6_fx_match.png` (the P11.1 burst+popup reference, pinned at `0.22`) was
refreshed for the new pop shape. The per-gem STAGGER of the explosions is the next
step (P18.2); this step is the per-gem pop SHAPE only. The change is render-only —
no `board.sx` model change, and normal play is byte-identical apart from the clear's
pop curve.
refreshed for the new pop shape. This step is the per-gem pop SHAPE only; the per-gem
STAGGER of the explosions follows in P18.2. The change is render-only — no `board.sx`
model change, and normal play is byte-identical apart from the clear's pop curve.
### Organic combine — staggered clear ripple (P18.2)
The matched gems no longer all explode at once: within a clearing round each gem's
pop (and its burst) START is offset by a small BOUNDED delay so the cells detonate
as a RIPPLE. `clear_ripple_t(t, u)` mirrors `fall_stagger_t`'s `(t-delay)/window`:
a gem's normalized rank `u ∈ [0,1]` (its diagonal `col+row` position within the
round's matched cells, lowest = `0`) delays its pop START by `CLEAR_STAGGER_MAX·u`
(`0.45` of the clear window), then plays the P18.1 `clear_pop_scale` curve over the
remaining `1 CLEAR_STAGGER_MAX`. The rank is normalized PER ROUND (not across the
board) so even a 3-match ripples across the full stagger budget. It is BOUNDED:
every matched gem still reaches local `1` (scale `0`, fully cleared) by the clear
segment's end — the last-to-start gem (`u=1`) lands exactly at `t==1` — so no gem is
left mid-pop at the seam to the fall. The bursts (`board_fx.sx`) carry the SAME
per-gem delay so they ripple in lockstep with the pops. `tests/easing.sx` pins the
envelope (locked `f(0,·)=0` / `f(1,·)=1` endpoints, bounded completion by `t==1`,
monotonicity, and the rank ordering).
INTRA-ROUND VISUAL ONLY: the per-round cascade audio (P10.10) is untouched — one
ascending cue per round at the round's clear, NOT per gem — and the model is
unchanged (same cells cleared, same final board). `CLEAR_ANIM_DUR` (`0.14` s) is
unchanged, so the cascade-cue snapshots (`tests/cascade_rounds.sx` / `cascade_cue.sx`)
don't churn and `M3TE_ANIM_TIME=0` still reproduces the resting board.
For `M3TE_FX=3` (the seed-1337 vertical red 3-match in column 5, rows 02) the clear
window is `[0.16, 0.30)` s; at `M3TE_ANIM_TIME=0.22` the ripple is at its clearest —
the TOP gem is collapsing, the MIDDLE is mid-burst, and the BOTTOM is still full-size
(not yet started):
```bash
# Staggered clear ripple (top collapsing / middle bursting / bottom not yet):
# goldens/p18_stagger.png
env SIMCTL_CHILD_M3TE_FX=3 SIMCTL_CHILD_M3TE_ANIM_TIME=0.22 \
xcrun simctl launch --terminate-running-process booted co.swipelab.m3te
# Past the timeline — all three cells cleared per the model, board continues:
env SIMCTL_CHILD_M3TE_FX=3 SIMCTL_CHILD_M3TE_ANIM_TIME=2.0 \
xcrun simctl launch --terminate-running-process booted co.swipelab.m3te
```
`goldens/p18_pop.png` (`M3TE_FX=3` at `0.21`), `goldens/p6_fx_match.png` (`M3TE_FX=3`
at `0.22`), and `goldens/p11_combo_deep.png` (`M3TE_FX=11` at `0.22`) were refreshed
— each was pinned mid-clear, so each now shows the staggered ripple instead of the
prior simultaneous pop.
### FPS counter — dev overlay (P20.1)