Mechanical sweep of all .sx sources, plan docs, and tests/expected
snapshots for the sx language rename (s8/s16/s32/s64 -> i8/i16/i32/i64).
Verified: tools/run_tests.sh 23/23.
Note: the ios-sim build has 2 pre-existing 'restart' dot-call errors
from the sx opt-in UFCS change (sx a47ea14) — independent of this
rename (present pre-sweep); migrated in the follow-up commit.
Drop the ':' before captures (for xs (x) / for 0..n (i)); the index
capture becomes the trailing open range (for xs, 0.. (x, i)). 136
headers across 26 files, mechanical.
Five headless tests (banner_layout, hit_test, swipe_commit,
swipe_intent, swipe_reshuffle) also gain a direct
#import "modules/ui/types.sx" — they named Point/Frame through a
transitive import, which bare visibility no longer permits.
Gates: sx build --target ios-sim main.sx links; tools/run_tests.sh
23/23.
Sharpen clear_pop_scale from a plain pop-then-shrink into a candy pop in
three beats over its local 0..1: a tiny anticipation squash dip (~8% below
rest), a snappy overshoot to ~1.40x via P15.1's ease_out_back, then an
accelerating collapse to nothing (ease_in_quad). Endpoints stay locked
(t=0 -> 1.0 rest, t=1 -> 0.0 gone), so the seam to the model board is clean
and M3TE_ANIM_TIME=0 still reproduces the rest board; the particle burst /
score popup compose on top unchanged. render_clear and CLEAR_ANIM_DUR are
untouched, so cascade-cue timing snapshots don't churn and the model is
unchanged.
tests/gem_pose.sx now pins the new envelope (locked rest endpoints, the
anticipation dip, the overshoot, the monotonic post-peak collapse) with its
expected snapshot updated.
goldens/p18_pop.png: new mid-clear pop golden at the overshoot peak
(M3TE_FX=3 M3TE_ANIM_TIME=0.21). goldens/p6_fx_match.png refreshed for the
new pop shape (same scene at its documented 0.22). README documents P18.1.
The restart button (BoardView.do_restart) reseeded the model and dropped
selection/drag/anim/FX, but left GemMotion.land_at carrying the prior move's
landing stamps. A restart fired right after a terminal cascade therefore
replayed that move's squash-bounce on the freshly seeded board instead of
showing a clean resting pose.
Factor the landing reset into GemMotion.reset_landings (init now delegates to
it) and call it from do_restart, so a restart returns every cell to its
resting idle pose. The idle clock keeps running, so the always-on idle simply
resumes from rest.
Regression: tests/gem_pose.sx section 7 stamps a cell mid-squash, asserts it
is squashing, then asserts reset_landings returns every cell to rest while
leaving the clock untouched. Fails on the pre-fix (no-op reset) behaviour,
passes after. Gate green: ios-sim build + 18/18 logic tests.
New gem_anim.sx adds a purely-visual per-gem pose set driven by a single
animation clock: a calm always-on idle breath (scale-pulse + bob, per-gem
phase, ramped in from rest), a selection pop, a landing squash-bounce, and
a clear pop. BoardView draws every settled gem through gem_pose_at /
gem_pose_frame; the move timeline (P6.1) and FX (P6.2) are untouched and the
input-lock semantics are unchanged (idle never locks input).
Determinism: the idle is always-on, so main reads M3TE_ANIM_TIME=<seconds>
to freeze the clock at a chosen phase (t==0 == the resting board, so the
pre-P6.3 goldens reproduce) and M3TE_SELECT=<cellIndex> to force a selection
for capture. tests/gem_pose.sx locks the t==0-rest invariant and the reaction
envelopes headlessly (fails if the idle ramp is dropped).
Goldens (deterministic capture): p6_idle_t0 (resting), p6_idle_mid (pinned
mid-breath), p6_select (selection pop on cell 3,3). Purely visual: no change
to model/score/moves/hit-testing.