@glissade/core 0.10.0 → 0.10.1-pre.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/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as validateTrack, A as GainEnvelope, At as pathType, B as emitDevWarning, C as resolveTweenTarget, Ct as ValueTypeInferenceError, D as ChildEntry, Dt as getValueType, E as AudioClip, Et as colorType, F as TimelineValidationError, Ft as vec2Type, G as TrackValidationError, H as Key, I as audioOffsetSamples, J as resolveEaseDerivative, K as key, L as compileTimeline, M as Marker, Mt as stringType, N as Timeline, Nt as vec2ArcType, O as CompiledTimeline, Ot as inferValueType, P as TimelineInit, Pt as vec2Equals, Q as track, R as isDurationEditable, S as isEditableNodeId, St as ValueTypeId, T as AssetRef, Tt as booleanType, U as KeyOpts, V as setDevWarning, W as Track, X as springTo, Y as sampleTrack, Z as stagger, _ as setSidecarTrack, _t as HandoffKind, a as SidecarOrphan, at as springEasing, b as TweenTarget, bt as UnknownValueTypeError, c as SidecarVersionError, ct as DEFAULT_EASE, d as emptySidecar, dt as UnknownEasingError, et as velocityAt, f as hashKeys, ft as cubicBezier, g as normalizeEditedKeys, gt as namedEasing, h as migrateSidecar, ht as easings, i as SidecarDocV1, it as spring, j as Json, jt as registerValueType, k as FontFaceRef, kt as numberType, l as assignKeyIds, lt as EaseSpec, m as mergeSidecarDetailed, mt as easingDerivatives, n as OrphanReason, nt as SpringConfig, o as SidecarTimelineEntry, ot as springEasingDerivative, p as mergeSidecar, pt as cubicBezierDerivative, q as resolveEase, r as SidecarDoc, rt as SpringEase, s as SidecarTrackEntry, st as springPresets, t as MergeResult, tt as RetargetSpring, u as deleteSidecarTrack, ut as EasingFn, v as TARGET_PATH, vt as PathContour, w as targetNodeId, wt as Vec2, x as UnresolvableTargetError, xt as ValueType, y as TargetCarrier, yt as PathValue, z as DevWarning } from "./sidecar.js";
1
+ import { $ as validateTrack, A as GainEnvelope, At as inferValueType, B as emitDevWarning, C as resolveTweenTarget, Ct as ValueType, D as ChildEntry, Dt as booleanType, E as AudioClip, Et as Vec2, F as TimelineValidationError, Ft as stringType, G as TrackValidationError, H as Key, I as audioOffsetSamples, It as vec2ArcType, J as resolveEaseDerivative, K as key, L as compileTimeline, Lt as vec2Equals, M as Marker, Mt as paintType, N as Timeline, Nt as pathType, O as CompiledTimeline, Ot as colorType, P as TimelineInit, Pt as registerValueType, Q as track, R as isDurationEditable, Rt as vec2Type, S as isEditableNodeId, St as UnknownValueTypeError, T as AssetRef, Tt as ValueTypeInferenceError, U as KeyOpts, V as setDevWarning, W as Track, X as springTo, Y as sampleTrack, Z as stagger, _ as setSidecarTrack, _t as ColorStop, a as SidecarOrphan, at as springEasing, b as TweenTarget, bt as PathContour, c as SidecarVersionError, ct as DEFAULT_EASE, d as emptySidecar, dt as UnknownEasingError, et as velocityAt, f as hashKeys, ft as cubicBezier, g as normalizeEditedKeys, gt as namedEasing, h as migrateSidecar, ht as easings, i as SidecarDocV1, it as spring, j as Json, jt as numberType, k as FontFaceRef, kt as getValueType, l as assignKeyIds, lt as EaseSpec, m as mergeSidecarDetailed, mt as easingDerivatives, n as OrphanReason, nt as SpringConfig, o as SidecarTimelineEntry, ot as springEasingDerivative, p as mergeSidecar, pt as cubicBezierDerivative, q as resolveEase, r as SidecarDoc, rt as SpringEase, s as SidecarTrackEntry, st as springPresets, t as MergeResult, tt as RetargetSpring, u as deleteSidecarTrack, ut as EasingFn, v as TARGET_PATH, vt as HandoffKind, w as targetNodeId, wt as ValueTypeId, x as UnresolvableTargetError, xt as PathValue, y as TargetCarrier, yt as Paint, z as DevWarning } from "./sidecar.js";
2
2
 
