P16.1: organic legal swap — overshoot/settle (ease_out_back)
Replace the legal swap's flat ease_out_cubic decelerating slide with the P15.1 ease_out_back overshoot curve: the two swapped gems shoot ~10% PAST their target cells, then settle exactly onto them. Purely visual — the curve pins f(0)=0 / f(1)=1, so t==0 is the rest pose and t==1 lands byte-on-cell; the committed move and final board are unchanged. SWAP_ANIM_DUR (0.16 s) is untouched, so the cascade-cue timing snapshots do not churn. Only the legal branch of render_swap changes; the illegal ping-back is left as-is for P16.2. Model/logic untouched (FFI is the only non-sx surface). Golden goldens/p16_swap.png: M3TE_FX=3 (top-row swap (5,0)<->(6,0)) pinned at M3TE_ANIM_TIME=0.10 (swap-phase t~0.625, near the overshoot peak). Measured against calibrated cell centers: the red lands ~8% left of col-5 and the green ~12% right of col-6 (both PAST target), while every unswapped gem stays centered; at M3TE_ANIM_TIME=0 the same gems sit dead-on their pre-swap cells. Gate: `sx build --target ios-sim main.sx` links clean; `tools/run_tests.sh` 22/22 (anim_plan, easing, cascade_rounds, cascade_cue all green).
This commit is contained in:
26
README.md
26
README.md
@@ -214,6 +214,32 @@ env SIMCTL_CHILD_M3TE_ANIM_TIME=0 SIMCTL_CHILD_M3TE_SELECT=27 \
|
||||
The selection gloss is purely visual: it never gates input (`BoardAnim.active`
|
||||
owns gating) and never touches board / score / move state.
|
||||
|
||||
### Organic swap motion (P16.1)
|
||||
|
||||
A legal swap no longer slides flatly into place: `render_swap` drives the two
|
||||
gems with `ease_out_back` (the P15.1 overshoot curve), so they shoot a touch PAST
|
||||
their target cells then settle exactly onto them. The curve pins `f(0)=0` and
|
||||
`f(1)=1`, so the swap stays purely visual — `t==0` is the rest pose and `t==1`
|
||||
lands byte-on-cell; the committed move and final board are unchanged. The reused
|
||||
`SWAP_ANIM_DUR` (0.16 s) is untouched, so the cascade-cue timing snapshots
|
||||
(`tests/cascade_rounds.sx` / `cascade_cue.sx`) don't churn.
|
||||
|
||||
Capture the overshoot with the same `M3TE_FX` hook, pinned near the peak
|
||||
(swap-phase `t ≈ 0.625`, where the gems are ~10 % past target):
|
||||
|
||||
```bash
|
||||
# Swapped gems caught PAST their target cells (overshoot): goldens/p16_swap.png
|
||||
env SIMCTL_CHILD_M3TE_FX=3 SIMCTL_CHILD_M3TE_ANIM_TIME=0.10 \
|
||||
xcrun simctl launch --terminate-running-process booted co.swipelab.m3te
|
||||
# Same swap at exact rest (t=0) — gems sit dead-on their pre-swap cells:
|
||||
env SIMCTL_CHILD_M3TE_FX=3 SIMCTL_CHILD_M3TE_ANIM_TIME=0 \
|
||||
xcrun simctl launch --terminate-running-process booted co.swipelab.m3te
|
||||
```
|
||||
|
||||
`M3TE_FX=3` is the top-row swap `(5,0)↔(6,0)` that completes the vertical red
|
||||
3-match in column 5; at `M3TE_ANIM_TIME=0.10` the red lands ~8 % left of col-5
|
||||
and the green ~12 % right of col-6 (every unswapped gem stays centered).
|
||||
|
||||
## Audio bank (P10) — final model
|
||||
|
||||
The SFX bank (`audio.sx`) is a purely additive layer over iOS **System Sound
|
||||
|
||||
@@ -415,7 +415,11 @@ BoardView :: struct {
|
||||
|
||||
p : f32 = ---;
|
||||
if mv.legal {
|
||||
p = ease_out_cubic(t);
|
||||
// Overshoot-and-settle: the two gems shoot a touch PAST their target
|
||||
// cells, then settle exactly onto them, instead of decelerating flatly
|
||||
// into place. ease_out_back pins f(0)=0 and f(1)=1, so t==0 is the rest
|
||||
// pose and t==1 lands byte-on-cell — the swap stays purely visual.
|
||||
p = ease_out_back(t);
|
||||
} else if t < 0.5 {
|
||||
p = ease_out_cubic(t * 2.0);
|
||||
} else {
|
||||
|
||||
BIN
goldens/p16_swap.png
Normal file
BIN
goldens/p16_swap.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.2 MiB |
Reference in New Issue
Block a user