P15.1: add extended easing toolkit + determinism snapshot (sx)
Pure, headless easing curves of t in [0,1] for the organic-animation pass (swap/fall/combine juice), placed alongside the existing ease_out_cubic / ease_in_quad in board_anim.sx: ease_in_cubic, ease_in_out_cubic, ease_out_back (bounded overshoot, settles to exactly 1), spring (damped wobble to exactly 1), and squash_envelope (signed squash-&-stretch landing shape). The math module has no exp/pow, so the decaying curves use a (1-t)^n polynomial envelope that hits 0 at t==1, pinning f(1) precisely. Additive only: no render code calls the new curves yet. tests/easing.sx locks, per curve, the endpoints, overshoot/undershoot bounds, and monotonicity-where- required (booleans only, so the snapshot is platform-stable), structured so P16.2 can append illegal-swap bounce-back assertions. Test count 21 -> 22.
This commit is contained in:
@@ -28,6 +28,54 @@ FALL_ANIM_DUR :f32: 0.22;
|
||||
ease_out_cubic :: (t: f32) -> f32 { u := t - 1.0; u * u * u + 1.0 }
|
||||
ease_in_quad :: (t: f32) -> f32 { t * t }
|
||||
|
||||
// --- Extended easing toolkit (P15.1) -----------------------------------------
|
||||
// Pure, headless curves of t in [0,1] for the organic-animation pass (swap/fall/
|
||||
// combine juice). Each has LOCKED endpoints and bounded, tasteful amplitude; NO
|
||||
// render code calls these yet — the transition steps (P16/P17/P18) wire them in
|
||||
// and tune feel. Companions to the two easing helpers above; the math module has
|
||||
// no exp/pow, so the decaying curves use a polynomial envelope that reaches
|
||||
// exactly 0 at t==1, which pins f(1) precisely instead of merely approaching it.
|
||||
// `tests/easing.sx` pins every endpoint, overshoot bound, and monotonicity here.
|
||||
|
||||
// Accelerate from rest: slow start, fast finish. Monotonic 0->1. Cubic companion
|
||||
// to ease_in_quad and the mirror of ease_out_cubic.
|
||||
ease_in_cubic :: (t: f32) -> f32 { t * t * t }
|
||||
|
||||
// Smooth accelerate-then-decelerate, symmetric about (0.5, 0.5). Monotonic 0->1.
|
||||
ease_in_out_cubic :: (t: f32) -> f32 {
|
||||
if t < 0.5 { return 4.0 * t * t * t; }
|
||||
u := -2.0 * t + 2.0;
|
||||
1.0 - u * u * u * 0.5
|
||||
}
|
||||
|
||||
// Overshoot ("back"): shoots ~10% past 1 then settles to EXACTLY 1, never dipping
|
||||
// below 0. Non-monotonic by design — the overshoot is the whole point.
|
||||
BACK_S :f32: 1.70158;
|
||||
ease_out_back :: (t: f32) -> f32 {
|
||||
u := t - 1.0;
|
||||
1.0 + (BACK_S + 1.0) * u * u * u + BACK_S * u * u
|
||||
}
|
||||
|
||||
// Damped spring: rises to 1, overshoots (~18%), then a small decaying wobble back
|
||||
// to EXACTLY 1. The (1-t)^3 envelope is 0 at t==1, so f(1) is locked.
|
||||
SPRING_OSC :f32: 1.0;
|
||||
spring :: (t: f32) -> f32 {
|
||||
if t <= 0.0 { return 0.0; }
|
||||
if t >= 1.0 { return 1.0; }
|
||||
d := 1.0 - t;
|
||||
1.0 - d * d * d * cos(TAU * SPRING_OSC * t)
|
||||
}
|
||||
|
||||
// Squash-&-stretch landing envelope: a signed, unit-ish shape that is 0 (rest) at
|
||||
// both ends, squashes on impact, then wobbles out with decay. Downstream applies
|
||||
// it as e.g. scale_x = 1 + A*s, scale_y = 1 - A*s for a tasteful amplitude A.
|
||||
SQUASH_OSC :f32: 1.5;
|
||||
squash_envelope :: (t: f32) -> f32 {
|
||||
if t <= 0.0 or t >= 1.0 { return 0.0; }
|
||||
d := 1.0 - t;
|
||||
sin(TAU * SQUASH_OSC * t) * d * d
|
||||
}
|
||||
|
||||
// One recorded cascade round. `before` is the board at the round's start (the
|
||||
// swapped board for round 0, the previous round's `after` otherwise — never has
|
||||
// holes). `matched` flags the cells cleared this round (they scale out). `src`
|
||||
|
||||
Reference in New Issue
Block a user