Skip to content

Commit 08916d0

Browse files
RuitingMaclaude
andcommitted
Cell: smoothstep rise on flare ignition
Each path-cell's lit envelope now has an attack phase: alpha ramps from 0 to peak across PATH_RISE_MS = 400 ms via smoothstep (t² · (3 − 2t)) before the fade phase begins. The pendulum-kick that lit alpha drives is smoothed along with it, so the orbital point spins up gradually rather than getting whacked at ignition — same "inertia" curve the pendulum integrator already exhibits when its omega target shifts. Each path's endTime extends by PATH_RISE_MS so the last cell on the slowest spread layer can complete both attack and release before the flare is reaped. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 5172c66 commit 08916d0

1 file changed

Lines changed: 19 additions & 6 deletions

File tree

src/components/CellSketch.astro

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,8 @@
120120
// max-blends again with the veil + momentum boost.
121121
const PATH_SPAWN_INTERVAL_MS = 5000; // mean ms between spawns (Poisson)
122122
const PATH_STEP_MS = 110; // ms between successive cell ignitions along the line
123-
const PATH_FADE_MS = 3500; // each cell's fade duration
123+
const PATH_RISE_MS = 400; // smooth ramp 0 → peak (envelope's attack phase)
124+
const PATH_FADE_MS = 3500; // peak → 0 (envelope's release phase)
124125
const PATH_FADE_GAMMA = 0.5; // <1 sustains brightness, falls fast at end (sqrt curve)
125126
const PATH_PEAK_ALPHA = 0.70; // peak alpha at the line core (full opacity ≡ 1)
126127
const PATH_MIN_LENGTH = 7; // Chebyshev cells; below this we skip & retry
@@ -418,6 +419,7 @@
418419
now +
419420
(linePath.length - 1) * PATH_STEP_MS +
420421
maxSpreadDist * PATH_SPREAD_STEP_MS +
422+
PATH_RISE_MS +
421423
PATH_FADE_MS,
422424
});
423425
}
@@ -502,18 +504,29 @@
502504
// Path-lit alpha for this cell at `now`. Computed here (before
503505
// physics integration) so it can both drive the pendulum kick
504506
// and be stored on V for the render pass — single lookup
505-
// instead of two. Non-linear fade: pow(1 - age/fade, gamma)
506-
// with gamma < 1 sustains brightness through most of fadeMs
507-
// and snaps off at the end.
507+
// instead of two. Envelope is attack + release:
508+
// age ∈ [0, RISE_MS): smoothstep ramp 0 → peak (the "inertia"
509+
// ramp the orbital pendulum already exhibits — matches it).
510+
// age ∈ [RISE_MS, RISE_MS+FADE_MS): pow(1 − t, FADE_GAMMA)
511+
// with gamma < 1 — sustains then snaps.
508512
let curLit = 0;
509513
if (activePaths.length > 0) {
510514
const key = cellKey(i, j);
515+
const totalMs = PATH_RISE_MS + PATH_FADE_MS;
511516
for (let pi = 0; pi < activePaths.length; pi++) {
512517
const entry = activePaths[pi].cells.get(key);
513518
if (!entry) continue;
514519
const age = now - entry.litAt;
515-
if (age < 0 || age > PATH_FADE_MS) continue;
516-
const a = entry.peak * Math.pow(1 - age / PATH_FADE_MS, PATH_FADE_GAMMA);
520+
if (age < 0 || age >= totalMs) continue;
521+
let envelope: number;
522+
if (age < PATH_RISE_MS) {
523+
const t = age / PATH_RISE_MS;
524+
envelope = t * t * (3 - 2 * t); // smoothstep
525+
} else {
526+
const fadeT = (age - PATH_RISE_MS) / PATH_FADE_MS;
527+
envelope = Math.pow(1 - fadeT, PATH_FADE_GAMMA);
528+
}
529+
const a = entry.peak * envelope;
517530
if (a > curLit) curLit = a;
518531
}
519532
}

0 commit comments

Comments
 (0)