@pixodesk/svg-animator-web 1.0.19 → 1.0.20

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
@@ -984,6 +984,10 @@ var PxMaskedByEffectSchema = implementsInterface()(px.object({
984
984
  maskUnits: px.string().optional(),
985
985
  maskContentUnits: px.string().optional()
986
986
  }));
987
+ var PxClipPathEffectSchema = implementsInterface()(px.object({
988
+ d: px.string().optional(),
989
+ animate: PxPropertyAnimationSchema.optional()
990
+ }));
987
991
  var PxTrimPathEffectSchema = implementsInterface()(px.object({
988
992
  offset: PxAnimatableNumberSchema.optional(),
989
993
  range: PxAnimatableVec2Schema.optional(),
@@ -1051,6 +1055,7 @@ var PxEffectsSchema = implementsInterface()(px.object({
1051
1055
  transformation: PxTransformationEffectSchema.optional(),
1052
1056
  repeater: PxRepeaterEffectSchema.optional(),
1053
1057
  maskedBy: PxMaskedByEffectSchema.optional(),
1058
+ clipPath: PxClipPathEffectSchema.optional(),
1054
1059
  trimPath: PxTrimPathEffectSchema.optional(),
1055
1060
  clone: PxCloneEffectSchema.optional(),
1056
1061
  isCombinedShape: px.boolean().optional(),
@@ -1357,6 +1362,17 @@ function formatOffset(o) {
1357
1362
  return pct + "%";
1358
1363
  }
1359
1364
 
1365
+ // src/effects/clipPathEffect.ts
1366
+ function applyClipPathEffect(node, fx, ctx) {
1367
+ if (!fx || !fx.d && !fx.animate) return node;
1368
+ const clipId = genId(ctx, "clip");
1369
+ const pathChild = { type: "path", d: fx.d };
1370
+ if (fx.animate) pathChild.animate = { d: fx.animate };
1371
+ ctx.defs.push({ type: "clipPath", id: clipId, children: [pathChild] });
1372
+ node.clipPath = "url(#" + clipId + ")";
1373
+ return node;
1374
+ }
1375
+
1360
1376
  // src/effects/maskedByEffect.ts
1361
1377
  function applyMaskedByEffect(node, fx, transformation, ctx) {
1362
1378
  if (!fx) return node;
@@ -1799,6 +1815,9 @@ function synthesiseScale(raw, i) {
1799
1815
  var RETIME_MATERIALISATION_MODE_INLINE_G = false;
1800
1816
  function asRetime(r) {
1801
1817
  var _a, _b;
1818
+ if (r.timeCrop) {
1819
+ console.warn("retime: `timeCrop` is not supported yet and will be ignored");
1820
+ }
1802
1821
  return { start: (_a = r.start) != null ? _a : 0, stretch: (_b = r.stretch) != null ? _b : 1 };
1803
1822
  }
1804
1823
  function concatRetime(child, parent) {
@@ -2217,6 +2236,8 @@ var SVG_CAMEL_CASE_ATTRS = /* @__PURE__ */ new Set([
2217
2236
  // Filter
2218
2237
  "filterUnits",
2219
2238
  "primitiveUnits",
2239
+ "tableValues",
2240
+ // feFuncR/G/B/A transfer table (type="table")
2220
2241
  "stdDeviation",
2221
2242
  "baseFrequency",
2222
2243
  "numOctaves",
@@ -2475,6 +2496,9 @@ function createPathSampler(d) {
2475
2496
  totalLength,
2476
2497
  closed,
2477
2498
  sampleAtDistance(dist) {
2499
+ if (closed && totalLength > 0 && (dist < 0 || dist > totalLength)) {
2500
+ return sampleOn((dist % totalLength + totalLength) % totalLength);
2501
+ }
2478
2502
  if (!closed && (dist < 0 || dist > totalLength)) {
2479
2503
  const edge = dist < 0 ? 0 : totalLength;
2480
2504
  const p = sampleOn(edge);
@@ -2731,6 +2755,19 @@ function soleFontOf(glyphs) {
2731
2755
  const names = Object.keys(glyphs);
2732
2756
  return names.length === 1 ? glyphs[names[0]] : void 0;
2733
2757
  }
2758
+ var MISSING_GLYPH_ADVANCE_EM = 0.6;
2759
+ function missingGlyphBoxEm(advanceEm, ascentEm) {
2760
+ if (advanceEm <= 0 || ascentEm <= 0) return "";
2761
+ const inset = 0.08;
2762
+ const x0 = advanceEm * inset, x1 = advanceEm * (1 - inset);
2763
+ const y1 = -ascentEm * (1 - inset);
2764
+ const bw = x1 - x0, bh = -y1;
2765
+ const t = Math.max(1, Math.min(bw, bh) * 0.12);
2766
+ const outer = "M" + x0 + " 0L" + x1 + " 0L" + x1 + " " + y1 + "L" + x0 + " " + y1 + "Z";
2767
+ if (bw <= 2 * t || bh <= 2 * t) return outer;
2768
+ const ix0 = x0 + t, ix1 = x1 - t, iyb = -t, iyt = y1 + t;
2769
+ return outer + "M" + ix0 + " " + iyb + "L" + ix0 + " " + iyt + "L" + ix1 + " " + iyt + "L" + ix1 + " " + iyb + "Z";
2770
+ }
2734
2771
  function materialiseGlyphTextHorizontal(node, opts) {
2735
2772
  var _a, _b, _c, _d;
2736
2773
  const { glyphs, create = jsonElementFactory, warnings } = opts;
@@ -2740,15 +2777,26 @@ function materialiseGlyphTextHorizontal(node, opts) {
2740
2777
  const lines = [{ start: pen.x, end: pen.x }];
2741
2778
  let line = 0;
2742
2779
  const renderChars = (content, s) => {
2780
+ var _a2;
2743
2781
  const gf = glyphFontFor(s, glyphs, soleFont, warnings);
2744
- if (!gf) return;
2745
- const scale = s.fontSize / gf.unitsPerEm;
2782
+ const upm = (gf == null ? void 0 : gf.unitsPerEm) || 1e3;
2783
+ const scale = s.fontSize / upm;
2784
+ const ascentEm = (_a2 = gf == null ? void 0 : gf.ascent) != null ? _a2 : 0.9 * upm;
2746
2785
  const paint = paintOf(s);
2747
2786
  for (let i = 0; i < content.length; i++) {
2748
2787
  const ch = content.charAt(i);
2749
- const g = gf.glyphs[ch];
2750
- if (g && g.d) placements.push({ glyphD: g.d, m: [scale, 0, 0, scale, pen.x, pen.y], paint, line, x: pen.x, y: pen.y, scale });
2751
- pen.x += (g ? g.width : 0) * scale + s.letterSpacing + (ch === " " ? s.wordSpacing : 0);
2788
+ const g = gf == null ? void 0 : gf.glyphs[ch];
2789
+ if (g && g.d) {
2790
+ placements.push({ glyphD: g.d, m: [scale, 0, 0, scale, pen.x, pen.y], paint, line, x: pen.x, y: pen.y, scale });
2791
+ pen.x += g.width * scale;
2792
+ } else if (/\S/.test(ch)) {
2793
+ const advEm = g && g.width > 0 ? g.width : MISSING_GLYPH_ADVANCE_EM * upm;
2794
+ placements.push({ glyphD: missingGlyphBoxEm(advEm, ascentEm), m: [scale, 0, 0, scale, pen.x, pen.y], paint, line, x: pen.x, y: pen.y, scale });
2795
+ pen.x += advEm * scale;
2796
+ } else {
2797
+ pen.x += (g ? g.width : 0) * scale;
2798
+ }
2799
+ pen.x += s.letterSpacing + (ch === " " ? s.wordSpacing : 0);
2752
2800
  lines[line].end = pen.x;
2753
2801
  }
2754
2802
  };
@@ -2783,24 +2831,152 @@ function materialiseGlyphTextHorizontal(node, opts) {
2783
2831
  }
2784
2832
  return toGroup(node, buildPaths(placements, create, warnings), create);
2785
2833
  }
2834
+ function layoutGlyphTextChars(node, opts) {
2835
+ var _a, _b, _c, _d, _e;
2836
+ if ((_a = opts.alongPath) == null ? void 0 : _a.pathD) return layoutGlyphTextCharsAlongPath(node, opts.alongPath.pathD, opts);
2837
+ const { glyphs, warnings } = opts;
2838
+ const soleFont = soleFontOf(glyphs);
2839
+ const pen = { x: (_b = parseLen(node.x)) != null ? _b : 0, y: (_c = parseLen(node.y)) != null ? _c : 0 };
2840
+ const boxes = [];
2841
+ const lines = [{ start: pen.x, end: pen.x }];
2842
+ let line = 0;
2843
+ const renderChars = (content, s) => {
2844
+ var _a2;
2845
+ const gf = glyphFontFor(s, glyphs, soleFont, warnings);
2846
+ const upm = (gf == null ? void 0 : gf.unitsPerEm) || 1e3;
2847
+ const scale = s.fontSize / upm;
2848
+ const ascent = ((_a2 = gf == null ? void 0 : gf.ascent) != null ? _a2 : 0.9 * upm) * scale;
2849
+ for (let i = 0; i < content.length; i++) {
2850
+ const ch = content.charAt(i);
2851
+ const g = gf == null ? void 0 : gf.glyphs[ch];
2852
+ const advance = (g ? g.width : 0) * scale + s.letterSpacing + (ch === " " ? s.wordSpacing : 0);
2853
+ boxes.push({ x: pen.x, y: pen.y, width: advance, ascent, fontSize: s.fontSize, line });
2854
+ pen.x += advance;
2855
+ lines[line].end = pen.x;
2856
+ }
2857
+ };
2858
+ const walk = (el, parentStyle) => {
2859
+ var _a2, _b2, _c2, _d2;
2860
+ const s = resolveStyle(el, parentStyle);
2861
+ const x = parseLen(el.x);
2862
+ const y = parseLen(el.y);
2863
+ if (x !== void 0) {
2864
+ pen.x = x;
2865
+ line = lines.length;
2866
+ lines.push({ start: pen.x, end: pen.x });
2867
+ }
2868
+ if (y !== void 0) pen.y = y;
2869
+ pen.x += (_a2 = parseLen(el.dx)) != null ? _a2 : 0;
2870
+ pen.y += (_b2 = parseLen(el.dy)) != null ? _b2 : 0;
2871
+ const content = (_c2 = str(el[TEXT_ATTR])) != null ? _c2 : str(el[TEXT_CONTENT_ATTR]);
2872
+ if (content && !((_d2 = el.children) == null ? void 0 : _d2.length)) renderChars(content, s);
2873
+ if (el.children) for (const ch of el.children) walk(ch, s);
2874
+ };
2875
+ const rootStyle = rootStyleOf(node);
2876
+ if (node.children) for (const ch of node.children) walk(ch, rootStyle);
2877
+ const rootContent = (_d = str(node[TEXT_ATTR])) != null ? _d : str(node[TEXT_CONTENT_ATTR]);
2878
+ if (rootContent && !((_e = node.children) == null ? void 0 : _e.length)) renderChars(rootContent, rootStyle);
2879
+ const anchor = str(node.textAnchor);
2880
+ if (anchor === "middle" || anchor === "end") {
2881
+ for (const b of boxes) {
2882
+ const w = lines[b.line].end - lines[b.line].start;
2883
+ b.x += anchor === "middle" ? -w / 2 : -w;
2884
+ }
2885
+ }
2886
+ return boxes.map((_f) => {
2887
+ var _g = _f, { line: _l } = _g, b = __objRest(_g, ["line"]);
2888
+ return b;
2889
+ });
2890
+ }
2891
+ function layoutGlyphTextCharsAlongPath(node, pathD, opts) {
2892
+ var _a;
2893
+ const { glyphs, warnings, alongPath } = opts;
2894
+ const sampler = createPathSampler(pathD);
2895
+ if (!sampler) {
2896
+ warnings == null ? void 0 : warnings.push("textGlyphs: unparsable along-path geometry (caret)");
2897
+ return [];
2898
+ }
2899
+ const soleFont = soleFontOf(glyphs);
2900
+ const chars = [];
2901
+ let adv = 0;
2902
+ const walk = (el, parentStyle) => {
2903
+ var _a2, _b, _c;
2904
+ const s = resolveStyle(el, parentStyle);
2905
+ const content = (_a2 = str(el[TEXT_ATTR])) != null ? _a2 : str(el[TEXT_CONTENT_ATTR]);
2906
+ if (content && !((_b = el.children) == null ? void 0 : _b.length)) {
2907
+ const gf = glyphFontFor(s, glyphs, soleFont, warnings);
2908
+ const upm = (gf == null ? void 0 : gf.unitsPerEm) || 1e3;
2909
+ const scale = s.fontSize / upm;
2910
+ const ascent = ((_c = gf == null ? void 0 : gf.ascent) != null ? _c : 0.9 * upm) * scale;
2911
+ for (let i = 0; i < content.length; i++) {
2912
+ const ch = content.charAt(i);
2913
+ const g = gf == null ? void 0 : gf.glyphs[ch];
2914
+ const glyphW = (g ? g.width : 0) * scale;
2915
+ const advance = glyphW + s.letterSpacing + (ch === " " ? s.wordSpacing : 0);
2916
+ chars.push({ advStart: adv, advEnd: adv + advance, glyphW, ascent, fontSize: s.fontSize });
2917
+ adv += advance;
2918
+ }
2919
+ }
2920
+ if (el.children) for (const ch of el.children) walk(ch, s);
2921
+ };
2922
+ walk(node, rootStyleOf(node));
2923
+ const width = adv;
2924
+ const k = (alongPath == null ? void 0 : alongPath.textLength) && alongPath.textLength > 0 && width > 0 ? alongPath.textLength / width : 1;
2925
+ const so = readAnimatable(alongPath == null ? void 0 : alongPath.startOffset);
2926
+ const { along: alongOffset, perp } = alongPathNodeOffsets(node);
2927
+ const base = alongOffset + (so.kind === "animated" /* Animated */ ? Number((_a = so.keyframes[0]) == null ? void 0 : _a.value) || 0 : so.kind === "static" /* Static */ ? Number(so.value) || 0 : 0);
2928
+ const withPerp = (p) => ({
2929
+ x: p.x - perp * Math.sin(p.angle),
2930
+ y: p.y + perp * Math.cos(p.angle),
2931
+ angle: p.angle
2932
+ });
2933
+ return chars.map((c) => {
2934
+ const dStart = base + c.advStart * k;
2935
+ const dEnd = base + c.advEnd * k;
2936
+ const p0 = withPerp(sampler.sampleAtDistance(dStart));
2937
+ const p1 = withPerp(sampler.sampleAtDistance(dEnd));
2938
+ const glyphMid = sampler.sampleAtDistance(base + (c.advStart + c.glyphW / 2) * k);
2939
+ return {
2940
+ x: p0.x,
2941
+ y: p0.y,
2942
+ width: c.advEnd - c.advStart,
2943
+ ascent: c.ascent,
2944
+ fontSize: c.fontSize,
2945
+ endX: p1.x,
2946
+ endY: p1.y,
2947
+ rotation: glyphMid.angle * 180 / Math.PI
2948
+ };
2949
+ });
2950
+ }
2786
2951
  function collectAlongPathCells(node, glyphs, soleFont, warnings) {
2787
2952
  const cells = [];
2788
2953
  let adv = 0;
2789
2954
  const walk = (el, parentStyle) => {
2790
- var _a, _b;
2955
+ var _a, _b, _c;
2791
2956
  const s = resolveStyle(el, parentStyle);
2792
2957
  const content = (_a = str(el[TEXT_ATTR])) != null ? _a : str(el[TEXT_CONTENT_ATTR]);
2793
2958
  if (content && !((_b = el.children) == null ? void 0 : _b.length)) {
2794
2959
  const gf = glyphFontFor(s, glyphs, soleFont, warnings);
2795
2960
  if (gf) {
2796
2961
  const scale = s.fontSize / gf.unitsPerEm;
2962
+ const ascentEm = (_c = gf.ascent) != null ? _c : 0.9 * gf.unitsPerEm;
2797
2963
  const paint = paintOf(s);
2798
2964
  for (let i = 0; i < content.length; i++) {
2799
2965
  const ch = content.charAt(i);
2800
2966
  const g = gf.glyphs[ch];
2801
- const glyphAdv = (g ? g.width : 0) * scale;
2802
- if (g && g.d) cells.push({ glyphD: g.d, widthEm: g.width, scale, paint, midBase: adv + glyphAdv / 2 });
2803
- adv += glyphAdv + s.letterSpacing + (ch === " " ? s.wordSpacing : 0);
2967
+ if (g && g.d) {
2968
+ const glyphAdv = g.width * scale;
2969
+ cells.push({ glyphD: g.d, widthEm: g.width, scale, paint, midBase: adv + glyphAdv / 2 });
2970
+ adv += glyphAdv;
2971
+ } else if (/\S/.test(ch)) {
2972
+ const wEm = g && g.width > 0 ? g.width : MISSING_GLYPH_ADVANCE_EM * gf.unitsPerEm;
2973
+ const boxAdv = wEm * scale;
2974
+ cells.push({ glyphD: missingGlyphBoxEm(wEm, ascentEm), widthEm: wEm, scale, paint, midBase: adv + boxAdv / 2 });
2975
+ adv += boxAdv;
2976
+ } else {
2977
+ adv += (g ? g.width : 0) * scale;
2978
+ }
2979
+ adv += s.letterSpacing + (ch === " " ? s.wordSpacing : 0);
2804
2980
  }
2805
2981
  }
2806
2982
  }
@@ -2809,10 +2985,17 @@ function collectAlongPathCells(node, glyphs, soleFont, warnings) {
2809
2985
  walk(node, rootStyleOf(node));
2810
2986
  return { cells, width: adv };
2811
2987
  }
2812
- function alongAffine(sampler, dist, scale, widthEm) {
2988
+ function alongAffine(sampler, dist, scale, widthEm, perp = 0) {
2813
2989
  const { x, y, angle } = sampler.sampleAtDistance(dist);
2814
2990
  const cos = Math.cos(angle), sin = Math.sin(angle), hw = widthEm / 2;
2815
- return [scale * cos, scale * sin, -scale * sin, scale * cos, x - scale * cos * hw, y - scale * sin * hw];
2991
+ return [scale * cos, scale * sin, -scale * sin, scale * cos, x - scale * cos * hw - perp * sin, y - scale * sin * hw + perp * cos];
2992
+ }
2993
+ function alongPathNodeOffsets(node) {
2994
+ var _a, _b, _c;
2995
+ return {
2996
+ along: ((_a = parseLen(node.x)) != null ? _a : 0) + ((_b = parseLen(node.dx)) != null ? _b : 0),
2997
+ perp: (_c = parseLen(node.dy)) != null ? _c : 0
2998
+ };
2816
2999
  }
2817
3000
  function materialiseGlyphTextAlongPath(node, pathD, startOffset, opts, textLength, pathOverflow) {
2818
3001
  var _a;
@@ -2825,6 +3008,7 @@ function materialiseGlyphTextAlongPath(node, pathD, startOffset, opts, textLengt
2825
3008
  const soleFont = soleFontOf(glyphs);
2826
3009
  const { cells, width } = collectAlongPathCells(node, glyphs, soleFont, warnings);
2827
3010
  if (!cells.length) return toGroup(node, [], create);
3011
+ const { along: alongOffset, perp } = alongPathNodeOffsets(node);
2828
3012
  if (textLength && textLength > 0 && width > 0) {
2829
3013
  const k = textLength / width;
2830
3014
  for (const c of cells) c.midBase *= k;
@@ -2832,9 +3016,9 @@ function materialiseGlyphTextAlongPath(node, pathD, startOffset, opts, textLengt
2832
3016
  const isClip = pathOverflow === "clip" && !sampler.closed;
2833
3017
  const so = readAnimatable(startOffset);
2834
3018
  if (so.kind === "animated" /* Animated */ && so.keyframes.length >= 2) {
2835
- return toGroup(node, buildAnimatedAlongPath(cells, sampler, so.keyframes, so.loop, create, isClip), create);
3019
+ return toGroup(node, buildAnimatedAlongPath(cells, sampler, so.keyframes, so.loop, create, isClip, alongOffset, perp), create);
2836
3020
  }
2837
- const base = so.kind === "animated" /* Animated */ ? Number((_a = so.keyframes[0]) == null ? void 0 : _a.value) || 0 : so.kind === "static" /* Static */ ? Number(so.value) || 0 : 0;
3021
+ const base = alongOffset + (so.kind === "animated" /* Animated */ ? Number((_a = so.keyframes[0]) == null ? void 0 : _a.value) || 0 : so.kind === "static" /* Static */ ? Number(so.value) || 0 : 0);
2838
3022
  const placeCells = isClip ? cells.filter((c) => {
2839
3023
  const d = base + c.midBase;
2840
3024
  return d >= 0 && d <= sampler.totalLength;
@@ -2842,7 +3026,7 @@ function materialiseGlyphTextAlongPath(node, pathD, startOffset, opts, textLengt
2842
3026
  const placements = placeCells.map((c) => ({
2843
3027
  glyphD: c.glyphD,
2844
3028
  paint: c.paint,
2845
- m: alongAffine(sampler, base + c.midBase, c.scale, c.widthEm)
3029
+ m: alongAffine(sampler, base + c.midBase, c.scale, c.widthEm, perp)
2846
3030
  }));
2847
3031
  return toGroup(node, buildPaths(placements, create, warnings), create);
2848
3032
  }
@@ -2852,10 +3036,10 @@ function roundN(v, n) {
2852
3036
  const f = __pow(10, n);
2853
3037
  return Math.round(v * f) / f;
2854
3038
  }
2855
- function buildAnimatedAlongPath(cells, sampler, sokfs, loop, create, isClip) {
3039
+ function buildAnimatedAlongPath(cells, sampler, sokfs, loop, create, isClip, alongOffset = 0, perp = 0) {
2856
3040
  const step = Math.max(sampler.totalLength / ALONG_PATH_MAX_STEPS, 0.5);
2857
3041
  const timeOf = (kf) => Number(kf.time) || 0;
2858
- const offOf = (kf) => Number(kf.value) || 0;
3042
+ const offOf = (kf) => alongOffset + (Number(kf.value) || 0);
2859
3043
  const onPath = (dist) => dist >= 0 && dist <= sampler.totalLength;
2860
3044
  const out = [];
2861
3045
  for (const c of cells) {
@@ -2863,10 +3047,11 @@ function buildAnimatedAlongPath(cells, sampler, sokfs, loop, create, isClip) {
2863
3047
  const d = transformPathData(c.glyphD, centred);
2864
3048
  const sampleKf = (dist, time) => {
2865
3049
  const { x, y, angle } = sampler.sampleAtDistance(dist);
3050
+ const cos = Math.cos(angle), sin = Math.sin(angle);
2866
3051
  return {
2867
3052
  time,
2868
3053
  value: {
2869
- ["translate" /* Translate */]: [roundN(x, 3), roundN(y, 3)],
3054
+ ["translate" /* Translate */]: [roundN(x - perp * sin, 3), roundN(y + perp * cos, 3)],
2870
3055
  ["rotate" /* Rotate */]: roundN(angle * 180 / Math.PI, 3)
2871
3056
  }
2872
3057
  };
@@ -3136,9 +3321,18 @@ function buildOutKfValue(prevV, nextV, p, translate, rotateDegFromAutoOrient, au
3136
3321
  if (pv === void 0 && nv === void 0) continue;
3137
3322
  value[k] = interpolatePart(pv, nv, p);
3138
3323
  }
3139
- if (rotateDegFromAutoOrient !== void 0) value.rotate = rotateDegFromAutoOrient;
3324
+ if (rotateDegFromAutoOrient !== void 0) {
3325
+ value.rotate = rotateDegFromAutoOrient + explicitRotateAt(prevV, nextV, p);
3326
+ }
3140
3327
  return value;
3141
3328
  }
3329
+ function explicitRotateAt(prevV, nextV, p) {
3330
+ const pv = typeof (prevV == null ? void 0 : prevV.rotate) === "number" ? prevV.rotate : void 0;
3331
+ const nv = typeof (nextV == null ? void 0 : nextV.rotate) === "number" ? nextV.rotate : void 0;
3332
+ if (pv === void 0 && nv === void 0) return 0;
3333
+ const r = interpolatePart(pv, nv, p);
3334
+ return typeof r === "number" ? r : 0;
3335
+ }
3142
3336
  function derivAngleForFirstKf(kf0, kf1) {
3143
3337
  const p0 = getKfTranslate(kf0);
3144
3338
  const p1 = getKfTranslate(kf1);
@@ -3159,10 +3353,12 @@ function insertSharpCornerStepKfIfNeeded(out, prevKf, nextKf, prevPos, nextPos,
3159
3353
  const lastV = (_a = lastKf.v) != null ? _a : lastKf.value;
3160
3354
  const prevExit = lastV == null ? void 0 : lastV.rotate;
3161
3355
  if (typeof prevExit !== "number") return;
3356
+ const boundaryV = getKfValueParts(prevKf);
3357
+ const prevExitTangent = prevExit - explicitRotateAt(boundaryV, boundaryV, 0);
3162
3358
  const seg = getSegmentCache(prevKf, nextKf, prevPos, nextPos);
3163
3359
  const tanAtStart = bezier2D_derivativeAt(seg.P0, seg.P1, seg.P2, seg.P3, 0);
3164
3360
  const nextEntry = Math.atan2(tanAtStart[1], tanAtStart[0]) * 180 / Math.PI;
3165
- const delta = wrappedAngleDelta(nextEntry, prevExit);
3361
+ const delta = wrappedAngleDelta(nextEntry, prevExitTangent);
3166
3362
  if (Math.abs(delta) <= rotationTol) return;
3167
3363
  const dupValue = buildOutKfValue(
3168
3364
  getKfValueParts(prevKf),
@@ -4361,7 +4557,7 @@ function applyPlayerEffects_exceptRetime(node, ctx) {
4361
4557
  const originalId = typeof node.id === "string" ? node.id : void 0;
4362
4558
  const innerIdForContentRef = originalId ? ctx.contentRefInnerIds.get(originalId) : void 0;
4363
4559
  if (!fx && !innerIdForContentRef) return node;
4364
- const { transformation, repeater, maskedBy, trimPath, clone: cloneFx, fillGradient, strokeGradient, textPath, text } = fx != null ? fx : {};
4560
+ const { transformation, repeater, maskedBy, clipPath, trimPath, clone: cloneFx, fillGradient, strokeGradient, textPath, text } = fx != null ? fx : {};
4365
4561
  const isCombinedShape = fx == null ? void 0 : fx.isCombinedShape;
4366
4562
  if (fx) delete node.effects;
4367
4563
  let n = node;
@@ -4387,6 +4583,7 @@ function applyPlayerEffects_exceptRetime(node, ctx) {
4387
4583
  n = applyTrimPathEffect(n, trimPath, isCombinedShape, ctx);
4388
4584
  n = applyRepeaterEffect(n, repeater, ctx);
4389
4585
  n = applyMaskedByEffect(n, maskedBy, transformation, ctx);
4586
+ n = applyClipPathEffect(n, clipPath, ctx);
4390
4587
  if (innerIdForContentRef) {
4391
4588
  applyRefHref(n, cloneFx, ctx);
4392
4589
  n = splitForContentRef(n, transformation, originalId, innerIdForContentRef, ctx);
@@ -4715,6 +4912,8 @@ function getNormalizedProps(props) {
4715
4912
  function renderNode(node, defs) {
4716
4913
  if (!node) return null;
4717
4914
  const _a = node, { type, children, style } = _a, props = __objRest(_a, ["type", "children", "style"]);
4915
+ const feFuncType = props.funcType;
4916
+ if (feFuncType !== void 0) delete props.funcType;
4718
4917
  const nodeDefs = getDefs(node) || defs;
4719
4918
  const resolvedStyle = resolveStyle2(style, nodeDefs);
4720
4919
  let childElements;
@@ -4727,13 +4926,15 @@ function renderNode(node, defs) {
4727
4926
  }
4728
4927
  }
4729
4928
  }
4730
- return createElement(
4929
+ const element = createElement(
4731
4930
  type || "g",
4732
4931
  getNormalizedProps(props),
4733
4932
  resolvedStyle,
4734
4933
  childElements,
4735
4934
  props[TEXT_ATTR] || props[TEXT_CONTENT_ATTR]
4736
4935
  );
4936
+ if (element && feFuncType !== void 0) element.setAttribute("type", feFuncType);
4937
+ return element;
4737
4938
  }
4738
4939
 
4739
4940
  // src/PxAnimatorTriggers.ts
@@ -4744,7 +4945,12 @@ function setupAnimationTriggers(api, config) {
4744
4945
  console.warn("setupAnimationTriggers: No root element found for animation.");
4745
4946
  return api;
4746
4947
  }
4948
+ let reversed = false;
4747
4949
  const start = () => {
4950
+ if (reversed) {
4951
+ reversed = false;
4952
+ api.setPlaybackRate(1);
4953
+ }
4748
4954
  api.play();
4749
4955
  };
4750
4956
  const handleEndAction = () => {
@@ -4756,6 +4962,8 @@ function setupAnimationTriggers(api, config) {
4756
4962
  api.cancel();
4757
4963
  break;
4758
4964
  case "reverse":
4965
+ reversed = true;
4966
+ api.setPlaybackRate(-1);
4759
4967
  api.play();
4760
4968
  break;
4761
4969
  case "continue":
@@ -4818,6 +5026,7 @@ function getSelector(id) {
4818
5026
  return "#" + id;
4819
5027
  }
4820
5028
  function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
5029
+ var _a;
4821
5030
  const config = getAnimatorConfig(doc) || {};
4822
5031
  const bindings = getNormalisedBindings(doc, PxAnimatorEngine.frames);
4823
5032
  const _iterations = config.iterations;
@@ -4828,18 +5037,24 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
4828
5037
  const duration = +(config.duration || DEFAULT_DURATION_MS);
4829
5038
  const totalDuration = duration && iterations ? duration * (iterations === Infinity ? Infinity : iterations) : duration ? (iterations != null ? iterations : 1) * duration : 0;
4830
5039
  const direction = config.direction || "normal";
5040
+ const fill = (_a = config.fill) != null ? _a : "forwards";
5041
+ const fillsForwards = fill === "forwards" || fill === "both";
5042
+ const fillsBackwards = fill === "backwards" || fill === "both";
4831
5043
  let timerId = null;
4832
5044
  let playing = false;
4833
- let timeBeforeLastStartMs = config.delay || 0;
5045
+ let timeBeforeLastStartMs = -(config.delay || 0);
4834
5046
  let lastStartedTs = 0;
4835
5047
  let playbackRate = 1;
4836
5048
  let finishCalled = false;
4837
5049
  const frameRate = config.frameRate;
4838
5050
  const minFrameIntervalMs = frameRate && frameRate > 0 ? 1e3 / frameRate : 0;
4839
5051
  let lastRenderTs = 0;
4840
- const getAnimCurrentTime = () => {
5052
+ const getRawAnimTime = () => {
4841
5053
  const runningElapsed = lastStartedTs ? (Date.now() - lastStartedTs) * playbackRate : 0;
4842
- let time = timeBeforeLastStartMs + runningElapsed;
5054
+ return timeBeforeLastStartMs + runningElapsed;
5055
+ };
5056
+ const getAnimCurrentTime = () => {
5057
+ let time = getRawAnimTime();
4843
5058
  if (Number.isFinite(totalDuration) && time > totalDuration) time = totalDuration;
4844
5059
  if (time < 0) time = 0;
4845
5060
  return time;
@@ -4884,40 +5099,59 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
4884
5099
  }
4885
5100
  }
4886
5101
  const tick = () => {
4887
- var _a;
5102
+ var _a2, _b;
4888
5103
  if (!adapter.isConnected()) {
4889
5104
  pauseAnim();
4890
5105
  return;
4891
5106
  }
4892
5107
  const currentTime = getAnimCurrentTime();
4893
- if (minFrameIntervalMs > 0) {
4894
- const now = Date.now();
4895
- if (lastRenderTs && now - lastRenderTs < minFrameIntervalMs) {
4896
- return;
4897
- }
4898
- lastRenderTs = now;
4899
- }
4900
- if (duration <= 0) {
5108
+ const rawTime = getRawAnimTime();
5109
+ if (rawTime < 0 && playbackRate > 0) {
5110
+ if (fillsBackwards) renderFrame(0);
5111
+ return;
4901
5112
  }
4902
- if (totalDuration && Number.isFinite(totalDuration) && currentTime >= totalDuration) {
4903
- renderFrame(totalDuration);
5113
+ if (playbackRate < 0 && rawTime <= 0) {
5114
+ pauseAnim();
5115
+ renderFrame(0);
4904
5116
  if (!finishCalled) {
4905
5117
  finishCalled = true;
4906
- (_a = callbacks == null ? void 0 : callbacks.onFinish) == null ? void 0 : _a.call(callbacks);
5118
+ (_a2 = callbacks == null ? void 0 : callbacks.onFinish) == null ? void 0 : _a2.call(callbacks);
4907
5119
  }
5120
+ return;
5121
+ }
5122
+ if (playbackRate > 0 && totalDuration && Number.isFinite(totalDuration) && currentTime >= totalDuration) {
4908
5123
  pauseAnim();
5124
+ renderFrame(fillsForwards ? totalDuration : 0);
5125
+ if (!finishCalled) {
5126
+ finishCalled = true;
5127
+ (_b = callbacks == null ? void 0 : callbacks.onFinish) == null ? void 0 : _b.call(callbacks);
5128
+ }
4909
5129
  return;
4910
5130
  }
5131
+ if (minFrameIntervalMs > 0) {
5132
+ const now = Date.now();
5133
+ if (lastRenderTs && now - lastRenderTs < minFrameIntervalMs) {
5134
+ return;
5135
+ }
5136
+ lastRenderTs = now;
5137
+ }
4911
5138
  renderFrame(currentTime);
4912
5139
  };
4913
5140
  if (config.delay) {
4914
- renderFrame(getAnimCurrentTime());
5141
+ if (config.delay < 0) {
5142
+ renderFrame(getAnimCurrentTime());
5143
+ } else if (fillsBackwards) {
5144
+ renderFrame(0);
5145
+ }
4915
5146
  }
4916
5147
  const _isPlaying = () => {
4917
5148
  if (!playing) return false;
4918
5149
  if (!adapter.isConnected()) {
4919
5150
  return false;
4920
5151
  }
5152
+ if (playbackRate < 0) {
5153
+ return getRawAnimTime() > 0;
5154
+ }
4921
5155
  if (Number.isFinite(totalDuration) && getAnimCurrentTime() >= totalDuration) return false;
4922
5156
  return true;
4923
5157
  };
@@ -4937,37 +5171,53 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
4937
5171
  };
4938
5172
  const startAnim = () => {
4939
5173
  if (playing) return;
4940
- if (Number.isFinite(totalDuration) && timeBeforeLastStartMs >= totalDuration) {
4941
- timeBeforeLastStartMs = 0;
4942
- finishCalled = false;
5174
+ if (playbackRate >= 0) {
5175
+ if (Number.isFinite(totalDuration) && timeBeforeLastStartMs >= totalDuration) {
5176
+ timeBeforeLastStartMs = 0;
5177
+ }
5178
+ } else {
5179
+ if (timeBeforeLastStartMs <= 0) {
5180
+ if (!Number.isFinite(totalDuration)) {
5181
+ console.warn("play: cannot start reverse playback of an infinite animation from time 0");
5182
+ return;
5183
+ }
5184
+ timeBeforeLastStartMs = totalDuration;
5185
+ }
4943
5186
  }
5187
+ finishCalled = false;
4944
5188
  playing = true;
4945
5189
  lastStartedTs = Date.now();
4946
5190
  loopAnim(true);
4947
5191
  };
4948
5192
  const pauseAnim = () => {
4949
5193
  if (!playing) return;
4950
- timeBeforeLastStartMs = getAnimCurrentTime();
5194
+ let raw = getRawAnimTime();
5195
+ if (Number.isFinite(totalDuration) && raw > totalDuration) raw = totalDuration;
5196
+ timeBeforeLastStartMs = raw;
4951
5197
  lastStartedTs = 0;
4952
5198
  playing = false;
4953
5199
  if (timerId !== null) {
4954
5200
  cancelAnimationFrame(timerId);
4955
5201
  timerId = null;
4956
5202
  }
4957
- renderFrame(timeBeforeLastStartMs);
5203
+ if (raw >= 0) {
5204
+ renderFrame(raw);
5205
+ } else if (fillsBackwards) {
5206
+ renderFrame(0);
5207
+ }
4958
5208
  };
4959
5209
  const cancelAnim = () => {
4960
- var _a;
5210
+ var _a2;
4961
5211
  pauseAnim();
4962
5212
  timeBeforeLastStartMs = 0;
4963
5213
  lastStartedTs = 0;
4964
5214
  playing = false;
4965
5215
  finishCalled = false;
4966
5216
  renderFrame(timeBeforeLastStartMs);
4967
- (_a = callbacks == null ? void 0 : callbacks.onCancel) == null ? void 0 : _a.call(callbacks);
5217
+ (_a2 = callbacks == null ? void 0 : callbacks.onCancel) == null ? void 0 : _a2.call(callbacks);
4968
5218
  };
4969
5219
  const finishAnim = (callOnFinish = true) => {
4970
- var _a;
5220
+ var _a2;
4971
5221
  if (Number.isFinite(totalDuration)) {
4972
5222
  timeBeforeLastStartMs = totalDuration;
4973
5223
  } else {
@@ -4975,10 +5225,14 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
4975
5225
  }
4976
5226
  lastStartedTs = 0;
4977
5227
  playing = false;
4978
- renderFrame(timeBeforeLastStartMs);
5228
+ if (timerId !== null) {
5229
+ cancelAnimationFrame(timerId);
5230
+ timerId = null;
5231
+ }
5232
+ renderFrame(fillsForwards ? timeBeforeLastStartMs : 0);
4979
5233
  if (callOnFinish && !finishCalled) {
4980
5234
  finishCalled = true;
4981
- (_a = callbacks == null ? void 0 : callbacks.onFinish) == null ? void 0 : _a.call(callbacks);
5235
+ (_a2 = callbacks == null ? void 0 : callbacks.onFinish) == null ? void 0 : _a2.call(callbacks);
4982
5236
  }
4983
5237
  };
4984
5238
  const api = {
@@ -4988,14 +5242,14 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
4988
5242
  return _isPlaying();
4989
5243
  },
4990
5244
  "play": () => {
4991
- var _a;
5245
+ var _a2;
4992
5246
  startAnim();
4993
- (_a = callbacks == null ? void 0 : callbacks.onPlay) == null ? void 0 : _a.call(callbacks);
5247
+ (_a2 = callbacks == null ? void 0 : callbacks.onPlay) == null ? void 0 : _a2.call(callbacks);
4994
5248
  },
4995
5249
  "pause": () => {
4996
- var _a;
5250
+ var _a2;
4997
5251
  pauseAnim();
4998
- (_a = callbacks == null ? void 0 : callbacks.onPause) == null ? void 0 : _a.call(callbacks);
5252
+ (_a2 = callbacks == null ? void 0 : callbacks.onPause) == null ? void 0 : _a2.call(callbacks);
4999
5253
  },
5000
5254
  "cancel": () => {
5001
5255
  cancelAnim();
@@ -5008,7 +5262,9 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
5008
5262
  console.warn("setPlaybackRate: rate must be finite and non-zero");
5009
5263
  return;
5010
5264
  }
5011
- const current = getAnimCurrentTime();
5265
+ let current = getRawAnimTime();
5266
+ if (Number.isFinite(totalDuration) && current > totalDuration) current = totalDuration;
5267
+ if (rate < 0 !== playbackRate < 0) finishCalled = false;
5012
5268
  playbackRate = rate;
5013
5269
  timeBeforeLastStartMs = current;
5014
5270
  if (playing) lastStartedTs = Date.now();
@@ -5021,10 +5277,13 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
5021
5277
  if (Number.isFinite(totalDuration) && newTime > totalDuration) newTime = totalDuration;
5022
5278
  timeBeforeLastStartMs = newTime;
5023
5279
  if (playing) lastStartedTs = Date.now();
5280
+ if (!Number.isFinite(totalDuration) || newTime < totalDuration) finishCalled = false;
5024
5281
  renderFrame(getAnimCurrentTime());
5025
5282
  },
5026
5283
  "destroy": () => {
5284
+ var _a2;
5027
5285
  api.cancel();
5286
+ (_a2 = callbacks == null ? void 0 : callbacks.onRemove) == null ? void 0 : _a2.call(callbacks);
5028
5287
  }
5029
5288
  };
5030
5289
  return api;
@@ -5189,6 +5448,8 @@ function createWebApiAnimator(doc, callbacks, rootElement, forceEvenIfHasUnsuppo
5189
5448
  if (typeof _iterations === "number") iterations = _iterations;
5190
5449
  if (_iterations === "infinite") iterations = Infinity;
5191
5450
  const unsupportedSet = /* @__PURE__ */ new Set();
5451
+ let finishNotified = false;
5452
+ let removeCalled = false;
5192
5453
  if (!(bindings == null ? void 0 : bindings.length)) {
5193
5454
  console.warn("createWebApiAnimator: No animation bindings defined");
5194
5455
  }
@@ -5205,7 +5466,11 @@ function createWebApiAnimator(doc, callbacks, rootElement, forceEvenIfHasUnsuppo
5205
5466
  }
5206
5467
  const keyframesMap = convertToWebApiKeyframes(animDef, unsupportedSet, config);
5207
5468
  const positiveDelay = config.delay && config.delay > 0 ? config.delay : void 0;
5208
- const seekPosition = config.delay && config.delay < 0 && config.duration ? -config.delay % config.duration : void 0;
5469
+ let seekPosition;
5470
+ if (config.delay && config.delay < 0 && config.duration) {
5471
+ const rawSeek = -config.delay;
5472
+ seekPosition = iterations === Infinity ? rawSeek % config.duration : Math.min(rawSeek, config.duration * (iterations != null ? iterations : 1));
5473
+ }
5209
5474
  const effectOptions = {
5210
5475
  duration: config.duration,
5211
5476
  delay: positiveDelay,
@@ -5226,13 +5491,17 @@ function createWebApiAnimator(doc, callbacks, rootElement, forceEvenIfHasUnsuppo
5226
5491
  const anim = new Animation(effect, document.timeline);
5227
5492
  if (callbacks == null ? void 0 : callbacks.onFinish) anim.onfinish = () => {
5228
5493
  var _a2;
5229
- return (_a2 = callbacks.onFinish) == null ? void 0 : _a2.call(callbacks);
5494
+ if (finishNotified) return;
5495
+ finishNotified = true;
5496
+ (_a2 = callbacks.onFinish) == null ? void 0 : _a2.call(callbacks);
5230
5497
  };
5231
5498
  if (callbacks == null ? void 0 : callbacks.onRemove) anim.onremove = () => {
5232
5499
  var _a2;
5233
- return (_a2 = callbacks.onRemove) == null ? void 0 : _a2.call(callbacks);
5500
+ if (removeCalled) return;
5501
+ removeCalled = true;
5502
+ (_a2 = callbacks.onRemove) == null ? void 0 : _a2.call(callbacks);
5234
5503
  };
5235
- if (seekPosition) {
5504
+ if (seekPosition !== void 0) {
5236
5505
  anim.currentTime = seekPosition;
5237
5506
  }
5238
5507
  animations.push(anim);
@@ -5256,6 +5525,7 @@ function createWebApiAnimator(doc, callbacks, rootElement, forceEvenIfHasUnsuppo
5256
5525
  },
5257
5526
  "play": () => {
5258
5527
  var _a2;
5528
+ finishNotified = false;
5259
5529
  animations.forEach((a) => a.play());
5260
5530
  (_a2 = callbacks == null ? void 0 : callbacks.onPlay) == null ? void 0 : _a2.call(callbacks);
5261
5531
  },
@@ -5266,6 +5536,7 @@ function createWebApiAnimator(doc, callbacks, rootElement, forceEvenIfHasUnsuppo
5266
5536
  },
5267
5537
  "cancel": () => {
5268
5538
  var _a2;
5539
+ finishNotified = false;
5269
5540
  animations.forEach((a) => a.cancel());
5270
5541
  (_a2 = callbacks == null ? void 0 : callbacks.onCancel) == null ? void 0 : _a2.call(callbacks);
5271
5542
  },
@@ -5295,13 +5566,19 @@ function createWebApiAnimator(doc, callbacks, rootElement, forceEvenIfHasUnsuppo
5295
5566
  return res !== null ? +res : null;
5296
5567
  },
5297
5568
  "setCurrentTime": (time) => {
5569
+ finishNotified = false;
5298
5570
  animations.forEach((a) => {
5299
5571
  a.currentTime = time;
5300
5572
  });
5301
5573
  },
5302
5574
  "destroy": () => {
5575
+ var _a2;
5303
5576
  api.cancel();
5304
5577
  animations.splice(0, animations.length);
5578
+ if (!removeCalled) {
5579
+ removeCalled = true;
5580
+ (_a2 = callbacks == null ? void 0 : callbacks.onRemove) == null ? void 0 : _a2.call(callbacks);
5581
+ }
5305
5582
  }
5306
5583
  };
5307
5584
  if (config.trigger) {
@@ -5445,7 +5722,6 @@ function createAnimatorImpl(doc, adapter, callbacks, containerElement) {
5445
5722
  const effectsWarnings = validateNodeEffects(doc);
5446
5723
  for (const w of effectsWarnings) console.warn("[PxAnimator] effects shape warning:", w);
5447
5724
  const animatorConfig = getAnimatorConfig(doc) || {};
5448
- animatorConfig.debug = true;
5449
5725
  const engine = animatorConfig.mode === PxAnimatorMode.frames ? PxAnimatorEngine.frames : PxAnimatorEngine.webapi;
5450
5726
  doc = materialiseAllInTree(doc, engine);
5451
5727
  let rootElement = null;
@@ -5474,37 +5750,55 @@ function createAnimator(options) {
5474
5750
  return createAnimatorImpl(data, adapter, callbacks, container);
5475
5751
  }
5476
5752
  let animator = null;
5753
+ let pending = [];
5754
+ let destroyed = false;
5755
+ const enqueue = (call) => {
5756
+ if (animator) {
5757
+ call(animator);
5758
+ } else if (pending) {
5759
+ pending.push(call);
5760
+ }
5761
+ };
5477
5762
  fetch(src).then((res) => res.json()).then((json) => {
5763
+ if (destroyed) return;
5478
5764
  if (isPxElementFileFormat(json)) {
5479
5765
  animator = createAnimatorImpl(json, adapter, callbacks, container);
5766
+ const queued = pending;
5767
+ pending = null;
5768
+ queued == null ? void 0 : queued.forEach((call) => call(animator));
5480
5769
  } else {
5481
- console.error("Invalid animation document format");
5770
+ console.error('createAnimator: invalid animation document format at "' + src + '"');
5482
5771
  }
5772
+ }).catch((err) => {
5773
+ pending = null;
5774
+ console.error('createAnimator: failed to load "' + src + '"', err);
5483
5775
  });
5484
5776
  return {
5485
5777
  "isReady": () => !!animator,
5486
5778
  "getRootElement": () => animator ? animator.getRootElement() : null,
5487
5779
  "isPlaying": () => (animator == null ? void 0 : animator.isPlaying()) || false,
5488
5780
  "play": () => {
5489
- animator == null ? void 0 : animator.play();
5781
+ enqueue((api) => api.play());
5490
5782
  },
5491
5783
  "pause": () => {
5492
- animator == null ? void 0 : animator.pause();
5784
+ enqueue((api) => api.pause());
5493
5785
  },
5494
5786
  "cancel": () => {
5495
- animator == null ? void 0 : animator.cancel();
5787
+ enqueue((api) => api.cancel());
5496
5788
  },
5497
5789
  "finish": () => {
5498
- animator == null ? void 0 : animator.finish();
5790
+ enqueue((api) => api.finish());
5499
5791
  },
5500
5792
  "setPlaybackRate": (rate) => {
5501
- animator == null ? void 0 : animator.setPlaybackRate(rate);
5793
+ enqueue((api) => api.setPlaybackRate(rate));
5502
5794
  },
5503
- "getCurrentTime": () => (animator == null ? void 0 : animator.getCurrentTime()) || 0,
5795
+ "getCurrentTime": () => animator ? animator.getCurrentTime() : null,
5504
5796
  "setCurrentTime": (time) => {
5505
- animator == null ? void 0 : animator.setCurrentTime(time);
5797
+ enqueue((api) => api.setCurrentTime(time));
5506
5798
  },
5507
5799
  "destroy": () => {
5800
+ destroyed = true;
5801
+ pending = null;
5508
5802
  animator == null ? void 0 : animator.destroy();
5509
5803
  }
5510
5804
  };
@@ -5785,6 +6079,7 @@ export {
5785
6079
  createAnimatorImpl,
5786
6080
  createBasicFrameLoopAnimator,
5787
6081
  createFrameLoopAnimator,
6082
+ createPathSampler,
5788
6083
  createWebApiAnimator,
5789
6084
  describeSchema,
5790
6085
  diffInEffect,
@@ -5799,6 +6094,7 @@ export {
5799
6094
  isPxElementFileFormat,
5800
6095
  isPxElementFileFormatDeep,
5801
6096
  jsonElementFactory,
6097
+ layoutGlyphTextChars,
5802
6098
  loadTagAnimators,
5803
6099
  materialiseAllInTree,
5804
6100
  materialiseAnimatedUseInstances,