3
3
  //#region src/signal.d.ts
4
4
 
@@ -357,4 +357,4 @@ interface CheckpointedSim {
357
357
  }
358
358
  declare function bakeCheckpointed<W, S = W>(cfg: CheckpointedBakeConfig<W, S>): CheckpointedSim;
359
359
  //#endregion
360
- 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 CoverageReport, type CurveSampler, DEFAULT_EASE, type DevWarning, type EaseSpec, type EasingFn, type Equals, type FontFaceRef, type FontMode, type FontRegistry, type FontUsage, FontValidationError, type GainEnvelope, type HandoffKind, type Json, type Key, type KeyOpts, type Marker, type MergeResult, type MissingGlyphs, type OkLab, type OrphanReason, type PathContour, type PathValue, type Playhead, type Position, PositionError, type ReadonlySignal, type ResolvedFace, type RetargetSpring, type Rgba, type Rng, type Scheduler, type SidecarDoc, type SidecarDocV1, type SidecarOrphan, type SidecarTimelineEntry, type SidecarTrackEntry, 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 ValidateFontsOptions, type ValueType, type ValueTypeId, ValueTypeInferenceError, type Vec2, type Vec2Signal, WriteDuringEvaluationError, assignKeyIds, audioOffsetSamples, bake, bakeCheckpointed, batch, beginReadPhase, bindTimeline, booleanType, buildFontRegistry, buildTimeline, colorType, compileTimeline, computed, createPlayhead, cubicBezier, cubicBezierDerivative, deleteSidecarTrack, easingDerivatives, easings, emitDevWarning, emptySidecar, endReadPhase, evaluateAt, formatColor, getTimelineCallbacks, getValueType, hashKeys, inReadPhase, inferValueType, isDurationEditable, isEditableNodeId, isExemptFamily, key, lerpColor, mergeSidecar, mergeSidecarDetailed, migrateSidecar, namedEasing, normalizeEditedKeys, numberType, oklabToRgba, parseCmap, parseColor, pathType, random, registerValueType, resolveEase, resolveEaseDerivative, resolveTweenTarget, rgbaToOklab, sampleTrack, setDevWarning, setScheduler, setSidecarTrack, signal, spring, springEasing, springEasingDerivative, springPresets, springTo, stagger, stringType, synchronousScheduler, targetNodeId, timeline, track, untracked, validateFonts, validateTrack, vec2ArcType, vec2Equals, vec2Signal, vec2Type, velocityAt };
360
+ export { type AssetRef, type AudioClip, type BakeConfig, BakeError, type BindTarget, type BindableSignal, type BoundTimeline, type CheckpointedBakeConfig, type CheckpointedSim, type ChildEntry, CircularDependencyError, ColorParseError, type ColorStop, type CompiledTimeline, type CoverageReport, type CurveSampler, DEFAULT_EASE, type DevWarning, type EaseSpec, type EasingFn, type Equals, type FontFaceRef, type FontMode, type FontRegistry, type FontUsage, FontValidationError, type GainEnvelope, type HandoffKind, type Json, type Key, type KeyOpts, type Marker, type MergeResult, type MissingGlyphs, type OkLab, type OrphanReason, type Paint, type PathContour, type PathValue, type Playhead, type Position, PositionError, type ReadonlySignal, type ResolvedFace, type RetargetSpring, type Rgba, type Rng, type Scheduler, type SidecarDoc, type SidecarDocV1, type SidecarOrphan, type SidecarTimelineEntry, type SidecarTrackEntry, 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 ValidateFontsOptions, type ValueType, type ValueTypeId, ValueTypeInferenceError, type Vec2, type Vec2Signal, WriteDuringEvaluationError, assignKeyIds, audioOffsetSamples, bake, bakeCheckpointed, batch, beginReadPhase, bindTimeline, booleanType, buildFontRegistry, buildTimeline, colorType, compileTimeline, computed, createPlayhead, cubicBezier, cubicBezierDerivative, deleteSidecarTrack, easingDerivatives, easings, emitDevWarning, emptySidecar, endReadPhase, evaluateAt, formatColor, getTimelineCallbacks, getValueType, hashKeys, inReadPhase, inferValueType, isDurationEditable, isEditableNodeId, isExemptFamily, key, lerpColor, mergeSidecar, mergeSidecarDetailed, migrateSidecar, namedEasing, normalizeEditedKeys, numberType, oklabToRgba, paintType, parseCmap, parseColor, pathType, random, registerValueType, resolveEase, resolveEaseDerivative, resolveTweenTarget, rgbaToOklab, sampleTrack, setDevWarning, setScheduler, setSidecarTrack, signal, spring, springEasing, springEasingDerivative, springPresets, springTo, stagger, stringType, synchronousScheduler, targetNodeId, timeline, track, untracked, validateFonts, validateTrack, vec2ArcType, vec2Equals, vec2Signal, vec2Type, velocityAt };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as vec2Equals, A as velocityAt, B as easings, C as resolveEase, D as stagger, E as springTo, F as DEFAULT_EASE, G as colorType, H as UnknownValueTypeError, I as UnknownEasingError, J as numberType, K as getValueType, L as cubicBezier, M as springEasing, N as springEasingDerivative, O as track, P as springPresets, Q as vec2ArcType, R as cubicBezierDerivative, S as key, T as sampleTrack, U as ValueTypeInferenceError, V as namedEasing, W as booleanType, X as registerValueType, Y as pathType, Z as stringType, _ as audioOffsetSamples, a as hashKeys, at as lerpColor, b as timeline$1, c as migrateSidecar, ct as rgbaToOklab, d as TARGET_PATH, et as vec2Type, f as UnresolvableTargetError, g as TimelineValidationError, h as targetNodeId, i as emptySidecar, it as formatColor, j as spring, k as validateTrack, l as normalizeEditedKeys, m as resolveTweenTarget, n as assignKeyIds, nt as setDevWarning, o as mergeSidecar, ot as oklabToRgba, p as isEditableNodeId, q as inferValueType, r as deleteSidecarTrack, rt as ColorParseError, s as mergeSidecarDetailed, st as parseColor, t as SidecarVersionError, tt as emitDevWarning, u as setSidecarTrack, v as compileTimeline, w as resolveEaseDerivative, x as TrackValidationError, y as isDurationEditable, z as easingDerivatives } from "./sidecar.js";
1
+ import { $ as vec2ArcType, A as velocityAt, B as easings, C as resolveEase, D as stagger, E as springTo, F as DEFAULT_EASE, G as colorType, H as UnknownValueTypeError, I as UnknownEasingError, J as numberType, K as getValueType, L as cubicBezier, M as springEasing, N as springEasingDerivative, O as track, P as springPresets, Q as stringType, R as cubicBezierDerivative, S as key, T as sampleTrack, U as ValueTypeInferenceError, V as namedEasing, W as booleanType, X as pathType, Y as paintType, Z as registerValueType, _ as audioOffsetSamples, a as hashKeys, at as formatColor, b as timeline$1, c as migrateSidecar, ct as parseColor, d as TARGET_PATH, et as vec2Equals, f as UnresolvableTargetError, g as TimelineValidationError, h as targetNodeId, i as emptySidecar, it as ColorParseError, j as spring, k as validateTrack, l as normalizeEditedKeys, lt as rgbaToOklab, m as resolveTweenTarget, n as assignKeyIds, nt as emitDevWarning, o as mergeSidecar, ot as lerpColor, p as isEditableNodeId, q as inferValueType, r as deleteSidecarTrack, rt as setDevWarning, s as mergeSidecarDetailed, st as oklabToRgba, t as SidecarVersionError, tt as vec2Type, u as setSidecarTrack, v as compileTimeline, w as resolveEaseDerivative, x as TrackValidationError, y as isDurationEditable, z as easingDerivatives } from "./sidecar.js";
2
2
  //#region src/ticker.ts
