Commit Graph

3 Commits

Author SHA1 Message Date
swipelab
cd8667d170 P11.3: glossier candy gem & selection feel (sx / iOS)
Make the selection highlight read as glossy candy without new art and
without disturbing the idle-rest invariant. board_view's render_selection
layers a soft outward glow (two concentric stroked rings — the renderer has
no blur), a warm wash, a bright rim doubled by a thin inner highlight for a
glassy edge, and a wet sheen that rides the selected gem's live pose. Every
layer is a rect/overlay (issue 0002 forbids a draw-time gem-texture tint).

The gloss is selection-only: render_selection runs solely when a cell is
selected, so the resting board (no selection) is byte-identical to before
and the t==0 idle pose stays exactly the static sprite (locked by
tests/gem_pose). The selection-pop motion still comes from gem_anim; no
board / score / move state changes and input stays gated by BoardAnim.active.

Updated goldens/p6_select.png; README documents the P11.3 selection gloss
and its reproduce commands (reusing the P6.3 M3TE_SELECT + M3TE_ANIM_TIME
hooks).
2026-06-05 21:15:44 +03:00
swipelab
219dd127dd P9.1: visual polish — frame the board off the screen bezel (sx, iOS sim)
Polish pass before final acceptance. The 8x8 grid was rendering flush to the
left/right screen edges (gems ~4pt from the bezel on iPhone 17). Add a content
margin (BOARD_INSET_X = 16pt) layered on top of the platform safe-area insets so
the grid is framed by the background, while the HUD keeps using the bare safe
insets so it still hugs the top below the Dynamic Island. The grid is
width-constrained in portrait, so this inset is what sizes it; vertical
centering inside the safe area is unchanged, and the win/lose banner (derived
from the grid) stays centered over the framed board.

Safe-area verified on a current iPhone simulator (iPhone 17, iOS 26): HUD below
the Dynamic Island, board far above the home indicator, forced win/lose banners
centered and unclipped.

The headless geometry tests (hit_test, banner_layout) call compute() with a
zero inset directly, so they are unaffected; full logic gate stays green (18/18).

Goldens: add p9_polish.png (resting board, M3TE_ANIM_TIME=0) as the canonical
polished layout. Re-capture the README-documented deterministic goldens whose
board position shifts by the 16pt margin (p4_board, p4_hud, p6_idle_t0,
p6_idle_mid, p6_select, p7_win, p7_lose, p7_restart). The in-flight move-timeline
goldens (p5_swap_*, p6_anim_*, p6_fx_*, p6_inputlock_board) and the p0 quad
goldens are not reproducible via the documented env pins (which pin only the idle
clock + level state), so they are left as-is.
2026-06-05 19:01:09 +03:00
swipelab
d35fa8a5a6 P6.3: per-gem idle/select/land/clear animations (sx, iOS sim)
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.
2026-06-05 07:59:16 +03:00