@glissade/core 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -0
- package/dist/index.d.ts +85 -5
- package/dist/index.js +304 -23
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# @glissade/core
|
|
2
|
+
|
|
3
|
+
The engine-agnostic heart: pull-based signals, the serializable keyframe **Timeline document**, the fluent builder that compiles to it, easing + closed-form springs, OKLab color, `bake()` for stateful simulation under seeking, and the v2 analytic layer (ease derivatives, `velocityAt`, `spring.retarget`). Zero DOM or Node dependencies; ≤ 11 kB gz.
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
npm i @glissade/core
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { timeline, spring } from '@glissade/core';
|
|
11
|
+
|
|
12
|
+
const doc = timeline((tl) => {
|
|
13
|
+
tl.to('dot/opacity', 1, { duration: 0.5 })
|
|
14
|
+
.to('dot/position.x', 520, { ease: spring({ stiffness: 170, damping: 14 }) })
|
|
15
|
+
.label('arrived')
|
|
16
|
+
.to('dot/fill', '#7c4dff', { duration: 0.6, at: 'arrived' });
|
|
17
|
+
});
|
|
18
|
+
// `doc` is plain JSON: nothing executes at play time, so any t samples in O(log keys)
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
One contract underneath everything: evaluation is a **pure function of time** — same inputs, same output, in any order.
|
|
22
|
+
|
|
23
|
+
## Part of glissade
|
|
24
|
+
|
|
25
|
+
*(glide & slide)* — programmatic motion graphics for TypeScript: realtime-first in any web page, deterministic headless video export from the same code, a visual studio over the same document. No generator functions.
|
|
26
|
+
|
|
27
|
+
- [Repository & full README](https://github.com/tyevco/glissade)
|
|
28
|
+
- [Getting started](https://github.com/tyevco/glissade/blob/main/docs/getting-started.md) · [Concepts](https://github.com/tyevco/glissade/blob/main/docs/concepts.md) · [Interactivity](https://github.com/tyevco/glissade/blob/main/docs/interactivity.md)
|
|
29
|
+
|
|
30
|
+
Apache-2.0.
|
package/dist/index.d.ts
CHANGED
|
@@ -49,12 +49,29 @@ declare function untracked<T>(fn: () => T): T;
|
|
|
49
49
|
* (spring overshoot); non-extrapolating types clamp.
|
|
50
50
|
*/
|
|
51
51
|
type Vec2 = readonly [number, number];
|
|
52
|
+
/** One bezier contour in Lottie's vertex form: anchor points + RELATIVE in/out tangents. */
|
|
53
|
+
interface PathContour {
|
|
54
|
+
closed: boolean;
|
|
55
|
+
v: Vec2[];
|
|
56
|
+
in: Vec2[];
|
|
57
|
+
out: Vec2[];
|
|
58
|
+
}
|
|
59
|
+
/** The 'path' document value (§2.2): plain JSON, serializes with no new hooks. */
|
|
60
|
+
type PathValue = PathContour[];
|
|
61
|
+
/** Transition handoff policies (v2 addendum §A.4/§B.1); 'crossfade' reserved. */
|
|
62
|
+
type HandoffKind = 'cut' | 'decay' | 'spring' | 'blend-from-frozen';
|
|
52
63
|
interface ValueType<T> {
|
|
53
64
|
id: string;
|
|
54
65
|
lerp(a: T, b: T, t: number): T;
|
|
55
66
|
/** Accepts easedT outside [0,1] (spring overshoot)? Otherwise clamped. */
|
|
56
67
|
extrapolates: boolean;
|
|
57
68
|
equals(a: T, b: T): boolean;
|
|
69
|
+
/** Optional linear-space operators (offset decay + reserved additive blending, §B.6). */
|
|
70
|
+
add?(a: T, b: T): T;
|
|
71
|
+
sub?(a: T, b: T): T;
|
|
72
|
+
scale?(a: T, k: number): T;
|
|
73
|
+
/** Type-class handoff default (§B.1): spring for kinetic, cut for hold-only. */
|
|
74
|
+
defaultHandoff?: HandoffKind;
|
|
58
75
|
}
|
|
59
76
|
type ValueTypeId = 'number' | 'vec2' | 'color' | 'string' | 'boolean' | (string & {});
|
|
60
77
|
declare function registerValueType<T>(vt: ValueType<T>): void;
|
|
@@ -68,6 +85,15 @@ declare const vec2Type: ValueType<Vec2>;
|
|
|
68
85
|
declare const colorType: ValueType<string>;
|
|
69
86
|
declare const stringType: ValueType<string>;
|
|
70
87
|
declare const booleanType: ValueType<boolean>;
|
|
88
|
+
/**
|
|
89
|
+
* Path morphing (§2.2): pairwise lerp of anchors and tangents — exactly how
|
|
90
|
+
* lottie-web morphs, so imported animations are pixel-faithful. Mismatched
|
|
91
|
+
* topology snaps (hold a, then b at t ≥ 1) with a one-time dev warning; the
|
|
92
|
+
* de Casteljau normalization fallback for arbitrary native morphs is tracked
|
|
93
|
+
* future work. Lerp-only: offsets are not well-defined under mismatched
|
|
94
|
+
* topology, so no add/sub/scale — handoffs blend from the frozen value.
|
|
95
|
+
*/
|
|
96
|
+
declare const pathType: ValueType<PathValue>;
|
|
71
97
|
declare class ValueTypeInferenceError extends Error {
|
|
72
98
|
constructor(value: unknown);
|
|
73
99
|
}
|
|
@@ -104,6 +130,12 @@ type EaseSpec = string | {
|
|
|
104
130
|
mass: number;
|
|
105
131
|
};
|
|
106
132
|
declare const easings: Record<string, EasingFn>;
|
|
133
|
+
/**
|
|
134
|
+
* Analytic derivatives d(u) of every named ease (§B.6) — closed-form, used
|
|
135
|
+
* for reading velocity off in-flight curves at interruption time. Property-
|
|
136
|
+
* tested against central differences at interior points.
|
|
137
|
+
*/
|
|
138
|
+
declare const easingDerivatives: Record<string, EasingFn>;
|
|
107
139
|
/** Default property-tween ease (Motion Canvas precedent). */
|
|
108
140
|
declare const DEFAULT_EASE = "easeInOutCubic";
|
|
109
141
|
/**
|
|
@@ -111,6 +143,8 @@ declare const DEFAULT_EASE = "easeInOutCubic";
|
|
|
111
143
|
* with a bisection fallback for the flat-derivative regions.
|
|
112
144
|
*/
|
|
113
145
|
declare function cubicBezier(p1x: number, p1y: number, p2x: number, p2y: number): EasingFn;
|
|
146
|
+
/** Analytic dy/dx of a cubic bézier ease: y'(s)/x'(s) at the solved parameter (§B.6). */
|
|
147
|
+
declare function cubicBezierDerivative(p1x: number, p1y: number, p2x: number, p2y: number): EasingFn;
|
|
114
148
|
declare class UnknownEasingError extends Error {
|
|
115
149
|
constructor(name: string);
|
|
116
150
|
}
|
|
@@ -144,10 +178,24 @@ declare function duration(cfg: SpringConfig, opts?: {
|
|
|
144
178
|
declare function value(cfg: SpringConfig, t: number, opts?: {
|
|
145
179
|
settleTolerance?: number;
|
|
146
180
|
}): number;
|
|
181
|
+
/**
|
|
182
|
+
* Velocity-matched retarget oscillator (v2 addendum §B.3): the same damped
|
|
183
|
+
* harmonic oscillator on an OFFSET in value units with nonzero initial
|
|
184
|
+
* velocity — y(0)=x0, y'(0)=v0, decaying to 0. No affine rescale (the target
|
|
185
|
+
* is exactly 0). Pure closed forms; seek-safe at any τ.
|
|
186
|
+
*/
|
|
187
|
+
interface RetargetSpring {
|
|
188
|
+
value(tau: number): number;
|
|
189
|
+
velocity(tau: number): number;
|
|
190
|
+
/** Earliest τ after which |value| stays within tol (default 0.005·|x0|+1e-6 floor). */
|
|
191
|
+
settleTime(tol?: number): number;
|
|
192
|
+
}
|
|
193
|
+
declare function retarget(cfg: SpringConfig, x0: number, v0: number): RetargetSpring;
|
|
147
194
|
interface SpringFactory {
|
|
148
195
|
(cfg: SpringConfig): SpringEase;
|
|
149
196
|
duration: typeof duration;
|
|
150
197
|
value: typeof value;
|
|
198
|
+
retarget: typeof retarget;
|
|
151
199
|
}
|
|
152
200
|
declare const spring: SpringFactory;
|
|
153
201
|
/**
|
|
@@ -155,6 +203,12 @@ declare const spring: SpringFactory;
|
|
|
155
203
|
* spring.duration(cfg) (validated at the document layer, §2.7).
|
|
156
204
|
*/
|
|
157
205
|
declare function springEasing(cfg: SpringConfig): EasingFn;
|
|
206
|
+
/**
|
|
207
|
+
* Analytic d/dp of springEasing (§B.6): oscillator derivative × the affine
|
|
208
|
+
* rescale factor × duration (chain rule p → t = p·D). Flat past p=1,
|
|
209
|
+
* matching value()'s clamp (right-derivative convention).
|
|
210
|
+
*/
|
|
211
|
+
declare function springEasingDerivative(cfg: SpringConfig): EasingFn;
|
|
158
212
|
//#endregion
|
|
159
213
|
//#region src/color.d.ts
|
|
160
214
|
/**
|
|
@@ -215,9 +269,29 @@ declare function track<T>(target: string, type: ValueTypeId, keys: Key<T>[], opt
|
|
|
215
269
|
editable?: boolean;
|
|
216
270
|
}): Track<T>;
|
|
217
271
|
declare function resolveEase(spec: EaseSpec | undefined): EasingFn;
|
|
272
|
+
/**
|
|
273
|
+
* Analytic d(u) for an ease spec (§B.6). Custom-registered eases without a
|
|
274
|
+
* derivative fall back to a symmetric difference with a one-time dev warning.
|
|
275
|
+
*/
|
|
276
|
+
declare function resolveEaseDerivative(spec: EaseSpec | undefined): EasingFn;
|
|
277
|
+
/**
|
|
278
|
+
* Analytic track derivative at time t, in value-units per second of local
|
|
279
|
+
* track time (v2 addendum §B.3/§B.6 conventions, pinned):
|
|
280
|
+
* (a) at a key boundary, velocity is the RIGHT derivative;
|
|
281
|
+
* (b) hold segments and the clamped regions outside the keys have v = 0;
|
|
282
|
+
* (c) types without sub/scale operators return null (no kinetic velocity).
|
|
283
|
+
*/
|
|
284
|
+
declare function velocityAt<T>(tr: Track<T>, t: number): T | null;
|
|
218
285
|
/** Pure sample of a track at time t (§2.4). */
|
|
219
286
|
declare function sampleTrack<T>(tr: Track<T>, t: number): T;
|
|
220
287
|
//#endregion
|
|
288
|
+
//#region src/devWarning.d.ts
|
|
289
|
+
/** The configurable dev-warning channel (no DOM lib in core; console may not exist). */
|
|
290
|
+
type DevWarning = (message: string) => void;
|
|
291
|
+
declare function setDevWarning(fn: DevWarning): void;
|
|
292
|
+
/** Internal: emit through the configurable channel. */
|
|
293
|
+
declare function emitDevWarning(message: string): void;
|
|
294
|
+
//#endregion
|
|
221
295
|
//#region src/timeline.d.ts
|
|
222
296
|
type Json = null | boolean | number | string | Json[] | {
|
|
223
297
|
[k: string]: Json;
|
|
@@ -293,10 +367,6 @@ interface CompiledTimeline {
|
|
|
293
367
|
/** Audio clips rebased to the root time axis (§5.3); sync timeScale scales playbackRate. */
|
|
294
368
|
audio: AudioClip[];
|
|
295
369
|
}
|
|
296
|
-
type DevWarning = (message: string) => void;
|
|
297
|
-
declare function setDevWarning(fn: DevWarning): void;
|
|
298
|
-
/** Internal: emit through the configurable dev-warning channel. */
|
|
299
|
-
|
|
300
370
|
declare function compileTimeline(doc: Timeline): CompiledTimeline;
|
|
301
371
|
//#endregion
|
|
302
372
|
//#region src/targetRef.d.ts
|
|
@@ -365,8 +435,18 @@ interface BindTarget {
|
|
|
365
435
|
bindSource(fn: () => unknown): void;
|
|
366
436
|
unbindSource(): void;
|
|
367
437
|
}
|
|
438
|
+
/** Analytic value/velocity access to one bound target (v2 addendum §B.6). */
|
|
439
|
+
interface CurveSampler {
|
|
440
|
+
readonly track: Track;
|
|
441
|
+
/** Pure sample at local timeline time t. */
|
|
442
|
+
value(t: number): unknown;
|
|
443
|
+
/** Analytic derivative per §B.3 conventions; null for types without operators. */
|
|
444
|
+
velocity(t: number): unknown | null;
|
|
445
|
+
}
|
|
368
446
|
interface BoundTimeline {
|
|
369
447
|
playhead: Playhead;
|
|
448
|
+
/** Per-target analytic samplers (additive, v2 §B.6); machines read these. */
|
|
449
|
+
samplers: ReadonlyMap<string, CurveSampler>;
|
|
370
450
|
/** Detach every track binding, freezing signals at their last values. */
|
|
371
451
|
unbind(): void;
|
|
372
452
|
}
|
|
@@ -459,4 +539,4 @@ declare function normalizeEditedKeys(keys: Key[]): Key[];
|
|
|
459
539
|
*/
|
|
460
540
|
declare function mergeSidecar(code: Timeline, sidecar: SidecarDoc | null | undefined): Timeline;
|
|
461
541
|
//#endregion
|
|
462
|
-
export { type AssetRef, type AudioClip, type BakeConfig, BakeError, type BindTarget, type BindableSignal, type BoundTimeline, type CheckpointedBakeConfig, type CheckpointedSim, type ChildEntry, CircularDependencyError, ColorParseError, type CompiledTimeline, DEFAULT_EASE, type DevWarning, type EaseSpec, type EasingFn, type Equals, type Json, type Key, type KeyOpts, type Marker, type OkLab, type Playhead, type Position, PositionError, type ReadonlySignal, type Rgba, type Rng, type SidecarDoc, SidecarVersionError, type Signal, type SignalOptions, type SpringConfig, type SpringEase, TARGET_PATH, type TargetCarrier, type Timeline, type TimelineBuilder, type TimelineInit, TimelineValidationError, type Track, TrackValidationError, type TweenOpts, type TweenTarget, UnboundTargetError, UnknownEasingError, UnknownValueTypeError, UnresolvableTargetError, type ValueType, type ValueTypeId, ValueTypeInferenceError, type Vec2, type Vec2Signal, WriteDuringEvaluationError, bake, bakeCheckpointed, beginReadPhase, bindTimeline, booleanType, buildTimeline, colorType, compileTimeline, computed, createPlayhead, cubicBezier, easings, emptySidecar, endReadPhase, evaluateAt, formatColor, getTimelineCallbacks, getValueType, inReadPhase, inferValueType, key, lerpColor, mergeSidecar, namedEasing, normalizeEditedKeys, numberType, oklabToRgba, parseColor, random, registerValueType, resolveEase, resolveTweenTarget, rgbaToOklab, sampleTrack, setDevWarning, signal, spring, springEasing, stringType, timeline, track, untracked, validateTrack, vec2Equals, vec2Signal, vec2Type };
|
|
542
|
+
export { type AssetRef, type AudioClip, type BakeConfig, BakeError, type BindTarget, type BindableSignal, type BoundTimeline, type CheckpointedBakeConfig, type CheckpointedSim, type ChildEntry, CircularDependencyError, ColorParseError, type CompiledTimeline, type CurveSampler, DEFAULT_EASE, type DevWarning, type EaseSpec, type EasingFn, type Equals, type HandoffKind, type Json, type Key, type KeyOpts, type Marker, type OkLab, type PathContour, type PathValue, type Playhead, type Position, PositionError, type ReadonlySignal, type RetargetSpring, type Rgba, type Rng, type SidecarDoc, SidecarVersionError, type Signal, type SignalOptions, type SpringConfig, type SpringEase, TARGET_PATH, type TargetCarrier, type Timeline, type TimelineBuilder, type TimelineInit, TimelineValidationError, type Track, TrackValidationError, type TweenOpts, type TweenTarget, UnboundTargetError, UnknownEasingError, UnknownValueTypeError, UnresolvableTargetError, type ValueType, type ValueTypeId, ValueTypeInferenceError, type Vec2, type Vec2Signal, WriteDuringEvaluationError, bake, bakeCheckpointed, beginReadPhase, bindTimeline, booleanType, buildTimeline, colorType, compileTimeline, computed, createPlayhead, cubicBezier, cubicBezierDerivative, easingDerivatives, easings, emitDevWarning, emptySidecar, endReadPhase, evaluateAt, formatColor, getTimelineCallbacks, getValueType, inReadPhase, inferValueType, key, lerpColor, mergeSidecar, namedEasing, normalizeEditedKeys, numberType, oklabToRgba, parseColor, pathType, random, registerValueType, resolveEase, resolveEaseDerivative, resolveTweenTarget, rgbaToOklab, sampleTrack, setDevWarning, signal, spring, springEasing, springEasingDerivative, stringType, timeline, track, untracked, validateTrack, vec2Equals, vec2Signal, vec2Type, velocityAt };
|
package/dist/index.js
CHANGED
|
@@ -287,6 +287,18 @@ function lerpColor(from, to, t) {
|
|
|
287
287
|
}));
|
|
288
288
|
}
|
|
289
289
|
//#endregion
|
|
290
|
+
//#region src/devWarning.ts
|
|
291
|
+
let devWarn = (msg) => {
|
|
292
|
+
globalThis.console?.warn(`[glissade] ${msg}`);
|
|
293
|
+
};
|
|
294
|
+
function setDevWarning(fn) {
|
|
295
|
+
devWarn = fn;
|
|
296
|
+
}
|
|
297
|
+
/** Internal: emit through the configurable channel. */
|
|
298
|
+
function emitDevWarning(message) {
|
|
299
|
+
devWarn(message);
|
|
300
|
+
}
|
|
301
|
+
//#endregion
|
|
290
302
|
//#region src/valueTypes.ts
|
|
291
303
|
/**
|
|
292
304
|
* Value-type registry with pluggable per-type interpolation (DESIGN.md §2.2).
|
|
@@ -312,20 +324,29 @@ const numberType = {
|
|
|
312
324
|
id: "number",
|
|
313
325
|
lerp: (a, b, t) => a + (b - a) * t,
|
|
314
326
|
extrapolates: true,
|
|
315
|
-
equals: Object.is
|
|
327
|
+
equals: Object.is,
|
|
328
|
+
add: (a, b) => a + b,
|
|
329
|
+
sub: (a, b) => a - b,
|
|
330
|
+
scale: (a, k) => a * k,
|
|
331
|
+
defaultHandoff: "spring"
|
|
316
332
|
};
|
|
317
333
|
const vec2Equals = (a, b) => a[0] === b[0] && a[1] === b[1];
|
|
318
334
|
const vec2Type = {
|
|
319
335
|
id: "vec2",
|
|
320
336
|
lerp: (a, b, t) => [a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t],
|
|
321
337
|
extrapolates: true,
|
|
322
|
-
equals: vec2Equals
|
|
338
|
+
equals: vec2Equals,
|
|
339
|
+
add: (a, b) => [a[0] + b[0], a[1] + b[1]],
|
|
340
|
+
sub: (a, b) => [a[0] - b[0], a[1] - b[1]],
|
|
341
|
+
scale: (a, k) => [a[0] * k, a[1] * k],
|
|
342
|
+
defaultHandoff: "spring"
|
|
323
343
|
};
|
|
324
344
|
const colorType = {
|
|
325
345
|
id: "color",
|
|
326
346
|
lerp: lerpColor,
|
|
327
347
|
extrapolates: true,
|
|
328
|
-
equals: (a, b) => a === b
|
|
348
|
+
equals: (a, b) => a === b,
|
|
349
|
+
defaultHandoff: "blend-from-frozen"
|
|
329
350
|
};
|
|
330
351
|
/** Discrete types: hold-only by construction (§2.2); lerp snaps at t=1. */
|
|
331
352
|
function discrete(id) {
|
|
@@ -333,22 +354,77 @@ function discrete(id) {
|
|
|
333
354
|
id,
|
|
334
355
|
lerp: (a, b, t) => t >= 1 ? b : a,
|
|
335
356
|
extrapolates: false,
|
|
336
|
-
equals: (a, b) => Object.is(a, b)
|
|
357
|
+
equals: (a, b) => Object.is(a, b),
|
|
358
|
+
defaultHandoff: "cut"
|
|
337
359
|
};
|
|
338
360
|
}
|
|
339
361
|
const stringType = discrete("string");
|
|
340
362
|
const booleanType = discrete("boolean");
|
|
363
|
+
const lerpV = (a, b, t) => [a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t];
|
|
364
|
+
/** Topology must match for a morph (contour count, closed flags, vertex counts). */
|
|
365
|
+
function pathTopologyMatches(a, b) {
|
|
366
|
+
if (a.length !== b.length) return false;
|
|
367
|
+
for (let i = 0; i < a.length; i++) {
|
|
368
|
+
const ca = a[i];
|
|
369
|
+
const cb = b[i];
|
|
370
|
+
if (ca.closed !== cb.closed || ca.v.length !== cb.v.length) return false;
|
|
371
|
+
}
|
|
372
|
+
return true;
|
|
373
|
+
}
|
|
374
|
+
let warnedPathTopology = false;
|
|
375
|
+
/**
|
|
376
|
+
* Path morphing (§2.2): pairwise lerp of anchors and tangents — exactly how
|
|
377
|
+
* lottie-web morphs, so imported animations are pixel-faithful. Mismatched
|
|
378
|
+
* topology snaps (hold a, then b at t ≥ 1) with a one-time dev warning; the
|
|
379
|
+
* de Casteljau normalization fallback for arbitrary native morphs is tracked
|
|
380
|
+
* future work. Lerp-only: offsets are not well-defined under mismatched
|
|
381
|
+
* topology, so no add/sub/scale — handoffs blend from the frozen value.
|
|
382
|
+
*/
|
|
383
|
+
const pathType = {
|
|
384
|
+
id: "path",
|
|
385
|
+
lerp: (a, b, t) => {
|
|
386
|
+
if (!pathTopologyMatches(a, b)) {
|
|
387
|
+
if (!warnedPathTopology) {
|
|
388
|
+
warnedPathTopology = true;
|
|
389
|
+
emitDevWarning("path lerp with mismatched topology (contour/vertex counts or closed flags differ): snapping instead of morphing — supply matched vertex counts (§2.2)");
|
|
390
|
+
}
|
|
391
|
+
return t >= 1 ? b : a;
|
|
392
|
+
}
|
|
393
|
+
return a.map((ca, i) => {
|
|
394
|
+
const cb = b[i];
|
|
395
|
+
return {
|
|
396
|
+
closed: ca.closed,
|
|
397
|
+
v: ca.v.map((p, j) => lerpV(p, cb.v[j], t)),
|
|
398
|
+
in: ca.in.map((p, j) => lerpV(p, cb.in[j], t)),
|
|
399
|
+
out: ca.out.map((p, j) => lerpV(p, cb.out[j], t))
|
|
400
|
+
};
|
|
401
|
+
});
|
|
402
|
+
},
|
|
403
|
+
extrapolates: false,
|
|
404
|
+
equals: (a, b) => {
|
|
405
|
+
if (a === b) return true;
|
|
406
|
+
if (!pathTopologyMatches(a, b)) return false;
|
|
407
|
+
const eq = (x, y) => x[0] === y[0] && x[1] === y[1];
|
|
408
|
+
return a.every((ca, i) => {
|
|
409
|
+
const cb = b[i];
|
|
410
|
+
return ca.v.every((p, j) => eq(p, cb.v[j])) && ca.in.every((p, j) => eq(p, cb.in[j])) && ca.out.every((p, j) => eq(p, cb.out[j]));
|
|
411
|
+
});
|
|
412
|
+
},
|
|
413
|
+
defaultHandoff: "blend-from-frozen"
|
|
414
|
+
};
|
|
341
415
|
var ValueTypeInferenceError = class extends Error {
|
|
342
416
|
constructor(value) {
|
|
343
417
|
super(`cannot infer a value type for ${JSON.stringify(value)}; register a custom type`);
|
|
344
418
|
this.name = "ValueTypeInferenceError";
|
|
345
419
|
}
|
|
346
420
|
};
|
|
421
|
+
const isContour = (c) => typeof c === "object" && c !== null && typeof c.closed === "boolean" && Array.isArray(c.v) && Array.isArray(c.in) && Array.isArray(c.out);
|
|
347
422
|
/** Infer a registered type id from a sample value (builder + bake authoring surfaces). */
|
|
348
423
|
function inferValueType(value) {
|
|
349
424
|
if (typeof value === "number") return "number";
|
|
350
425
|
if (typeof value === "boolean") return "boolean";
|
|
351
426
|
if (Array.isArray(value) && value.length === 2 && value.every((v) => typeof v === "number")) return "vec2";
|
|
427
|
+
if (Array.isArray(value) && value.length > 0 && value.every(isContour)) return "path";
|
|
352
428
|
if (typeof value === "string") try {
|
|
353
429
|
parseColor(value);
|
|
354
430
|
return "color";
|
|
@@ -362,6 +438,7 @@ registerValueType(vec2Type);
|
|
|
362
438
|
registerValueType(colorType);
|
|
363
439
|
registerValueType(stringType);
|
|
364
440
|
registerValueType(booleanType);
|
|
441
|
+
registerValueType(pathType);
|
|
365
442
|
//#endregion
|
|
366
443
|
//#region src/vec2Signal.ts
|
|
367
444
|
/**
|
|
@@ -456,13 +533,75 @@ const easings = {
|
|
|
456
533
|
easeOutBounce: bounceOut,
|
|
457
534
|
easeInOutBounce: (t) => t < .5 ? (1 - bounceOut(1 - 2 * t)) / 2 : (1 + bounceOut(2 * t - 1)) / 2
|
|
458
535
|
};
|
|
459
|
-
|
|
460
|
-
const
|
|
536
|
+
function bounceOutD(t) {
|
|
537
|
+
const n1 = 7.5625;
|
|
538
|
+
const d1 = 2.75;
|
|
539
|
+
if (t < 1 / d1) return 2 * n1 * t;
|
|
540
|
+
if (t < 2 / d1) return 2 * n1 * (t - 1.5 / d1);
|
|
541
|
+
if (t < 2.5 / d1) return 2 * n1 * (t - 2.25 / d1);
|
|
542
|
+
return 2 * n1 * (t - 2.625 / d1);
|
|
543
|
+
}
|
|
544
|
+
const LN2 = Math.LN2;
|
|
461
545
|
/**
|
|
462
|
-
*
|
|
463
|
-
*
|
|
546
|
+
* Analytic derivatives d(u) of every named ease (§B.6) — closed-form, used
|
|
547
|
+
* for reading velocity off in-flight curves at interruption time. Property-
|
|
548
|
+
* tested against central differences at interior points.
|
|
464
549
|
*/
|
|
465
|
-
|
|
550
|
+
const easingDerivatives = {
|
|
551
|
+
linear: () => 1,
|
|
552
|
+
easeInQuad: (t) => 2 * t,
|
|
553
|
+
easeOutQuad: (t) => 2 * (1 - t),
|
|
554
|
+
easeInOutQuad: (t) => t < .5 ? 4 * t : 4 * (1 - t),
|
|
555
|
+
easeInCubic: (t) => 3 * t ** 2,
|
|
556
|
+
easeOutCubic: (t) => 3 * (1 - t) ** 2,
|
|
557
|
+
easeInOutCubic: (t) => t < .5 ? 12 * t ** 2 : 12 * (1 - t) ** 2,
|
|
558
|
+
easeInQuart: (t) => 4 * t ** 3,
|
|
559
|
+
easeOutQuart: (t) => 4 * (1 - t) ** 3,
|
|
560
|
+
easeInOutQuart: (t) => t < .5 ? 32 * t ** 3 : 32 * (1 - t) ** 3,
|
|
561
|
+
easeInQuint: (t) => 5 * t ** 4,
|
|
562
|
+
easeOutQuint: (t) => 5 * (1 - t) ** 4,
|
|
563
|
+
easeInOutQuint: (t) => t < .5 ? 80 * t ** 4 : 80 * (1 - t) ** 4,
|
|
564
|
+
easeInSine: (t) => Math.PI / 2 * Math.sin(t * Math.PI / 2),
|
|
565
|
+
easeOutSine: (t) => Math.PI / 2 * Math.cos(t * Math.PI / 2),
|
|
566
|
+
easeInOutSine: (t) => Math.PI / 2 * Math.sin(Math.PI * t),
|
|
567
|
+
easeInExpo: (t) => t === 0 ? 0 : 10 * LN2 * 2 ** (10 * t - 10),
|
|
568
|
+
easeOutExpo: (t) => t === 1 ? 0 : 10 * LN2 * 2 ** (-10 * t),
|
|
569
|
+
easeInOutExpo: (t) => t === 0 || t === 1 ? 0 : t < .5 ? 10 * LN2 * 2 ** (20 * t - 10) : 10 * LN2 * 2 ** (-20 * t + 10),
|
|
570
|
+
easeInCirc: (t) => t / Math.sqrt(1 - t * t),
|
|
571
|
+
easeOutCirc: (t) => (1 - t) / Math.sqrt(1 - (t - 1) * (t - 1)),
|
|
572
|
+
easeInOutCirc: (t) => t < .5 ? 2 * t / Math.sqrt(1 - 4 * t * t) : (2 - 2 * t) / Math.sqrt(1 - (-2 * t + 2) ** 2),
|
|
573
|
+
easeInBack: (t) => 3 * c3 * t ** 2 - 2 * c1 * t,
|
|
574
|
+
easeOutBack: (t) => 3 * c3 * (t - 1) ** 2 + 2 * c1 * (t - 1),
|
|
575
|
+
easeInOutBack: (t) => t < .5 ? 12 * 3.5949095 * t ** 2 - 4 * c2 * t : 3 * 3.5949095 * (2 * t - 2) ** 2 + 2 * c2 * (2 * t - 2),
|
|
576
|
+
easeInElastic: (t) => {
|
|
577
|
+
if (t === 0 || t === 1) return 0;
|
|
578
|
+
const theta = (t * 10 - 10.75) * c4;
|
|
579
|
+
const amp = 2 ** (10 * t - 10);
|
|
580
|
+
return -(10 * LN2 * amp * Math.sin(theta) + amp * 10 * c4 * Math.cos(theta));
|
|
581
|
+
},
|
|
582
|
+
easeOutElastic: (t) => {
|
|
583
|
+
if (t === 0 || t === 1) return 0;
|
|
584
|
+
const phi = (t * 10 - .75) * c4;
|
|
585
|
+
const amp = 2 ** (-10 * t);
|
|
586
|
+
return -10 * LN2 * amp * Math.sin(phi) + amp * 10 * c4 * Math.cos(phi);
|
|
587
|
+
},
|
|
588
|
+
easeInOutElastic: (t) => {
|
|
589
|
+
if (t === 0 || t === 1) return 0;
|
|
590
|
+
const psi = (20 * t - 11.125) * c5;
|
|
591
|
+
if (t < .5) {
|
|
592
|
+
const amp = 2 ** (20 * t - 10);
|
|
593
|
+
return -(20 * LN2 * amp * Math.sin(psi) + amp * 20 * c5 * Math.cos(psi)) / 2;
|
|
594
|
+
}
|
|
595
|
+
const amp = 2 ** (-20 * t + 10);
|
|
596
|
+
return (-20 * LN2 * amp * Math.sin(psi) + amp * 20 * c5 * Math.cos(psi)) / 2;
|
|
597
|
+
},
|
|
598
|
+
easeInBounce: (t) => bounceOutD(1 - t),
|
|
599
|
+
easeOutBounce: bounceOutD,
|
|
600
|
+
easeInOutBounce: (t) => t < .5 ? bounceOutD(1 - 2 * t) : bounceOutD(2 * t - 1)
|
|
601
|
+
};
|
|
602
|
+
/** Default property-tween ease (Motion Canvas precedent). */
|
|
603
|
+
const DEFAULT_EASE = "easeInOutCubic";
|
|
604
|
+
function bezierKernel(p1x, p1y, p2x, p2y) {
|
|
466
605
|
const ax = 3 * p1x - 3 * p2x + 1;
|
|
467
606
|
const bx = 3 * p2x - 6 * p1x;
|
|
468
607
|
const cx = 3 * p1x;
|
|
@@ -472,6 +611,7 @@ function cubicBezier(p1x, p1y, p2x, p2y) {
|
|
|
472
611
|
const sampleX = (u) => ((ax * u + bx) * u + cx) * u;
|
|
473
612
|
const sampleY = (u) => ((ay * u + by) * u + cy) * u;
|
|
474
613
|
const sampleDX = (u) => (3 * ax * u + 2 * bx) * u + cx;
|
|
614
|
+
const sampleDY = (u) => (3 * ay * u + 2 * by) * u + cy;
|
|
475
615
|
const solveU = (x) => {
|
|
476
616
|
let u = x;
|
|
477
617
|
for (let i = 0; i < 8; i++) {
|
|
@@ -491,10 +631,33 @@ function cubicBezier(p1x, p1y, p2x, p2y) {
|
|
|
491
631
|
}
|
|
492
632
|
return u;
|
|
493
633
|
};
|
|
634
|
+
return {
|
|
635
|
+
sampleY,
|
|
636
|
+
sampleDX,
|
|
637
|
+
sampleDY,
|
|
638
|
+
solveU
|
|
639
|
+
};
|
|
640
|
+
}
|
|
641
|
+
/**
|
|
642
|
+
* CSS-style cubic bézier where x is time and y is progress. Newton's method
|
|
643
|
+
* with a bisection fallback for the flat-derivative regions.
|
|
644
|
+
*/
|
|
645
|
+
function cubicBezier(p1x, p1y, p2x, p2y) {
|
|
646
|
+
const k = bezierKernel(p1x, p1y, p2x, p2y);
|
|
494
647
|
return (t) => {
|
|
495
648
|
if (t <= 0) return 0;
|
|
496
649
|
if (t >= 1) return 1;
|
|
497
|
-
return sampleY(solveU(t));
|
|
650
|
+
return k.sampleY(k.solveU(t));
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
/** Analytic dy/dx of a cubic bézier ease: y'(s)/x'(s) at the solved parameter (§B.6). */
|
|
654
|
+
function cubicBezierDerivative(p1x, p1y, p2x, p2y) {
|
|
655
|
+
const k = bezierKernel(p1x, p1y, p2x, p2y);
|
|
656
|
+
return (t) => {
|
|
657
|
+
const u = k.solveU(Math.min(1, Math.max(0, t)));
|
|
658
|
+
const dx = k.sampleDX(u);
|
|
659
|
+
if (Math.abs(dx) < 1e-9) return 0;
|
|
660
|
+
return k.sampleDY(u) / dx;
|
|
498
661
|
};
|
|
499
662
|
}
|
|
500
663
|
var UnknownEasingError = class extends Error {
|
|
@@ -519,6 +682,20 @@ function params(cfg) {
|
|
|
519
682
|
zeta: cfg.damping / (2 * Math.sqrt(cfg.stiffness * mass))
|
|
520
683
|
};
|
|
521
684
|
}
|
|
685
|
+
/** Raw closed-form spring velocity at time t — d/dt of rawValue's three branches. */
|
|
686
|
+
function rawDerivative(cfg, t) {
|
|
687
|
+
if (t <= 0) return 0;
|
|
688
|
+
const { w0, zeta } = params(cfg);
|
|
689
|
+
if (Math.abs(zeta - 1) < 1e-9) return w0 * w0 * t * Math.exp(-w0 * t);
|
|
690
|
+
if (zeta < 1) {
|
|
691
|
+
const wd = w0 * Math.sqrt(1 - zeta * zeta);
|
|
692
|
+
return Math.exp(-zeta * w0 * t) * (w0 * w0 / wd) * Math.sin(wd * t);
|
|
693
|
+
}
|
|
694
|
+
const s = Math.sqrt(zeta * zeta - 1);
|
|
695
|
+
const r1 = -w0 * (zeta - s);
|
|
696
|
+
const r2 = -w0 * (zeta + s);
|
|
697
|
+
return r1 * r2 * (Math.exp(r1 * t) - Math.exp(r2 * t)) / (r1 - r2);
|
|
698
|
+
}
|
|
522
699
|
/** Raw closed-form spring position at time t (seconds). Approaches 1, may overshoot. */
|
|
523
700
|
function rawValue(cfg, t) {
|
|
524
701
|
if (t <= 0) return 0;
|
|
@@ -565,6 +742,53 @@ function value(cfg, t, opts) {
|
|
|
565
742
|
const d = duration(cfg, opts);
|
|
566
743
|
return rawValue(cfg, Math.min(t, d)) / rawValue(cfg, d);
|
|
567
744
|
}
|
|
745
|
+
function retarget(cfg, x0, v0) {
|
|
746
|
+
const { w0, zeta } = params(cfg);
|
|
747
|
+
let value0;
|
|
748
|
+
let velocity0;
|
|
749
|
+
let envelope;
|
|
750
|
+
if (Math.abs(zeta - 1) < 1e-9) {
|
|
751
|
+
const b = v0 + w0 * x0;
|
|
752
|
+
value0 = (tau) => tau <= 0 ? x0 : Math.exp(-w0 * tau) * (x0 + b * tau);
|
|
753
|
+
velocity0 = (tau) => tau <= 0 ? v0 : Math.exp(-w0 * tau) * (v0 - w0 * b * tau);
|
|
754
|
+
envelope = (tau) => Math.exp(-w0 * tau) * (Math.abs(x0) + Math.abs(b) * tau);
|
|
755
|
+
} else if (zeta < 1) {
|
|
756
|
+
const wd = w0 * Math.sqrt(1 - zeta * zeta);
|
|
757
|
+
const c2v = (v0 + zeta * w0 * x0) / wd;
|
|
758
|
+
const amp = Math.hypot(x0, c2v);
|
|
759
|
+
value0 = (tau) => tau <= 0 ? x0 : Math.exp(-zeta * w0 * tau) * (x0 * Math.cos(wd * tau) + c2v * Math.sin(wd * tau));
|
|
760
|
+
velocity0 = (tau) => tau <= 0 ? v0 : Math.exp(-zeta * w0 * tau) * (v0 * Math.cos(wd * tau) - (w0 * w0 * x0 + zeta * w0 * v0) / wd * Math.sin(wd * tau));
|
|
761
|
+
envelope = (tau) => Math.exp(-zeta * w0 * tau) * amp;
|
|
762
|
+
} else {
|
|
763
|
+
const s = Math.sqrt(zeta * zeta - 1);
|
|
764
|
+
const rp = w0 * (-zeta + s);
|
|
765
|
+
const rm = w0 * (-zeta - s);
|
|
766
|
+
const cp = (v0 - rm * x0) / (rp - rm);
|
|
767
|
+
const cm = (rp * x0 - v0) / (rp - rm);
|
|
768
|
+
value0 = (tau) => tau <= 0 ? x0 : cp * Math.exp(rp * tau) + cm * Math.exp(rm * tau);
|
|
769
|
+
velocity0 = (tau) => tau <= 0 ? v0 : cp * rp * Math.exp(rp * tau) + cm * rm * Math.exp(rm * tau);
|
|
770
|
+
envelope = (tau) => Math.abs(cp) * Math.exp(rp * tau) + Math.abs(cm) * Math.exp(rm * tau);
|
|
771
|
+
}
|
|
772
|
+
const settleTime = (tol) => {
|
|
773
|
+
const eps = tol ?? Math.abs(x0) * .005 + 1e-6;
|
|
774
|
+
if (envelope(0) <= eps && Math.abs(v0) < 1e-12) return 0;
|
|
775
|
+
let hi = 1 / w0;
|
|
776
|
+
let guard = 0;
|
|
777
|
+
while (envelope(hi) > eps && guard++ < 64) hi *= 2;
|
|
778
|
+
let lo = 0;
|
|
779
|
+
for (let i = 0; i < 64 && hi - lo > 1e-9; i++) {
|
|
780
|
+
const mid = (lo + hi) / 2;
|
|
781
|
+
if (Math.max(envelope(mid), envelope(mid * 1.05 + 1e-6)) > eps) lo = mid;
|
|
782
|
+
else hi = mid;
|
|
783
|
+
}
|
|
784
|
+
return hi;
|
|
785
|
+
};
|
|
786
|
+
return {
|
|
787
|
+
value: value0,
|
|
788
|
+
velocity: velocity0,
|
|
789
|
+
settleTime
|
|
790
|
+
};
|
|
791
|
+
}
|
|
568
792
|
const spring = Object.assign((cfg) => {
|
|
569
793
|
params(cfg);
|
|
570
794
|
return {
|
|
@@ -575,7 +799,8 @@ const spring = Object.assign((cfg) => {
|
|
|
575
799
|
};
|
|
576
800
|
}, {
|
|
577
801
|
duration,
|
|
578
|
-
value
|
|
802
|
+
value,
|
|
803
|
+
retarget
|
|
579
804
|
});
|
|
580
805
|
/**
|
|
581
806
|
* The spring as a normalized easing over a segment whose length must equal
|
|
@@ -585,6 +810,16 @@ function springEasing(cfg) {
|
|
|
585
810
|
const d = duration(cfg);
|
|
586
811
|
return (p) => value(cfg, p * d);
|
|
587
812
|
}
|
|
813
|
+
/**
|
|
814
|
+
* Analytic d/dp of springEasing (§B.6): oscillator derivative × the affine
|
|
815
|
+
* rescale factor × duration (chain rule p → t = p·D). Flat past p=1,
|
|
816
|
+
* matching value()'s clamp (right-derivative convention).
|
|
817
|
+
*/
|
|
818
|
+
function springEasingDerivative(cfg) {
|
|
819
|
+
const d = duration(cfg);
|
|
820
|
+
const scale = d / rawValue(cfg, d);
|
|
821
|
+
return (p) => p >= 1 ? 0 : rawDerivative(cfg, p * d) * scale;
|
|
822
|
+
}
|
|
588
823
|
//#endregion
|
|
589
824
|
//#region src/track.ts
|
|
590
825
|
/**
|
|
@@ -645,6 +880,27 @@ function resolveEase(spec) {
|
|
|
645
880
|
if (spec.kind === "cubicBezier") return cubicBezier(...spec.pts);
|
|
646
881
|
return springEasing(spec);
|
|
647
882
|
}
|
|
883
|
+
const warnedNumericDerivative = /* @__PURE__ */ new Set();
|
|
884
|
+
/**
|
|
885
|
+
* Analytic d(u) for an ease spec (§B.6). Custom-registered eases without a
|
|
886
|
+
* derivative fall back to a symmetric difference with a one-time dev warning.
|
|
887
|
+
*/
|
|
888
|
+
function resolveEaseDerivative(spec) {
|
|
889
|
+
if (spec === void 0) return easingDerivatives["linear"];
|
|
890
|
+
if (typeof spec === "string") {
|
|
891
|
+
const d = easingDerivatives[spec];
|
|
892
|
+
if (d) return d;
|
|
893
|
+
const fn = namedEasing(spec);
|
|
894
|
+
if (!warnedNumericDerivative.has(spec)) {
|
|
895
|
+
warnedNumericDerivative.add(spec);
|
|
896
|
+
emitDevWarning(`easing '${spec}' has no registered derivative; velocity uses a numeric fallback — register one in easingDerivatives for exact interruption handoff`);
|
|
897
|
+
}
|
|
898
|
+
const h = 1e-5;
|
|
899
|
+
return (u) => (fn(Math.min(1, u + h)) - fn(Math.max(0, u - h))) / (Math.min(1, u + h) - Math.max(0, u - h));
|
|
900
|
+
}
|
|
901
|
+
if (spec.kind === "cubicBezier") return cubicBezierDerivative(...spec.pts);
|
|
902
|
+
return springEasingDerivative(spec);
|
|
903
|
+
}
|
|
648
904
|
const samplerStates = /* @__PURE__ */ new WeakMap();
|
|
649
905
|
function state(tr) {
|
|
650
906
|
let s = samplerStates.get(tr);
|
|
@@ -684,6 +940,34 @@ function findSegment(keys, t, hint) {
|
|
|
684
940
|
}
|
|
685
941
|
return lo;
|
|
686
942
|
}
|
|
943
|
+
/**
|
|
944
|
+
* Analytic track derivative at time t, in value-units per second of local
|
|
945
|
+
* track time (v2 addendum §B.3/§B.6 conventions, pinned):
|
|
946
|
+
* (a) at a key boundary, velocity is the RIGHT derivative;
|
|
947
|
+
* (b) hold segments and the clamped regions outside the keys have v = 0;
|
|
948
|
+
* (c) types without sub/scale operators return null (no kinetic velocity).
|
|
949
|
+
*/
|
|
950
|
+
function velocityAt(tr, t) {
|
|
951
|
+
const vt = getValueType(tr.type);
|
|
952
|
+
if (!vt.sub || !vt.scale) return null;
|
|
953
|
+
const keys = tr.keys;
|
|
954
|
+
const n = keys.length;
|
|
955
|
+
const s = state(tr);
|
|
956
|
+
const i = findSegment(keys, t, s.cursor);
|
|
957
|
+
const zero = vt.scale(vt.sub(keys[0].value, keys[0].value), 0);
|
|
958
|
+
if (i === 0 || i >= n) return zero;
|
|
959
|
+
const arrival = keys[i];
|
|
960
|
+
if (arrival.interp === "hold") return zero;
|
|
961
|
+
const prev = keys[i - 1];
|
|
962
|
+
const segDur = arrival.t - prev.t;
|
|
963
|
+
const p = (t - prev.t) / segDur;
|
|
964
|
+
if (!vt.extrapolates) {
|
|
965
|
+
const eased = easeFor(tr, s, i)(p);
|
|
966
|
+
if (eased < 0 || eased > 1) return zero;
|
|
967
|
+
}
|
|
968
|
+
const d = resolveEaseDerivative(arrival.ease)(p);
|
|
969
|
+
return vt.scale(vt.sub(arrival.value, prev.value), d / segDur);
|
|
970
|
+
}
|
|
687
971
|
/** Pure sample of a track at time t (§2.4). */
|
|
688
972
|
function sampleTrack(tr, t) {
|
|
689
973
|
const keys = tr.keys;
|
|
@@ -740,16 +1024,6 @@ function validateSpringKeys(tr) {
|
|
|
740
1024
|
}
|
|
741
1025
|
}
|
|
742
1026
|
}
|
|
743
|
-
let devWarn = (msg) => {
|
|
744
|
-
globalThis.console?.warn(`[glissade] ${msg}`);
|
|
745
|
-
};
|
|
746
|
-
function setDevWarning(fn) {
|
|
747
|
-
devWarn = fn;
|
|
748
|
-
}
|
|
749
|
-
/** Internal: emit through the configurable dev-warning channel. */
|
|
750
|
-
function emitDevWarning(message) {
|
|
751
|
-
devWarn(message);
|
|
752
|
-
}
|
|
753
1027
|
function rebaseKeys(keys, at, timeScale) {
|
|
754
1028
|
return keys.map((k) => ({
|
|
755
1029
|
...k,
|
|
@@ -797,7 +1071,7 @@ function coalesce(entries) {
|
|
|
797
1071
|
const existingStart = existing.keys[0].t;
|
|
798
1072
|
const existingEnd = existing.keys[existing.keys.length - 1].t;
|
|
799
1073
|
const kept = existing.keys.filter((k) => k.t < start || k.t > end);
|
|
800
|
-
if (existingStart <= end && start <= existingEnd)
|
|
1074
|
+
if (existingStart <= end && start <= existingEnd) emitDevWarning(`overlapping tracks for '${tr.target}' in [${start}, ${end}]: later insertion wins (${existing.keys.length - kept.length} earlier key(s) dropped)`);
|
|
801
1075
|
existing.keys = [...kept, ...tr.keys].sort((a, b) => a.t - b.t);
|
|
802
1076
|
}
|
|
803
1077
|
return byTarget;
|
|
@@ -1103,14 +1377,21 @@ var UnboundTargetError = class extends Error {
|
|
|
1103
1377
|
*/
|
|
1104
1378
|
function bindTimeline(compiled, resolve, playhead = createPlayhead()) {
|
|
1105
1379
|
const bound = [];
|
|
1380
|
+
const samplers = /* @__PURE__ */ new Map();
|
|
1106
1381
|
for (const [target, tr] of compiled.tracks) {
|
|
1107
1382
|
const sig = resolve(target);
|
|
1108
1383
|
if (!sig) throw new UnboundTargetError(target);
|
|
1109
1384
|
sig.bindSource(() => sampleTrack(tr, playhead()));
|
|
1110
1385
|
bound.push(sig);
|
|
1386
|
+
samplers.set(target, {
|
|
1387
|
+
track: tr,
|
|
1388
|
+
value: (t) => sampleTrack(tr, t),
|
|
1389
|
+
velocity: (t) => velocityAt(tr, t)
|
|
1390
|
+
});
|
|
1111
1391
|
}
|
|
1112
1392
|
return {
|
|
1113
1393
|
playhead,
|
|
1394
|
+
samplers,
|
|
1114
1395
|
unbind: () => {
|
|
1115
1396
|
for (const sig of bound) sig.unbindSource();
|
|
1116
1397
|
}
|
|
@@ -1328,4 +1609,4 @@ function mergeSidecar(code, sidecar) {
|
|
|
1328
1609
|
return merged;
|
|
1329
1610
|
}
|
|
1330
1611
|
//#endregion
|
|
1331
|
-
export { BakeError, CircularDependencyError, ColorParseError, DEFAULT_EASE, PositionError, SidecarVersionError, TARGET_PATH, TimelineValidationError, TrackValidationError, UnboundTargetError, UnknownEasingError, UnknownValueTypeError, UnresolvableTargetError, ValueTypeInferenceError, WriteDuringEvaluationError, bake, bakeCheckpointed, beginReadPhase, bindTimeline, booleanType, buildTimeline, colorType, compileTimeline, computed, createPlayhead, cubicBezier, easings, emptySidecar, endReadPhase, evaluateAt, formatColor, getTimelineCallbacks, getValueType, inReadPhase, inferValueType, key, lerpColor, mergeSidecar, namedEasing, normalizeEditedKeys, numberType, oklabToRgba, parseColor, random, registerValueType, resolveEase, resolveTweenTarget, rgbaToOklab, sampleTrack, setDevWarning, signal, spring, springEasing, stringType, timeline, track, untracked, validateTrack, vec2Equals, vec2Signal, vec2Type };
|
|
1612
|
+
export { BakeError, CircularDependencyError, ColorParseError, DEFAULT_EASE, PositionError, SidecarVersionError, TARGET_PATH, TimelineValidationError, TrackValidationError, UnboundTargetError, UnknownEasingError, UnknownValueTypeError, UnresolvableTargetError, ValueTypeInferenceError, WriteDuringEvaluationError, bake, bakeCheckpointed, beginReadPhase, bindTimeline, booleanType, buildTimeline, colorType, compileTimeline, computed, createPlayhead, cubicBezier, cubicBezierDerivative, easingDerivatives, easings, emitDevWarning, emptySidecar, endReadPhase, evaluateAt, formatColor, getTimelineCallbacks, getValueType, inReadPhase, inferValueType, key, lerpColor, mergeSidecar, namedEasing, normalizeEditedKeys, numberType, oklabToRgba, parseColor, pathType, random, registerValueType, resolveEase, resolveEaseDerivative, resolveTweenTarget, rgbaToOklab, sampleTrack, setDevWarning, signal, spring, springEasing, springEasingDerivative, stringType, timeline, track, untracked, validateTrack, vec2Equals, vec2Signal, vec2Type, velocityAt };
|
package/package.json
CHANGED