@pixodesk/svg-animator-vue 1.0.24 → 1.0.27

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.umd.js CHANGED
@@ -56813,114 +56813,582 @@ ${codeFrame}` : message);
56813
56813
  return a;
56814
56814
  };
56815
56815
  var __spreadProps2 = (a, b) => __defProps2(a, __getOwnPropDescs2(b));
56816
- function pathStr(path) {
56817
- if (!path.length) return ".";
56818
- let result = "";
56819
- for (const seg of path) {
56820
- if (seg.startsWith("[")) result += seg;
56821
- else result += (result ? "." : "") + seg;
56822
- }
56823
- return result;
56824
- }
56825
- var Base = class {
56826
- _canSanitize(raw) {
56827
- return this.isValid(raw);
56816
+ function bezierToSvgPath(path, forceCurves = false) {
56817
+ var _a, _b, _c, _d;
56818
+ const v = path.v;
56819
+ const i = path.i;
56820
+ const o = path.o;
56821
+ const c = path.c;
56822
+ if (!v.length) return "";
56823
+ const d = [];
56824
+ const len = v.length;
56825
+ d.push("M" + v[0][0] + "," + v[0][1]);
56826
+ for (let idx = 1; idx < len; idx++) {
56827
+ const prevV = v[idx - 1];
56828
+ const prevO = (_a = o == null ? void 0 : o[idx - 1]) != null ? _a : prevV;
56829
+ const currI = (_b = i == null ? void 0 : i[idx]) != null ? _b : v[idx];
56830
+ const currV = v[idx];
56831
+ const isLine = !forceCurves && (prevO[0] === prevV[0] && prevO[1] === prevV[1]) && (currI[0] === currV[0] && currI[1] === currV[1]);
56832
+ if (isLine) {
56833
+ d.push("L" + currV[0] + "," + currV[1]);
56834
+ } else {
56835
+ d.push("C" + prevO[0] + "," + prevO[1] + "," + currI[0] + "," + currI[1] + "," + currV[0] + "," + currV[1]);
56836
+ }
56828
56837
  }
56829
- optional() {
56830
- return new Optional(this);
56838
+ if (c && len > 0) {
56839
+ const lastV = v[len - 1];
56840
+ const lastO = (_c = o == null ? void 0 : o[len - 1]) != null ? _c : lastV;
56841
+ const firstI = (_d = i == null ? void 0 : i[0]) != null ? _d : v[0];
56842
+ const firstV = v[0];
56843
+ const isLine = !forceCurves && (lastO[0] === lastV[0] && lastO[1] === lastV[1]) && (firstI[0] === firstV[0] && firstI[1] === firstV[1]);
56844
+ if (!isLine) {
56845
+ d.push("C" + lastO[0] + "," + lastO[1] + "," + firstI[0] + "," + firstI[1] + "," + firstV[0] + "," + firstV[1]);
56846
+ }
56847
+ d.push("z");
56831
56848
  }
56832
- };
56833
- var Optional = class extends Base {
56834
- constructor(inner) {
56835
- super();
56836
- this.inner = inner;
56837
- this._default = void 0;
56849
+ return d.join("");
56850
+ }
56851
+ function interpolateNum(a, b, t) {
56852
+ return a + (b - a) * t;
56853
+ }
56854
+ function interpolateVec(a, b, t) {
56855
+ const res = [];
56856
+ const count = Math.max(a.length, b.length);
56857
+ for (let i = 0; i < count; i++) {
56858
+ res[i] = interpolateNum(a[i] || 0, b[i] || 0, t);
56838
56859
  }
56839
- sanitize(raw) {
56840
- if (raw === void 0 || raw === null) return void 0;
56841
- return this.inner._canSanitize(raw) ? this.inner.sanitize(raw) : void 0;
56860
+ return res;
56861
+ }
56862
+ function interpolateColor(a, b, t) {
56863
+ return [
56864
+ interpolateNum(a[0] || 0, b[0] || 0, t),
56865
+ interpolateNum(a[1] || 0, b[1] || 0, t),
56866
+ interpolateNum(a[2] || 0, b[2] || 0, t),
56867
+ interpolateNum(a[3] === void 0 ? 1 : a[3], b[3] === void 0 ? 1 : b[3], t)
56868
+ ];
56869
+ }
56870
+ function interpolateBeziers(paths1, paths2, progress) {
56871
+ const count = Math.max(paths1.length, paths2.length);
56872
+ const res = [];
56873
+ for (let i = 0; i < count; i++) {
56874
+ res.push(interpolateBezier(paths1[i], paths2[i], progress));
56842
56875
  }
56843
- isValid(raw, ctx, path) {
56844
- if (raw === void 0 || raw === null) return true;
56845
- return this.inner.isValid(raw, ctx, path);
56876
+ return res;
56877
+ }
56878
+ function interpolateBezier(path1, path2, progress) {
56879
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
56880
+ if (!path1 || !path2) return path1 || path2 || { v: [] };
56881
+ const t = Math.min(Math.max(progress, 0), 1);
56882
+ const len = Math.min(path1.v.length, path2.v.length);
56883
+ const v = [];
56884
+ const i = [];
56885
+ const o = [];
56886
+ for (let idx = 0; idx < len; idx++) {
56887
+ const v1 = path1.v[idx];
56888
+ const v2 = path2.v[idx];
56889
+ v.push(interpolateVec(v1, v2, t));
56890
+ const i1 = (_b = (_a = path1.i) == null ? void 0 : _a[idx]) != null ? _b : v1;
56891
+ const i2 = (_d = (_c = path2.i) == null ? void 0 : _c[idx]) != null ? _d : v2;
56892
+ i.push(interpolateVec(i1, i2, t));
56893
+ const o1 = (_f = (_e = path1.o) == null ? void 0 : _e[idx]) != null ? _f : v1;
56894
+ const o2 = (_h = (_g = path2.o) == null ? void 0 : _g[idx]) != null ? _h : v2;
56895
+ o.push(interpolateVec(o1, o2, t));
56846
56896
  }
56847
- _canSanitize(raw) {
56848
- return raw === void 0 || raw === null || this.inner._canSanitize(raw);
56897
+ return { v, i: i.length ? i : void 0, o: o.length ? o : void 0, c: (_i = path1.c) != null ? _i : path2.c };
56898
+ }
56899
+ function remap(value, inMin, inMax, outMin, outMax) {
56900
+ if (inMax === inMin) return outMin;
56901
+ const t = (value - inMin) / (inMax - inMin);
56902
+ return outMin + t * (outMax - outMin);
56903
+ }
56904
+ function solveCubicBezierX(p1x, p2x, x) {
56905
+ if (x <= 0) return 0;
56906
+ if (x >= 1) return 1;
56907
+ const cx = 3 * p1x;
56908
+ const bx = 3 * (p2x - p1x) - cx;
56909
+ const ax = 1 - cx - bx;
56910
+ function sampleX(t) {
56911
+ return ((ax * t + bx) * t + cx) * t;
56849
56912
  }
56850
- };
56851
- var Str = class extends Base {
56852
- constructor(_default = "") {
56853
- super();
56854
- this._default = _default;
56913
+ function sampleDX(t) {
56914
+ return (3 * ax * t + 2 * bx) * t + cx;
56855
56915
  }
56856
- sanitize(raw) {
56857
- return typeof raw === "string" ? raw : this._default;
56916
+ let t2 = x;
56917
+ let t0 = 0;
56918
+ let t1 = 1;
56919
+ for (let i = 0; i < 8; i++) {
56920
+ const x2 = sampleX(t2) - x;
56921
+ if (Math.abs(x2) < 1e-6) return t2;
56922
+ const d2 = sampleDX(t2);
56923
+ if (Math.abs(d2) < 1e-6) break;
56924
+ t2 -= x2 / d2;
56858
56925
  }
56859
- isValid(raw, ctx, path) {
56860
- if (typeof raw === "string") return true;
56861
- ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected string, got " + typeof raw);
56862
- return false;
56926
+ t2 = x;
56927
+ while (t0 < t1) {
56928
+ const x2 = sampleX(t2);
56929
+ if (Math.abs(x2 - x) < 1e-6) return t2;
56930
+ if (x > x2) t0 = t2;
56931
+ else t1 = t2;
56932
+ t2 = (t1 + t0) / 2;
56863
56933
  }
56864
- };
56865
- var Num = class extends Base {
56866
- constructor(_default = 0) {
56867
- super();
56868
- this._default = _default;
56934
+ return t2;
56935
+ }
56936
+ function cubicBezier(easing) {
56937
+ const [p1x, p1y, p2x, p2y] = easing;
56938
+ const cy = 3 * p1y;
56939
+ const by = 3 * (p2y - p1y) - cy;
56940
+ const ay = 1 - cy - by;
56941
+ function sampleCurveY(t) {
56942
+ return ((ay * t + by) * t + cy) * t;
56869
56943
  }
56870
- sanitize(raw) {
56871
- return typeof raw === "number" && isFinite(raw) ? raw : this._default;
56944
+ return function(x) {
56945
+ return sampleCurveY(solveCubicBezierX(p1x, p2x, x));
56946
+ };
56947
+ }
56948
+ function lerp2(a, b, t) {
56949
+ return [a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t];
56950
+ }
56951
+ function subdivideCubicBezier(p0, p1, p2, p3, t) {
56952
+ const q0 = lerp2(p0, p1, t);
56953
+ const q1 = lerp2(p1, p2, t);
56954
+ const q2 = lerp2(p2, p3, t);
56955
+ const r0 = lerp2(q0, q1, t);
56956
+ const r1 = lerp2(q1, q2, t);
56957
+ const s = lerp2(r0, r1, t);
56958
+ return {
56959
+ left: [p0, q0, r0, s],
56960
+ right: [s, r1, q2, p3]
56961
+ };
56962
+ }
56963
+ function splitEasing(easing, xFraction) {
56964
+ if (!easing) return { left: void 0, right: void 0 };
56965
+ if (xFraction <= 0) return { left: void 0, right: easing };
56966
+ if (xFraction >= 1) return { left: easing, right: void 0 };
56967
+ const [x1, y1, x2, y2] = easing;
56968
+ const t = solveCubicBezierX(x1, x2, xFraction);
56969
+ const p0 = [0, 0];
56970
+ const p1 = [x1, y1];
56971
+ const p2 = [x2, y2];
56972
+ const p3 = [1, 1];
56973
+ const { left, right } = subdivideCubicBezier(p0, p1, p2, p3, t);
56974
+ const sx = left[3][0];
56975
+ const sy = left[3][1];
56976
+ let leftEasing;
56977
+ if (sx > 1e-9 && Math.abs(sy) > 1e-9) {
56978
+ leftEasing = [
56979
+ left[1][0] / sx,
56980
+ left[1][1] / sy,
56981
+ left[2][0] / sx,
56982
+ left[2][1] / sy
56983
+ ];
56872
56984
  }
56873
- isValid(raw, ctx, path) {
56874
- if (typeof raw === "number" && isFinite(raw)) return true;
56875
- ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected finite number, got " + JSON.stringify(raw));
56876
- return false;
56985
+ let rightEasing;
56986
+ const rx = 1 - sx;
56987
+ const ry = 1 - sy;
56988
+ if (rx > 1e-9 && Math.abs(ry) > 1e-9) {
56989
+ rightEasing = [
56990
+ (right[1][0] - sx) / rx,
56991
+ (right[1][1] - sy) / ry,
56992
+ (right[2][0] - sx) / rx,
56993
+ (right[2][1] - sy) / ry
56994
+ ];
56877
56995
  }
56878
- };
56879
- var Bool = class extends Base {
56880
- constructor(_default = false) {
56881
- super();
56882
- this._default = _default;
56996
+ return { left: leftEasing, right: rightEasing };
56997
+ }
56998
+ function reverseEasing(easing) {
56999
+ if (!easing) return void 0;
57000
+ return [1 - easing[2], 1 - easing[3], 1 - easing[0], 1 - easing[1]];
57001
+ }
57002
+ function toRGBA(color) {
57003
+ const r = Math.round(color[0] * 255);
57004
+ const g = Math.round(color[1] * 255);
57005
+ const b = Math.round(color[2] * 255);
57006
+ return color.length === 4 ? "rgba(" + r + "," + g + "," + b + "," + color[3] + ")" : "rgb(" + r + "," + g + "," + b + ")";
57007
+ }
57008
+ function parseRgba(s) {
57009
+ var _a;
57010
+ const inner = (_a = s.match(/rgba?\((.*)\)/)) == null ? void 0 : _a[1];
57011
+ if (!inner) throw new Error("Invalid rgb/rgba format");
57012
+ const parts = inner.split(",").map((v) => +v.trim());
57013
+ return [parts[0] / 255, parts[1] / 255, parts[2] / 255, ...parts[3] !== void 0 ? [parts[3]] : []];
57014
+ }
57015
+ function parseHex(s) {
57016
+ const hex = s.slice(1);
57017
+ const isShort = hex.length <= 4;
57018
+ const r = isShort ? hex[0] + hex[0] : hex.slice(0, 2);
57019
+ const g = isShort ? hex[1] + hex[1] : hex.slice(2, 4);
57020
+ const b = isShort ? hex[2] + hex[2] : hex.slice(4, 6);
57021
+ const a = hex.length === 4 ? hex[3] + hex[3] : hex.length === 8 ? hex.slice(6, 8) : null;
57022
+ const result = [
57023
+ parseInt(r, 16) / 255,
57024
+ parseInt(g, 16) / 255,
57025
+ parseInt(b, 16) / 255
57026
+ ];
57027
+ if (a !== null) {
57028
+ result.push(parseInt(a, 16) / 255);
56883
57029
  }
56884
- sanitize(raw) {
56885
- return typeof raw === "boolean" ? raw : this._default;
57030
+ return result;
57031
+ }
57032
+ function parseColor(s) {
57033
+ if (!s) return void 0;
57034
+ if (Array.isArray(s)) return s;
57035
+ if (typeof s !== "string") return void 0;
57036
+ if (s.startsWith("#")) {
57037
+ return parseHex(s);
57038
+ } else if (s.startsWith("rgb")) {
57039
+ return parseRgba(s);
57040
+ } else {
57041
+ console.warn("Unsupported color format: " + s);
56886
57042
  }
56887
- isValid(raw, ctx, path) {
56888
- if (typeof raw === "boolean") return true;
56889
- ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected boolean, got " + typeof raw);
56890
- return false;
57043
+ return void 0;
57044
+ }
57045
+ var COLOUR_ATTR_NAMES = /* @__PURE__ */ new Set(["color", "fill", "flood-color", "lighting-color", "stop-color", "stroke"]);
57046
+ var TRANSFORM_FN_NAMES = /* @__PURE__ */ new Set(["translate", "rotate", "scale", "skew"]);
57047
+ var PCT_BASED_ATTR_NAMES = /* @__PURE__ */ new Set(["offset-distance", "offsetDistance"]);
57048
+ function composeTransformParts(parts, opts) {
57049
+ var _a;
57050
+ if (!parts) return "";
57051
+ const withUnits = (_a = opts == null ? void 0 : opts.withUnits) != null ? _a : true;
57052
+ const segs = [];
57053
+ const t = parts.translate;
57054
+ const o = parts.origin;
57055
+ const r = parts.rotate;
57056
+ const k = parts.skew;
57057
+ const s = parts.scale;
57058
+ const tu = withUnits ? "px" : "";
57059
+ const ru = withUnits ? "deg" : "";
57060
+ if (t) segs.push("translate(" + t[0] + tu + "," + t[1] + tu + ")");
57061
+ if (o) segs.push("translate(" + o[0] + tu + "," + o[1] + tu + ")");
57062
+ if (r !== void 0 && r !== null) segs.push("rotate(" + r + ru + ")");
57063
+ if (k !== void 0 && k !== null) segs.push("skewX(" + k + ru + ")");
57064
+ if (s) segs.push("scale(" + s[0] + "," + s[1] + ")");
57065
+ if (o) segs.push("translate(" + -o[0] + tu + "," + -o[1] + tu + ")");
57066
+ return segs.join("");
57067
+ }
57068
+ var STYLE_ATTR_NAMES = /* @__PURE__ */ new Set(["offset-distance", "offsetDistance"]);
57069
+ var DEFAULT_DURATION_MS = 1e3;
57070
+ function kebabToCamelCaseWord(kebab) {
57071
+ return kebab.includes("-") ? kebab.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase()) : kebab;
57072
+ }
57073
+ function isCamelCaseWord(word) {
57074
+ return !word.includes("-") && /[a-z][A-Z]/.test(word);
57075
+ }
57076
+ var SVG_CAMEL_CASE_ATTRS = /* @__PURE__ */ new Set([
57077
+ // Transform/positioning
57078
+ "viewBox",
57079
+ "preserveAspectRatio",
57080
+ // Gradient
57081
+ "gradientUnits",
57082
+ "gradientTransform",
57083
+ "spreadMethod",
57084
+ // Pattern
57085
+ "patternUnits",
57086
+ "patternContentUnits",
57087
+ "patternTransform",
57088
+ // Clipping/masking
57089
+ "clipPathUnits",
57090
+ "maskUnits",
57091
+ "maskContentUnits",
57092
+ // Marker (SVG spec keeps these camelCase, like viewBox)
57093
+ "markerUnits",
57094
+ "markerWidth",
57095
+ "markerHeight",
57096
+ "refX",
57097
+ "refY",
57098
+ // Text
57099
+ "textLength",
57100
+ "lengthAdjust",
57101
+ "startOffset",
57102
+ // Filter
57103
+ "filterUnits",
57104
+ "primitiveUnits",
57105
+ "tableValues",
57106
+ // feFuncR/G/B/A transfer table (type="table")
57107
+ "stdDeviation",
57108
+ "baseFrequency",
57109
+ "numOctaves",
57110
+ "surfaceScale",
57111
+ "diffuseConstant",
57112
+ "specularConstant",
57113
+ "specularExponent",
57114
+ "kernelMatrix",
57115
+ "kernelUnitLength",
57116
+ "edgeMode",
57117
+ "preserveAlpha",
57118
+ "targetX",
57119
+ "targetY"
57120
+ // // Animation
57121
+ // 'attributeName',
57122
+ // 'attributeType',
57123
+ // 'calcMode',
57124
+ // 'keyTimes',
57125
+ // 'keySplines',
57126
+ // 'repeatCount',
57127
+ // 'repeatDur'
57128
+ ]);
57129
+ function camelCaseToKebabWordIfNeeded(camel) {
57130
+ return SVG_CAMEL_CASE_ATTRS.has(camel) ? camel : camel.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
57131
+ }
57132
+ function clamp(value, min, max) {
57133
+ return Math.max(min, Math.min(value, max));
57134
+ }
57135
+ function bezier2D_pointAt(P0, P1, P2, P3, t) {
57136
+ if (t <= 0) return [P0[0], P0[1]];
57137
+ if (t >= 1) return [P3[0], P3[1]];
57138
+ const u = 1 - t;
57139
+ const u2 = u * u;
57140
+ const u3 = u2 * u;
57141
+ const t2 = t * t;
57142
+ const t3 = t2 * t;
57143
+ const w0 = u3;
57144
+ const w1 = 3 * t * u2;
57145
+ const w2 = 3 * t2 * u;
57146
+ const w3 = t3;
57147
+ return [
57148
+ w0 * P0[0] + w1 * P1[0] + w2 * P2[0] + w3 * P3[0],
57149
+ w0 * P0[1] + w1 * P1[1] + w2 * P2[1] + w3 * P3[1]
57150
+ ];
57151
+ }
57152
+ var BEZIER_T_NUDGE = 1e-4;
57153
+ function bezier2D_derivativeAt(P0, P1, P2, P3, t) {
57154
+ const result = _bezier2D_derivativeAtRaw(P0, P1, P2, P3, t);
57155
+ if (result[0] === 0 && result[1] === 0) {
57156
+ const nudgedT = t < 0.5 ? t + BEZIER_T_NUDGE : t - BEZIER_T_NUDGE;
57157
+ return _bezier2D_derivativeAtRaw(P0, P1, P2, P3, nudgedT);
57158
+ }
57159
+ return result;
57160
+ }
57161
+ function _bezier2D_derivativeAtRaw(P0, P1, P2, P3, t) {
57162
+ const u = 1 - t;
57163
+ const a = 3 * u * u;
57164
+ const b = 6 * t * u;
57165
+ const c = 3 * t * t;
57166
+ return [
57167
+ a * (P1[0] - P0[0]) + b * (P2[0] - P1[0]) + c * (P3[0] - P2[0]),
57168
+ a * (P1[1] - P0[1]) + b * (P2[1] - P1[1]) + c * (P3[1] - P2[1])
57169
+ ];
57170
+ }
57171
+ function bezier2D_arcLengthLUT(P0, P1, P2, P3, steps = 100) {
57172
+ const n = steps + 1;
57173
+ const ts = new Float64Array(n);
57174
+ const ds = new Float64Array(n);
57175
+ let prev = bezier2D_pointAt(P0, P1, P2, P3, 0);
57176
+ ts[0] = 0;
57177
+ ds[0] = 0;
57178
+ let cum = 0;
57179
+ for (let i = 1; i < n; i++) {
57180
+ const t = i / steps;
57181
+ const cur = bezier2D_pointAt(P0, P1, P2, P3, t);
57182
+ const dx = cur[0] - prev[0];
57183
+ const dy = cur[1] - prev[1];
57184
+ cum += Math.sqrt(dx * dx + dy * dy);
57185
+ ts[i] = t;
57186
+ ds[i] = cum;
57187
+ prev = cur;
57188
+ }
57189
+ return { ts, ds };
57190
+ }
57191
+ function bezier2D_tForDistance(lut, distance) {
57192
+ const { ts, ds } = lut;
57193
+ const last = ds.length - 1;
57194
+ if (distance <= 0) return ts[0];
57195
+ if (distance >= ds[last]) return ts[last];
57196
+ let lo = 1;
57197
+ let hi = last;
57198
+ while (lo < hi) {
57199
+ const mid = lo + hi >>> 1;
57200
+ if (ds[mid] < distance) lo = mid + 1;
57201
+ else hi = mid;
57202
+ }
57203
+ const dPrev = ds[hi - 1];
57204
+ const dCur = ds[hi];
57205
+ const span = dCur - dPrev;
57206
+ const frac = span > 0 ? (distance - dPrev) / span : 0;
57207
+ return ts[hi - 1] + frac * (ts[hi] - ts[hi - 1]);
57208
+ }
57209
+ function bezier2D_arcAtT(lut, t) {
57210
+ const { ts, ds } = lut;
57211
+ const last = ts.length - 1;
57212
+ if (t <= ts[0]) return ds[0];
57213
+ if (t >= ts[last]) return ds[last];
57214
+ let lo = 1, hi = last;
57215
+ while (lo < hi) {
57216
+ const mid = lo + hi >>> 1;
57217
+ if (ts[mid] < t) lo = mid + 1;
57218
+ else hi = mid;
57219
+ }
57220
+ const tPrev = ts[hi - 1];
57221
+ const span = ts[hi] - tPrev;
57222
+ const frac = span > 0 ? (t - tPrev) / span : 0;
57223
+ return ds[hi - 1] + frac * (ds[hi] - ds[hi - 1]);
57224
+ }
57225
+ function invertEasing(easing) {
57226
+ if (!easing) return (y) => y;
57227
+ const flipped = [easing[1], easing[0], easing[3], easing[2]];
57228
+ return cubicBezier(flipped);
57229
+ }
57230
+ function isScrollTimeline(config) {
57231
+ return (config == null ? void 0 : config.timelineSource) === "scroll";
57232
+ }
57233
+ function scrollTotalDurationMs(config) {
57234
+ const duration = typeof (config == null ? void 0 : config.duration) === "number" && config.duration > 0 ? config.duration : DEFAULT_DURATION_MS;
57235
+ const iterations = typeof (config == null ? void 0 : config.iterations) === "number" && config.iterations > 0 ? config.iterations : 1;
57236
+ return duration * iterations;
57237
+ }
57238
+ function scrollPhaseInterval(phase, subjectSize, scrollportSize) {
57239
+ const s = subjectSize, vp = scrollportSize;
57240
+ switch (phase) {
57241
+ case "cover":
57242
+ return [0, s + vp];
57243
+ case "entry":
57244
+ return [0, Math.min(s, vp)];
57245
+ case "contain":
57246
+ return [Math.min(s, vp), Math.max(s, vp)];
57247
+ case "exit":
57248
+ return [Math.max(s, vp), s + vp];
57249
+ case "entry-crossing":
57250
+ return [0, s];
57251
+ case "exit-crossing":
57252
+ return [vp, s + vp];
57253
+ }
57254
+ }
57255
+ var DEFAULT_PHASE = "cover";
57256
+ function resolveRangePointU(point, defaultFraction, subjectSize, scrollportSize) {
57257
+ var _a;
57258
+ const [u0, u1] = scrollPhaseInterval((_a = point == null ? void 0 : point.phase) != null ? _a : DEFAULT_PHASE, subjectSize, scrollportSize);
57259
+ const fraction = typeof (point == null ? void 0 : point.fraction) === "number" ? point.fraction : defaultFraction;
57260
+ return u0 + fraction * (u1 - u0);
57261
+ }
57262
+ function scrollViewProgress(subjectStart, subjectSize, scrollportSize, range) {
57263
+ const u = scrollportSize - subjectStart;
57264
+ const uStart = resolveRangePointU(range == null ? void 0 : range.start, 0, subjectSize, scrollportSize);
57265
+ const uEnd = resolveRangePointU(range == null ? void 0 : range.end, 1, subjectSize, scrollportSize);
57266
+ if (uEnd <= uStart) return u >= uEnd ? 1 : 0;
57267
+ return clamp((u - uStart) / (uEnd - uStart), 0, 1);
57268
+ }
57269
+ function scrollOffsetProgress(offset, maxOffset, range) {
57270
+ var _a, _b;
57271
+ const raw = maxOffset > 0 ? clamp(offset / maxOffset, 0, 1) : 1;
57272
+ const start = typeof ((_a = range == null ? void 0 : range.start) == null ? void 0 : _a.fraction) === "number" ? range.start.fraction : 0;
57273
+ const end = typeof ((_b = range == null ? void 0 : range.end) == null ? void 0 : _b.fraction) === "number" ? range.end.fraction : 1;
57274
+ if (end <= start) return raw >= end ? 1 : 0;
57275
+ return clamp((raw - start) / (end - start), 0, 1);
57276
+ }
57277
+ function scrollResolveAxis(axis, writingMode) {
57278
+ const a = axis != null ? axis : "block";
57279
+ if (a === "x" || a === "y") return a;
57280
+ const vertical = !!writingMode && writingMode.startsWith("vertical");
57281
+ if (a === "inline") return vertical ? "y" : "x";
57282
+ return vertical ? "x" : "y";
57283
+ }
57284
+ function pathStr(path) {
57285
+ if (!path.length) return ".";
57286
+ let result = "";
57287
+ for (const seg of path) {
57288
+ if (seg.startsWith("[")) result += seg;
57289
+ else result += (result ? "." : "") + seg;
57290
+ }
57291
+ return result;
57292
+ }
57293
+ var Base = class {
57294
+ _canSanitize(raw) {
57295
+ return this.isValid(raw);
57296
+ }
57297
+ optional() {
57298
+ return new Optional(this);
56891
57299
  }
56892
57300
  };
56893
- var Literal = class extends Base {
56894
- constructor(value) {
57301
+ var Optional = class extends Base {
57302
+ constructor(inner) {
56895
57303
  super();
56896
- this.value = value;
56897
- this._default = value;
57304
+ this.inner = inner;
57305
+ this._default = void 0;
56898
57306
  }
56899
57307
  sanitize(raw) {
56900
- return raw === this.value ? this.value : this._default;
57308
+ if (raw === void 0 || raw === null) return void 0;
57309
+ return this.inner._canSanitize(raw) ? this.inner.sanitize(raw) : void 0;
56901
57310
  }
56902
57311
  isValid(raw, ctx, path) {
56903
- if (raw === this.value) return true;
56904
- ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected " + JSON.stringify(this.value) + ", got " + JSON.stringify(raw));
56905
- return false;
57312
+ if (raw === void 0 || raw === null) return true;
57313
+ return this.inner.isValid(raw, ctx, path);
57314
+ }
57315
+ _canSanitize(raw) {
57316
+ return raw === void 0 || raw === null || this.inner._canSanitize(raw);
56906
57317
  }
56907
57318
  };
56908
- var Enum = class extends Base {
56909
- constructor(values, defaultVal) {
57319
+ var Str = class extends Base {
57320
+ constructor(_default = "") {
56910
57321
  super();
56911
- this.values = values;
56912
- this._default = defaultVal != null ? defaultVal : values[0];
57322
+ this._default = _default;
56913
57323
  }
56914
57324
  sanitize(raw) {
56915
- return this.values.includes(raw) ? raw : this._default;
57325
+ return typeof raw === "string" ? raw : this._default;
56916
57326
  }
56917
57327
  isValid(raw, ctx, path) {
56918
- if (this.values.includes(raw)) return true;
56919
- 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));
57328
+ if (typeof raw === "string") return true;
57329
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected string, got " + typeof raw);
56920
57330
  return false;
56921
57331
  }
56922
57332
  };
56923
- var Union = class extends Base {
57333
+ var Num = class extends Base {
57334
+ constructor(_default = 0) {
57335
+ super();
57336
+ this._default = _default;
57337
+ }
57338
+ sanitize(raw) {
57339
+ return typeof raw === "number" && isFinite(raw) ? raw : this._default;
57340
+ }
57341
+ isValid(raw, ctx, path) {
57342
+ if (typeof raw === "number" && isFinite(raw)) return true;
57343
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected finite number, got " + JSON.stringify(raw));
57344
+ return false;
57345
+ }
57346
+ };
57347
+ var Bool = class extends Base {
57348
+ constructor(_default = false) {
57349
+ super();
57350
+ this._default = _default;
57351
+ }
57352
+ sanitize(raw) {
57353
+ return typeof raw === "boolean" ? raw : this._default;
57354
+ }
57355
+ isValid(raw, ctx, path) {
57356
+ if (typeof raw === "boolean") return true;
57357
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected boolean, got " + typeof raw);
57358
+ return false;
57359
+ }
57360
+ };
57361
+ var Literal = class extends Base {
57362
+ constructor(value) {
57363
+ super();
57364
+ this.value = value;
57365
+ this._default = value;
57366
+ }
57367
+ sanitize(raw) {
57368
+ return raw === this.value ? this.value : this._default;
57369
+ }
57370
+ isValid(raw, ctx, path) {
57371
+ if (raw === this.value) return true;
57372
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": expected " + JSON.stringify(this.value) + ", got " + JSON.stringify(raw));
57373
+ return false;
57374
+ }
57375
+ };
57376
+ var Enum = class extends Base {
57377
+ constructor(values, defaultVal) {
57378
+ super();
57379
+ this.values = values;
57380
+ this._default = defaultVal != null ? defaultVal : values[0];
57381
+ }
57382
+ sanitize(raw) {
57383
+ return this.values.includes(raw) ? raw : this._default;
57384
+ }
57385
+ isValid(raw, ctx, path) {
57386
+ if (this.values.includes(raw)) return true;
57387
+ 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));
57388
+ return false;
57389
+ }
57390
+ };
57391
+ var Union = class extends Base {
56924
57392
  constructor(schemas, defaultVal) {
56925
57393
  super();
56926
57394
  this.schemas = schemas;
@@ -57457,6 +57925,22 @@ ${codeFrame}` : message);
57457
57925
  styles: px.record(px.any()).optional(),
