P18.1: organic combine — anticipation pop on match clear (sx, iOS sim)

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.
This commit is contained in:
swipelab
2026-06-06 13:01:37 +03:00
parent 0a90dfff19
commit 54a7eba432
6 changed files with 78 additions and 12 deletions

View File

@@ -7,7 +7,7 @@ select_start_rest true select_end_rest true select_mid_pops true
== land squash envelope ==
land_start_rest true land_end_rest true land_mid_wobbles true
== clear pop envelope ==
clear_start_full true clear_end_gone true clear_overshoots true
clear_start_full true clear_end_gone true clear_dips true clear_overshoots true clear_collapses true
== gem motion land bookkeeping ==
motion_init true motion_no_land true motion_fresh_land true
== gem motion restart resets landings ==

View File

@@ -71,15 +71,30 @@ main :: () -> s32 {
if !l_end { fails += 1; }
if !l_mid { fails += 1; }
// 5. Clear pop: full at t=0, gone at t=1, overshoots above 1 in between.
// 5. Clear pop: full at t=0, gone at t=1, a tiny anticipation dip BELOW rest in
// the gather window, an overshoot above 1 mid-window, then — past the peak —
// a strictly monotonic collapse to nothing (a single clean pop, no second
// reversal). The locked t=0/t=1 endpoints keep the seam to the model board.
print("== clear pop envelope ==\n");
c_start := approx(clear_pop_scale(0.0), 1.0);
c_end := approx(clear_pop_scale(1.0), 0.0);
c_dip := clear_pop_scale(CLEAR_DIP_T * 0.5) < 1.0;
c_peak := clear_pop_scale(0.30) > 1.1;
print("clear_start_full {} clear_end_gone {} clear_overshoots {}\n", c_start, c_end, c_peak);
c_collapse := true;
pc := clear_pop_scale(CLEAR_POP_RISE);
for 1..21: (i) {
tt := CLEAR_POP_RISE + (1.0 - CLEAR_POP_RISE) * cast(f32) i / 20.0;
vv := clear_pop_scale(tt);
if vv > pc + 0.000001 { c_collapse = false; }
pc = vv;
}
print("clear_start_full {} clear_end_gone {} clear_dips {} clear_overshoots {} clear_collapses {}\n",
c_start, c_end, c_dip, c_peak, c_collapse);
if !c_start { fails += 1; }
if !c_end { fails += 1; }
if !c_dip { fails += 1; }
if !c_peak { fails += 1; }
if !c_collapse { fails += 1; }
// 6. GemMotion land bookkeeping: fresh state is unpinned at t=0, a never-
// landed cell rests, and a freshly-stamped land reads age 0.