P17.2: organic fall — per-column stagger (cascade pour)

render_fall now offsets each COLUMN's drop START by a small bounded delay
(fall_stagger_t) so a refilled/collapsed row pours in as a left-to-right cascade
instead of every gem snapping down in one flat lockstep row. Column col waits
FALL_STAGGER_MAX (0.30) * col/7 of the fall window, then falls over the remaining
1 - 0.30, with that local progress fed through ease_in_cubic so each column still
accelerates under gravity within its own window.

Bounded by construction: the last column lands EXACTLY at t=1 and every earlier
column strictly before it, so no gem is ever left mid-air at the segment end — the
seam to the next round / settled board stays invisible and move.final is untouched.

FALL_ANIM_DUR (0.22s) and the timeline helpers (phase/total/cascade_rounds_started)
are unchanged, so the per-round cascade-cue timing snapshots don't churn and live
per-round audio is unaffected. Render-only — no board.sx model change.

tests/easing.sx pins fall_stagger_t: f(0)=0, f(1)=1 across all columns (no gem
unlanded), per-column monotonicity, and the mid-fall cascade ordering (each later
column strictly behind the one before). tests/anim_plan.sx (final==model,
contiguity) stays green.

Golden goldens/p17_stagger.png: M3TE_FX=11 (depth-5 cascade, seed 1337) pinned at
M3TE_ANIM_TIME=1.91 — round 4 refills columns 2-7 by one cell each, so the top row
reads as a left-to-right staircase (vs the pre-stagger flat row in p17_fall.png).
This commit is contained in:
swipelab
2026-06-06 11:35:36 +03:00
parent 8d4e7acd2b
commit 02d856275c
6 changed files with 98 additions and 3 deletions

View File

@@ -309,6 +309,41 @@ swap→(clear,fall)\* timeline (swap 0.16, then clear 0.14 + fall 0.22 per round
`1.51` lands squarely in round 3's fall. The change is render-only — no `board.sx`
model change, and normal play is byte-identical apart from the fall's motion curve.
### Organic fall — per-column stagger (P17.2)
The fall no longer drops a whole row in lockstep: `render_fall` offsets each
COLUMN's drop START by a small bounded delay (`fall_stagger_t`), so a refilled row
pours in as a left-to-right cascade. Column `col` waits `FALL_STAGGER_MAX·col/7`
(`FALL_STAGGER_MAX = 0.30`) of the fall window, then falls over the remaining
`1 - 0.30`, feeding that local progress through `ease_in_cubic` so each column still
accelerates under gravity within its own window. The LAST column lands EXACTLY at
`t=1` and every earlier column strictly before it, so NO gem is ever left mid-air at
the segment end — the seam to the next round / settled board stays invisible and
`move.final` is untouched (`tests/anim_plan.sx` contiguity stays green;
`tests/easing.sx` pins `fall_stagger_t`'s `f(0)=0`, `f(1)=1`, monotonicity, and the
mid-fall cascade ordering). `FALL_ANIM_DUR` (0.22 s) is unchanged, so the per-round
cascade-cue snapshots don't churn.
The cleanest tell is a round where several adjacent columns refill the SAME
distance: in lockstep their gems share one height (a flat row); staggered, they
form a diagonal. On seed 1337, `M3TE_FX=11` **round 4** refills columns 27 by one
cell each (its fall window `[1.74, 1.96)` s); at `1.91` the leading column has just
landed while the trailing column is still ~⅔ cell high, so the top row reads as a
left-to-right staircase instead of a flat band (contrast `goldens/p17_fall.png`,
which is pre-stagger lockstep):
```bash
# Refilled row pouring in as a staggered cascade: goldens/p17_stagger.png
env SIMCTL_CHILD_M3TE_FX=11 SIMCTL_CHILD_M3TE_ANIM_TIME=1.91 \
xcrun simctl launch --terminate-running-process booted co.swipelab.m3te
# Same cascade past the timeline — every gem landed exactly on the model board:
env SIMCTL_CHILD_M3TE_FX=11 SIMCTL_CHILD_M3TE_ANIM_TIME=3.0 \
xcrun simctl launch --terminate-running-process booted co.swipelab.m3te
```
The change is render-only — no `board.sx` model change, and normal play is
byte-identical apart from the fall's per-column timing.
## Audio bank (P10) — final model
The SFX bank (`audio.sx`) is a purely additive layer over iOS **System Sound