57458
57926
  glyphs: px.record(PxGlyphFontSchema).optional()
57459
57927
  }));
57928
+ var PX_SCROLL_PHASES = ["cover", "contain", "entry", "exit", "entry-crossing", "exit-crossing"];
57929
+ var PxScrollRangePointSchema = implementsInterface()(px.object({
57930
+ phase: px.enum(PX_SCROLL_PHASES).optional(),
57931
+ fraction: px.number().optional()
57932
+ }));
57933
+ var PxScrollRangeSchema = px.object({
57934
+ start: PxScrollRangePointSchema.optional(),
57935
+ end: PxScrollRangePointSchema.optional()
57936
+ });
57937
+ var PxScrollSchema = implementsInterface()(px.object({
57938
+ driver: px.enum(["custom", "native"]).optional(),
57939
+ kind: px.enum(["view", "scroll"]).optional(),
57940
+ axis: px.enum(["block", "inline", "x", "y"]).optional(),
57941
+ source: px.enum(["nearest", "root"]).optional(),
57942
+ range: PxScrollRangeSchema.optional()
57943
+ }));
57460
57944
  var PxAnimatorConfigSchema = implementsInterface()(px.object({
57461
57945
  mode: px.enum([PxAnimatorMode.auto, PxAnimatorMode.waapi, PxAnimatorMode.frames]).optional(),
57462
57946
  duration: px.number().optional(),
@@ -57472,6 +57956,7 @@ ${codeFrame}` : message);
57472
57956
  definitions: PxDefsSchema.optional(),
57473
57957
  animateById: px.record(PxElementAnimationSchema).optional(),
57474
57958
  timelineSource: px.string().optional(),
57959
+ scroll: PxScrollSchema.optional(),
57475
57960
  debugInstName: px.string().optional()
57476
57961
  }));
57477
57962
  var PxBindingSchema = implementsInterface()(px.object({
@@ -57486,591 +57971,179 @@ ${codeFrame}` : message);
57486
57971
  // `defined`, not `any`: the KEY's presence is what identifies this branch (V6).
57487
57972
  px.object({ value: px.defined() }),
57488
57973
  // Bare transform parts record — the canonical static `transform` on the wire (T2).
57489
- PxTransformPartsSchema
57490
- ]);
57491
- var PxAnimatableNumberSchema = px.union([
57492
- px.number(),
57493
- px.object({ value: px.number() }),
57494
- PxPropertyAnimationSchema
57495
- ]);
57496
- var PxAnimatableVec2Schema = px.union([
57497
- px.tuple([px.number(), px.number()]),
57498
- px.object({ value: px.tuple([px.number(), px.number()]) }),
57499
- PxPropertyAnimationSchema
57500
- ]);
57501
- var PxAnimatableStringSchema = px.union([
57502
- px.string(),
57503
- px.object({ value: px.string() }),
57504
- PxPropertyAnimationSchema
57505
- ]);
57506
- var PxTransformByEffectSchema = implementsInterface()(px.object({
57507
- translate: PxAnimatableVec2Schema.optional(),
57508
- rotate: PxAnimatableNumberSchema.optional(),
57509
- scale: PxAnimatableVec2Schema.optional(),
57510
- skew: PxAnimatableNumberSchema.optional(),
57511
- origin: PxAnimatableVec2Schema.optional()
57512
- }));
57513
- var PxRepeaterEffectSchema = implementsInterface()(px.object({
57514
- // STATIC config, not a channel (V2/SCHEMA-DESIGN R5): the copy COUNT is read
57515
- // once at expansion time and never sampled — plain number, no `keyframes`.
57516
- copies: px.number().optional(),
57517
- translate: PxAnimatableVec2Schema.optional(),
57518
- rotate: PxAnimatableNumberSchema.optional(),
57519
- skew: PxAnimatableNumberSchema.optional(),
57520
- scale: PxAnimatableVec2Schema.optional(),
57521
- origin: PxAnimatableVec2Schema.optional()
57522
- }));
57523
- var PxMaskedByEffectSchema = implementsInterface()(px.object({
57524
- sourceId: px.string().optional(),
57525
- maskType: px.enum([PxMaskType.luminance, PxMaskType.alpha]).optional(),
57526
- maskUnits: px.enum([PxUnits.userSpaceOnUse, PxUnits.objectBoundingBox]).optional(),
57527
- maskContentUnits: px.enum([PxUnits.userSpaceOnUse, PxUnits.objectBoundingBox]).optional(),
57528
- x: px.number().optional(),
57529
- y: px.number().optional(),
57530
- width: px.number().optional(),
57531
- height: px.number().optional()
57532
- }));
57533
- var PxClipPathEffectSchema = implementsInterface()(px.object({
57534
- d: PxAnimatableStringSchema.optional(),
57535
- animate: PxPropertyAnimationSchema.optional()
57536
- }));
57537
- var PxTrimPathEffectSchema = implementsInterface()(px.object({
57538
- offset: PxAnimatableNumberSchema.optional(),
57539
- range: PxAnimatableVec2Schema.optional(),
57540
- subPaths: px.enum([PxTrimSubPaths.separate, PxTrimSubPaths.combined]).optional()
57541
- }));
57542
- var PxRetimeEffectSchema = implementsInterface()(px.object({
57543
- sourceId: px.string().optional(),
57544
- start: px.number().optional(),
57545
- stretch: px.number().optional(),
57546
- timeCrop: px.tuple([px.number(), px.number()]).optional()
57547
- }));
57548
- var PxCloneEffectSchema = implementsInterface()(px.object({
57549
- // Contextual kind — the `type` convention, see `PxNodeBase.type`.
57550
- type: px.enum([PxCloneType.content]).optional(),
57551
- sourceId: px.string().optional(),
57552
- retime: PxRetimeEffectSchema.optional()
57553
- }));
57554
- var PxGradientStopSchema = implementsInterface()(px.object({
57555
- offset: px.number(),
57556
- color: px.string()
57557
- }));
57558
- var PxAnimatableGradientStopsSchema = px.union([
57559
- px.array(PxGradientStopSchema),
57560
- px.object({ value: px.array(PxGradientStopSchema) }),
57561
- PxPropertyAnimationSchema
57562
- ]);
57563
- var PxFillGradientEffectSchema = implementsInterface()(px.object({
57564
- // Contextual kind — the `type` convention, see `PxNodeBase.type`.
57565
- type: px.enum([PxGradientType.linear, PxGradientType.radial]),
57566
- p1: PxAnimatableVec2Schema.optional(),
57567
- p2: PxAnimatableVec2Schema.optional(),
57568
- c: PxAnimatableVec2Schema.optional(),
57569
- r: PxAnimatableNumberSchema.optional(),
57570
- fp: PxAnimatableVec2Schema.optional(),
57571
- stops: PxAnimatableGradientStopsSchema.optional(),
57572
- gradientUnits: px.enum([PxGradientUnits.userSpaceOnUse, PxGradientUnits.objectBoundingBox]).optional(),
57573
- spreadMethod: px.enum([PxGradientSpreadMethod.pad, PxGradientSpreadMethod.reflect, PxGradientSpreadMethod.repeat]).optional(),
57574
- gradientTransform: px.string().optional()
57575
- }));
57576
- var PxStrokeGradientEffectSchema = PxFillGradientEffectSchema;
57577
- var PxTextPathEffectSchema = implementsInterface()(px.object({
57578
- path: px.string(),
57579
- pathOverflow: px.enum([PxPathOverflow.clip, PxPathOverflow.extend]).optional(),
57580
- lengthAdjust: px.enum([PxLengthAdjust.spacing, PxLengthAdjust.spacingAndGlyphs]).optional(),
57581
- method: px.enum([PxTextPathMethod.align, PxTextPathMethod.stretch]).optional(),
57582
- spacing: px.enum([PxTextPathSpacing.auto, PxTextPathSpacing.exact]).optional(),
57583
- startOffset: PxAnimatableNumberSchema.optional(),
57584
- textLength: PxAnimatableNumberSchema.optional()
57585
- }));
57586
- var PxTextEffectSchema = implementsInterface()(px.object({
57587
- useGlyphs: px.boolean().optional()
57588
- }));
57589
- var PxEffectsSchema = implementsInterface()(px.object({
57590
- transformBy: PxTransformByEffectSchema.optional(),
57591
- repeater: PxRepeaterEffectSchema.optional(),
57592
- maskedBy: PxMaskedByEffectSchema.optional(),
57593
- clipPath: PxClipPathEffectSchema.optional(),
57594
- trimPath: PxTrimPathEffectSchema.optional(),
57595
- clone: PxCloneEffectSchema.optional(),
57596
- fillGradient: PxFillGradientEffectSchema.optional(),
57597
- strokeGradient: PxStrokeGradientEffectSchema.optional(),
57598
- textPath: PxTextPathEffectSchema.optional(),
57599
- text: PxTextEffectSchema.optional()
57600
- }));
57601
- function validateNodeEffects(root, opts) {
57602
- const warnings = [];
57603
- const walk = (node, path) => {
57604
- if (node && node.effects) {
57605
- const ctx = { errors: [], warnings: [], strict: !!(opts == null ? void 0 : opts.strict) };
57606
- const ok = PxEffectsSchema.isValid(node.effects, ctx, [path + ".effects"]);
57607
- if (!ok) {
57608
- for (const err of ctx.errors) warnings.push(err);
57609
- }
57610
- }
57611
- if (node && Array.isArray(node.children)) {
57612
- node.children.forEach((c, i) => walk(c, path + ".children[" + i + "]"));
57613
- }
57614
- };
57615
- walk(root, "root");
57616
- return warnings;
57617
- }
57618
- var PxNodeBase = px.openObject({
57619
- // CONVENTION (SCHEMA-DESIGN R1 / issues N4): `type` is the ONE word for "what
57620
- // kind of thing is this", discriminated by its CARRIER — here the node TAG
57621
- // (`rect`, `text`), and inside a sub-object that object's kind (`clone.type`,
57622
- // `fillGradient.type`, editor `preset.type`). Each sits in its own object, so
57623
- // the carrier disambiguates completely; synonyms (`cloneKind`, `presetShape`)
57624
- // would add words that all mean "type" and still need the carrier to read.
57625
- // Guarding a `type` SLOT against a wrong VALUE is the job of strict enums
57626
- // (issues V3), never of distinct key names.
57627
- type: px.string(),
57628
- id: px.string().optional(),
57629
- meta: px.any().optional(),
57630
- // Player-effects bucket emitted by the Editor's lightweight design format.
57631
- // Consumed and removed by `applyPlayerEffects` before any other normalisation
57632
- // (see `createAnimatorImpl`), so downstream code never sees it.
57633
- effects: PxEffectsSchema.optional(),
57634
- // `PxElementAnimation` (not just `PxAnimationDefinition`) — accepts
57635
- // string ref / array of refs / inline definition / mixed array; mirrors
57636
- // `animator.animateById` map values and what `processNode` resolves at runtime.
57637
- animate: PxElementAnimationSchema.optional(),
57638
- style: px.union([px.string(), px.record(px.union([px.string(), px.number()]))]).optional()
57639
- }, PxAttrValueSchema);
57640
- var PxNodeSchema = px.openObject(__spreadProps2(__spreadValues2({}, PxNodeBase._shape), {
57641
- children: px.lazy(() => px.array(PxNodeSchema), []).optional()
57642
- }), PxAttrValueSchema);
57643
- var PxSvgNodeExtra = px.object({
57644
- width: px.number().optional(),
57645
- height: px.number().optional(),
57646
- viewBox: px.string().optional(),
57647
- animator: PxAnimatorConfigSchema.optional()
57648
- });
57649
- var PxAnimatedSvgDocumentSchema = px.openObject(__spreadProps2(__spreadValues2(__spreadValues2({}, PxNodeBase._shape), PxSvgNodeExtra._shape), {
57650
- type: px.literal("svg"),
57651
- // override string → literal to require 'svg'
57652
- children: px.array(PxNodeSchema).optional()
57653
- }), PxAttrValueSchema);
57654
- var PxBezierPathSchema = implementsInterface()(px.object({
57655
- v: px.array(px.array(px.number())),
57656
- i: px.array(px.array(px.number())).optional(),
57657
- o: px.array(px.array(px.number())).optional(),
57658
- c: px.boolean().optional()
57659
- }));
57660
- function bezierToSvgPath(path, forceCurves = false) {
57661
- var _a, _b, _c, _d;
57662
- const v = path.v;
57663
- const i = path.i;
57664
- const o = path.o;
57665
- const c = path.c;
57666
- if (!v.length) return "";
57667
- const d = [];
57668
- const len = v.length;
57669
- d.push("M" + v[0][0] + "," + v[0][1]);
57670
- for (let idx = 1; idx < len; idx++) {
57671
- const prevV = v[idx - 1];
57672
- const prevO = (_a = o == null ? void 0 : o[idx - 1]) != null ? _a : prevV;
57673
- const currI = (_b = i == null ? void 0 : i[idx]) != null ? _b : v[idx];
57674
- const currV = v[idx];
57675
- const isLine = !forceCurves && (prevO[0] === prevV[0] && prevO[1] === prevV[1]) && (currI[0] === currV[0] && currI[1] === currV[1]);
57676
- if (isLine) {
57677
- d.push("L" + currV[0] + "," + currV[1]);
57678
- } else {
57679
- d.push("C" + prevO[0] + "," + prevO[1] + "," + currI[0] + "," + currI[1] + "," + currV[0] + "," + currV[1]);
57680
- }
57681
- }
57682
- if (c && len > 0) {
57683
- const lastV = v[len - 1];
57684
- const lastO = (_c = o == null ? void 0 : o[len - 1]) != null ? _c : lastV;
57685
- const firstI = (_d = i == null ? void 0 : i[0]) != null ? _d : v[0];
57686
- const firstV = v[0];
57687
- const isLine = !forceCurves && (lastO[0] === lastV[0] && lastO[1] === lastV[1]) && (firstI[0] === firstV[0] && firstI[1] === firstV[1]);
57688
- if (!isLine) {
57689
- d.push("C" + lastO[0] + "," + lastO[1] + "," + firstI[0] + "," + firstI[1] + "," + firstV[0] + "," + firstV[1]);
57690
- }
57691
- d.push("z");
57692
- }
57693
- return d.join("");
57694
- }
57695
- function interpolateNum(a, b, t) {
57696
- return a + (b - a) * t;
57697
- }
57698
- function interpolateVec(a, b, t) {
57699
- const res = [];
57700
- const count = Math.max(a.length, b.length);
57701
- for (let i = 0; i < count; i++) {
57702
- res[i] = interpolateNum(a[i] || 0, b[i] || 0, t);
57703
- }
57704
- return res;
57705
- }
57706
- function interpolateColor(a, b, t) {
57707
- return [
57708
- interpolateNum(a[0] || 0, b[0] || 0, t),
57709
- interpolateNum(a[1] || 0, b[1] || 0, t),
57710
- interpolateNum(a[2] || 0, b[2] || 0, t),
57711
- interpolateNum(a[3] === void 0 ? 1 : a[3], b[3] === void 0 ? 1 : b[3], t)
57712
- ];
57713
- }
57714
- function interpolateBeziers(paths1, paths2, progress) {
57715
- const count = Math.max(paths1.length, paths2.length);
57716
- const res = [];
57717
- for (let i = 0; i < count; i++) {
57718
- res.push(interpolateBezier(paths1[i], paths2[i], progress));
57719
- }
57720
- return res;
57721
- }
57722
- function interpolateBezier(path1, path2, progress) {
57723
- var _a, _b, _c, _d, _e, _f, _g, _h, _i;
57724
- if (!path1 || !path2) return path1 || path2 || { v: [] };
57725
- const t = Math.min(Math.max(progress, 0), 1);
57726
- const len = Math.min(path1.v.length, path2.v.length);
57727
- const v = [];
57728
- const i = [];
57729
- const o = [];
57730
- for (let idx = 0; idx < len; idx++) {
57731
- const v1 = path1.v[idx];
57732
- const v2 = path2.v[idx];
57733
- v.push(interpolateVec(v1, v2, t));
57734
- const i1 = (_b = (_a = path1.i) == null ? void 0 : _a[idx]) != null ? _b : v1;
57735
- const i2 = (_d = (_c = path2.i) == null ? void 0 : _c[idx]) != null ? _d : v2;
57736
- i.push(interpolateVec(i1, i2, t));
57737
- const o1 = (_f = (_e = path1.o) == null ? void 0 : _e[idx]) != null ? _f : v1;
57738
- const o2 = (_h = (_g = path2.o) == null ? void 0 : _g[idx]) != null ? _h : v2;
57739
- o.push(interpolateVec(o1, o2, t));
57740
- }
57741
- return { v, i: i.length ? i : void 0, o: o.length ? o : void 0, c: (_i = path1.c) != null ? _i : path2.c };
57742
- }
57743
- function remap(value, inMin, inMax, outMin, outMax) {
57744
- if (inMax === inMin) return outMin;
57745
- const t = (value - inMin) / (inMax - inMin);
57746
- return outMin + t * (outMax - outMin);
57747
- }
57748
- function solveCubicBezierX(p1x, p2x, x) {
57749
- if (x <= 0) return 0;
57750
- if (x >= 1) return 1;
57751
- const cx = 3 * p1x;
57752
- const bx = 3 * (p2x - p1x) - cx;
57753
- const ax = 1 - cx - bx;
57754
- function sampleX(t) {
57755
- return ((ax * t + bx) * t + cx) * t;
57756
- }
57757
- function sampleDX(t) {
57758
- return (3 * ax * t + 2 * bx) * t + cx;
57759
- }
57760
- let t2 = x;
57761
- let t0 = 0;
57762
- let t1 = 1;
57763
- for (let i = 0; i < 8; i++) {
57764
- const x2 = sampleX(t2) - x;
57765
- if (Math.abs(x2) < 1e-6) return t2;
57766
- const d2 = sampleDX(t2);
57767
- if (Math.abs(d2) < 1e-6) break;
57768
- t2 -= x2 / d2;
57769
- }
57770
- t2 = x;
57771
- while (t0 < t1) {
57772
- const x2 = sampleX(t2);
57773
- if (Math.abs(x2 - x) < 1e-6) return t2;
57774
- if (x > x2) t0 = t2;
57775
- else t1 = t2;
57776
- t2 = (t1 + t0) / 2;
57777
- }
57778
- return t2;
57779
- }
57780
- function cubicBezier(easing) {
57781
- const [p1x, p1y, p2x, p2y] = easing;
57782
- const cy = 3 * p1y;
57783
- const by = 3 * (p2y - p1y) - cy;
57784
- const ay = 1 - cy - by;
57785
- function sampleCurveY(t) {
57786
- return ((ay * t + by) * t + cy) * t;
57787
- }
57788
- return function(x) {
57789
- return sampleCurveY(solveCubicBezierX(p1x, p2x, x));
57790
- };
57791
- }
57792
- function lerp2(a, b, t) {
57793
- return [a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t];
57794
- }
57795
- function subdivideCubicBezier(p0, p1, p2, p3, t) {
57796
- const q0 = lerp2(p0, p1, t);
57797
- const q1 = lerp2(p1, p2, t);
57798
- const q2 = lerp2(p2, p3, t);
57799
- const r0 = lerp2(q0, q1, t);
57800
- const r1 = lerp2(q1, q2, t);
57801
- const s = lerp2(r0, r1, t);
57802
- return {
57803
- left: [p0, q0, r0, s],
57804
- right: [s, r1, q2, p3]
57805
- };
57806
- }
57807
- function splitEasing(easing, xFraction) {
57808
- if (!easing) return { left: void 0, right: void 0 };
57809
- if (xFraction <= 0) return { left: void 0, right: easing };
57810
- if (xFraction >= 1) return { left: easing, right: void 0 };
57811
- const [x1, y1, x2, y2] = easing;
57812
- const t = solveCubicBezierX(x1, x2, xFraction);
57813
- const p0 = [0, 0];
57814
- const p1 = [x1, y1];
57815
- const p2 = [x2, y2];
57816
- const p3 = [1, 1];
57817
- const { left, right } = subdivideCubicBezier(p0, p1, p2, p3, t);
57818
- const sx = left[3][0];
57819
- const sy = left[3][1];
57820
- let leftEasing;
57821
- if (sx > 1e-9 && Math.abs(sy) > 1e-9) {
57822
- leftEasing = [
57823
- left[1][0] / sx,
57824
- left[1][1] / sy,
57825
- left[2][0] / sx,
57826
- left[2][1] / sy
57827
- ];
57828
- }
57829
- let rightEasing;
57830
- const rx = 1 - sx;
57831
- const ry = 1 - sy;
57832
- if (rx > 1e-9 && Math.abs(ry) > 1e-9) {
57833
- rightEasing = [
57834
- (right[1][0] - sx) / rx,
57835
- (right[1][1] - sy) / ry,
57836
- (right[2][0] - sx) / rx,
57837
- (right[2][1] - sy) / ry
57838
- ];
57839
- }
57840
- return { left: leftEasing, right: rightEasing };
57841
- }
57842
- function reverseEasing(easing) {
57843
- if (!easing) return void 0;
57844
- return [1 - easing[2], 1 - easing[3], 1 - easing[0], 1 - easing[1]];
57845
- }
57846
- function toRGBA(color) {
57847
- const r = Math.round(color[0] * 255);
57848
- const g = Math.round(color[1] * 255);
57849
- const b = Math.round(color[2] * 255);
57850
- return color.length === 4 ? "rgba(" + r + "," + g + "," + b + "," + color[3] + ")" : "rgb(" + r + "," + g + "," + b + ")";
57851
- }
57852
- function parseRgba(s) {
57853
- var _a;
57854
- const inner = (_a = s.match(/rgba?\((.*)\)/)) == null ? void 0 : _a[1];
57855
- if (!inner) throw new Error("Invalid rgb/rgba format");
57856
- const parts = inner.split(",").map((v) => +v.trim());
57857
- return [parts[0] / 255, parts[1] / 255, parts[2] / 255, ...parts[3] !== void 0 ? [parts[3]] : []];
57858
- }
57859
- function parseHex(s) {
57860
- const hex = s.slice(1);
57861
- const isShort = hex.length <= 4;
57862
- const r = isShort ? hex[0] + hex[0] : hex.slice(0, 2);
57863
- const g = isShort ? hex[1] + hex[1] : hex.slice(2, 4);
57864
- const b = isShort ? hex[2] + hex[2] : hex.slice(4, 6);
57865
- const a = hex.length === 4 ? hex[3] + hex[3] : hex.length === 8 ? hex.slice(6, 8) : null;
57866
- const result = [
57867
- parseInt(r, 16) / 255,
57868
- parseInt(g, 16) / 255,
57869
- parseInt(b, 16) / 255
57870
- ];
57871
- if (a !== null) {
57872
- result.push(parseInt(a, 16) / 255);
57873
- }
57874
- return result;
57875
- }
57876
- function parseColor(s) {
57877
- if (!s) return void 0;
57878
- if (Array.isArray(s)) return s;
57879
- if (typeof s !== "string") return void 0;
57880
- if (s.startsWith("#")) {
57881
- return parseHex(s);
57882
- } else if (s.startsWith("rgb")) {
57883
- return parseRgba(s);
57884
- } else {
57885
- console.warn("Unsupported color format: " + s);
57886
- }
57887
- return void 0;
57888
- }
57889
- var COLOUR_ATTR_NAMES = /* @__PURE__ */ new Set(["color", "fill", "flood-color", "lighting-color", "stop-color", "stroke"]);
57890
- var TRANSFORM_FN_NAMES = /* @__PURE__ */ new Set(["translate", "rotate", "scale", "skew"]);
57891
- var PCT_BASED_ATTR_NAMES = /* @__PURE__ */ new Set(["offset-distance", "offsetDistance"]);
57892
- function composeTransformParts(parts, opts) {
57893
- var _a;
57894
- if (!parts) return "";
57895
- const withUnits = (_a = opts == null ? void 0 : opts.withUnits) != null ? _a : true;
57896
- const segs = [];
57897
- const t = parts.translate;
57898
- const o = parts.origin;
57899
- const r = parts.rotate;
57900
- const k = parts.skew;
57901
- const s = parts.scale;
57902
- const tu = withUnits ? "px" : "";
57903
- const ru = withUnits ? "deg" : "";
57904
- if (t) segs.push("translate(" + t[0] + tu + "," + t[1] + tu + ")");
57905
- if (o) segs.push("translate(" + o[0] + tu + "," + o[1] + tu + ")");
57906
- if (r !== void 0 && r !== null) segs.push("rotate(" + r + ru + ")");
57907
- if (k !== void 0 && k !== null) segs.push("skewX(" + k + ru + ")");
57908
- if (s) segs.push("scale(" + s[0] + "," + s[1] + ")");
57909
- if (o) segs.push("translate(" + -o[0] + tu + "," + -o[1] + tu + ")");
57910
- return segs.join("");
57911
- }
57912
- var STYLE_ATTR_NAMES = /* @__PURE__ */ new Set(["offset-distance", "offsetDistance"]);
57913
- var DEFAULT_DURATION_MS = 1e3;
57914
- function kebabToCamelCaseWord(kebab) {
57915
- return kebab.includes("-") ? kebab.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase()) : kebab;
57916
- }
57917
- function isCamelCaseWord(word) {
57918
- return !word.includes("-") && /[a-z][A-Z]/.test(word);
57919
- }
57920
- var SVG_CAMEL_CASE_ATTRS = /* @__PURE__ */ new Set([
57921
- // Transform/positioning
57922
- "viewBox",
57923
- "preserveAspectRatio",
57924
- // Gradient
57925
- "gradientUnits",
57926
- "gradientTransform",
57927
- "spreadMethod",
57928
- // Pattern
57929
- "patternUnits",
57930
- "patternContentUnits",
57931
- "patternTransform",
57932
- // Clipping/masking
57933
- "clipPathUnits",
57934
- "maskUnits",
57935
- "maskContentUnits",
57936
- // Marker (SVG spec keeps these camelCase, like viewBox)
57937
- "markerUnits",
57938
- "markerWidth",
57939
- "markerHeight",
57940
- "refX",
57941
- "refY",
57942
- // Text
57943
- "textLength",
57944
- "lengthAdjust",
57945
- "startOffset",
57946
- // Filter
57947
- "filterUnits",
57948
- "primitiveUnits",
57949
- "tableValues",
57950
- // feFuncR/G/B/A transfer table (type="table")
57951
- "stdDeviation",
57952
- "baseFrequency",
57953
- "numOctaves",
57954
- "surfaceScale",
57955
- "diffuseConstant",
57956
- "specularConstant",
57957
- "specularExponent",
57958
- "kernelMatrix",
57959
- "kernelUnitLength",
57960
- "edgeMode",
57961
- "preserveAlpha",
57962
- "targetX",
57963
- "targetY"
57964
- // // Animation
57965
- // 'attributeName',
57966
- // 'attributeType',
57967
- // 'calcMode',
57968
- // 'keyTimes',
57969
- // 'keySplines',
57970
- // 'repeatCount',
57971
- // 'repeatDur'
57972
- ]);
57973
- function camelCaseToKebabWordIfNeeded(camel) {
57974
- return SVG_CAMEL_CASE_ATTRS.has(camel) ? camel : camel.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
57975
- }
57976
- function clamp(value, min, max) {
57977
- return Math.max(min, Math.min(value, max));
57978
- }
57979
- function bezier2D_pointAt(P0, P1, P2, P3, t) {
57980
- if (t <= 0) return [P0[0], P0[1]];
57981
- if (t >= 1) return [P3[0], P3[1]];
57982
- const u = 1 - t;
57983
- const u2 = u * u;
57984
- const u3 = u2 * u;
57985
- const t2 = t * t;
57986
- const t3 = t2 * t;
57987
- const w0 = u3;
57988
- const w1 = 3 * t * u2;
57989
- const w2 = 3 * t2 * u;
57990
- const w3 = t3;
57991
- return [
57992
- w0 * P0[0] + w1 * P1[0] + w2 * P2[0] + w3 * P3[0],
57993
- w0 * P0[1] + w1 * P1[1] + w2 * P2[1] + w3 * P3[1]
57994
- ];
57995
- }
57996
- var BEZIER_T_NUDGE = 1e-4;
57997
- function bezier2D_derivativeAt(P0, P1, P2, P3, t) {
57998
- const result = _bezier2D_derivativeAtRaw(P0, P1, P2, P3, t);
57999
- if (result[0] === 0 && result[1] === 0) {
58000
- const nudgedT = t < 0.5 ? t + BEZIER_T_NUDGE : t - BEZIER_T_NUDGE;
58001
- return _bezier2D_derivativeAtRaw(P0, P1, P2, P3, nudgedT);
58002
- }
58003
- return result;
58004
- }
58005
- function _bezier2D_derivativeAtRaw(P0, P1, P2, P3, t) {
58006
- const u = 1 - t;
58007
- const a = 3 * u * u;
58008
- const b = 6 * t * u;
58009
- const c = 3 * t * t;
58010
- return [
58011
- a * (P1[0] - P0[0]) + b * (P2[0] - P1[0]) + c * (P3[0] - P2[0]),
58012
- a * (P1[1] - P0[1]) + b * (P2[1] - P1[1]) + c * (P3[1] - P2[1])
58013
- ];
58014
- }
58015
- function bezier2D_arcLengthLUT(P0, P1, P2, P3, steps = 100) {
58016
- const n = steps + 1;
58017
- const ts = new Float64Array(n);
58018
- const ds = new Float64Array(n);
58019
- let prev = bezier2D_pointAt(P0, P1, P2, P3, 0);
58020
- ts[0] = 0;
58021
- ds[0] = 0;
58022
- let cum = 0;
58023
- for (let i = 1; i < n; i++) {
58024
- const t = i / steps;
58025
- const cur = bezier2D_pointAt(P0, P1, P2, P3, t);
58026
- const dx = cur[0] - prev[0];
58027
- const dy = cur[1] - prev[1];
58028
- cum += Math.sqrt(dx * dx + dy * dy);
58029
- ts[i] = t;
58030
- ds[i] = cum;
58031
- prev = cur;
58032
- }
58033
- return { ts, ds };
58034
- }
58035
- function bezier2D_tForDistance(lut, distance) {
58036
- const { ts, ds } = lut;
58037
- const last = ds.length - 1;
58038
- if (distance <= 0) return ts[0];
58039
- if (distance >= ds[last]) return ts[last];
58040
- let lo = 1;
58041
- let hi = last;
58042
- while (lo < hi) {
58043
- const mid = lo + hi >>> 1;
58044
- if (ds[mid] < distance) lo = mid + 1;
58045
- else hi = mid;
58046
- }
58047
- const dPrev = ds[hi - 1];
58048
- const dCur = ds[hi];
58049
- const span = dCur - dPrev;
58050
- const frac = span > 0 ? (distance - dPrev) / span : 0;
58051
- return ts[hi - 1] + frac * (ts[hi] - ts[hi - 1]);
58052
- }
58053
- function bezier2D_arcAtT(lut, t) {
58054
- const { ts, ds } = lut;
58055
- const last = ts.length - 1;
58056
- if (t <= ts[0]) return ds[0];
58057
- if (t >= ts[last]) return ds[last];
58058
- let lo = 1, hi = last;
58059
- while (lo < hi) {
58060
- const mid = lo + hi >>> 1;
58061
- if (ts[mid] < t) lo = mid + 1;
58062
- else hi = mid;
58063
- }
58064
- const tPrev = ts[hi - 1];
58065
- const span = ts[hi] - tPrev;
58066
- const frac = span > 0 ? (t - tPrev) / span : 0;
58067
- return ds[hi - 1] + frac * (ds[hi] - ds[hi - 1]);
58068
- }
58069
- function invertEasing(easing) {
58070
- if (!easing) return (y) => y;
58071
- const flipped = [easing[1], easing[0], easing[3], easing[2]];
58072
- return cubicBezier(flipped);
57974
+ PxTransformPartsSchema
57975
+ ]);
57976
+ var PxAnimatableNumberSchema = px.union([
57977
+ px.number(),
57978
+ px.object({ value: px.number() }),
57979
+ PxPropertyAnimationSchema
57980
+ ]);
57981
+ var PxAnimatableVec2Schema = px.union([
57982
+ px.tuple([px.number(), px.number()]),
57983
+ px.object({ value: px.tuple([px.number(), px.number()]) }),
57984
+ PxPropertyAnimationSchema
57985
+ ]);
57986
+ var PxAnimatableStringSchema = px.union([
57987
+ px.string(),
57988
+ px.object({ value: px.string() }),
57989
+ PxPropertyAnimationSchema
57990
+ ]);
57991
+ var PxTransformByEffectSchema = implementsInterface()(px.object({
57992
+ translate: PxAnimatableVec2Schema.optional(),
57993
+ rotate: PxAnimatableNumberSchema.optional(),
57994
+ scale: PxAnimatableVec2Schema.optional(),
57995
+ skew: PxAnimatableNumberSchema.optional(),
57996
+ origin: PxAnimatableVec2Schema.optional()
57997
+ }));
57998
+ var PxRepeaterEffectSchema = implementsInterface()(px.object({
57999
+ // STATIC config, not a channel (V2/SCHEMA-DESIGN R5): the copy COUNT is read
58000
+ // once at expansion time and never sampled — plain number, no `keyframes`.
58001
+ copies: px.number().optional(),
58002
+ translate: PxAnimatableVec2Schema.optional(),
58003
+ rotate: PxAnimatableNumberSchema.optional(),
58004
+ skew: PxAnimatableNumberSchema.optional(),
58005
+ scale: PxAnimatableVec2Schema.optional(),
58006
+ origin: PxAnimatableVec2Schema.optional()
58007
+ }));
58008
+ var PxMaskedByEffectSchema = implementsInterface()(px.object({
58009
+ sourceId: px.string().optional(),
58010
+ maskType: px.enum([PxMaskType.luminance, PxMaskType.alpha]).optional(),
58011
+ maskUnits: px.enum([PxUnits.userSpaceOnUse, PxUnits.objectBoundingBox]).optional(),
58012
+ maskContentUnits: px.enum([PxUnits.userSpaceOnUse, PxUnits.objectBoundingBox]).optional(),
58013
+ x: px.number().optional(),
58014
+ y: px.number().optional(),
58015
+ width: px.number().optional(),
58016
+ height: px.number().optional()
58017
+ }));
58018
+ var PxClipPathEffectSchema = implementsInterface()(px.object({
58019
+ d: PxAnimatableStringSchema.optional(),
58020
+ animate: PxPropertyAnimationSchema.optional()
58021
+ }));
58022
+ var PxTrimPathEffectSchema = implementsInterface()(px.object({
58023
+ offset: PxAnimatableNumberSchema.optional(),
58024
+ range: PxAnimatableVec2Schema.optional(),
58025
+ subPaths: px.enum([PxTrimSubPaths.separate, PxTrimSubPaths.combined]).optional()
58026
+ }));
58027
+ var PxRetimeEffectSchema = implementsInterface()(px.object({
58028
+ sourceId: px.string().optional(),
58029
+ start: px.number().optional(),
58030
+ stretch: px.number().optional(),
58031
+ timeCrop: px.tuple([px.number(), px.number()]).optional()
58032
+ }));
58033
+ var PxCloneEffectSchema = implementsInterface()(px.object({
58034
+ // Contextual kind — the `type` convention, see `PxNodeBase.type`.
58035
+ type: px.enum([PxCloneType.content]).optional(),
58036
+ sourceId: px.string().optional(),
58037
+ retime: PxRetimeEffectSchema.optional()
58038
+ }));
58039
+ var PxGradientStopSchema = implementsInterface()(px.object({
58040
+ offset: px.number(),
58041
+ color: px.string()
58042
+ }));
58043
+ var PxAnimatableGradientStopsSchema = px.union([
58044
+ px.array(PxGradientStopSchema),
58045
+ px.object({ value: px.array(PxGradientStopSchema) }),
58046
+ PxPropertyAnimationSchema
58047
+ ]);
58048
+ var PxFillGradientEffectSchema = implementsInterface()(px.object({
58049
+ // Contextual kind — the `type` convention, see `PxNodeBase.type`.
58050
+ type: px.enum([PxGradientType.linear, PxGradientType.radial]),
58051
+ p1: PxAnimatableVec2Schema.optional(),
58052
+ p2: PxAnimatableVec2Schema.optional(),
58053
+ c: PxAnimatableVec2Schema.optional(),
58054
+ r: PxAnimatableNumberSchema.optional(),
58055
+ fp: PxAnimatableVec2Schema.optional(),
58056
+ stops: PxAnimatableGradientStopsSchema.optional(),
58057
+ gradientUnits: px.enum([PxGradientUnits.userSpaceOnUse, PxGradientUnits.objectBoundingBox]).optional(),
58058
+ spreadMethod: px.enum([PxGradientSpreadMethod.pad, PxGradientSpreadMethod.reflect, PxGradientSpreadMethod.repeat]).optional(),
58059
+ gradientTransform: px.string().optional()
58060
+ }));
58061
+ var PxStrokeGradientEffectSchema = PxFillGradientEffectSchema;
58062
+ var PxTextPathEffectSchema = implementsInterface()(px.object({
58063
+ path: px.string(),
58064
+ pathOverflow: px.enum([PxPathOverflow.clip, PxPathOverflow.extend]).optional(),
58065
+ lengthAdjust: px.enum([PxLengthAdjust.spacing, PxLengthAdjust.spacingAndGlyphs]).optional(),
58066
+ method: px.enum([PxTextPathMethod.align, PxTextPathMethod.stretch]).optional(),
58067
+ spacing: px.enum([PxTextPathSpacing.auto, PxTextPathSpacing.exact]).optional(),
58068
+ startOffset: PxAnimatableNumberSchema.optional(),
58069
+ textLength: PxAnimatableNumberSchema.optional()
58070
+ }));
58071
+ var PxTextEffectSchema = implementsInterface()(px.object({
58072
+ useGlyphs: px.boolean().optional()
58073
+ }));
58074
+ var PxEffectsSchema = implementsInterface()(px.object({
58075
+ transformBy: PxTransformByEffectSchema.optional(),
58076
+ repeater: PxRepeaterEffectSchema.optional(),
58077
+ maskedBy: PxMaskedByEffectSchema.optional(),
58078
+ clipPath: PxClipPathEffectSchema.optional(),
58079
+ trimPath: PxTrimPathEffectSchema.optional(),
58080
+ clone: PxCloneEffectSchema.optional(),
58081
+ fillGradient: PxFillGradientEffectSchema.optional(),
58082
+ strokeGradient: PxStrokeGradientEffectSchema.optional(),
58083
+ textPath: PxTextPathEffectSchema.optional(),
58084
+ text: PxTextEffectSchema.optional()
58085
+ }));
58086
+ function validateNodeEffects(root, opts) {
58087
+ const warnings = [];
58088
+ const walk = (node, path) => {
58089
+ if (node && node.effects) {
58090
+ const ctx = { errors: [], warnings: [], strict: !!(opts == null ? void 0 : opts.strict) };
58091
+ const ok = PxEffectsSchema.isValid(node.effects, ctx, [path + ".effects"]);
58092
+ if (!ok) {
58093
+ for (const err of ctx.errors) warnings.push(err);
58094
+ }
58095
+ }
58096
+ if (node && Array.isArray(node.children)) {
58097
+ node.children.forEach((c, i) => walk(c, path + ".children[" + i + "]"));
58098
+ }
58099
+ };
58100
+ walk(root, "root");
58101
+ return warnings;
58073
58102
  }
