@pixodesk/svg-animator-core 1.0.26 → 1.0.28

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.js CHANGED
@@ -31,111 +31,583 @@ var __objRest = (source, exclude) => {
31
31
  return target;
32
32
  };
33
33
 
34
- // src/PxSchema.ts
35
- function pathStr(path) {
36
- if (!path.length) return ".";
37
- let result = "";
38
- for (const seg of path) {
39
- if (seg.startsWith("[")) result += seg;
40
- else result += (result ? "." : "") + seg;
34
+ // src/PxAnimatorUtil.ts
35
+ function bezierToSvgPath(path, forceCurves = false) {
36
+ var _a, _b, _c, _d;
37
+ const v = path.v;
38
+ const i = path.i;
39
+ const o = path.o;
40
+ const c = path.c;
41
+ if (!v.length) return "";
42
+ const d = [];
43
+ const len = v.length;
44
+ d.push("M" + v[0][0] + "," + v[0][1]);
45
+ for (let idx = 1; idx < len; idx++) {
46
+ const prevV = v[idx - 1];
47
+ const prevO = (_a = o == null ? void 0 : o[idx - 1]) != null ? _a : prevV;
48
+ const currI = (_b = i == null ? void 0 : i[idx]) != null ? _b : v[idx];
49
+ const currV = v[idx];
50
+ const isLine = !forceCurves && (prevO[0] === prevV[0] && prevO[1] === prevV[1]) && (currI[0] === currV[0] && currI[1] === currV[1]);
51
+ if (isLine) {
52
+ d.push("L" + currV[0] + "," + currV[1]);
53
+ } else {
54
+ d.push("C" + prevO[0] + "," + prevO[1] + "," + currI[0] + "," + currI[1] + "," + currV[0] + "," + currV[1]);
55
+ }
41
56
  }
42
- return result;
43
- }
44
- var Base = class {
45
- _canSanitize(raw) {
46
- return this.isValid(raw);
57
+ if (c && len > 0) {
58
+ const lastV = v[len - 1];
59
+ const lastO = (_c = o == null ? void 0 : o[len - 1]) != null ? _c : lastV;
60
+ const firstI = (_d = i == null ? void 0 : i[0]) != null ? _d : v[0];
61
+ const firstV = v[0];
62
+ const isLine = !forceCurves && (lastO[0] === lastV[0] && lastO[1] === lastV[1]) && (firstI[0] === firstV[0] && firstI[1] === firstV[1]);
63
+ if (!isLine) {
64
+ d.push("C" + lastO[0] + "," + lastO[1] + "," + firstI[0] + "," + firstI[1] + "," + firstV[0] + "," + firstV[1]);
65
+ }
66
+ d.push("z");
47
67
  }
48
- optional() {
49
- return new Optional(this);
68
+ return d.join("");
69
+ }
70
+ function interpolateNum(a, b, t) {
71
+ return a + (b - a) * t;
72
+ }
73
+ function interpolateVec(a, b, t) {
74
+ const res = [];
75
+ const count = Math.max(a.length, b.length);
76
+ for (let i = 0; i < count; i++) {
77
+ res[i] = interpolateNum(a[i] || 0, b[i] || 0, t);
50
78
  }
51
- };
52
- var Optional = class extends Base {
53
- constructor(inner) {
54
- super();
55
- this.inner = inner;
56
- this._default = void 0;
79
+ return res;
80
+ }
81
+ function interpolateColor(a, b, t) {
82
+ return [
83
+ interpolateNum(a[0] || 0, b[0] || 0, t),
84
+ interpolateNum(a[1] || 0, b[1] || 0, t),
85
+ interpolateNum(a[2] || 0, b[2] || 0, t),
86
+ interpolateNum(a[3] === void 0 ? 1 : a[3], b[3] === void 0 ? 1 : b[3], t)
87
+ ];
88
+ }
89
+ function interpolateBeziers(paths1, paths2, progress) {
90
+ const count = Math.max(paths1.length, paths2.length);
91
+ const res = [];
92
+ for (let i = 0; i < count; i++) {
93
+ res.push(interpolateBezier(paths1[i], paths2[i], progress));
57
94
  }
58
- sanitize(raw) {
59
- if (raw === void 0 || raw === null) return void 0;
60
- return this.inner._canSanitize(raw) ? this.inner.sanitize(raw) : void 0;
95
+ return res;
96
+ }
97
+ function interpolateBezier(path1, path2, progress) {
98
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
99
+ if (!path1 || !path2) return path1 || path2 || { v: [] };
100
+ const t = Math.min(Math.max(progress, 0), 1);
101
+ const len = Math.min(path1.v.length, path2.v.length);
102
+ const v = [];
103
+ const i = [];
104
+ const o = [];
105
+ for (let idx = 0; idx < len; idx++) {
106
+ const v1 = path1.v[idx];
107
+ const v2 = path2.v[idx];
108
+ v.push(interpolateVec(v1, v2, t));
109
+ const i1 = (_b = (_a = path1.i) == null ? void 0 : _a[idx]) != null ? _b : v1;
110
+ const i2 = (_d = (_c = path2.i) == null ? void 0 : _c[idx]) != null ? _d : v2;
111
+ i.push(interpolateVec(i1, i2, t));
112
+ const o1 = (_f = (_e = path1.o) == null ? void 0 : _e[idx]) != null ? _f : v1;
113
+ const o2 = (_h = (_g = path2.o) == null ? void 0 : _g[idx]) != null ? _h : v2;
114
+ o.push(interpolateVec(o1, o2, t));
61
115
  }
62
- isValid(raw, ctx, path) {
63
- if (raw === void 0 || raw === null) return true;
64
- return this.inner.isValid(raw, ctx, path);
116
+ return { v, i: i.length ? i : void 0, o: o.length ? o : void 0, c: (_i = path1.c) != null ? _i : path2.c };
117
+ }
118
+ function remap(value, inMin, inMax, outMin, outMax) {
119
+ if (inMax === inMin) return outMin;
120
+ const t = (value - inMin) / (inMax - inMin);
121
+ return outMin + t * (outMax - outMin);
122
+ }
123
+ function solveCubicBezierX(p1x, p2x, x) {
124
+ if (x <= 0) return 0;
125
+ if (x >= 1) return 1;
126
+ const cx = 3 * p1x;
127
+ const bx = 3 * (p2x - p1x) - cx;
128
+ const ax = 1 - cx - bx;
129
+ function sampleX(t) {
130
+ return ((ax * t + bx) * t + cx) * t;
65
131
  }
66
- _canSanitize(raw) {
67
- return raw === void 0 || raw === null || this.inner._canSanitize(raw);
132
+ function sampleDX(t) {
133
+ return (3 * ax * t + 2 * bx) * t + cx;
68
134
  }
69
- };
70
- var Str = class extends Base {
71
- constructor(_default = "") {
72
- super();
73
- this._default = _default;
135
+ let t2 = x;
136
+ let t0 = 0;
137
+ let t1 = 1;
138
+ for (let i = 0; i < 8; i++) {
139
+ const x2 = sampleX(t2) - x;
140
+ if (Math.abs(x2) < 1e-6) return t2;
141
+ const d2 = sampleDX(t2);
142
+ if (Math.abs(d2) < 1e-6) break;
143
+ t2 -= x2 / d2;
74
144
  }
75
- sanitize(raw) {
76
- return typeof raw === "string" ? raw : this._default;
145
+ t2 = x;
146
+ while (t0 < t1) {
147
+ const x2 = sampleX(t2);
148
+ if (Math.abs(x2 - x) < 1e-6) return t2;
149
+ if (x > x2) t0 = t2;
150
+ else t1 = t2;
151
+ t2 = (t1 + t0) / 2;
77
152
  }
78
- isValid(raw, ctx, path) {
79
- if (typeof raw === "string") return true;
80
- ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected string, got " + typeof raw);
81
- return false;
153
+ return t2;
154
+ }
155
+ function cubicBezier(easing) {
156
+ const [p1x, p1y, p2x, p2y] = easing;
157
+ const cy = 3 * p1y;
158
+ const by = 3 * (p2y - p1y) - cy;
159
+ const ay = 1 - cy - by;
160
+ function sampleCurveY(t) {
161
+ return ((ay * t + by) * t + cy) * t;
82
162
  }
83
- };
84
- var Num = class extends Base {
85
- constructor(_default = 0) {
86
- super();
87
- this._default = _default;
163
+ return function(x) {
164
+ return sampleCurveY(solveCubicBezierX(p1x, p2x, x));
165
+ };
166
+ }
167
+ function lerp2(a, b, t) {
168
+ return [a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t];
169
+ }
170
+ function subdivideCubicBezier(p0, p1, p2, p3, t) {
171
+ const q0 = lerp2(p0, p1, t);
172
+ const q1 = lerp2(p1, p2, t);
173
+ const q2 = lerp2(p2, p3, t);
174
+ const r0 = lerp2(q0, q1, t);
175
+ const r1 = lerp2(q1, q2, t);
176
+ const s = lerp2(r0, r1, t);
177
+ return {
178
+ left: [p0, q0, r0, s],
179
+ right: [s, r1, q2, p3]
180
+ };
181
+ }
182
+ function splitEasing(easing, xFraction) {
183
+ if (!easing) return { left: void 0, right: void 0 };
184
+ if (xFraction <= 0) return { left: void 0, right: easing };
185
+ if (xFraction >= 1) return { left: easing, right: void 0 };
186
+ const [x1, y1, x2, y2] = easing;
187
+ const t = solveCubicBezierX(x1, x2, xFraction);
188
+ const p0 = [0, 0];
189
+ const p1 = [x1, y1];
190
+ const p2 = [x2, y2];
191
+ const p3 = [1, 1];
192
+ const { left, right } = subdivideCubicBezier(p0, p1, p2, p3, t);
193
+ const sx = left[3][0];
194
+ const sy = left[3][1];
195
+ let leftEasing;
196
+ if (sx > 1e-9 && Math.abs(sy) > 1e-9) {
197
+ leftEasing = [
198
+ left[1][0] / sx,
199
+ left[1][1] / sy,
200
+ left[2][0] / sx,
201
+ left[2][1] / sy
202
+ ];
88
203
  }
89
- sanitize(raw) {
90
- return typeof raw === "number" && isFinite(raw) ? raw : this._default;
204
+ let rightEasing;
205
+ const rx = 1 - sx;
206
+ const ry = 1 - sy;
207
+ if (rx > 1e-9 && Math.abs(ry) > 1e-9) {
208
+ rightEasing = [
209
+ (right[1][0] - sx) / rx,
210
+ (right[1][1] - sy) / ry,
211
+ (right[2][0] - sx) / rx,
212
+ (right[2][1] - sy) / ry
213
+ ];
91
214
  }
92
- isValid(raw, ctx, path) {
93
- if (typeof raw === "number" && isFinite(raw)) return true;
94
- ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected finite number, got " + JSON.stringify(raw));
95
- return false;
215
+ return { left: leftEasing, right: rightEasing };
216
+ }
217
+ function reverseEasing(easing) {
218
+ if (!easing) return void 0;
219
+ return [1 - easing[2], 1 - easing[3], 1 - easing[0], 1 - easing[1]];
220
+ }
221
+ function toRGBA(color) {
222
+ const r = Math.round(color[0] * 255);
223
+ const g = Math.round(color[1] * 255);
224
+ const b = Math.round(color[2] * 255);
225
+ return color.length === 4 ? "rgba(" + r + "," + g + "," + b + "," + color[3] + ")" : "rgb(" + r + "," + g + "," + b + ")";
226
+ }
227
+ function parseRgba(s) {
228
+ var _a;
229
+ const inner = (_a = s.match(/rgba?\((.*)\)/)) == null ? void 0 : _a[1];
230
+ if (!inner) throw new Error("Invalid rgb/rgba format");
231
+ const parts = inner.split(",").map((v) => +v.trim());
232
+ return [parts[0] / 255, parts[1] / 255, parts[2] / 255, ...parts[3] !== void 0 ? [parts[3]] : []];
233
+ }
234
+ function parseHex(s) {
235
+ const hex = s.slice(1);
236
+ const isShort = hex.length <= 4;
237
+ const r = isShort ? hex[0] + hex[0] : hex.slice(0, 2);
238
+ const g = isShort ? hex[1] + hex[1] : hex.slice(2, 4);
239
+ const b = isShort ? hex[2] + hex[2] : hex.slice(4, 6);
240
+ const a = hex.length === 4 ? hex[3] + hex[3] : hex.length === 8 ? hex.slice(6, 8) : null;
241
+ const result = [
242
+ parseInt(r, 16) / 255,
243
+ parseInt(g, 16) / 255,
244
+ parseInt(b, 16) / 255
245
+ ];
246
+ if (a !== null) {
247
+ result.push(parseInt(a, 16) / 255);
96
248
  }
97
- };
98
- var Bool = class extends Base {
99
- constructor(_default = false) {
100
- super();
101
- this._default = _default;
249
+ return result;
250
+ }
251
+ function parseColor(s) {
252
+ if (!s) return void 0;
253
+ if (Array.isArray(s)) return s;
254
+ if (typeof s !== "string") return void 0;
255
+ if (s.startsWith("#")) {
256
+ return parseHex(s);
257
+ } else if (s.startsWith("rgb")) {
258
+ return parseRgba(s);
259
+ } else {
260
+ console.warn("Unsupported color format: " + s);
102
261
  }
103
- sanitize(raw) {
104
- return typeof raw === "boolean" ? raw : this._default;
262
+ return void 0;
263
+ }
264
+ var COLOUR_ATTR_NAMES = /* @__PURE__ */ new Set(["color", "fill", "flood-color", "lighting-color", "stop-color", "stroke"]);
265
+ var TRANSFORM_FN_NAMES = /* @__PURE__ */ new Set(["translate", "rotate", "scale", "skew"]);
266
+ var PCT_BASED_ATTR_NAMES = /* @__PURE__ */ new Set(["offset-distance", "offsetDistance"]);
267
+ function composeTransformParts(parts, opts) {
268
+ var _a;
269
+ if (!parts) return "";
270
+ const withUnits = (_a = opts == null ? void 0 : opts.withUnits) != null ? _a : true;
271
+ const segs = [];
272
+ const t = parts.translate;
273
+ const o = parts.origin;
274
+ const r = parts.rotate;
275
+ const k = parts.skew;
276
+ const s = parts.scale;
277
+ const tu = withUnits ? "px" : "";
278
+ const ru = withUnits ? "deg" : "";
279
+ if (t) segs.push("translate(" + t[0] + tu + "," + t[1] + tu + ")");
280
+ if (o) segs.push("translate(" + o[0] + tu + "," + o[1] + tu + ")");
281
+ if (r !== void 0 && r !== null) segs.push("rotate(" + r + ru + ")");
282
+ if (k !== void 0 && k !== null) segs.push("skewX(" + k + ru + ")");
283
+ if (s) segs.push("scale(" + s[0] + "," + s[1] + ")");
284
+ if (o) segs.push("translate(" + -o[0] + tu + "," + -o[1] + tu + ")");
285
+ return segs.join("");
286
+ }
287
+ var STYLE_ATTR_NAMES = /* @__PURE__ */ new Set(["offset-distance", "offsetDistance"]);
288
+ var DEFAULT_DURATION_MS = 1e3;
289
+ function kebabToCamelCaseWord(kebab) {
290
+ return kebab.includes("-") ? kebab.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase()) : kebab;
291
+ }
292
+ function isCamelCaseWord(word) {
293
+ return !word.includes("-") && /[a-z][A-Z]/.test(word);
294
+ }
295
+ var SVG_CAMEL_CASE_ATTRS = /* @__PURE__ */ new Set([
296
+ // Transform/positioning
297
+ "viewBox",
298
+ "preserveAspectRatio",
299
+ // Gradient
300
+ "gradientUnits",
301
+ "gradientTransform",
302
+ "spreadMethod",
303
+ // Pattern
304
+ "patternUnits",
305
+ "patternContentUnits",
306
+ "patternTransform",
307
+ // Clipping/masking
308
+ "clipPathUnits",
309
+ "maskUnits",
310
+ "maskContentUnits",
311
+ // Marker (SVG spec keeps these camelCase, like viewBox)
312
+ "markerUnits",
313
+ "markerWidth",
314
+ "markerHeight",
315
+ "refX",
316
+ "refY",
317
+ // Text
318
+ "textLength",
319
+ "lengthAdjust",
320
+ "startOffset",
321
+ // Filter
322
+ "filterUnits",
323
+ "primitiveUnits",
324
+ "tableValues",
325
+ // feFuncR/G/B/A transfer table (type="table")
326
+ "stdDeviation",
327
+ "baseFrequency",
328
+ "numOctaves",
329
+ "surfaceScale",
330
+ "diffuseConstant",
331
+ "specularConstant",
332
+ "specularExponent",
333
+ "kernelMatrix",
334
+ "kernelUnitLength",
335
+ "edgeMode",
336
+ "preserveAlpha",
337
+ "targetX",
338
+ "targetY"
339
+ // // Animation
340
+ // 'attributeName',
341
+ // 'attributeType',
342
+ // 'calcMode',
343
+ // 'keyTimes',
344
+ // 'keySplines',
345
+ // 'repeatCount',
346
+ // 'repeatDur'
347
+ ]);
348
+ function camelCaseToKebabWordIfNeeded(camel) {
349
+ return SVG_CAMEL_CASE_ATTRS.has(camel) ? camel : camel.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
350
+ }
351
+ function clamp(value, min, max) {
352
+ return Math.max(min, Math.min(value, max));
353
+ }
354
+ function bezier2D_pointAt(P0, P1, P2, P3, t) {
355
+ if (t <= 0) return [P0[0], P0[1]];
356
+ if (t >= 1) return [P3[0], P3[1]];
357
+ const u = 1 - t;
358
+ const u2 = u * u;
359
+ const u3 = u2 * u;
360
+ const t2 = t * t;
361
+ const t3 = t2 * t;
362
+ const w0 = u3;
363
+ const w1 = 3 * t * u2;
364
+ const w2 = 3 * t2 * u;
365
+ const w3 = t3;
366
+ return [
367
+ w0 * P0[0] + w1 * P1[0] + w2 * P2[0] + w3 * P3[0],
368
+ w0 * P0[1] + w1 * P1[1] + w2 * P2[1] + w3 * P3[1]
369
+ ];
370
+ }
371
+ var BEZIER_T_NUDGE = 1e-4;
372
+ function bezier2D_derivativeAt(P0, P1, P2, P3, t) {
373
+ const result = _bezier2D_derivativeAtRaw(P0, P1, P2, P3, t);
374
+ if (result[0] === 0 && result[1] === 0) {
375
+ const nudgedT = t < 0.5 ? t + BEZIER_T_NUDGE : t - BEZIER_T_NUDGE;
376
+ return _bezier2D_derivativeAtRaw(P0, P1, P2, P3, nudgedT);
105
377
  }
106
- isValid(raw, ctx, path) {
107
- if (typeof raw === "boolean") return true;
108
- ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected boolean, got " + typeof raw);
109
- return false;
378
+ return result;
379
+ }
380
+ function _bezier2D_derivativeAtRaw(P0, P1, P2, P3, t) {
381
+ const u = 1 - t;
382
+ const a = 3 * u * u;
383
+ const b = 6 * t * u;
384
+ const c = 3 * t * t;
385
+ return [
386
+ a * (P1[0] - P0[0]) + b * (P2[0] - P1[0]) + c * (P3[0] - P2[0]),
387
+ a * (P1[1] - P0[1]) + b * (P2[1] - P1[1]) + c * (P3[1] - P2[1])
388
+ ];
389
+ }
390
+ function bezier2D_arcLengthLUT(P0, P1, P2, P3, steps = 100) {
391
+ const n = steps + 1;
392
+ const ts = new Float64Array(n);
393
+ const ds = new Float64Array(n);
394
+ let prev = bezier2D_pointAt(P0, P1, P2, P3, 0);
395
+ ts[0] = 0;
396
+ ds[0] = 0;
397
+ let cum = 0;
398
+ for (let i = 1; i < n; i++) {
399
+ const t = i / steps;
400
+ const cur = bezier2D_pointAt(P0, P1, P2, P3, t);
401
+ const dx = cur[0] - prev[0];
402
+ const dy = cur[1] - prev[1];
403
+ cum += Math.sqrt(dx * dx + dy * dy);
404
+ ts[i] = t;
405
+ ds[i] = cum;
406
+ prev = cur;
407
+ }
408
+ return { ts, ds };
409
+ }
410
+ function bezier2D_tForDistance(lut, distance) {
411
+ const { ts, ds } = lut;
412
+ const last = ds.length - 1;
413
+ if (distance <= 0) return ts[0];
414
+ if (distance >= ds[last]) return ts[last];
415
+ let lo = 1;
416
+ let hi = last;
417
+ while (lo < hi) {
418
+ const mid = lo + hi >>> 1;
419
+ if (ds[mid] < distance) lo = mid + 1;
420
+ else hi = mid;
421
+ }
422
+ const dPrev = ds[hi - 1];
423
+ const dCur = ds[hi];
424
+ const span = dCur - dPrev;
425
+ const frac = span > 0 ? (distance - dPrev) / span : 0;
426
+ return ts[hi - 1] + frac * (ts[hi] - ts[hi - 1]);
427
+ }
428
+ function bezier2D_arcAtT(lut, t) {
429
+ const { ts, ds } = lut;
430
+ const last = ts.length - 1;
431
+ if (t <= ts[0]) return ds[0];
432
+ if (t >= ts[last]) return ds[last];
433
+ let lo = 1, hi = last;
434
+ while (lo < hi) {
435
+ const mid = lo + hi >>> 1;
436
+ if (ts[mid] < t) lo = mid + 1;
437
+ else hi = mid;
438
+ }
439
+ const tPrev = ts[hi - 1];
440
+ const span = ts[hi] - tPrev;
441
+ const frac = span > 0 ? (t - tPrev) / span : 0;
442
+ return ds[hi - 1] + frac * (ds[hi] - ds[hi - 1]);
443
+ }
444
+ function invertEasing(easing) {
445
+ if (!easing) return (y) => y;
446
+ const flipped = [easing[1], easing[0], easing[3], easing[2]];
447
+ return cubicBezier(flipped);
448
+ }
449
+
450
+ // src/PxScrollMath.ts
451
+ function isScrollTimeline(config) {
452
+ return (config == null ? void 0 : config.timelineSource) === "scroll";
453
+ }
454
+ function scrollTotalDurationMs(config) {
455
+ const duration = typeof (config == null ? void 0 : config.duration) === "number" && config.duration > 0 ? config.duration : DEFAULT_DURATION_MS;
456
+ const iterations = typeof (config == null ? void 0 : config.iterations) === "number" && config.iterations > 0 ? config.iterations : 1;
457
+ return duration * iterations;
458
+ }
459
+ function scrollPhaseInterval(phase, subjectSize, scrollportSize) {
460
+ const s = subjectSize, vp = scrollportSize;
461
+ switch (phase) {
462
+ case "cover":
463
+ return [0, s + vp];
464
+ case "entry":
465
+ return [0, Math.min(s, vp)];
466
+ case "contain":
467
+ return [Math.min(s, vp), Math.max(s, vp)];
468
+ case "exit":
469
+ return [Math.max(s, vp), s + vp];
470
+ case "entry-crossing":
471
+ return [0, s];
472
+ case "exit-crossing":
473
+ return [vp, s + vp];
474
+ }
475
+ }
476
+ var DEFAULT_PHASE = "cover";
477
+ function resolveRangePointU(point, defaultFraction, subjectSize, scrollportSize) {
478
+ var _a;
479
+ const [u0, u1] = scrollPhaseInterval((_a = point == null ? void 0 : point.phase) != null ? _a : DEFAULT_PHASE, subjectSize, scrollportSize);
480
+ const fraction = typeof (point == null ? void 0 : point.fraction) === "number" ? point.fraction : defaultFraction;
481
+ return u0 + fraction * (u1 - u0);
482
+ }
483
+ function scrollViewProgress(subjectStart, subjectSize, scrollportSize, range) {
484
+ const u = scrollportSize - subjectStart;
485
+ const uStart = resolveRangePointU(range == null ? void 0 : range.start, 0, subjectSize, scrollportSize);
486
+ const uEnd = resolveRangePointU(range == null ? void 0 : range.end, 1, subjectSize, scrollportSize);
487
+ if (uEnd <= uStart) return u >= uEnd ? 1 : 0;
488
+ return clamp((u - uStart) / (uEnd - uStart), 0, 1);
489
+ }
490
+ function scrollOffsetProgress(offset, maxOffset, range) {
491
+ var _a, _b;
492
+ const raw = maxOffset > 0 ? clamp(offset / maxOffset, 0, 1) : 1;
493
+ const start = typeof ((_a = range == null ? void 0 : range.start) == null ? void 0 : _a.fraction) === "number" ? range.start.fraction : 0;
494
+ const end = typeof ((_b = range == null ? void 0 : range.end) == null ? void 0 : _b.fraction) === "number" ? range.end.fraction : 1;
495
+ if (end <= start) return raw >= end ? 1 : 0;
496
+ return clamp((raw - start) / (end - start), 0, 1);
497
+ }
498
+ function scrollResolveAxis(axis, writingMode) {
499
+ const a = axis != null ? axis : "block";
500
+ if (a === "x" || a === "y") return a;
501
+ const vertical = !!writingMode && writingMode.startsWith("vertical");
502
+ if (a === "inline") return vertical ? "y" : "x";
503
+ return vertical ? "x" : "y";
504
+ }
505
+
506
+ // src/PxSchema.ts
507
+ function pathStr(path) {
508
+ if (!path.length) return ".";
509
+ let result = "";
510
+ for (const seg of path) {
511
+ if (seg.startsWith("[")) result += seg;
512
+ else result += (result ? "." : "") + seg;
513
+ }
514
+ return result;
515
+ }
516
+ var Base = class {
517
+ _canSanitize(raw) {
518
+ return this.isValid(raw);
519
+ }
520
+ optional() {
521
+ return new Optional(this);
110
522
  }
111
523
  };
112
- var Literal = class extends Base {
113
- constructor(value) {
524
+ var Optional = class extends Base {
525
+ constructor(inner) {
114
526
  super();
115
- this.value = value;
116
- this._default = value;
527
+ this.inner = inner;
528
+ this._default = void 0;
117
529
  }
118
530
  sanitize(raw) {
119
- return raw === this.value ? this.value : this._default;
531
+ if (raw === void 0 || raw === null) return void 0;
532
+ return this.inner._canSanitize(raw) ? this.inner.sanitize(raw) : void 0;
120
533
  }
121
534
  isValid(raw, ctx, path) {
122
- if (raw === this.value) return true;
123
- ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected " + JSON.stringify(this.value) + ", got " + JSON.stringify(raw));
124
- return false;
535
+ if (raw === void 0 || raw === null) return true;
536
+ return this.inner.isValid(raw, ctx, path);
537
+ }
538
+ _canSanitize(raw) {
539
+ return raw === void 0 || raw === null || this.inner._canSanitize(raw);
125
540
  }
126
541
  };
127
- var Enum = class extends Base {
128
- constructor(values, defaultVal) {
542
+ var Str = class extends Base {
543
+ constructor(_default = "") {
129
544
  super();
130
- this.values = values;
131
- this._default = defaultVal != null ? defaultVal : values[0];
545
+ this._default = _default;
132
546
  }
133
547
  sanitize(raw) {
134
- return this.values.includes(raw) ? raw : this._default;
548
+ return typeof raw === "string" ? raw : this._default;
135
549
  }
136
550
  isValid(raw, ctx, path) {
137
- if (this.values.includes(raw)) return true;
138
- ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected one of " + this.values.map((v) => JSON.stringify(v)).join(" | ") + ", got " + JSON.stringify(raw));
551
+ if (typeof raw === "string") return true;
552
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected string, got " + typeof raw);
553
+ return false;
554
+ }
555
+ };
556
+ var Num = class extends Base {
557
+ constructor(_default = 0) {
558
+ super();
559
+ this._default = _default;
560
+ }
561
+ sanitize(raw) {
562
+ return typeof raw === "number" && isFinite(raw) ? raw : this._default;
563
+ }
564
+ isValid(raw, ctx, path) {
565
+ if (typeof raw === "number" && isFinite(raw)) return true;
566
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected finite number, got " + JSON.stringify(raw));
567
+ return false;
568
+ }
569
+ };
570
+ var Bool = class extends Base {
571
+ constructor(_default = false) {
572
+ super();
573
+ this._default = _default;
574
+ }
575
+ sanitize(raw) {
576
+ return typeof raw === "boolean" ? raw : this._default;
577
+ }
578
+ isValid(raw, ctx, path) {
579
+ if (typeof raw === "boolean") return true;
580
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected boolean, got " + typeof raw);
581
+ return false;
582
+ }
583
+ };
584
+ var Literal = class extends Base {
585
+ constructor(value) {
586
+ super();
587
+ this.value = value;
588
+ this._default = value;
589
+ }
590
+ sanitize(raw) {
591
+ return raw === this.value ? this.value : this._default;
592
+ }
593
+ isValid(raw, ctx, path) {
594
+ if (raw === this.value) return true;
595
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected " + JSON.stringify(this.value) + ", got " + JSON.stringify(raw));
596
+ return false;
597
+ }
598
+ };
599
+ var Enum = class extends Base {
600
+ constructor(values, defaultVal) {
601
+ super();
602
+ this.values = values;
603
+ this._default = defaultVal != null ? defaultVal : values[0];
604
+ }
605
+ sanitize(raw) {
606
+ return this.values.includes(raw) ? raw : this._default;
607
+ }
608
+ isValid(raw, ctx, path) {
609
+ if (this.values.includes(raw)) return true;
610
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected one of " + this.values.map((v) => JSON.stringify(v)).join(" | ") + ", got " + JSON.stringify(raw));
139
611
  return false;
140
612
  }
141
613
  };
@@ -698,6 +1170,28 @@ var PxDefsSchema = implementsInterface()(px.object({
698
1170
  styles: px.record(px.any()).optional(),
699
1171
  glyphs: px.record(PxGlyphFontSchema).optional()
700
1172
  }));
1173
+ var PX_SCROLL_PHASES = ["cover", "contain", "entry", "exit", "entry-crossing", "exit-crossing"];
1174
+ var PxScrollRangePointSchema = implementsInterface()(px.object({
1175
+ phase: px.enum(PX_SCROLL_PHASES).optional(),
1176
+ fraction: px.number().optional()
1177
+ }));
1178
+ var PxScrollRangeSchema = px.object({
1179
+ start: PxScrollRangePointSchema.optional(),
1180
+ end: PxScrollRangePointSchema.optional()
1181
+ });
1182
+ var PxScrollSchema = implementsInterface()(px.object({
1183
+ driver: px.enum(["custom", "native"]).optional(),
1184
+ kind: px.enum(["view", "scroll"]).optional(),
1185
+ axis: px.enum(["block", "inline", "x", "y"]).optional(),
1186
+ source: px.enum(["nearest", "root"]).optional(),
1187
+ // Free-form: the two keywords `parent`/`scroller` plus any CSS selector.
1188
+ subject: px.string().optional(),
1189
+ smoothing: px.number().optional(),
1190
+ pin: px.boolean().optional(),
1191
+ pinTop: px.number().optional(),
1192
+ pinDistance: px.number().optional(),
1193
+ range: PxScrollRangeSchema.optional()
1194
+ }));
701
1195
  var PxAnimatorConfigSchema = implementsInterface()(px.object({
702
1196
  mode: px.enum([PxAnimatorMode.auto, PxAnimatorMode.waapi, PxAnimatorMode.frames]).optional(),
703
1197
  duration: px.number().optional(),
@@ -713,6 +1207,7 @@ var PxAnimatorConfigSchema = implementsInterface()(px.object({
713
1207
  definitions: PxDefsSchema.optional(),
714
1208
  animateById: px.record(PxElementAnimationSchema).optional(),
715
1209
  timelineSource: px.string().optional(),
1210
+ scroll: PxScrollSchema.optional(),
716
1211
  debugInstName: px.string().optional()
717
1212
  }));
718
1213
  var PxBindingSchema = implementsInterface()(px.object({
@@ -905,422 +1400,6 @@ function isPxElementFileFormatDeep(fileJson) {
905
1400
  return { valid, errors: valid ? [] : ["Document failed schema validation"] };
906
1401
  }
907
1402
 
908
- // src/PxAnimatorUtil.ts
909
- function bezierToSvgPath(path, forceCurves = false) {
910
- var _a, _b, _c, _d;
911
- const v = path.v;
912
- const i = path.i;
913
- const o = path.o;
914
- const c = path.c;
915
- if (!v.length) return "";
916
- const d = [];
917
- const len = v.length;
918
- d.push("M" + v[0][0] + "," + v[0][1]);
919
- for (let idx = 1; idx < len; idx++) {
920
- const prevV = v[idx - 1];
921
- const prevO = (_a = o == null ? void 0 : o[idx - 1]) != null ? _a : prevV;
922
- const currI = (_b = i == null ? void 0 : i[idx]) != null ? _b : v[idx];
923
- const currV = v[idx];
924
- const isLine = !forceCurves && (prevO[0] === prevV[0] && prevO[1] === prevV[1]) && (currI[0] === currV[0] && currI[1] === currV[1]);
925
- if (isLine) {
926
- d.push("L" + currV[0] + "," + currV[1]);
927
- } else {
928
- d.push("C" + prevO[0] + "," + prevO[1] + "," + currI[0] + "," + currI[1] + "," + currV[0] + "," + currV[1]);
929
- }
930
- }
931
- if (c && len > 0) {
932
- const lastV = v[len - 1];
933
- const lastO = (_c = o == null ? void 0 : o[len - 1]) != null ? _c : lastV;
934
- const firstI = (_d = i == null ? void 0 : i[0]) != null ? _d : v[0];
935
- const firstV = v[0];
936
- const isLine = !forceCurves && (lastO[0] === lastV[0] && lastO[1] === lastV[1]) && (firstI[0] === firstV[0] && firstI[1] === firstV[1]);
937
- if (!isLine) {
938
- d.push("C" + lastO[0] + "," + lastO[1] + "," + firstI[0] + "," + firstI[1] + "," + firstV[0] + "," + firstV[1]);
939
- }
940
- d.push("z");
941
- }
942
- return d.join("");
943
- }
944
- function interpolateNum(a, b, t) {
945
- return a + (b - a) * t;
946
- }
947
- function interpolateVec(a, b, t) {
948
- const res = [];
949
- const count = Math.max(a.length, b.length);
950
- for (let i = 0; i < count; i++) {
951
- res[i] = interpolateNum(a[i] || 0, b[i] || 0, t);
952
- }
953
- return res;
954
- }
955
- function interpolateColor(a, b, t) {
956
- return [
957
- interpolateNum(a[0] || 0, b[0] || 0, t),
958
- interpolateNum(a[1] || 0, b[1] || 0, t),
959
- interpolateNum(a[2] || 0, b[2] || 0, t),
960
- interpolateNum(a[3] === void 0 ? 1 : a[3], b[3] === void 0 ? 1 : b[3], t)
961
- ];
962
- }
963
- function interpolateBeziers(paths1, paths2, progress) {
964
- const count = Math.max(paths1.length, paths2.length);
965
- const res = [];
966
- for (let i = 0; i < count; i++) {
967
- res.push(interpolateBezier(paths1[i], paths2[i], progress));
968
- }
969
- return res;
970
- }
971
- function interpolateBezier(path1, path2, progress) {
972
- var _a, _b, _c, _d, _e, _f, _g, _h, _i;
973
- if (!path1 || !path2) return path1 || path2 || { v: [] };
974
- const t = Math.min(Math.max(progress, 0), 1);
975
- const len = Math.min(path1.v.length, path2.v.length);
976
- const v = [];
977
- const i = [];
978
- const o = [];
979
- for (let idx = 0; idx < len; idx++) {
980
- const v1 = path1.v[idx];
981
- const v2 = path2.v[idx];
982
- v.push(interpolateVec(v1, v2, t));
983
- const i1 = (_b = (_a = path1.i) == null ? void 0 : _a[idx]) != null ? _b : v1;
984
- const i2 = (_d = (_c = path2.i) == null ? void 0 : _c[idx]) != null ? _d : v2;
985
- i.push(interpolateVec(i1, i2, t));
986
- const o1 = (_f = (_e = path1.o) == null ? void 0 : _e[idx]) != null ? _f : v1;
987
- const o2 = (_h = (_g = path2.o) == null ? void 0 : _g[idx]) != null ? _h : v2;
988
- o.push(interpolateVec(o1, o2, t));
989
- }
990
- return { v, i: i.length ? i : void 0, o: o.length ? o : void 0, c: (_i = path1.c) != null ? _i : path2.c };
991
- }
992
- function remap(value, inMin, inMax, outMin, outMax) {
993
- if (inMax === inMin) return outMin;
994
- const t = (value - inMin) / (inMax - inMin);
995
- return outMin + t * (outMax - outMin);
996
- }
997
- function solveCubicBezierX(p1x, p2x, x) {
998
- if (x <= 0) return 0;
999
- if (x >= 1) return 1;
1000
- const cx = 3 * p1x;
1001
- const bx = 3 * (p2x - p1x) - cx;
1002
- const ax = 1 - cx - bx;
1003
- function sampleX(t) {
1004
- return ((ax * t + bx) * t + cx) * t;
1005
- }
1006
- function sampleDX(t) {
1007
- return (3 * ax * t + 2 * bx) * t + cx;
1008
- }
1009
- let t2 = x;
1010
- let t0 = 0;
1011
- let t1 = 1;
1012
- for (let i = 0; i < 8; i++) {
1013
- const x2 = sampleX(t2) - x;
1014
- if (Math.abs(x2) < 1e-6) return t2;
1015
- const d2 = sampleDX(t2);
1016
- if (Math.abs(d2) < 1e-6) break;
1017
- t2 -= x2 / d2;
1018
- }
1019
- t2 = x;
1020
- while (t0 < t1) {
1021
- const x2 = sampleX(t2);
1022
- if (Math.abs(x2 - x) < 1e-6) return t2;
1023
- if (x > x2) t0 = t2;
1024
- else t1 = t2;
1025
- t2 = (t1 + t0) / 2;
1026
- }
1027
- return t2;
1028
- }
1029
- function cubicBezier(easing) {
1030
- const [p1x, p1y, p2x, p2y] = easing;
1031
- const cy = 3 * p1y;
1032
- const by = 3 * (p2y - p1y) - cy;
1033
- const ay = 1 - cy - by;
1034
- function sampleCurveY(t) {
1035
- return ((ay * t + by) * t + cy) * t;
1036
- }
1037
- return function(x) {
1038
- return sampleCurveY(solveCubicBezierX(p1x, p2x, x));
1039
- };
1040
- }
1041
- function lerp2(a, b, t) {
1042
- return [a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t];
1043
- }
1044
- function subdivideCubicBezier(p0, p1, p2, p3, t) {
1045
- const q0 = lerp2(p0, p1, t);
1046
- const q1 = lerp2(p1, p2, t);
1047
- const q2 = lerp2(p2, p3, t);
1048
- const r0 = lerp2(q0, q1, t);
1049
- const r1 = lerp2(q1, q2, t);
1050
- const s = lerp2(r0, r1, t);
1051
- return {
1052
- left: [p0, q0, r0, s],
1053
- right: [s, r1, q2, p3]
1054
- };
1055
- }
1056
- function splitEasing(easing, xFraction) {
1057
- if (!easing) return { left: void 0, right: void 0 };
1058
- if (xFraction <= 0) return { left: void 0, right: easing };
1059
- if (xFraction >= 1) return { left: easing, right: void 0 };
1060
- const [x1, y1, x2, y2] = easing;
1061
- const t = solveCubicBezierX(x1, x2, xFraction);
1062
- const p0 = [0, 0];
1063
- const p1 = [x1, y1];
1064
- const p2 = [x2, y2];
1065
- const p3 = [1, 1];
1066
- const { left, right } = subdivideCubicBezier(p0, p1, p2, p3, t);
1067
- const sx = left[3][0];
1068
- const sy = left[3][1];
1069
- let leftEasing;
1070
- if (sx > 1e-9 && Math.abs(sy) > 1e-9) {
1071
- leftEasing = [
1072
- left[1][0] / sx,
1073
- left[1][1] / sy,
1074
- left[2][0] / sx,
1075
- left[2][1] / sy
1076
- ];
1077
- }
1078
- let rightEasing;
1079
- const rx = 1 - sx;
1080
- const ry = 1 - sy;
1081
- if (rx > 1e-9 && Math.abs(ry) > 1e-9) {
1082
- rightEasing = [
1083
- (right[1][0] - sx) / rx,
1084
- (right[1][1] - sy) / ry,
1085
- (right[2][0] - sx) / rx,
1086
- (right[2][1] - sy) / ry
1087
- ];
1088
- }
1089
- return { left: leftEasing, right: rightEasing };
1090
- }
1091
- function reverseEasing(easing) {
1092
- if (!easing) return void 0;
1093
- return [1 - easing[2], 1 - easing[3], 1 - easing[0], 1 - easing[1]];
1094
- }
1095
- function toRGBA(color) {
1096
- const r = Math.round(color[0] * 255);
1097
- const g = Math.round(color[1] * 255);
1098
- const b = Math.round(color[2] * 255);
1099
- return color.length === 4 ? "rgba(" + r + "," + g + "," + b + "," + color[3] + ")" : "rgb(" + r + "," + g + "," + b + ")";
1100
- }
1101
- function parseRgba(s) {
1102
- var _a;
1103
- const inner = (_a = s.match(/rgba?\((.*)\)/)) == null ? void 0 : _a[1];
1104
- if (!inner) throw new Error("Invalid rgb/rgba format");
1105
- const parts = inner.split(",").map((v) => +v.trim());
1106
- return [parts[0] / 255, parts[1] / 255, parts[2] / 255, ...parts[3] !== void 0 ? [parts[3]] : []];
1107
- }
1108
- function parseHex(s) {
1109
- const hex = s.slice(1);
1110
- const isShort = hex.length <= 4;
1111
- const r = isShort ? hex[0] + hex[0] : hex.slice(0, 2);
1112
- const g = isShort ? hex[1] + hex[1] : hex.slice(2, 4);
1113
- const b = isShort ? hex[2] + hex[2] : hex.slice(4, 6);
1114
- const a = hex.length === 4 ? hex[3] + hex[3] : hex.length === 8 ? hex.slice(6, 8) : null;
1115
- const result = [
1116
- parseInt(r, 16) / 255,
1117
- parseInt(g, 16) / 255,
1118
- parseInt(b, 16) / 255
1119
- ];
1120
- if (a !== null) {
1121
- result.push(parseInt(a, 16) / 255);
1122
- }
1123
- return result;
1124
- }
1125
- function parseColor(s) {
1126
- if (!s) return void 0;
1127
- if (Array.isArray(s)) return s;
1128
- if (typeof s !== "string") return void 0;
1129
- if (s.startsWith("#")) {
1130
- return parseHex(s);
1131
- } else if (s.startsWith("rgb")) {
1132
- return parseRgba(s);
1133
- } else {
1134
- console.warn("Unsupported color format: " + s);
1135
- }
1136
- return void 0;
1137
- }
1138
- var COLOUR_ATTR_NAMES = /* @__PURE__ */ new Set(["color", "fill", "flood-color", "lighting-color", "stop-color", "stroke"]);
1139
- var TRANSFORM_FN_NAMES = /* @__PURE__ */ new Set(["translate", "rotate", "scale", "skew"]);
1140
- var PCT_BASED_ATTR_NAMES = /* @__PURE__ */ new Set(["offset-distance", "offsetDistance"]);
1141
- function composeTransformParts(parts, opts) {
1142
- var _a;
1143
- if (!parts) return "";
1144
- const withUnits = (_a = opts == null ? void 0 : opts.withUnits) != null ? _a : true;
1145
- const segs = [];
1146
- const t = parts.translate;
1147
- const o = parts.origin;
1148
- const r = parts.rotate;
1149
- const k = parts.skew;
1150
- const s = parts.scale;
1151
- const tu = withUnits ? "px" : "";
1152
- const ru = withUnits ? "deg" : "";
1153
- if (t) segs.push("translate(" + t[0] + tu + "," + t[1] + tu + ")");
1154
- if (o) segs.push("translate(" + o[0] + tu + "," + o[1] + tu + ")");
1155
- if (r !== void 0 && r !== null) segs.push("rotate(" + r + ru + ")");
1156
- if (k !== void 0 && k !== null) segs.push("skewX(" + k + ru + ")");
1157
- if (s) segs.push("scale(" + s[0] + "," + s[1] + ")");
1158
- if (o) segs.push("translate(" + -o[0] + tu + "," + -o[1] + tu + ")");
1159
- return segs.join("");
1160
- }
1161
- var STYLE_ATTR_NAMES = /* @__PURE__ */ new Set(["offset-distance", "offsetDistance"]);
1162
- var DEFAULT_DURATION_MS = 1e3;
1163
- function kebabToCamelCaseWord(kebab) {
1164
- return kebab.includes("-") ? kebab.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase()) : kebab;
1165
- }
1166
- function isCamelCaseWord(word) {
1167
- return !word.includes("-") && /[a-z][A-Z]/.test(word);
1168
- }
1169
- var SVG_CAMEL_CASE_ATTRS = /* @__PURE__ */ new Set([
1170
- // Transform/positioning
1171
- "viewBox",
1172
- "preserveAspectRatio",
1173
- // Gradient
1174
- "gradientUnits",
1175
- "gradientTransform",
1176
- "spreadMethod",
1177
- // Pattern
1178
- "patternUnits",
1179
- "patternContentUnits",
1180
- "patternTransform",
1181
- // Clipping/masking
1182
- "clipPathUnits",
1183
- "maskUnits",
1184
- "maskContentUnits",
1185
- // Marker (SVG spec keeps these camelCase, like viewBox)
1186
- "markerUnits",
1187
- "markerWidth",
1188
- "markerHeight",
1189
- "refX",
1190
- "refY",
1191
- // Text
1192
- "textLength",
1193
- "lengthAdjust",
1194
- "startOffset",
1195
- // Filter
1196
- "filterUnits",
1197
- "primitiveUnits",
1198
- "tableValues",
1199
- // feFuncR/G/B/A transfer table (type="table")
1200
- "stdDeviation",
1201
- "baseFrequency",
1202
- "numOctaves",
1203
- "surfaceScale",
1204
- "diffuseConstant",
1205
- "specularConstant",
1206
- "specularExponent",
1207
- "kernelMatrix",
1208
- "kernelUnitLength",
1209
- "edgeMode",
1210
- "preserveAlpha",
1211
- "targetX",
1212
- "targetY"
1213
- // // Animation
1214
- // 'attributeName',
1215
- // 'attributeType',
1216
- // 'calcMode',
1217
- // 'keyTimes',
1218
- // 'keySplines',
1219
- // 'repeatCount',
1220
- // 'repeatDur'
1221
- ]);
1222
- function camelCaseToKebabWordIfNeeded(camel) {
1223
- return SVG_CAMEL_CASE_ATTRS.has(camel) ? camel : camel.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
1224
- }
1225
- function clamp(value, min, max) {
1226
- return Math.max(min, Math.min(value, max));
1227
- }
1228
- function bezier2D_pointAt(P0, P1, P2, P3, t) {
1229
- if (t <= 0) return [P0[0], P0[1]];
1230
- if (t >= 1) return [P3[0], P3[1]];
1231
- const u = 1 - t;
1232
- const u2 = u * u;
1233
- const u3 = u2 * u;
1234
- const t2 = t * t;
1235
- const t3 = t2 * t;
1236
- const w0 = u3;
1237
- const w1 = 3 * t * u2;
1238
- const w2 = 3 * t2 * u;
1239
- const w3 = t3;
1240
- return [
1241
- w0 * P0[0] + w1 * P1[0] + w2 * P2[0] + w3 * P3[0],
1242
- w0 * P0[1] + w1 * P1[1] + w2 * P2[1] + w3 * P3[1]
1243
- ];
1244
- }
1245
- var BEZIER_T_NUDGE = 1e-4;
1246
- function bezier2D_derivativeAt(P0, P1, P2, P3, t) {
1247
- const result = _bezier2D_derivativeAtRaw(P0, P1, P2, P3, t);
1248
- if (result[0] === 0 && result[1] === 0) {
1249
- const nudgedT = t < 0.5 ? t + BEZIER_T_NUDGE : t - BEZIER_T_NUDGE;
1250
- return _bezier2D_derivativeAtRaw(P0, P1, P2, P3, nudgedT);
1251
- }
1252
- return result;
1253
- }
1254
- function _bezier2D_derivativeAtRaw(P0, P1, P2, P3, t) {
1255
- const u = 1 - t;
1256
- const a = 3 * u * u;
1257
- const b = 6 * t * u;
1258
- const c = 3 * t * t;
1259
- return [
1260
- a * (P1[0] - P0[0]) + b * (P2[0] - P1[0]) + c * (P3[0] - P2[0]),
1261
- a * (P1[1] - P0[1]) + b * (P2[1] - P1[1]) + c * (P3[1] - P2[1])
1262
- ];
1263
- }
1264
- function bezier2D_arcLengthLUT(P0, P1, P2, P3, steps = 100) {
1265
- const n = steps + 1;
1266
- const ts = new Float64Array(n);
1267
- const ds = new Float64Array(n);
1268
- let prev = bezier2D_pointAt(P0, P1, P2, P3, 0);
1269
- ts[0] = 0;
1270
- ds[0] = 0;
1271
- let cum = 0;
1272
- for (let i = 1; i < n; i++) {
1273
- const t = i / steps;
1274
- const cur = bezier2D_pointAt(P0, P1, P2, P3, t);
1275
- const dx = cur[0] - prev[0];
1276
- const dy = cur[1] - prev[1];
1277
- cum += Math.sqrt(dx * dx + dy * dy);
1278
- ts[i] = t;
1279
- ds[i] = cum;
1280
- prev = cur;
1281
- }
1282
- return { ts, ds };
1283
- }
1284
- function bezier2D_tForDistance(lut, distance) {
1285
- const { ts, ds } = lut;
1286
- const last = ds.length - 1;
1287
- if (distance <= 0) return ts[0];
1288
- if (distance >= ds[last]) return ts[last];
1289
- let lo = 1;
1290
- let hi = last;
1291
- while (lo < hi) {
1292
- const mid = lo + hi >>> 1;
1293
- if (ds[mid] < distance) lo = mid + 1;
1294
- else hi = mid;
1295
- }
1296
- const dPrev = ds[hi - 1];
1297
- const dCur = ds[hi];
1298
- const span = dCur - dPrev;
1299
- const frac = span > 0 ? (distance - dPrev) / span : 0;
1300
- return ts[hi - 1] + frac * (ts[hi] - ts[hi - 1]);
1301
- }
1302
- function bezier2D_arcAtT(lut, t) {
1303
- const { ts, ds } = lut;
1304
- const last = ts.length - 1;
1305
- if (t <= ts[0]) return ds[0];
1306
- if (t >= ts[last]) return ds[last];
1307
- let lo = 1, hi = last;
1308
- while (lo < hi) {
1309
- const mid = lo + hi >>> 1;
1310
- if (ts[mid] < t) lo = mid + 1;
1311
- else hi = mid;
1312
- }
1313
- const tPrev = ts[hi - 1];
1314
- const span = ts[hi] - tPrev;
1315
- const frac = span > 0 ? (t - tPrev) / span : 0;
1316
- return ds[hi - 1] + frac * (ds[hi] - ds[hi - 1]);
1317
- }
1318
- function invertEasing(easing) {
1319
- if (!easing) return (y) => y;
1320
- const flipped = [easing[1], easing[0], easing[3], easing[2]];
1321
- return cubicBezier(flipped);
1322
- }
1323
-
1324
1403
  // src/PxIdUtil.ts
1325
1404
  var _idCounter = 0;
1326
1405
  function generateUniqueId() {
@@ -5973,6 +6052,9 @@ export {
5973
6052
  PxPropertyAnimationSchema,
5974
6053
  PxRepeaterEffectSchema,
5975
6054
  PxRetimeEffectSchema,
6055
+ PxScrollRangePointSchema,
6056
+ PxScrollRangeSchema,
6057
+ PxScrollSchema,
5976
6058
  PxStrokeGradientEffectSchema,
5977
6059
  PxSvgNodeExtra,
5978
6060
  PxTextEffectSchema,
@@ -6014,6 +6096,7 @@ export {
6014
6096
  interpolateValue,
6015
6097
  isPxElementFileFormat,
6016
6098
  isPxElementFileFormatDeep,
6099
+ isScrollTimeline,
6017
6100
  jsonElementFactory,
6018
6101
  kebabToCamelCaseWord,
6019
6102
  layoutGlyphTextChars,
@@ -6032,6 +6115,11 @@ export {
6032
6115
  reverseEasing,
6033
6116
  sanitiseAttributeValue,
6034
6117
  schemaKeys,
6118
+ scrollOffsetProgress,
6119
+ scrollPhaseInterval,
6120
+ scrollResolveAxis,
6121
+ scrollTotalDurationMs,
6122
+ scrollViewProgress,
6035
6123
  shiftAnimatable,
6036
6124
  splitEasing,
6037
6125
  subdivideCubicBezier,