3
3
  /** The default scheduler: flush synchronously, preserving pre-ticker timing. */
4
4
  const synchronousScheduler = (flush) => flush();
@@ -1083,4 +1083,4 @@ function bakeCheckpointed(cfg) {
1083
1083
  };
1084
1084
  }
1085
1085
  //#endregion
1086
- export { BakeError, CircularDependencyError, ColorParseError, DEFAULT_EASE, FontValidationError, PositionError, SidecarVersionError, TARGET_PATH, TimelineValidationError, TrackValidationError, UnboundTargetError, UnknownEasingError, UnknownValueTypeError, UnresolvableTargetError, ValueTypeInferenceError, WriteDuringEvaluationError, assignKeyIds, audioOffsetSamples, bake, bakeCheckpointed, batch, beginReadPhase, bindTimeline, booleanType, buildFontRegistry, buildTimeline, colorType, compileTimeline, computed, createPlayhead, cubicBezier, cubicBezierDerivative, deleteSidecarTrack, easingDerivatives, easings, emitDevWarning, emptySidecar, endReadPhase, evaluateAt, formatColor, getTimelineCallbacks, getValueType, hashKeys, inReadPhase, inferValueType, isDurationEditable, isEditableNodeId, isExemptFamily, key, lerpColor, mergeSidecar, mergeSidecarDetailed, migrateSidecar, namedEasing, normalizeEditedKeys, numberType, oklabToRgba, parseCmap, parseColor, pathType, random, registerValueType, resolveEase, resolveEaseDerivative, resolveTweenTarget, rgbaToOklab, sampleTrack, setDevWarning, setScheduler, setSidecarTrack, signal, spring, springEasing, springEasingDerivative, springPresets, springTo, stagger, stringType, synchronousScheduler, targetNodeId, timeline, track, untracked, validateFonts, validateTrack, vec2ArcType, vec2Equals, vec2Signal, vec2Type, velocityAt };
1086
+ export { BakeError, CircularDependencyError, ColorParseError, DEFAULT_EASE, FontValidationError, PositionError, SidecarVersionError, TARGET_PATH, TimelineValidationError, TrackValidationError, UnboundTargetError, UnknownEasingError, UnknownValueTypeError, UnresolvableTargetError, ValueTypeInferenceError, WriteDuringEvaluationError, assignKeyIds, audioOffsetSamples, bake, bakeCheckpointed, batch, beginReadPhase, bindTimeline, booleanType, buildFontRegistry, buildTimeline, colorType, compileTimeline, computed, createPlayhead, cubicBezier, cubicBezierDerivative, deleteSidecarTrack, easingDerivatives, easings, emitDevWarning, emptySidecar, endReadPhase, evaluateAt, formatColor, getTimelineCallbacks, getValueType, hashKeys, inReadPhase, inferValueType, isDurationEditable, isEditableNodeId, isExemptFamily, key, lerpColor, mergeSidecar, mergeSidecarDetailed, migrateSidecar, namedEasing, normalizeEditedKeys, numberType, oklabToRgba, paintType, parseCmap, parseColor, pathType, random, registerValueType, resolveEase, resolveEaseDerivative, resolveTweenTarget, rgbaToOklab, sampleTrack, setDevWarning, setScheduler, setSidecarTrack, signal, spring, springEasing, springEasingDerivative, springPresets, springTo, stagger, stringType, synchronousScheduler, targetNodeId, timeline, track, untracked, validateFonts, validateTrack, vec2ArcType, vec2Equals, vec2Signal, vec2Type, velocityAt };
package/dist/sidecar.d.ts CHANGED
@@ -55,6 +55,39 @@ declare const booleanType: ValueType<boolean>;
55
55
  * topology, so no add/sub/scale — handoffs blend from the frozen value.