58103
+ var PxNodeBase = px.openObject({
58104
+ // CONVENTION (SCHEMA-DESIGN R1 / issues N4): `type` is the ONE word for "what
58105
+ // kind of thing is this", discriminated by its CARRIER — here the node TAG
58106
+ // (`rect`, `text`), and inside a sub-object that object's kind (`clone.type`,
58107
+ // `fillGradient.type`, editor `preset.type`). Each sits in its own object, so
58108
+ // the carrier disambiguates completely; synonyms (`cloneKind`, `presetShape`)
58109
+ // would add words that all mean "type" and still need the carrier to read.
58110
+ // Guarding a `type` SLOT against a wrong VALUE is the job of strict enums
58111
+ // (issues V3), never of distinct key names.
58112
+ type: px.string(),
58113
+ id: px.string().optional(),
58114
+ meta: px.any().optional(),
58115
+ // Player-effects bucket emitted by the Editor's lightweight design format.
58116
+ // Consumed and removed by `applyPlayerEffects` before any other normalisation
58117
+ // (see `createAnimatorImpl`), so downstream code never sees it.
58118
+ effects: PxEffectsSchema.optional(),
58119
+ // `PxElementAnimation` (not just `PxAnimationDefinition`) — accepts
58120
+ // string ref / array of refs / inline definition / mixed array; mirrors
58121
+ // `animator.animateById` map values and what `processNode` resolves at runtime.
58122
+ animate: PxElementAnimationSchema.optional(),
58123
+ style: px.union([px.string(), px.record(px.union([px.string(), px.number()]))]).optional()
58124
+ }, PxAttrValueSchema);
58125
+ var PxNodeSchema = px.openObject(__spreadProps2(__spreadValues2({}, PxNodeBase._shape), {
58126
+ children: px.lazy(() => px.array(PxNodeSchema), []).optional()
58127
+ }), PxAttrValueSchema);
58128
+ var PxSvgNodeExtra = px.object({
58129
+ // `"100%"` and other SVG length strings are legal here — a number-only slot rejected
58130
+ // real documents (e.g. apple-store-look-14-main.json) at the root <svg>.
58131
+ width: px.union([px.number(), px.string()]).optional(),
58132
+ height: px.union([px.number(), px.string()]).optional(),
58133
+ viewBox: px.string().optional(),
58134
+ animator: PxAnimatorConfigSchema.optional()
58135
+ });
58136
+ var PxAnimatedSvgDocumentSchema = px.openObject(__spreadProps2(__spreadValues2(__spreadValues2({}, PxNodeBase._shape), PxSvgNodeExtra._shape), {
58137
+ type: px.literal("svg"),
58138
+ // override string → literal to require 'svg'
58139
+ children: px.array(PxNodeSchema).optional()
58140
+ }), PxAttrValueSchema);
58141
+ var PxBezierPathSchema = implementsInterface()(px.object({
58142
+ v: px.array(px.array(px.number())),
58143
+ i: px.array(px.array(px.number())).optional(),
58144
+ o: px.array(px.array(px.number())).optional(),
58145
+ c: px.boolean().optional()
58146
+ }));
58074
58147
  var _idCounter = 0;
