Building a curve by mouse alone was fiddly: there was no way to put a
point on an exact value, no grid, and the running preview could not be
stopped at a chosen moment. The hand cursor over points also looked
like a link instead of a drawing tool.
- Number fields t and v in the header show the selected point. Typing
or dragging on them goes through the same rules as a mouse drag, so
points never overtake and handles stay clamped. One undo step each.
t is greyed out on the two end points.
- The magnet button from Vector art snaps points and handles to a
0.05 grid in t and v, when placing on free space and when dragging.
- Points and handles keep the default arrow in the curve tab and in
Vector art. The pixel art palette dropped pointer as well, which is
beyond the issue. Collider corners never had it.
- The preview now starts off. A vertical time line with a knob under
the t axis sets t when dragged sideways. Dragging the dot on the
rail jumps to the first t where the curve reaches that value, or to
the closest one if it never does.
- The rules are pure functions in curveView.ts (withCurvePointSet,
snappedToGrid, shareAtValue, previewSecondsAt), the canvas only
calls them.
Tests:
- ./check.sh: 180 files, 2616 tests, CHECK EXIT 0
- GM_STEPS=1,47,53: ALL PASSED, 87 checks
- 4 new unit tests in curve-view.test.ts, 4 new e2e checks in 53
(53h-53k) and 1 in 47, all with real mouse and keyboard
- Counter-probes bite: without "first t" 1 unit test fails, with
pointer, no snap, no field commit, no scrub or preview on 5 browser
checks fail, pointer in Vector art fails the new 47 check
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The built-in eases cover the usual shapes, but a game often wants its
own: a coin that bounces twice, a door that overshoots and settles.
A new asset type holds such a curve, and keys and the Lerp node can
pick it instead of a built-in ease.
- New asset type "curve": points like in Vector art, x is t and y is
the value. A new curve is the straight line from (0, 0) to (1, 1).
- One pure evaluation in src/core/model/curve.ts serves the timeline
preview, the running game and the Lerp node.
- The curve always has one value per t. The end points stay at t 0
and 1, points cannot pass each other, and a handle that reaches past
its neighbour is shortened along its direction. Loading a hand-edited
file applies the same rules.
- Curve tab: click on the line to insert a point that keeps the shape,
click on free space to put one there, drag points and handles,
double-click or Delete removes, Alt-click toggles round and sharp.
Every step is one undo step.
- Presets: all 30 built-in eases plus Linear, fitted with adaptive
subdivision. Each stays within 0.4 % of the built-in ease.
- Preview: a dot runs along the curve once a second, a second dot
shows only the value. The Preview button stops it.
- Animation keys get "Curve" under Easing with a curve picker. Lerp
gets "Curve" under Ease, and its result may overshoot b.
- A missing or unpicked curve runs linear. The inspector says so, the
node shows it as a problem, and deleting a used curve warns with the
number of keys and Lerp nodes.
Tests:
- ./check.sh: 180 files, 2612 tests, CHECK EXIT 0
- GM_STEPS=1-6,25,53: ALL PASSED, 309 checks
- New e2e module 53 with 13 checks, all with the real mouse. Expected
values come from its own Bezier evaluation.
- Counter-checks bite: without Bezier evaluation 4 unit tests fail,
without handle clamping 2. In the browser, a key that cannot find its
curve, a click that sets no point and a handle drag that moves the
point all turn checks red.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>