56
56
  */
57
57
  declare const pathType: ValueType<PathValue>;
58
+ /** A gradient color stop: `offset` 0..1 along the gradient, `color` a CSS string. */
59
+ interface ColorStop {
60
+ offset: number;
61
+ color: string;
62
+ }
63
+ /**
64
+ * A fill/stroke paint (§2.2 animatable document value): a solid color, or a
65
+ * `linear`/`radial` gradient. Geometry (`from`/`to`, `center`/`radius`) is in
66
+ * the shape's LOCAL space; omit it to default to the filled path's bounds.
67
+ * Plain JSON — serializes with no hooks; animatable via `paintType`.
68
+ */
69
+ type Paint = {
70
+ kind: 'color';
71
+ color: string;
72
+ } | {
73
+ kind: 'linear';
74
+ stops: ColorStop[];
75
+ from?: [number, number];
76
+ to?: [number, number];
77
+ } | {
78
+ kind: 'radial';
79
+ stops: ColorStop[];
80
+ center?: [number, number];
81
+ radius?: number;
82
+ };
83
+ /**
84
+ * Gradient paint morphing (§2.2): a solid color lifts to a uniform gradient to
85
+ * meet the other side, then matched-kind/matched-stop-count gradients lerp their
86
+ * stops (offset + oklab color) and geometry pairwise; a mismatched kind or stop
87
+ * count snaps (hold a, then b at t ≥ 1) with a one-time dev warning. Lerp-only —
88
+ * no offsets under mismatch — so handoffs blend from the frozen value.
89
+ */
90
+ declare const paintType: ValueType<Paint>;
58
91
  declare class ValueTypeInferenceError extends Error {
59
92
  constructor(value: unknown);
60
93
  }