58075
58148
  function generateUniqueId() {
58076
58149
  const timestamp = Date.now().toString(36);
@@ -58671,7 +58744,7 @@ ${codeFrame}` : message);
58671
58744
  if (newAnimate) cloned.animate = newAnimate;
58672
58745
  return cloned;
58673
58746
  }
58674
- var LOOP_JUMP_SHIFT_MS = 10;
58747
+ var LOOP_JUMP_SHIFT_MS = 1;
58675
58748
  function deepEqualValue(a, b) {
58676
58749
  if (a === b) return true;
58677
58750
  if (typeof a !== typeof b || a === null || b === null || typeof a !== "object") return false;
@@ -58920,6 +58993,8 @@ ${codeFrame}` : message);
58920
58993
  const looped = [];
58921
58994
  const separateBoundary = loop.extend !== PxLoopExtend.before;
58922
58995
  const originalTerminalKf = keyframes[keyframes.length - 1];
58996
+ let terminalEasingOverride;
58997
+ let hasTerminalEasingOverride = false;
58923
58998
  function appendRep(repStart, isReversed, partial) {
58924
58999
  var _a2;
58925
59000
  let entries;
@@ -58960,7 +59035,16 @@ ${codeFrame}` : message);
58960
59035
  const prevKf = looped.length > 0 ? looped[looped.length - 1] : originalTerminalKf;
58961
59036
  const isBoundary = separateBoundary && i === 0 && prevKf !== void 0 && Math.abs(((_a2 = prevKf.t) != null ? _a2 : 0) - (repStart + entry.relT * segDuration)) < 1e-9;
58962
59037
  if (isBoundary) {
58963
- if (deepEqualValue(prevKf.v, entry.v)) continue;
59038
+ if (deepEqualValue(prevKf.v, entry.v)) {
59039
+ if (looped.length > 0) {
59040
+ prevKf.e = entry.e;
59041
+ prevKf.tangentOut = entry.tangentOut;
59042
+ } else {
59043
+ terminalEasingOverride = entry.e;
59044
+ hasTerminalEasingOverride = true;
59045
+ }
59046
+ continue;
59047
+ }
58964
59048
  if (looped.length > 0) {
58965
59049
  delete prevKf.tangentIn;
58966
59050
  delete prevKf.tangentOut;
@@ -59041,6 +59125,11 @@ ${codeFrame}` : message);
59041
59125
  if (loop.extend === PxLoopExtend.before) {
59042
59126
  return [...looped, ...keyframes];
59043
59127
  } else {
59128
+ if (hasTerminalEasingOverride && keyframes.length > 0) {
59129
+ const head = keyframes.slice(0, -1);
59130
+ const tail = __spreadProps2(__spreadValues2({}, keyframes[keyframes.length - 1]), { e: terminalEasingOverride });
59131
+ return [...head, tail, ...looped];
59132
+ }
59044
59133
  return [...keyframes, ...looped];
59045
59134
  }
