Offer the easings of an animation key on Lerp and sound FX ramps
A timed Set sound FX parameters ran only linearly, and a Lerp had four quadratic eases of its own. An animation key already had the full set. Now all three offer the same choice: Linear, Step, the ten curves from Sine to Bounce with In, Out or In-out, and a drawn Curve asset. - easingParams in src/core/graph/nodes/easing.ts gives a node the fields Easing, Direction and Curve from the key's own lists, and easingOfParams reads them back as a key interpolation. - There is no migration. A Lerp saved with the old in, out or inOut runs linear until its easing is picked again. - Set sound FX parameters hands the easing to the player. Linear and Step stay ramps of the audio clock, every other easing goes to setValueCurveAtTime as 200 samples a second, in semitones and dB. - Step now reaches its end at t 1. A key never asked for that, it reads the next key itself, so animations play as before. - The curve-in-use count and the warning for a gone curve cover the sound node too. Tests: - node-catalog: Lerp with cubic in, quad out and in-out, a curve without a direction, step, an unknown easing as linear. The sound node hands on a curve, step and a gone curve as linear. - sound-library: an eased change becomes a curve in semitones and decibels, a step a jump at the end. - node-catalog and curve after dropping the old values: 399, green. - e2e 6, 34, 53 on melektaus-atx: ALL PASSED, 198 checks. In Chrome a 2 s Quad in from depth 7 to -5 read speed 0.864 early and 0.5 at the end, a 1 s Step held 1 and then jumped to 0.5. - Counter-check: with curves sent as linear ramps, the curve test of the sound library fails. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
501a1524ed
commit
e7a360db73
17 files changed
+347
-104
No files matched your search
+15
-7
@@ -1150,8 +1150,9 @@ export async function graph(t) {
|
||||
|
||||
await showTab('scene');
|
||||
|
||||
// 6z-iii. Lerp (#246): typed into the palette it arrives linear with a 0…1 range, and the ease
|
||||
// picked in the inspector lands on the node and on its setting row.
|
||||
// 6z-iii. Lerp (#246): typed into the palette it arrives linear with a 0…1 range, and the easing
|
||||
// picked in the inspector – the choice an animation key has – lands on the node and on its
|
||||
// setting rows: a curve brings its direction along.
|
||||
async function lerpNode() {
|
||||
await mutate(`
|
||||
const p = __gm.state.project;
|
||||
@@ -1177,20 +1178,27 @@ export async function graph(t) {
|
||||
'typing "lerp" into the palette adds a linear Lerp from 0 to 1',
|
||||
lerp?.type === 'Lerp' &&
|
||||
JSON.stringify(inputs) === JSON.stringify(['a 0', 'b 1', 't 0']) &&
|
||||
JSON.stringify(settings) === JSON.stringify(['Ease: Linear']),
|
||||
JSON.stringify(settings) === JSON.stringify(['Easing: Linear']),
|
||||
JSON.stringify({ lerp, inputs, settings }),
|
||||
);
|
||||
const easeField = await json(`__gm.inspectorField('Ease')`);
|
||||
const easeField = await json(`__gm.inspectorField('Easing')`);
|
||||
if (easeField) {
|
||||
await click(easeField.x, easeField.y);
|
||||
await clickText('Cubic');
|
||||
}
|
||||
const directionField = await json(`__gm.inspectorField('Direction')`);
|
||||
if (directionField) {
|
||||
await click(directionField.x, directionField.y);
|
||||
await clickText('Out');
|
||||
}
|
||||
const picked = lerp ? (await asset('lerpy')).graph.nodes.find((n) => n.id === lerp.id) : null;
|
||||
const pickedRows = lerp ? await json(`__gm.graph.nodeSettings(${JSON.stringify(lerp.id)})`) : null;
|
||||
check(
|
||||
'picking "Out" in the inspector sets the node and its setting row',
|
||||
picked?.params.ease === 'out' && JSON.stringify(pickedRows) === JSON.stringify(['Ease: Out']),
|
||||
JSON.stringify({ easeField, params: picked?.params, pickedRows }),
|
||||
'picking "Cubic" and "Out" in the inspector sets the node and its setting rows',
|
||||
picked?.params.ease === 'cubic' &&
|
||||
picked.params.direction === 'out' &&
|
||||
JSON.stringify(pickedRows) === JSON.stringify(['Easing: Cubic', 'Direction: Out']),
|
||||
JSON.stringify({ easeField, directionField, params: picked?.params, pickedRows }),
|
||||
);
|
||||
await shot('22-lerp');
|
||||
await mutate(`
|
||||
|
||||
@@ -492,6 +492,38 @@ export async function sound(t) {
|
||||
JSON.stringify({ early, later, afterHalf }),
|
||||
);
|
||||
await stop();
|
||||
// The easings of an animation key: Quad in hands the clock a curve, which is still near the start
|
||||
// 0.7 s in and only then falls to the end (speed 0.5). Read a little later than that for the
|
||||
// round trips, it is above 0.8 until 1.1 s; linear is below 0.79 from 0.7 s on.
|
||||
await mutate(`
|
||||
const tune = __gm.state.project.assets.find((a) => a.id === 'sn-logic').graph.nodes.find((n) => n.id === 'sn-tune');
|
||||
Object.assign(tune.params, { ease: 'quad', direction: 'in' });`);
|
||||
await play();
|
||||
await waitFor(speed, (s) => typeof s === 'number');
|
||||
await new Promise((resolve) => setTimeout(resolve, 700));
|
||||
const easedEarly = await speed();
|
||||
const easedEnd = await waitFor(speed, (s) => typeof s === 'number' && s < 0.52);
|
||||
check(
|
||||
'Set sound FX parameters with Quad in ramps slowly first, then on to the end',
|
||||
easedEarly > 0.8 && easedEarly < 0.995 && easedEnd < 0.52,
|
||||
JSON.stringify({ easedEarly, easedEnd }),
|
||||
);
|
||||
await stop();
|
||||
// Step holds the pitch for the whole time and then jumps there.
|
||||
await mutate(`
|
||||
const tune = __gm.state.project.assets.find((a) => a.id === 'sn-logic').graph.nodes.find((n) => n.id === 'sn-tune');
|
||||
Object.assign(tune.params, { ease: 'step', time: 1 });`);
|
||||
await play();
|
||||
await waitFor(speed, (s) => typeof s === 'number');
|
||||
await new Promise((resolve) => setTimeout(resolve, 500));
|
||||
const stepHeld = await speed();
|
||||
const stepEnd = await waitFor(speed, (s) => typeof s === 'number' && s < 0.9);
|
||||
check(
|
||||
'Set sound FX parameters with Step holds the pitch for the time, then jumps to the end',
|
||||
stepHeld === 1 && Math.abs(stepEnd - 0.5) < 0.001,
|
||||
JSON.stringify({ stepHeld, stepEnd }),
|
||||
);
|
||||
await stop();
|
||||
await mutate(`
|
||||
const logic = __gm.state.project.assets.find((a) => a.id === 'sn-logic');
|
||||
logic.variables = [];
|
||||
|
||||
@@ -235,7 +235,7 @@ export async function curves(t) {
|
||||
);
|
||||
await shot('53-curve-key');
|
||||
|
||||
// 53e. A Lerp picks it too – Ease: Curve, then the curve in its row – and the game logs its value.
|
||||
// 53e. A Lerp picks it too – Easing: Curve, then the curve in its row – and the game logs its value.
|
||||
await mutate(`
|
||||
const p = __gm.state.project;
|
||||
p.assets.push({ id: 'cv-lerpy', type: 'behavior', name: 'Curve lerp', props: { enabled: true, runInEditor: false },
|
||||
@@ -270,7 +270,7 @@ export async function curves(t) {
|
||||
await settle();
|
||||
return option;
|
||||
};
|
||||
await pick('Ease', 'Curve');
|
||||
await pick('Easing', 'Curve');
|
||||
const unpicked = await json("__gm.graph.nodeSettings('cv-lerp')");
|
||||
const name = await json(`__gm.state.project.assets.find((a) => a.id === ${JSON.stringify(curveId)}).name`);
|
||||
const picked = await pick('Curve', `${name} (curve)`);
|
||||
@@ -279,7 +279,7 @@ export async function curves(t) {
|
||||
);
|
||||
const settings = await json("__gm.graph.nodeSettings('cv-lerp')");
|
||||
check(
|
||||
'Ease: Curve brings the Curve row onto the node, and picking the curve there sets it',
|
||||
'Easing: Curve brings the Curve row onto the node, and picking the curve there sets it',
|
||||
params?.ease === 'curve' &&
|
||||
params.curve === curveId &&
|
||||
Boolean(picked) &&
|
||||
|
||||
Reference in new issue
Block a user