@@ -507,4 +540,4 @@ declare function mergeSidecar(code: Timeline, sidecar: SidecarDoc | SidecarDocV1
507
540
  */
508
541
  declare function normalizeEditedKeys(keys: Key[]): Key[];
509
542
  //#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 };
543
+ export { validateTrack as $, GainEnvelope as A, inferValueType as At, emitDevWarning as B, resolveTweenTarget as C, ValueType as Ct, ChildEntry as D, booleanType as Dt, AudioClip as E, Vec2 as Et, TimelineValidationError as F, stringType as Ft, TrackValidationError as G, Key as H, audioOffsetSamples as I, vec2ArcType as It, resolveEaseDerivative as J, key as K, compileTimeline as L, vec2Equals as Lt, Marker as M, paintType as Mt, Timeline as N, pathType as Nt, CompiledTimeline as O, colorType as Ot, TimelineInit as P, registerValueType as Pt, track as Q, isDurationEditable as R, vec2Type as Rt, isEditableNodeId as S, UnknownValueTypeError as St, AssetRef as T, ValueTypeInferenceError as Tt, KeyOpts as U, setDevWarning as V, Track as W, springTo as X, sampleTrack as Y, stagger as Z, setSidecarTrack as _, ColorStop as _t, SidecarOrphan as a, springEasing as at, TweenTarget as b, PathContour 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, numberType as jt, FontFaceRef as k, getValueType 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, HandoffKind as vt, targetNodeId as w, ValueTypeId as wt, UnresolvableTargetError as x, PathValue as xt, TargetCarrier as y, Paint as yt, DevWarning as z };
package/dist/sidecar.js CHANGED
@@ -234,6 +234,86 @@ const pathType = {
234
234
  },
235
235
  defaultHandoff: "blend-from-frozen"
236
236
  };
