Visual-juice vibe-pass, FX-only — no logic/state changes, input gating
still owned by BoardAnim.active.
- board_fx.sx: bigger, punchier match bursts — peak size 1.95->2.50 cells,
combo bonus 0.55->0.72, and the per-gem fx tints saturated a touch (low
channel trimmed, dominant/mid lifted) so every burst pops as a brighter,
more vivid candy colour. The hot per-pixel tint loop's hoisted locals are
preserved (issue 0001).
- gem_anim.sx: snappier clear pop — faster rise (0.30->0.18 of the window)
to a bigger overshoot (CLEAR_POP_A 0.22->0.34) so the matched-gem clear
reads as a candy snap. gem_pose's clear-pop invariants still hold.
- main.sx: M3TE_FX=<n> deterministic match-FX capture hook, mirroring the
M3TE_SELECT pattern. Commits the n-th currently-legal swap at startup via
the normal plan_and_commit path and begins the move timeline + burst/popup
FX; M3TE_ANIM_TIME pins the phase and the frame loop holds the move/FX
frozen while pinned, so the burst + "+points" screenshot identically every
run. A larger M3TE_ANIM_TIME captures the settled, FX-gone board. Startup-
only and guarded, so normal play is untouched.
- README.md: document the new M3TE_FX pin alongside the other capture hooks.
- goldens/p6_fx_match.png: updated deterministic golden (iOS 26 sim,
SIMCTL_CHILD_M3TE_FX=3 SIMCTL_CHILD_M3TE_ANIM_TIME=0.22) — the vertical
red 3-match, burst region +1.4% mean luminance / 3.2:1 brighter:dimmer vs
the same scene on the pre-juice constants.
Gate: ios-sim build links, 19/19 logic tests green (incl. gem_pose t=0 rest).
Extend the HUD to show the per-level goal (SCORE x / target) alongside
moves. When the model's level_status (P7.1) is won/lost, draw a centered
overlay banner ("YOU WIN!" / "OUT OF MOVES") with a "PLAY AGAIN" restart
button over the dimmed board; the banner appears once any winning/losing
cascade animation settles. Status is read from the model, never recomputed
in the view.
A finished level freezes board-cell input; only the restart button is live.
Its rect is derived from the shared BoardLayout grid (new BannerLayout), so
the hit-test lands exactly on the drawn button. A tap reseeds the same
starting level through board.restart and clears the transient view layers,
returning to a clean in_progress board.
Banner is text + rects only (honours colour/alpha; no draw-time image tint,
issue 0002). New env capture hooks (M3TE_TARGET / M3TE_MOVE_LIMIT /
M3TE_RESTART) force a terminal status / restart for deterministic goldens.
Tests: tests/banner_layout.sx locks the restart button rect <-> hit-test
round-trip headlessly. Goldens p7_win / p7_lose / p7_restart captured on the
iOS simulator.
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.
Add a real logic-test gate so future pure-sx game logic fails the build on a
bad assertion:
- tests/test.sx: `expect(cond, msg)` assert helper — prints a greppable
`FAIL <file>:<line>: <msg>` and exits non-zero via process.exit on failure.
- tools/run_tests.sh: snapshot runner mirroring sx/tests/run_examples.sh; runs
each tests/<name>.sx and diffs stdout + exit code against tests/expected/.
Exits 0 iff all tests pass.
- tests/arith.sx (+ expected snapshots): seed passing sanity test.
- README.md: document both halves of the gate — logic runner and the
reproducible ios-sim build/launch sequence (with device discovery).