59046
59135
  }
@@ -59157,6 +59246,9 @@ ${codeFrame}` : message);
59157
59246
  function normalizeAnimationDefinition(animDef, duration, defs, engine = PxAnimatorEngine.waapi) {
59158
59247
  const normalized = {};
59159
59248
  for (const [propName, propAnim] of Object.entries(animDef)) {
59249
+ if (propName === "transform" && propAnim.alongPathMode === "offsetPath" && animDef["offsetDistance"] !== void 0) {
59250
+ continue;
59251
+ }
59160
59252
  const normalizedKfs = normalizeKeyframes(propName, propAnim, duration, defs);
59161
59253
  if (normalizedKfs.length > 0) {
59162
59254
  const out = { kfs: normalizedKfs };
@@ -61836,9 +61928,138 @@ ${codeFrame}` : message);
61836
61928
  applyAllRetimeEffects(node, ctx);
61837
61929
  return node;
61838
61930
  }
61931
+ var kfTime = (kf) => {
61932
+ var _a, _b;
61933
+ return (_b = (_a = kf.t) != null ? _a : kf.time) != null ? _b : 0;
61934
+ };
61935
+ var kfValue = (kf) => {
61936
+ var _a;
61937
+ return (_a = kf.v) != null ? _a : kf.value;
61938
+ };
61939
+ var kfEasing = (kf) => {
61940
+ var _a;
61941
+ return (_a = kf.e) != null ? _a : kf.easing;
61942
+ };
61943
+ var kfTangentIn = (kf) => {
61944
+ var _a;
61945
+ return (_a = kf.tangentIn) != null ? _a : kf.ti;
61946
+ };
61947
+ var kfTangentOut = (kf) => {
61948
+ var _a;
61949
+ return (_a = kf.tangentOut) != null ? _a : kf.to;
61950
+ };
61951
+ function cubicAt(p0, c1, c2, p1, t) {
61952
+ const u = 1 - t;
61953
+ const a = u * u * u, b = 3 * u * u * t, c = 3 * u * t * t, d = t * t * t;
61954
+ return [
61955
+ a * p0[0] + b * c1[0] + c * c2[0] + d * p1[0],
61956
+ a * p0[1] + b * c1[1] + c * c2[1] + d * p1[1]
61957
+ ];
61958
+ }
61959
+ function cubicLength(p0, c1, c2, p1, steps = 64) {
61960
+ let len = 0;
61961
+ let prev = p0;
61962
+ for (let i = 1; i <= steps; i++) {
61963
+ const pt = cubicAt(p0, c1, c2, p1, i / steps);
61964
+ len += Math.hypot(pt[0] - prev[0], pt[1] - prev[1]);
61965
+ prev = pt;
61966
+ }
61967
+ return len;
61968
+ }
61969
+ var fmt2 = (n) => {
61970
+ const r = Math.round(n * 1e4) / 1e4;
61971
+ return Object.is(r, -0) ? "0" : String(r);
61972
+ };
61973
+ function buildOffsetPath(propAnim) {
61974
+ var _a, _b, _c, _d;
61975
+ if (propAnim.alongPathMode !== "offsetPath") return void 0;
61976
+ const kfs = (_a = propAnim.keyframes) != null ? _a : propAnim.kfs;
61977
+ if (!kfs || kfs.length < 2) return void 0;
61978
+ const first = kfValue(kfs[0]);
61979
+ const anchor = (first == null ? void 0 : first.origin) && first.origin.length >= 2 ? [first.origin[0], first.origin[1]] : [0, 0];
61980
+ const points = [];
61981
+ for (const kf of kfs) {
61982
+ const v = kfValue(kf);
61983
+ const tr = v == null ? void 0 : v.translate;
61984
+ if (!tr || tr.length < 2) return void 0;
61985
+ const parts = Object.keys(v);
61986
+ if (parts.some((p) => p !== "translate" && p !== "origin")) return void 0;
61987
+ const o = (_b = v == null ? void 0 : v.origin) != null ? _b : [0, 0];
61988
+ if (o[0] !== anchor[0] || o[1] !== anchor[1]) return void 0;
61989
+ points.push([tr[0] + anchor[0], tr[1] + anchor[1]]);
61990
+ }
61991
+ if (!kfs.some((kf) => kfTangentIn(kf) || kfTangentOut(kf))) return void 0;
61992
+ let d = "M" + fmt2(points[0][0]) + "," + fmt2(points[0][1]);
61993
+ const segLens = [];
61994
+ for (let i = 0; i < points.length - 1; i++) {
61995
+ const p0 = points[i], p1 = points[i + 1];
61996
+ const to = (_c = kfTangentOut(kfs[i])) != null ? _c : [0, 0];
61997
+ const ti = (_d = kfTangentIn(kfs[i + 1])) != null ? _d : [0, 0];
61998
+ const c1 = [p0[0] + to[0], p0[1] + to[1]];
61999
+ const c2 = [p1[0] + ti[0], p1[1] + ti[1]];
62000
+ d += "C" + fmt2(c1[0]) + "," + fmt2(c1[1]) + "," + fmt2(c2[0]) + "," + fmt2(c2[1]) + "," + fmt2(p1[0]) + "," + fmt2(p1[1]);
62001
+ segLens.push(cubicLength(p0, c1, c2, p1));
62002
+ }
62003
+ const total = segLens.reduce((a, b) => a + b, 0);
62004
+ if (!(total > 0)) return void 0;
62005
+ const distanceKfs = [];
62006
+ let cum = 0;
62007
+ for (let i = 0; i < kfs.length; i++) {
62008
+ if (i > 0) cum += segLens[i - 1];
62009
+ const out = { t: kfTime(kfs[i]), v: cum / total };
62010
+ const e = kfEasing(kfs[i]);
62011
+ if (e !== void 0) out.e = e;
62012
+ distanceKfs.push(out);
62013
+ }
62014
+ return { pathStr: d, distanceKfs, autoOrient: !!propAnim.autoOrient, anchor };
62015
+ }
62016
+ function materialiseOffsetPathsInTree(root) {
62017
+ const walk = (node) => {
62018
+ var _a;
62019
+ let out = node;
62020
+ const anim = node.animate;
62021
+ const transform = anim == null ? void 0 : anim["transform"];
62022
+ if (transform) {
62023
+ const built = buildOffsetPath(transform);
62024
+ if (built) {
62025
+ const newAnimate = __spreadValues2({}, anim);
62026
+ delete newAnimate["transform"];
62027
+ const distance = { keyframes: built.distanceKfs };
62028
+ if (transform.loop !== void 0) distance.loop = transform.loop;
62029
+ newAnimate["offsetDistance"] = distance;
62030
+ const staticTr = node.transform;
62031
+ let newTransform = staticTr;
62032
+ if (staticTr && typeof staticTr === "object") {
62033
+ const t = __spreadValues2({}, staticTr);
62034
+ delete t["translate"];
62035
+ delete t["origin"];
62036
+ newTransform = Object.keys(t).length ? t : void 0;
62037
+ }
62038
+ out = __spreadProps2(__spreadValues2({}, node), {
62039
+ animate: newAnimate,
62040
+ style: __spreadProps2(__spreadValues2({}, node.style), {
62041
+ offsetPath: "path('" + built.pathStr + "')",
62042
+ offsetAnchor: fmt2(built.anchor[0]) + "px " + fmt2(built.anchor[1]) + "px",
62043
+ offsetRotate: built.autoOrient ? "auto" : "0deg",
62044
+ offsetDistance: "0%"
62045
+ })
62046
+ });
62047
+ if (newTransform !== void 0) out.transform = newTransform;
62048
+ else delete out.transform;
62049
+ }
62050
+ }
62051
+ if ((_a = out.children) == null ? void 0 : _a.length) {
62052
+ const children = out.children.map(walk);
62053
+ if (children.some((c, i) => c !== out.children[i])) out = __spreadProps2(__spreadValues2({}, out), { children });
62054
+ }
62055
+ return out;
62056
+ };
62057
+ return walk(root);
62058
+ }
61839
62059
  function materialiseAllInTree(doc, engine, opts) {
61840
62060
  var _a, _b;
61841
62061
  let root = applyPlayerEffects(doc).root;
62062
+ root = materialiseOffsetPathsInTree(root);
61842
62063
  const duration = (_b = (_a = getAnimatorConfig(root)) == null ? void 0 : _a.duration) != null ? _b : DEFAULT_DURATION_MS;
61843
62064
  root = materialiseInternalLoopsInTree(root, duration);
61844
62065
  if (engine === PxAnimatorEngine.waapi) {
@@ -62278,7 +62499,13 @@ ${codeFrame}` : message);
62278
62499
  const api = __spreadProps(__spreadValues({}, basicApi), {
62279
62500
  "getRootElement": () => rootElement || null
62280
62501
  });
62281
- if (config.trigger) setupAnimationTriggers(api, config.trigger);
62502
+ if (config.trigger) {
62503
+ if (isScrollTimeline(config)) {
62504
+ console.warn("scroll timeline: `animator.trigger` is ignored (triggers do not apply to scroll-driven playback)");
62505
+ } else {
62506
+ setupAnimationTriggers(api, config.trigger);
62507
+ }
62508
+ }
62282
62509
  return api;
62283
62510
  }
62284
62511
  function createDomAdapter(rootElement) {
@@ -62334,6 +62561,8 @@ ${codeFrame}` : message);
62334
62561
  } else if (propName === "d") {
62335
62562
  const paths = value && typeof value === "object" && Array.isArray(value.paths) ? value.paths : [];
62336
62563
  cssValue = 'path("' + paths.map((bz) => bezierToSvgPath(bz, true)).join("") + '")';
62564
+ } else if (PCT_BASED_ATTR_NAMES.has(propName) && typeof value === "number") {
62565
+ cssValue = value * 100 + "%";
62337
62566
  } else {
62338
62567
  cssValue = "" + value;
62339
62568
  }