237
+ const lerpN = (a, b, t) => a + (b - a) * t;
238
+ const lerpPt = (a, b, t) => [lerpN(a[0], b[0], t), lerpN(a[1], b[1], t)];
239
+ /** Lift a solid color to a uniform gradient matching `shape` (every stop = color),
240
+ * so a color↔gradient tween fades smoothly instead of snapping. */
241
+ function liftColor(color, shape) {
242
+ const stops = shape.stops.map((s) => ({
243
+ offset: s.offset,
244
+ color
245
+ }));
246
+ return shape.kind === "radial" ? {
247
+ kind: "radial",
248
+ stops,
249
+ ...shape.center ? { center: shape.center } : {},
250
+ ...shape.radius !== void 0 ? { radius: shape.radius } : {}
251
+ } : {
252
+ kind: "linear",
253
+ stops,
254
+ ...shape.from ? { from: shape.from } : {},
255
+ ...shape.to ? { to: shape.to } : {}
256
+ };
257
+ }
258
+ let warnedPaintShape = false;
259
+ function paintSnap(t, a, b) {
260
+ if (!warnedPaintShape) {
261
+ warnedPaintShape = true;
262
+ emitDevWarning("paint lerp across mismatched gradient shapes (different kind or stop count): snapping instead of interpolating — match the kind + stop count on both keyframes (§2.2)");
263
+ }
264
+ return t >= 1 ? b : a;
265
+ }
266
+ const stopsEqual = (a, b) => a.length === b.length && a.every((s, i) => s.offset === b[i].offset && s.color === b[i].color);
267
+ /**
268
+ * Gradient paint morphing (§2.2): a solid color lifts to a uniform gradient to
269
+ * meet the other side, then matched-kind/matched-stop-count gradients lerp their
270
+ * stops (offset + oklab color) and geometry pairwise; a mismatched kind or stop
271
+ * count snaps (hold a, then b at t ≥ 1) with a one-time dev warning. Lerp-only —
272
+ * no offsets under mismatch — so handoffs blend from the frozen value.
273
+ */
274
+ const paintType = {
275
+ id: "paint",
276
+ lerp: (a, b, t) => {
277
+ if (a.kind === "color" && b.kind === "color") return {
278
+ kind: "color",
279
+ color: lerpColor(a.color, b.color, t)
280
+ };
281
+ let A = a;
282
+ let B = b;
283
+ if (A.kind === "color" && B.kind !== "color") A = liftColor(A.color, B);
284
+ else if (B.kind === "color" && A.kind !== "color") B = liftColor(B.color, A);
285
+ if (A.kind === "color" || B.kind === "color" || A.kind !== B.kind || A.stops.length !== B.stops.length) return paintSnap(t, a, b);
286
+ const stops = A.stops.map((sa, i) => ({
287
+ offset: lerpN(sa.offset, B.stops[i].offset, t),
288
+ color: lerpColor(sa.color, B.stops[i].color, t)
289
+ }));
290
+ if (A.kind === "radial" && B.kind === "radial") return {
291
+ kind: "radial",
292
+ stops,
293
+ ...A.center && B.center ? { center: lerpPt(A.center, B.center, t) } : A.center ? { center: A.center } : {},
294
+ ...A.radius !== void 0 && B.radius !== void 0 ? { radius: lerpN(A.radius, B.radius, t) } : A.radius !== void 0 ? { radius: A.radius } : {}
295
+ };
296
+ if (A.kind === "linear" && B.kind === "linear") return {
297
+ kind: "linear",
298
+ stops,
299
+ ...A.from && B.from ? { from: lerpPt(A.from, B.from, t) } : A.from ? { from: A.from } : {},
300
+ ...A.to && B.to ? { to: lerpPt(A.to, B.to, t) } : A.to ? { to: A.to } : {}
301
+ };
302
+ return paintSnap(t, a, b);
303
+ },
304
+ extrapolates: false,
305
+ equals: (a, b) => {
306
+ if (a === b) return true;
307
+ if (a.kind !== b.kind) return false;
308
+ if (a.kind === "color") return b.kind === "color" && a.color === b.color;
309
+ if (b.kind === "color") return false;
310
+ if (!stopsEqual(a.stops, b.stops)) return false;
311
+ if (a.kind === "radial" && b.kind === "radial") return JSON.stringify(a.center) === JSON.stringify(b.center) && a.radius === b.radius;
312
+ if (a.kind === "linear" && b.kind === "linear") return JSON.stringify(a.from) === JSON.stringify(b.from) && JSON.stringify(a.to) === JSON.stringify(b.to);
313
+ return false;
314
+ },
315
+ defaultHandoff: "blend-from-frozen"
316
+ };
237
317
  var ValueTypeInferenceError = class extends Error {
238
318
  constructor(value) {
239
319
  super(`cannot infer a value type for ${JSON.stringify(value)}; register a custom type`);
@@ -241,10 +321,12 @@ var ValueTypeInferenceError = class extends Error {
241
321
  }
242
322
  };
243
323
  const isContour = (c) => typeof c === "object" && c !== null && typeof c.closed === "boolean" && Array.isArray(c.v) && Array.isArray(c.in) && Array.isArray(c.out);
324
+ const isPaint = (v) => typeof v === "object" && v !== null && (v.kind === "color" || v.kind === "linear" || v.kind === "radial");
244
325
  /** Infer a registered type id from a sample value (builder + bake authoring surfaces). */
245
326
  function inferValueType(value) {
246
327
  if (typeof value === "number") return "number";
247
328
  if (typeof value === "boolean") return "boolean";
329
+ if (isPaint(value)) return "paint";
248
330
  if (Array.isArray(value) && value.length === 2 && value.every((v) => typeof v === "number")) return "vec2";
249
331
  if (Array.isArray(value) && value.length > 0 && value.every(isContour)) return "path";
250
332
  if (typeof value === "string") try {
@@ -262,6 +344,7 @@ registerValueType(colorType);
262
344
  registerValueType(stringType);
263
345
  registerValueType(booleanType);
264
346
  registerValueType(pathType);
347
+ registerValueType(paintType);
265
348
  //#endregion
266
349
  //#region src/easing.ts
267
350
  const c1 = 1.70158;
@@ -1266,4 +1349,4 @@ function normalizeEditedKeys(keys) {
1266
1349
  return out;
1267
1350
  }
1268
1351
  //#endregion
1269
- export { vec2Equals as $, velocityAt as A, easings as B, resolveEase as C, stagger as D, springTo as E, DEFAULT_EASE as F, colorType as G, UnknownValueTypeError as H, UnknownEasingError as I, numberType as J, getValueType as K, cubicBezier as L, springEasing as M, springEasingDerivative as N, track as O, springPresets as P, vec2ArcType as Q, cubicBezierDerivative as R, key as S, sampleTrack as T, ValueTypeInferenceError as U, namedEasing as V, booleanType as W, registerValueType as X, pathType as Y, stringType as Z, audioOffsetSamples as _, hashKeys as a, lerpColor as at, timeline as b, migrateSidecar as c, rgbaToOklab as ct, TARGET_PATH as d, vec2Type as et, UnresolvableTargetError as f, TimelineValidationError as g, targetNodeId as h, emptySidecar as i, formatColor as it, spring as j, validateTrack as k, normalizeEditedKeys as l, resolveTweenTarget as m, assignKeyIds as n, setDevWarning as nt, mergeSidecar as o, oklabToRgba as ot, isEditableNodeId as p, inferValueType as q, deleteSidecarTrack as r, ColorParseError as rt, mergeSidecarDetailed as s, parseColor as st, SidecarVersionError as t, emitDevWarning as tt, setSidecarTrack as u, compileTimeline as v, resolveEaseDerivative as w, TrackValidationError as x, isDurationEditable as y, easingDerivatives as z };
1352
+ export { vec2ArcType as $, velocityAt as A, easings as B, resolveEase as C, stagger as D, springTo as E, DEFAULT_EASE as F, colorType as G, UnknownValueTypeError as H, UnknownEasingError as I, numberType as J, getValueType as K, cubicBezier as L, springEasing as M, springEasingDerivative as N, track as O, springPresets as P, stringType as Q, cubicBezierDerivative as R, key as S, sampleTrack as T, ValueTypeInferenceError as U, namedEasing as V, booleanType as W, pathType as X, paintType as Y, registerValueType as Z, audioOffsetSamples as _, hashKeys as a, formatColor as at, timeline as b, migrateSidecar as c, parseColor as ct, TARGET_PATH as d, vec2Equals as et, UnresolvableTargetError as f, TimelineValidationError as g, targetNodeId as h, emptySidecar as i, ColorParseError as it, spring as j, validateTrack as k, normalizeEditedKeys as l, rgbaToOklab as lt, resolveTweenTarget as m, assignKeyIds as n, emitDevWarning as nt, mergeSidecar as o, lerpColor as ot, isEditableNodeId as p, inferValueType as q, deleteSidecarTrack as r, setDevWarning as rt, mergeSidecarDetailed as s, oklabToRgba as st, SidecarVersionError as t, vec2Type as tt, setSidecarTrack as u, compileTimeline as v, resolveEaseDerivative as w, TrackValidationError as x, isDurationEditable as y, easingDerivatives as z };
@@ -1,4 +1,4 @@
1
- import { H as Key, N as Timeline, S as isEditableNodeId, St as ValueTypeId, a as SidecarOrphan, lt as EaseSpec, r as SidecarDoc, w as targetNodeId } from "./sidecar.js";
1
+ import { H as Key, N as Timeline, S as isEditableNodeId, a as SidecarOrphan, lt as EaseSpec, r as SidecarDoc, w as targetNodeId, wt as ValueTypeId } from "./sidecar.js";
2
2
 
3
3
  //#region src/timelinePatch.d.ts
4
4
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glissade/core",
3
- "version": "0.10.0",
3
+ "version": "0.10.1-pre.0",
4
4
  "description": "glissade core: signals, tracks, timeline document, evaluation, easing, springs, seeded RNG. Zero DOM/Node dependencies.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",