@glissade/core 0.8.1 → 0.9.0-pre.1
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/dist/index.d.ts +79 -442
- package/dist/index.js +255 -1180
- package/dist/sidecar.d.ts +510 -0
- package/dist/sidecar.js +1269 -0
- package/dist/studioHost.d.ts +126 -0
- package/dist/studioHost.js +262 -0
- package/package.json +5 -1
|
@@ -0,0 +1,510 @@
|
|
|
1
|
+
//#region src/valueTypes.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Value-type registry with pluggable per-type interpolation (DESIGN.md §2.2).
|
|
4
|
+
* `extrapolates` declares whether a type's lerp accepts easedT outside [0,1]
|
|
5
|
+
* (spring overshoot); non-extrapolating types clamp.
|
|
6
|
+
*/
|
|
7
|
+
type Vec2 = readonly [number, number];
|
|
8
|
+
/** One bezier contour in Lottie's vertex form: anchor points + RELATIVE in/out tangents. */
|
|
9
|
+
interface PathContour {
|
|
10
|
+
closed: boolean;
|
|
11
|
+
v: Vec2[];
|
|
12
|
+
in: Vec2[];
|
|
13
|
+
out: Vec2[];
|
|
14
|
+
}
|
|
15
|
+
/** The 'path' document value (§2.2): plain JSON, serializes with no new hooks. */
|
|
16
|
+
type PathValue = PathContour[];
|
|
17
|
+
/** Transition handoff policies (v2 addendum §A.4/§B.1); 'crossfade' reserved. */
|
|
18
|
+
type HandoffKind = 'cut' | 'decay' | 'spring' | 'blend-from-frozen';
|
|
19
|
+
interface ValueType<T> {
|
|
20
|
+
id: string;
|
|
21
|
+
lerp(a: T, b: T, t: number): T;
|
|
22
|
+
/** Accepts easedT outside [0,1] (spring overshoot)? Otherwise clamped. */
|
|
23
|
+
extrapolates: boolean;
|
|
24
|
+
equals(a: T, b: T): boolean;
|
|
25
|
+
/** Optional linear-space operators (offset decay + reserved additive blending, §B.6). */
|
|
26
|
+
add?(a: T, b: T): T;
|
|
27
|
+
sub?(a: T, b: T): T;
|
|
28
|
+
scale?(a: T, k: number): T;
|
|
29
|
+
/** Type-class handoff default (§B.1): spring for kinetic, cut for hold-only. */
|
|
30
|
+
defaultHandoff?: HandoffKind;
|
|
31
|
+
/** Document (de)serialization; default identity for JSON-native types (§2.2). */
|
|
32
|
+
serialize?(value: T): unknown;
|
|
33
|
+
deserialize?(raw: unknown): T;
|
|
34
|
+
}
|
|
35
|
+
type ValueTypeId = 'number' | 'vec2' | 'color' | 'string' | 'boolean' | (string & {});
|
|
36
|
+
declare function registerValueType<T>(vt: ValueType<T>): void;
|
|
37
|
+
declare class UnknownValueTypeError extends Error {
|
|
38
|
+
constructor(id: string);
|
|
39
|
+
}
|
|
40
|
+
declare function getValueType<T = unknown>(id: ValueTypeId): ValueType<T>;
|
|
41
|
+
declare const numberType: ValueType<number>;
|
|
42
|
+
declare const vec2Equals: (a: Vec2, b: Vec2) => boolean;
|
|
43
|
+
declare const vec2Type: ValueType<Vec2>;
|
|
44
|
+
/** vec2 swept along a circular arc: polar lerp of radius + shortest-path angle (§2.2). */
|
|
45
|
+
declare const vec2ArcType: ValueType<Vec2>;
|
|
46
|
+
declare const colorType: ValueType<string>;
|
|
47
|
+
declare const stringType: ValueType<string>;
|
|
48
|
+
declare const booleanType: ValueType<boolean>;
|
|
49
|
+
/**
|
|
50
|
+
* Path morphing (§2.2): pairwise lerp of anchors and tangents — exactly how
|
|
51
|
+
* lottie-web morphs, so imported animations are pixel-faithful. Mismatched
|
|
52
|
+
* topology snaps (hold a, then b at t ≥ 1) with a one-time dev warning; the
|
|
53
|
+
* de Casteljau normalization fallback for arbitrary native morphs is tracked
|
|
54
|
+
* future work. Lerp-only: offsets are not well-defined under mismatched
|
|
55
|
+
* topology, so no add/sub/scale — handoffs blend from the frozen value.
|
|
56
|
+
*/
|
|
57
|
+
declare const pathType: ValueType<PathValue>;
|
|
58
|
+
declare class ValueTypeInferenceError extends Error {
|
|
59
|
+
constructor(value: unknown);
|
|
60
|
+
}
|
|
61
|
+
/** Infer a registered type id from a sample value (builder + bake authoring surfaces). */
|
|
62
|
+
declare function inferValueType(value: unknown): ValueTypeId;
|
|
63
|
+
//#endregion
|
|
64
|
+
//#region src/easing.d.ts
|
|
65
|
+
/**
|
|
66
|
+
* Easing registry + cubic bézier (DESIGN.md §2.2). All functions map [0,1]→ℝ
|
|
67
|
+
* with f(0)=0 and f(1)=1; back/elastic intentionally leave [0,1].
|
|
68
|
+
*/
|
|
69
|
+
type EasingFn = (t: number) => number;
|
|
70
|
+
type EaseSpec = string | {
|
|
71
|
+
kind: 'cubicBezier';
|
|
72
|
+
pts: [number, number, number, number];
|
|
73
|
+
} | {
|
|
74
|
+
kind: 'spring';
|
|
75
|
+
stiffness: number;
|
|
76
|
+
damping: number;
|
|
77
|
+
mass: number;
|
|
78
|
+
};
|
|
79
|
+
declare const easings: Record<string, EasingFn>;
|
|
80
|
+
/**
|
|
81
|
+
* Analytic derivatives d(u) of every named ease (§B.6) — closed-form, used
|
|
82
|
+
* for reading velocity off in-flight curves at interruption time. Property-
|
|
83
|
+
* tested against central differences at interior points.
|
|
84
|
+
*/
|
|
85
|
+
declare const easingDerivatives: Record<string, EasingFn>;
|
|
86
|
+
/** Default property-tween ease (Motion Canvas precedent). */
|
|
87
|
+
declare const DEFAULT_EASE = "easeInOutCubic";
|
|
88
|
+
/**
|
|
89
|
+
* CSS-style cubic bézier where x is time and y is progress. Newton's method
|
|
90
|
+
* with a bisection fallback for the flat-derivative regions.
|
|
91
|
+
*/
|
|
92
|
+
declare function cubicBezier(p1x: number, p1y: number, p2x: number, p2y: number): EasingFn;
|
|
93
|
+
/** Analytic dy/dx of a cubic bézier ease: y'(s)/x'(s) at the solved parameter (§B.6). */
|
|
94
|
+
declare function cubicBezierDerivative(p1x: number, p1y: number, p2x: number, p2y: number): EasingFn;
|
|
95
|
+
declare class UnknownEasingError extends Error {
|
|
96
|
+
constructor(name: string);
|
|
97
|
+
}
|
|
98
|
+
declare function namedEasing(name: string): EasingFn;
|
|
99
|
+
//#endregion
|
|
100
|
+
//#region src/spring.d.ts
|
|
101
|
+
interface SpringConfig {
|
|
102
|
+
stiffness: number;
|
|
103
|
+
damping: number;
|
|
104
|
+
mass?: number;
|
|
105
|
+
}
|
|
106
|
+
interface SpringEase {
|
|
107
|
+
kind: 'spring';
|
|
108
|
+
stiffness: number;
|
|
109
|
+
damping: number;
|
|
110
|
+
mass: number;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Settle duration: the earliest time after which |x - 1| stays within
|
|
114
|
+
* settleTolerance. Closed-form via the decay envelope for the underdamped
|
|
115
|
+
* case; bisection on the monotone tail otherwise. Deterministic.
|
|
116
|
+
*/
|
|
117
|
+
declare function duration(cfg: SpringConfig, opts?: {
|
|
118
|
+
settleTolerance?: number;
|
|
119
|
+
}): number;
|
|
120
|
+
/**
|
|
121
|
+
* Spring progress at local time t, affinely rescaled so value(duration) = 1
|
|
122
|
+
* exactly — the raw form only approaches 1, and an unscaled curve would snap
|
|
123
|
+
* at the key (§2.7 "endpoint continuity"). May exceed 1 (overshoot).
|
|
124
|
+
*/
|
|
125
|
+
declare function value(cfg: SpringConfig, t: number, opts?: {
|
|
126
|
+
settleTolerance?: number;
|
|
127
|
+
}): number;
|
|
128
|
+
/**
|
|
129
|
+
* Velocity-matched retarget oscillator (v2 addendum §B.3): the same damped
|
|
130
|
+
* harmonic oscillator on an OFFSET in value units with nonzero initial
|
|
131
|
+
* velocity — y(0)=x0, y'(0)=v0, decaying to 0. No affine rescale (the target
|
|
132
|
+
* is exactly 0). Pure closed forms; seek-safe at any τ.
|
|
133
|
+
*/
|
|
134
|
+
interface RetargetSpring {
|
|
135
|
+
value(tau: number): number;
|
|
136
|
+
velocity(tau: number): number;
|
|
137
|
+
/** Earliest τ after which |value| stays within tol (default 0.005·|x0|+1e-6 floor). */
|
|
138
|
+
settleTime(tol?: number): number;
|
|
139
|
+
}
|
|
140
|
+
declare function retarget(cfg: SpringConfig, x0: number, v0: number): RetargetSpring;
|
|
141
|
+
interface SpringFactory {
|
|
142
|
+
(cfg: SpringConfig): SpringEase;
|
|
143
|
+
duration: typeof duration;
|
|
144
|
+
value: typeof value;
|
|
145
|
+
retarget: typeof retarget;
|
|
146
|
+
}
|
|
147
|
+
declare const spring: SpringFactory;
|
|
148
|
+
/**
|
|
149
|
+
* Named spring feels (react-spring conventions, mass 1) — a vocabulary instead
|
|
150
|
+
* of hand-tuned stiffness/damping. Use `spring(springPresets.wobbly)` or
|
|
151
|
+
* `springTo(t, a, b, springPresets.gentle)`.
|
|
152
|
+
*/
|
|
153
|
+
declare const springPresets: {
|
|
154
|
+
readonly default: {
|
|
155
|
+
readonly stiffness: 170;
|
|
156
|
+
readonly damping: 26;
|
|
157
|
+
};
|
|
158
|
+
readonly gentle: {
|
|
159
|
+
readonly stiffness: 120;
|
|
160
|
+
readonly damping: 14;
|
|
161
|
+
};
|
|
162
|
+
readonly wobbly: {
|
|
163
|
+
readonly stiffness: 180;
|
|
164
|
+
readonly damping: 12;
|
|
165
|
+
};
|
|
166
|
+
readonly stiff: {
|
|
167
|
+
readonly stiffness: 210;
|
|
168
|
+
readonly damping: 20;
|
|
169
|
+
};
|
|
170
|
+
readonly slow: {
|
|
171
|
+
readonly stiffness: 280;
|
|
172
|
+
readonly damping: 60;
|
|
173
|
+
};
|
|
174
|
+
readonly molasses: {
|
|
175
|
+
readonly stiffness: 280;
|
|
176
|
+
readonly damping: 120;
|
|
177
|
+
};
|
|
178
|
+
};
|
|
179
|
+
/**
|
|
180
|
+
* The spring as a normalized easing over a segment whose length must equal
|
|
181
|
+
* spring.duration(cfg) (validated at the document layer, §2.7).
|
|
182
|
+
*/
|
|
183
|
+
declare function springEasing(cfg: SpringConfig): EasingFn;
|
|
184
|
+
/**
|
|
185
|
+
* Analytic d/dp of springEasing (§B.6): oscillator derivative × the affine
|
|
186
|
+
* rescale factor × duration (chain rule p → t = p·D). Flat past p=1,
|
|
187
|
+
* matching value()'s clamp (right-derivative convention).
|
|
188
|
+
*/
|
|
189
|
+
declare function springEasingDerivative(cfg: SpringConfig): EasingFn;
|
|
190
|
+
//#endregion
|
|
191
|
+
//#region src/track.d.ts
|
|
192
|
+
interface Key<T = unknown> {
|
|
193
|
+
t: number;
|
|
194
|
+
value: T;
|
|
195
|
+
/** Shape of the segment ARRIVING at this key (from the previous key). */
|
|
196
|
+
ease?: EaseSpec;
|
|
197
|
+
interp?: 'default' | 'hold';
|
|
198
|
+
/** Stable key id (studio-assigned); optional in code-authored documents. */
|
|
199
|
+
id?: string;
|
|
200
|
+
/** Builder-resolved implicit from-value; re-resolved on merge (§2.6, §6.2). */
|
|
201
|
+
derived?: boolean;
|
|
202
|
+
/** Reserved (§4.7): a v2 synthesized-transition leading key reads the live value. v1 accepts but ignores it. */
|
|
203
|
+
from?: 'live';
|
|
204
|
+
}
|
|
205
|
+
interface Track<T = unknown> {
|
|
206
|
+
/** Canonical path: '<nodeId>/<prop.path>', e.g. 'circle/position.x'. */
|
|
207
|
+
target: string;
|
|
208
|
+
type: ValueTypeId;
|
|
209
|
+
/** Sorted by t; enforced by validateTrack(). */
|
|
210
|
+
keys: Key<T>[];
|
|
211
|
+
/** Studio may own this track's keys via sidecar (§6.2). */
|
|
212
|
+
editable?: boolean;
|
|
213
|
+
/** Reserved (§2.2/§B.6): v2 additive blending. v1 accepts but ignores it (coalesce stays last-wins). */
|
|
214
|
+
additive?: boolean;
|
|
215
|
+
}
|
|
216
|
+
declare class TrackValidationError extends Error {
|
|
217
|
+
constructor(target: string, message: string);
|
|
218
|
+
}
|
|
219
|
+
declare function validateTrack(track: Track): void;
|
|
220
|
+
type KeyOpts<T> = Partial<Omit<Key<T>, 't' | 'value'>>;
|
|
221
|
+
declare function key<T>(t: number, value: T, easeOrOpts?: EaseSpec | KeyOpts<T>): Key<T>;
|
|
222
|
+
/**
|
|
223
|
+
* The settle-ON-the-beat helper: a spring key must sit at prev.t +
|
|
224
|
+
* spring.duration(cfg) (§2.7), so beat-anchored authoring otherwise means
|
|
225
|
+
* hand-computing the launch time. springTo returns the [launch, settle] key
|
|
226
|
+
* pair with the arithmetic done — spread it into a raw track():
|
|
227
|
+
* track('x/width', 'number', [...springTo(beats.start('drop'), 0, 320, cfg)])
|
|
228
|
+
*/
|
|
229
|
+
declare function springTo<T>(endT: number, from: T, to: T, cfg: SpringConfig): [Key<T>, Key<T>];
|
|
230
|
+
/**
|
|
231
|
+
* Cascade a set of tracks by shifting each one's key times — the classic
|
|
232
|
+
* stagger for animating a list of nodes with a delay between them. `delay` is
|
|
233
|
+
* the per-index gap in seconds, or a function of the index for non-linear
|
|
234
|
+
* cascades. Pure: returns new tracks, leaving the inputs untouched.
|
|
235
|
+
*
|
|
236
|
+
* stagger(items.map((it, i) => track(`${it.id}/opacity`, 'number',
|
|
237
|
+
* [key(0, 0), key(0.3, 1, 'easeOutCubic')])), 0.08)
|
|
238
|
+
*/
|
|
239
|
+
declare function stagger<T>(tracks: readonly Track<T>[], delay: number | ((index: number) => number)): Track<T>[];
|
|
240
|
+
declare function track<T>(target: string, type: ValueTypeId, keys: Key<T>[], opts?: {
|
|
241
|
+
editable?: boolean;
|
|
242
|
+
}): Track<T>;
|
|
243
|
+
declare function resolveEase(spec: EaseSpec | undefined): EasingFn;
|
|
244
|
+
/**
|
|
245
|
+
* Analytic d(u) for an ease spec (§B.6). Custom-registered eases without a
|
|
246
|
+
* derivative fall back to a symmetric difference with a one-time dev warning.
|
|
247
|
+
*/
|
|
248
|
+
declare function resolveEaseDerivative(spec: EaseSpec | undefined): EasingFn;
|
|
249
|
+
/**
|
|
250
|
+
* Analytic track derivative at time t, in value-units per second of local
|
|
251
|
+
* track time (v2 addendum §B.3/§B.6 conventions, pinned):
|
|
252
|
+
* (a) at a key boundary, velocity is the RIGHT derivative;
|
|
253
|
+
* (b) hold segments and the clamped regions outside the keys have v = 0;
|
|
254
|
+
* (c) types without sub/scale operators return null (no kinetic velocity).
|
|
255
|
+
*/
|
|
256
|
+
declare function velocityAt<T>(tr: Track<T>, t: number): T | null;
|
|
257
|
+
/** Pure sample of a track at time t (§2.4). */
|
|
258
|
+
declare function sampleTrack<T>(tr: Track<T>, t: number): T;
|
|
259
|
+
//#endregion
|
|
260
|
+
//#region src/devWarning.d.ts
|
|
261
|
+
/** The configurable dev-warning channel (no DOM lib in core; console may not exist). */
|
|
262
|
+
type DevWarning = (message: string) => void;
|
|
263
|
+
declare function setDevWarning(fn: DevWarning): void;
|
|
264
|
+
/** Internal: emit through the configurable channel. */
|
|
265
|
+
declare function emitDevWarning(message: string): void;
|
|
266
|
+
//#endregion
|
|
267
|
+
//#region src/timeline.d.ts
|
|
268
|
+
type Json = null | boolean | number | string | Json[] | {
|
|
269
|
+
[k: string]: Json;
|
|
270
|
+
};
|
|
271
|
+
interface Marker {
|
|
272
|
+
t: number;
|
|
273
|
+
name: string;
|
|
274
|
+
data?: Json;
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* One concrete font face within a family — a (weight, style) variant at a URL.
|
|
278
|
+
* `weight`/`style` default to 400/'normal' (the CSS regular face). Lives on
|
|
279
|
+
* AssetRef.faces; a bare `{ kind: 'font', url }` is exactly the 400/normal face
|
|
280
|
+
* with no extra variants (so existing documents stay byte-identical, §3.6).
|
|
281
|
+
*/
|
|
282
|
+
interface FontFaceRef {
|
|
283
|
+
url: string;
|
|
284
|
+
weight?: number | undefined;
|
|
285
|
+
style?: 'normal' | 'italic' | undefined;
|
|
286
|
+
}
|
|
287
|
+
interface AssetRef {
|
|
288
|
+
kind: 'font' | 'image' | 'audio' | 'video' | 'timeline';
|
|
289
|
+
url: string;
|
|
290
|
+
/**
|
|
291
|
+
* Font only (§3.6): the explicit face set for this family. When present, the
|
|
292
|
+
* loaders register EVERY face (not the single `url`); the family-level `url`
|
|
293
|
+
* is the implicit 400/normal face. Omitted = the bare single-face form.
|
|
294
|
+
*/
|
|
295
|
+
faces?: FontFaceRef[] | undefined;
|
|
296
|
+
/**
|
|
297
|
+
* Font only (§3.6): the explicit fallback family chain, in order. The
|
|
298
|
+
* registry resolves `[family, ...fallback]` for glyph coverage. Omitted = no
|
|
299
|
+
* declared fallback (system fallback still applies in the rasterizer).
|
|
300
|
+
*/
|
|
301
|
+
fallback?: string[] | undefined;
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* A gain envelope: keys of linear gain multipliers on the clip's local time
|
|
305
|
+
* axis. A full Track satisfies it structurally, but its target/type carry no
|
|
306
|
+
* meaning here — `{ keys: [...] }` is all a clip needs.
|
|
307
|
+
*/
|
|
308
|
+
interface GainEnvelope {
|
|
309
|
+
keys: Key[];
|
|
310
|
+
}
|
|
311
|
+
/** Audio is timeline metadata, never a render product (§5.3). */
|
|
312
|
+
interface AudioClip {
|
|
313
|
+
asset: AssetRef;
|
|
314
|
+
/** timeline seconds (frame-quantized at export via sample-position arithmetic) */
|
|
315
|
+
at: number;
|
|
316
|
+
/** seconds within the source asset */
|
|
317
|
+
trim?: {
|
|
318
|
+
start: number;
|
|
319
|
+
end: number;
|
|
320
|
+
};
|
|
321
|
+
gain?: GainEnvelope;
|
|
322
|
+
playbackRate?: number;
|
|
323
|
+
}
|
|
324
|
+
interface ChildEntry {
|
|
325
|
+
timeline: Timeline;
|
|
326
|
+
/** Offset on the parent time axis. */
|
|
327
|
+
at: number;
|
|
328
|
+
/**
|
|
329
|
+
* 'add': flattened at compile time into the parent's track space.
|
|
330
|
+
* 'sync': opaque sub-timeline with its own clock (parent t maps through
|
|
331
|
+
* at/timeScale); never coalesced against parent tracks.
|
|
332
|
+
*/
|
|
333
|
+
mode: 'add' | 'sync';
|
|
334
|
+
/** sync-mode only: child plays at this rate. */
|
|
335
|
+
timeScale?: number;
|
|
336
|
+
}
|
|
337
|
+
interface Timeline {
|
|
338
|
+
version: 1;
|
|
339
|
+
duration?: number;
|
|
340
|
+
/**
|
|
341
|
+
* Studio opt-in (§6.2 rule 4): the timeline duration is code-owned and
|
|
342
|
+
* read-only in the editor UNLESS this flag is set (via `editableDuration()`
|
|
343
|
+
* on the builder, or directly). Mirrors `track.editable` for tracks.
|
|
344
|
+
*/
|
|
345
|
+
editableDuration?: boolean;
|
|
346
|
+
fps?: number;
|
|
347
|
+
posterTime?: number;
|
|
348
|
+
tracks: Track[];
|
|
349
|
+
labels?: Record<string, number>;
|
|
350
|
+
markers?: Marker[];
|
|
351
|
+
children?: ChildEntry[];
|
|
352
|
+
audio?: AudioClip[];
|
|
353
|
+
assets?: Record<string, AssetRef>;
|
|
354
|
+
}
|
|
355
|
+
interface TimelineInit {
|
|
356
|
+
tracks?: Track[];
|
|
357
|
+
duration?: number;
|
|
358
|
+
/** Studio opt-in: expose the duration to editor editing (§6.2 rule 4). */
|
|
359
|
+
editableDuration?: boolean;
|
|
360
|
+
fps?: number;
|
|
361
|
+
posterTime?: number;
|
|
362
|
+
labels?: Record<string, number>;
|
|
363
|
+
markers?: Marker[];
|
|
364
|
+
children?: ChildEntry[];
|
|
365
|
+
audio?: AudioClip[];
|
|
366
|
+
assets?: Record<string, AssetRef>;
|
|
367
|
+
}
|
|
368
|
+
declare class TimelineValidationError extends Error {
|
|
369
|
+
constructor(message: string);
|
|
370
|
+
}
|
|
371
|
+
interface CompiledTimeline {
|
|
372
|
+
duration: number;
|
|
373
|
+
labels: Record<string, number>;
|
|
374
|
+
markers: Marker[];
|
|
375
|
+
/** One track per target (§2.2), keys rebased to the root time axis. */
|
|
376
|
+
tracks: Map<string, Track>;
|
|
377
|
+
/** Audio clips rebased to the root time axis (§5.3); sync timeScale scales playbackRate. */
|
|
378
|
+
audio: AudioClip[];
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Sample-indexed clip offset — the single A/V-sync source of truth (§5.3),
|
|
382
|
+
* `round(at * sampleRate)`. Both the CLI (FFmpeg) and the browser
|
|
383
|
+
* (OfflineAudioContext) mixers derive their delay from this, so A/V offsets
|
|
384
|
+
* agree across paths by construction rather than one rounding to milliseconds
|
|
385
|
+
* and the other to raw float seconds. Default rate is the canonical mix grid.
|
|
386
|
+
*/
|
|
387
|
+
declare function audioOffsetSamples(at: number, sampleRate?: number): number;
|
|
388
|
+
/**
|
|
389
|
+
* Studio reader (§6.2 rule 4): is this timeline's duration opted into editor
|
|
390
|
+
* editing? Code-owned and read-only by default; `editableDuration()` flips it.
|
|
391
|
+
*/
|
|
392
|
+
declare function isDurationEditable(doc: Timeline): boolean;
|
|
393
|
+
declare function compileTimeline(doc: Timeline): CompiledTimeline;
|
|
394
|
+
//#endregion
|
|
395
|
+
//#region src/targetRef.d.ts
|
|
396
|
+
/**
|
|
397
|
+
* Target references (DESIGN.md §2.6): the builder accepts either a canonical
|
|
398
|
+
* target string ('circle/opacity') or a property signal that carries its own
|
|
399
|
+
* path — attached by the scene package at node construction via TARGET_PATH.
|
|
400
|
+
*/
|
|
401
|
+
declare const TARGET_PATH: unique symbol;
|
|
402
|
+
interface TargetCarrier {
|
|
403
|
+
[TARGET_PATH]?: string;
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* A target string, or any object carrying TARGET_PATH (property signals of
|
|
407
|
+
* id-bearing nodes). Typed as `object` because signals are callables and the
|
|
408
|
+
* symbol prop is attached dynamically; resolution is checked at build time.
|
|
409
|
+
*/
|
|
410
|
+
type TweenTarget = string | object;
|
|
411
|
+
declare class UnresolvableTargetError extends Error {
|
|
412
|
+
constructor(message?: string);
|
|
413
|
+
}
|
|
414
|
+
/** The node-id portion of a canonical `nodeId/prop.path` target. */
|
|
415
|
+
declare function targetNodeId(target: string): string;
|
|
416
|
+
/**
|
|
417
|
+
* The single editable-host rule (§6.4 sub-decision, the 0.9 locked predicate):
|
|
418
|
+
* only a node with an EXPLICIT, non-structural id can host an editable or
|
|
419
|
+
* editor-created track. Structural fallback ids (`~Type.ordinal`, §6.5) are
|
|
420
|
+
* inspection-only and reorder-fragile, so they are never editable nor valid
|
|
421
|
+
* track targets. Lives here (the addressing module) so the builder guard, the
|
|
422
|
+
* scene, and the studio host all share ONE definition.
|
|
423
|
+
*/
|
|
424
|
+
declare function isEditableNodeId(id: string | undefined | null): id is string;
|
|
425
|
+
declare function resolveTweenTarget(target: TweenTarget): string;
|
|
426
|
+
//#endregion
|
|
427
|
+
//#region src/sidecar.d.ts
|
|
428
|
+
type OrphanReason = 'node-missing' | 'prop-missing' | 'type-changed';
|
|
429
|
+
interface SidecarTrackEntry {
|
|
430
|
+
/** value type, so an editor-created track binds without a code baseline. */
|
|
431
|
+
type: ValueTypeId;
|
|
432
|
+
/** hash of the code baseline this track branched from; null = editor-created. */
|
|
433
|
+
baseHash: string | null;
|
|
434
|
+
keys: Key[];
|
|
435
|
+
}
|
|
436
|
+
interface SidecarOrphan {
|
|
437
|
+
type: ValueTypeId;
|
|
438
|
+
keys: Key[];
|
|
439
|
+
reason: OrphanReason;
|
|
440
|
+
}
|
|
441
|
+
interface SidecarTimelineEntry {
|
|
442
|
+
/** editor-owned tracks, keyed by canonical target. */
|
|
443
|
+
tracks: Record<string, SidecarTrackEntry>;
|
|
444
|
+
/** editor-created labels. */
|
|
445
|
+
labels?: Record<string, number>;
|
|
446
|
+
/** tracks parked off the merge because their target drifted (§6.2 rule 3). */
|
|
447
|
+
orphans?: Record<string, SidecarOrphan>;
|
|
448
|
+
}
|
|
449
|
+
interface SidecarDoc {
|
|
450
|
+
sidecarVersion: 2;
|
|
451
|
+
/** edits namespaced by timeline id; the linear timeline is 'main'. */
|
|
452
|
+
timelines: Record<string, SidecarTimelineEntry>;
|
|
453
|
+
}
|
|
454
|
+
/** The flat v1 shape, accepted on load and migrated forward. */
|
|
455
|
+
interface SidecarDocV1 {
|
|
456
|
+
sidecarVersion: 1;
|
|
457
|
+
tracks: Track[];
|
|
458
|
+
labels?: Record<string, number>;
|
|
459
|
+
}
|
|
460
|
+
declare class SidecarVersionError extends Error {
|
|
461
|
+
constructor(version: unknown);
|
|
462
|
+
}
|
|
463
|
+
declare function emptySidecar(): SidecarDoc;
|
|
464
|
+
/** Lift a v1 (or already-v2) document to the v2 shape. Throws on unknown versions. */
|
|
465
|
+
declare function migrateSidecar(doc: SidecarDoc | SidecarDocV1 | null | undefined): SidecarDoc | null;
|
|
466
|
+
/** Stable hash of a code track's keys — the baseline an editor branch records. */
|
|
467
|
+
declare function hashKeys(keys: readonly Key[]): string;
|
|
468
|
+
/** Assign stable monotonic `k<N>` ids to keys lacking one; existing ids preserved. */
|
|
469
|
+
declare function assignKeyIds(keys: readonly Key[]): Key[];
|
|
470
|
+
/**
|
|
471
|
+
* Set one editable track's keys in the sidecar (§6.2) — the studio write path.
|
|
472
|
+
* `codeBaselineKeys` is the code track this branches from (null = editor-created
|
|
473
|
+
* with no baseline). Keys get stable `k<N>` ids. Returns a new document.
|
|
474
|
+
*/
|
|
475
|
+
declare function setSidecarTrack(doc: SidecarDoc, timelineId: string, target: string, type: ValueTypeId, keys: Key[], codeBaselineKeys: readonly Key[] | null): SidecarDoc;
|
|
476
|
+
/**
|
|
477
|
+
* Remove one editor-owned track from the sidecar (§6.2 rule 7 write-back): the
|
|
478
|
+
* "extract edits to code" affordance deletes the sidecar entry after copying its
|
|
479
|
+
* `key(...)` source to the clipboard. Source is never mutated — the user pastes
|
|
480
|
+
* the generated calls themselves. A missing entry is a no-op (returns the input
|
|
481
|
+
* unchanged); the document is never mutated in place.
|
|
482
|
+
*/
|
|
483
|
+
declare function deleteSidecarTrack(doc: SidecarDoc, timelineId: string, target: string): SidecarDoc;
|
|
484
|
+
interface MergeResult {
|
|
485
|
+
timeline: Timeline;
|
|
486
|
+
/** targets whose code baseline changed beneath the editor's keys (§6.2 rule 2). */
|
|
487
|
+
drift: string[];
|
|
488
|
+
/** sidecar tracks parked off the merge (§6.2 rule 3). */
|
|
489
|
+
orphans: Record<string, SidecarOrphan>;
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* Merge with the full §6.2 report: the bindable Timeline, the list of targets
|
|
493
|
+
* whose code baseline drifted, and the orphaned tracks (type-changed, or whose
|
|
494
|
+
* code track vanished). Orphans are NEVER merged, so a drifted edit can't make
|
|
495
|
+
* the whole overlay fail to bind — the good edits survive. Inputs unmutated.
|
|
496
|
+
*/
|
|
497
|
+
declare function mergeSidecarDetailed(code: Timeline, sidecar: SidecarDoc | SidecarDocV1 | null | undefined): MergeResult;
|
|
498
|
+
/** Merge the sidecar overlay onto the code baseline → a bindable Timeline (§6.2). */
|
|
499
|
+
declare function mergeSidecar(code: Timeline, sidecar: SidecarDoc | SidecarDocV1 | null | undefined): Timeline;
|
|
500
|
+
/**
|
|
501
|
+
* Editor-edit normalization (§2.7 invariant): a spring-eased key's t is
|
|
502
|
+
* intrinsic — prev.t + spring.duration(cfg) — so after any retime, sort and
|
|
503
|
+
* re-pin spring keys to their predecessors. Dragging a spring key itself
|
|
504
|
+
* therefore snaps back; retiming its predecessor carries it along. Returns a
|
|
505
|
+
* new array. Colliding keys are NUDGED apart (+1ms), never deleted — an editor
|
|
506
|
+
* must not silently destroy keyframe data on an exact-t collision.
|
|
507
|
+
*/
|
|
508
|
+
declare function normalizeEditedKeys(keys: Key[]): Key[];
|
|
509
|
+
//#endregion
|
|
510
|
+
export { validateTrack as $, GainEnvelope as A, pathType as At, emitDevWarning as B, resolveTweenTarget as C, ValueTypeInferenceError as Ct, ChildEntry as D, getValueType as Dt, AudioClip as E, colorType as Et, TimelineValidationError as F, vec2Type as Ft, TrackValidationError as G, Key as H, audioOffsetSamples as I, resolveEaseDerivative as J, key as K, compileTimeline as L, Marker as M, stringType as Mt, Timeline as N, vec2ArcType as Nt, CompiledTimeline as O, inferValueType as Ot, TimelineInit as P, vec2Equals as Pt, track as Q, isDurationEditable as R, isEditableNodeId as S, ValueTypeId as St, AssetRef as T, booleanType as Tt, KeyOpts as U, setDevWarning as V, Track as W, springTo as X, sampleTrack as Y, stagger as Z, setSidecarTrack as _, HandoffKind as _t, SidecarOrphan as a, springEasing as at, TweenTarget as b, UnknownValueTypeError as bt, SidecarVersionError as c, DEFAULT_EASE as ct, emptySidecar as d, UnknownEasingError as dt, velocityAt as et, hashKeys as f, cubicBezier as ft, normalizeEditedKeys as g, namedEasing as gt, migrateSidecar as h, easings as ht, SidecarDocV1 as i, spring as it, Json as j, registerValueType as jt, FontFaceRef as k, numberType as kt, assignKeyIds as l, EaseSpec as lt, mergeSidecarDetailed as m, easingDerivatives as mt, OrphanReason as n, SpringConfig as nt, SidecarTimelineEntry as o, springEasingDerivative as ot, mergeSidecar as p, cubicBezierDerivative as pt, resolveEase as q, SidecarDoc as r, SpringEase as rt, SidecarTrackEntry as s, springPresets as st, MergeResult as t, RetargetSpring as tt, deleteSidecarTrack as u, EasingFn as ut, TARGET_PATH as v, PathContour as vt, targetNodeId as w, Vec2 as wt, UnresolvableTargetError as x, ValueType as xt, TargetCarrier as y, PathValue as yt, DevWarning as z };
|