@@ -62402,7 +62631,7 @@ ${codeFrame}` : message);
62402
62631
  }
62403
62632
  return result;
62404
62633
  }
62405
- function createWebApiAnimator(doc, callbacks, rootElement, forceEvenIfHasUnsupportedAttrs) {
62634
+ function createWebApiAnimator(doc, callbacks, rootElement, forceEvenIfHasUnsupportedAttrs, scrollTimeline) {
62406
62635
  var _a;
62407
62636
  const config = getAnimatorConfig(doc) || {};
62408
62637
  if (!rootElement) {
@@ -62461,7 +62690,12 @@ ${codeFrame}` : message);
62461
62690
  if (keyframes.length > 0) {
62462
62691
  try {
62463
62692
  const effect = new KeyframeEffect(element, keyframes, effectOptions);
62464
- const anim = new Animation(effect, document.timeline);
62693
+ const anim = new Animation(effect, scrollTimeline ? scrollTimeline.timeline : document.timeline);
62694
+ if (scrollTimeline) {
62695
+ const a = anim;
62696
+ if (scrollTimeline.rangeStart) a.rangeStart = scrollTimeline.rangeStart;
62697
+ if (scrollTimeline.rangeEnd) a.rangeEnd = scrollTimeline.rangeEnd;
62698
+ }
62465
62699
  if (callbacks == null ? void 0 : callbacks.onFinish) anim.onfinish = () => {
62466
62700
  var _a2;
62467
62701
  if (finishNotified) return;
@@ -62555,10 +62789,133 @@ ${codeFrame}` : message);
62555
62789
  }
62556
62790
  };
62557
62791
  if (config.trigger) {
62558
- setupAnimationTriggers(api, config.trigger);
62792
+ if (config.timelineSource === "scroll") {
62793
+ console.warn("scroll timeline: `animator.trigger` is ignored (triggers do not apply to scroll-driven playback)");
62794
+ } else {
62795
+ setupAnimationTriggers(api, config.trigger);
62796
+ }
62797
+ }
62798
+ if (scrollTimeline) {
62799
+ animations.forEach((a) => a.play());
62559
62800
  }
62560
62801
  return api;
62561
62802
  }
62803
+ function nativeRangeOffset(point, defaultFraction, view) {
62804
+ var _a, _b, _c;
62805
+ const fraction = typeof (point == null ? void 0 : point.fraction) === "number" ? point.fraction : defaultFraction;
62806
+ const pct = (_b = (_a = globalThis.CSS) == null ? void 0 : _a.percent) == null ? void 0 : _b.call(_a, fraction * 100);
62807
+ if (pct === void 0) return void 0;
62808
+ return view ? { rangeName: (_c = point == null ? void 0 : point.phase) != null ? _c : "cover", offset: pct } : { offset: pct };
62809
+ }
62810
+ function createNativeScrollTimeline(subject, config) {
62811
+ var _a, _b, _c, _d;
62812
+ if (!config || !isScrollTimeline(config)) return null;
62813
+ const scroll = config.scroll || {};
62814
+ const kind = (_a = scroll.kind) != null ? _a : "view";
62815
+ const g = globalThis;
62816
+ const view = kind === "view";
62817
+ const Ctor = view ? g.ViewTimeline : g.ScrollTimeline;
62818
+ if (typeof Ctor !== "function") return null;
62819
+ const axis = (_b = scroll.axis) != null ? _b : "block";
62820
+ let timeline;
62821
+ try {
62822
+ if (view) {
62823
+ timeline = new Ctor({ subject, axis });
62824
+ } else {
62825
+ const source = scroll.source === "root" ? documentScroller() : findNearestScroller(subject, "y") || findNearestScroller(subject, "x") || documentScroller();
62826
+ timeline = new Ctor({ source, axis });
62827
+ }
62828
+ } catch (e) {
62829
+ console.warn("scroll timeline: native timeline construction failed \u2014 falling back to the custom driver", e);
62830
+ return null;
62831
+ }
62832
+ return {
62833
+ timeline,
62834
+ rangeStart: nativeRangeOffset((_c = scroll.range) == null ? void 0 : _c.start, 0, view),
62835
+ rangeEnd: nativeRangeOffset((_d = scroll.range) == null ? void 0 : _d.end, 1, view)
62836
+ };
62837
+ }
62838
+ function findNearestScroller(el, axis) {
62839
+ for (let p = el.parentElement; p; p = p.parentElement) {
62840
+ const style = getComputedStyle(p);
62841
+ const overflow = axis === "y" ? style.overflowY : style.overflowX;
62842
+ if (overflow === "auto" || overflow === "scroll" || overflow === "hidden" || overflow === "overlay") {
62843
+ return p;
62844
+ }
62845
+ }
62846
+ return null;
62847
+ }
62848
+ function documentScroller() {
62849
+ return document.scrollingElement || document.documentElement;
62850
+ }
62851
+ function createScrollDriver(subject, config, onProgress) {
62852
+ var _a;
62853
+ if (!config || !isScrollTimeline(config)) return null;
62854
+ const scroll = config.scroll || {};
62855
+ const kind = (_a = scroll.kind) != null ? _a : "view";
62856
+ const nearest = findNearestScroller(subject, "y") || findNearestScroller(subject, "x");
62857
+ const scroller = kind === "scroll" && scroll.source === "root" ? documentScroller() : nearest || documentScroller();
62858
+ const isRootScroller = scroller === documentScroller();
62859
+ const axis = scrollResolveAxis(scroll.axis, getComputedStyle(scroller).writingMode);
62860
+ const compute = () => {
62861
+ if (kind === "scroll") {
62862
+ const offset = axis === "y" ? scroller.scrollTop : scroller.scrollLeft;
62863
+ const maxOffset = axis === "y" ? scroller.scrollHeight - scroller.clientHeight : scroller.scrollWidth - scroller.clientWidth;
62864
+ return scrollOffsetProgress(offset, maxOffset, scroll.range);
62865
+ }
62866
+ const subjectRect = subject.getBoundingClientRect();
62867
+ let portStart, portSize;
62868
+ if (isRootScroller) {
62869
+ portStart = 0;
62870
+ portSize = axis === "y" ? document.documentElement.clientHeight : document.documentElement.clientWidth;
62871
+ } else {
62872
+ const portRect = scroller.getBoundingClientRect();
62873
+ portStart = axis === "y" ? portRect.top : portRect.left;
62874
+ portSize = axis === "y" ? scroller.clientHeight : scroller.clientWidth;
62875
+ }
62876
+ const subjectStart = (axis === "y" ? subjectRect.top : subjectRect.left) - portStart;
62877
+ const subjectSize = axis === "y" ? subjectRect.height : subjectRect.width;
62878
+ return scrollViewProgress(subjectStart, subjectSize, portSize, scroll.range);
62879
+ };
62880
+ let rafId = null;
62881
+ let destroyed = false;
62882
+ const tick = () => {
62883
+ rafId = null;
62884
+ if (destroyed) return;
62885
+ onProgress(compute());
62886
+ };
62887
+ const schedule = () => {
62888
+ if (destroyed || rafId !== null) return;
62889
+ rafId = requestAnimationFrame(tick);
62890
+ };
62891
+ const scrollTarget = isRootScroller ? window : scroller;
62892
+ scrollTarget.addEventListener("scroll", schedule, { passive: true });
62893
+ window.addEventListener("resize", schedule, { passive: true });
62894
+ let resizeObserver;
62895
+ if (typeof ResizeObserver !== "undefined") {
62896
+ resizeObserver = new ResizeObserver(schedule);
62897
+ resizeObserver.observe(subject);
62898
+ if (!isRootScroller) resizeObserver.observe(scroller);
62899
+ }
62900
+ const driver = {
62901
+ destroy: () => {
62902
+ if (destroyed) return;
62903
+ destroyed = true;
62904
+ scrollTarget.removeEventListener("scroll", schedule);
62905
+ window.removeEventListener("resize", schedule);
62906
+ resizeObserver == null ? void 0 : resizeObserver.disconnect();
62907
+ if (rafId !== null) {
62908
+ cancelAnimationFrame(rafId);
62909
+ rafId = null;
62910
+ }
62911
+ },
62912
+ refresh: () => {
62913
+ if (!destroyed) onProgress(compute());
62914
+ }
62915
+ };
62916
+ driver.refresh();
62917
+ return driver;
62918
+ }
62562
62919
  function finaliseAnimator(animatorConfig, callbacks, make) {
62563
62920
  let apiRef;
62564
62921
  let effectiveCallbacks = callbacks;
@@ -62580,6 +62937,44 @@ ${codeFrame}` : message);
62580
62937
  }
62581
62938
  function bindWithEngineChoice(doc, adapter, callbacks, rootElement) {
62582
62939
  const animatorConfig = getAnimatorConfig(doc) || {};
62940
+ if (isScrollTimeline(animatorConfig)) {
62941
+ return finaliseAnimator(animatorConfig, callbacks, (cb) => {
62942
+ var _a, _b;
62943
+ if (animatorConfig.mode !== PxAnimatorMode.frames && ((_a = animatorConfig.scroll) == null ? void 0 : _a.driver) === "native" && rootElement) {
62944
+ const native = createNativeScrollTimeline(rootElement, animatorConfig);
62945
+ if (native) {
62946
+ const api2 = createWebApiAnimator(
62947
+ doc,
62948
+ cb,
62949
+ rootElement,
62950
+ animatorConfig.mode === PxAnimatorMode.waapi,
62951
+ native
62952
+ );
62953
+ if (api2) return api2;
62954
+ }
62955
+ }
62956
+ const api = (animatorConfig.mode !== PxAnimatorMode.frames ? createWebApiAnimator(doc, cb, rootElement, animatorConfig.mode === PxAnimatorMode.waapi) : null) || createFrameLoopAnimator(doc, adapter, cb, rootElement);
62957
+ const subject = ((_b = api.getRootElement) == null ? void 0 : _b.call(api)) || rootElement;
62958
+ if (subject) {
62959
+ const totalMs = scrollTotalDurationMs(animatorConfig);
62960
+ const driver = createScrollDriver(
62961
+ subject,
62962
+ animatorConfig,
62963
+ (progress) => api.setCurrentTime(progress * totalMs)
62964
+ );
62965
+ if (driver) {
62966
+ const destroy = api.destroy.bind(api);
62967
+ api.destroy = () => {
62968
+ driver.destroy();
62969
+ destroy();
62970
+ };
62971
+ }
62972
+ } else {
62973
+ console.warn("scroll timeline: no root element to observe \u2014 animation will stay at frame 0");
62974
+ }
62975
+ return api;
62976
+ });
62977
+ }
62583
62978
  return finaliseAnimator(animatorConfig, callbacks, (cb) => {
62584
62979
  if (animatorConfig.mode === PxAnimatorMode.frames) {
62585
62980
  return createFrameLoopAnimator(doc, adapter, cb, rootElement);