Offer the easings of an animation key on Lerp and sound FX ramps
game-maker / gate (push) Successful in 3m15s
game-maker / suite (push) Successful in 15m36s

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:
adminandClaude Opus 5.5 committed 2026-10-05 22:05:00 +02:00
1 parent 501a1524ed
commit e7a360db73
17 files changed
+347 -104

No files matched your search

+4 -3
View File
@@ -13,7 +13,7 @@ import {
} from './Graph';
import type { GraphLookup } from './lookup';
import { nodeDef, type NodeDef, type PortDef } from './NodeRegistry';
import { lerpProblem } from './nodes/data/Lerp';
import { easingProblem } from './nodes/easing';
import { withSplits } from './portSplits';
import { agreedType, type SharedPortGroup } from './portTypes';
@@ -375,13 +375,14 @@ export function ghostProblem(node: GraphNode, graph: Graph, def: NodeDef): strin
/**
* Why this call cannot do anything, or null if it can. A call is the one node that depends on a
* *different* graph, so it is the one node that can look perfectly healthy and still be dead. A
* `Lerp` depends on another asset as well, the curve it eases along (#247), and says so here too.
* `Lerp` or a `Set sound FX parameters` depends on another asset as well, the curve it eases along
* (#247), and says so here too.
*/
export function callProblem(node: GraphNode, lookup: GraphLookup, ownerId = ''): string | null {
if (node.type === ON_BEHAVIOR) return listenProblem(node, lookup, ownerId);
if (node.type === SHADER_CALL) return functionCallProblem(node, lookup, ownerId);
if (node.type === SOUND_FX_PARAMETERS) return soundFxParametersProblem(node, lookup);
if (node.type !== RUN_BEHAVIOR) return lerpProblem(node, lookup);
if (node.type !== RUN_BEHAVIOR) return easingProblem(node, lookup);
const id = textOf(node.params[BEHAVIOR_PARAM] ?? '');
if (!id) return 'No behavior picked';
if (id === ownerId) return 'A behavior cannot run itself';