@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.cjs CHANGED
@@ -100,6 +100,7 @@ __export(index_exports, {
100
100
  createAnimatorImpl: () => createAnimatorImpl,
101
101
  createBasicFrameLoopAnimator: () => createBasicFrameLoopAnimator,
102
102
  createFrameLoopAnimator: () => createFrameLoopAnimator,
103
+ createPathSampler: () => createPathSampler,
103
104
  createWebApiAnimator: () => createWebApiAnimator,
104
105
  describeSchema: () => describeSchema,
105
106
  diffInEffect: () => diffInEffect,
@@ -114,6 +115,7 @@ __export(index_exports, {
114
115
  isPxElementFileFormat: () => isPxElementFileFormat,
115
116
  isPxElementFileFormatDeep: () => isPxElementFileFormatDeep,
116
117
  jsonElementFactory: () => jsonElementFactory,
118
+ layoutGlyphTextChars: () => layoutGlyphTextChars,
117
119
  loadTagAnimators: () => loadTagAnimators,
118
120
  materialiseAllInTree: () => materialiseAllInTree,
119
121
  materialiseAnimatedUseInstances: () => materialiseAnimatedUseInstances,
@@ -1090,6 +1092,10 @@ var PxMaskedByEffectSchema = implementsInterface()(px.object({
1090
1092
  maskUnits: px.string().optional(),
1091
1093
  maskContentUnits: px.string().optional()
1092
1094
  }));
1095
+ var PxClipPathEffectSchema = implementsInterface()(px.object({
1096
+ d: px.string().optional(),
1097
+ animate: PxPropertyAnimationSchema.optional()
1098
+ }));
1093
1099
  var PxTrimPathEffectSchema = implementsInterface()(px.object({
1094
1100
  offset: PxAnimatableNumberSchema.optional(),
1095
1101
  range: PxAnimatableVec2Schema.optional(),
@@ -1157,6 +1163,7 @@ var PxEffectsSchema = implementsInterface()(px.object({
1157
1163
  transformation: PxTransformationEffectSchema.optional(),
1158
1164
  repeater: PxRepeaterEffectSchema.optional(),
1159
1165
  maskedBy: PxMaskedByEffectSchema.optional(),
1166
+ clipPath: PxClipPathEffectSchema.optional(),
1160
1167
  trimPath: PxTrimPathEffectSchema.optional(),
1161
1168
  clone: PxCloneEffectSchema.optional(),
1162
1169
  isCombinedShape: px.boolean().optional(),
@@ -1463,6 +1470,17 @@ function formatOffset(o) {
1463
1470
  return pct + "%";
1464
1471
  }
1465
1472
 
1473
+ // src/effects/clipPathEffect.ts
1474
+ function applyClipPathEffect(node, fx, ctx) {
1475
+ if (!fx || !fx.d && !fx.animate) return node;
1476
+ const clipId = genId(ctx, "clip");
1477
+ const pathChild = { type: "path", d: fx.d };
1478
+ if (fx.animate) pathChild.animate = { d: fx.animate };
1479
+ ctx.defs.push({ type: "clipPath", id: clipId, children: [pathChild] });
1480
+ node.clipPath = "url(#" + clipId + ")";
1481
+ return node;
1482
+ }
1483
+
1466
1484
  // src/effects/maskedByEffect.ts
1467
1485
  function applyMaskedByEffect(node, fx, transformation, ctx) {
1468
1486
  if (!fx) return node;
@@ -1905,6 +1923,9 @@ function synthesiseScale(raw, i) {
1905
1923
  var RETIME_MATERIALISATION_MODE_INLINE_G = false;
1906
1924
  function asRetime(r) {
1907
1925
  var _a, _b;
1926
+ if (r.timeCrop) {
1927
+ console.warn("retime: `timeCrop` is not supported yet and will be ignored");
1928
+ }
1908
1929
  return { start: (_a = r.start) != null ? _a : 0, stretch: (_b = r.stretch) != null ? _b : 1 };
1909
1930
  }
1910
1931
  function concatRetime(child, parent) {
@@ -2323,6 +2344,8 @@ var SVG_CAMEL_CASE_ATTRS = /* @__PURE__ */ new Set([
2323
2344
  // Filter
2324
2345
  "filterUnits",
2325
2346
  "primitiveUnits",
2347
+ "tableValues",
2348
+ // feFuncR/G/B/A transfer table (type="table")
2326
2349
  "stdDeviation",
2327
2350
  "baseFrequency",
2328
2351
  "numOctaves",
@@ -2581,6 +2604,9 @@ function createPathSampler(d) {
2581
2604
  totalLength,
2582
2605
  closed,
2583
2606
  sampleAtDistance(dist) {
2607
+ if (closed && totalLength > 0 && (dist < 0 || dist > totalLength)) {
2608
+ return sampleOn((dist % totalLength + totalLength) % totalLength);
2609
+ }
2584
2610
  if (!closed && (dist < 0 || dist > totalLength)) {
2585
2611
  const edge = dist < 0 ? 0 : totalLength;
2586
2612
  const p = sampleOn(edge);
@@ -2837,6 +2863,19 @@ function soleFontOf(glyphs) {
2837
2863
  const names = Object.keys(glyphs);
2838
2864
  return names.length === 1 ? glyphs[names[0]] : void 0;
2839
2865
  }
2866
+ var MISSING_GLYPH_ADVANCE_EM = 0.6;
2867
+ function missingGlyphBoxEm(advanceEm, ascentEm) {
2868
+ if (advanceEm <= 0 || ascentEm <= 0) return "";
2869
+ const inset = 0.08;
2870
+ const x0 = advanceEm * inset, x1 = advanceEm * (1 - inset);
2871
+ const y1 = -ascentEm * (1 - inset);
2872
+ const bw = x1 - x0, bh = -y1;
2873
+ const t = Math.max(1, Math.min(bw, bh) * 0.12);
2874
+ const outer = "M" + x0 + " 0L" + x1 + " 0L" + x1 + " " + y1 + "L" + x0 + " " + y1 + "Z";
2875
+ if (bw <= 2 * t || bh <= 2 * t) return outer;
2876
+ const ix0 = x0 + t, ix1 = x1 - t, iyb = -t, iyt = y1 + t;
2877
+ return outer + "M" + ix0 + " " + iyb + "L" + ix0 + " " + iyt + "L" + ix1 + " " + iyt + "L" + ix1 + " " + iyb + "Z";
2878
+ }
2840
2879
  function materialiseGlyphTextHorizontal(node, opts) {
2841
2880
  var _a, _b, _c, _d;
2842
2881
  const { glyphs, create = jsonElementFactory, warnings } = opts;
@@ -2846,15 +2885,26 @@ function materialiseGlyphTextHorizontal(node, opts) {
2846
2885
  const lines = [{ start: pen.x, end: pen.x }];
2847
2886
  let line = 0;
2848
2887
  const renderChars = (content, s) => {
2888
+ var _a2;
2849
2889
  const gf = glyphFontFor(s, glyphs, soleFont, warnings);
2850
- if (!gf) return;
2851
- const scale = s.fontSize / gf.unitsPerEm;
2890
+ const upm = (gf == null ? void 0 : gf.unitsPerEm) || 1e3;
2891
+ const scale = s.fontSize / upm;
2892
+ const ascentEm = (_a2 = gf == null ? void 0 : gf.ascent) != null ? _a2 : 0.9 * upm;
2852
2893
  const paint = paintOf(s);
2853
2894
  for (let i = 0; i < content.length; i++) {
2854
2895
  const ch = content.charAt(i);
2855
- const g = gf.glyphs[ch];
2856
- 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 });
2857
- pen.x += (g ? g.width : 0) * scale + s.letterSpacing + (ch === " " ? s.wordSpacing : 0);
2896
+ const g = gf == null ? void 0 : gf.glyphs[ch];
2897
+ if (g && g.d) {
2898
+ placements.push({ glyphD: g.d, m: [scale, 0, 0, scale, pen.x, pen.y], paint, line, x: pen.x, y: pen.y, scale });
2899
+ pen.x += g.width * scale;
2900
+ } else if (/\S/.test(ch)) {
2901
+ const advEm = g && g.width > 0 ? g.width : MISSING_GLYPH_ADVANCE_EM * upm;
2902
+ placements.push({ glyphD: missingGlyphBoxEm(advEm, ascentEm), m: [scale, 0, 0, scale, pen.x, pen.y], paint, line, x: pen.x, y: pen.y, scale });
2903
+ pen.x += advEm * scale;
2904
+ } else {
2905
+ pen.x += (g ? g.width : 0) * scale;
2906
+ }
2907
+ pen.x += s.letterSpacing + (ch === " " ? s.wordSpacing : 0);
2858
2908
  lines[line].end = pen.x;
2859
2909
  }
2860
2910
  };
@@ -2889,24 +2939,152 @@ function materialiseGlyphTextHorizontal(node, opts) {
2889
2939
  }
2890
2940
  return toGroup(node, buildPaths(placements, create, warnings), create);
2891
2941
  }
2942
+ function layoutGlyphTextChars(node, opts) {
2943
+ var _a, _b, _c, _d, _e;
2944
+ if ((_a = opts.alongPath) == null ? void 0 : _a.pathD) return layoutGlyphTextCharsAlongPath(node, opts.alongPath.pathD, opts);
2945
+ const { glyphs, warnings } = opts;
2946
+ const soleFont = soleFontOf(glyphs);
2947
+ const pen = { x: (_b = parseLen(node.x)) != null ? _b : 0, y: (_c = parseLen(node.y)) != null ? _c : 0 };
2948
+ const boxes = [];
2949
+ const lines = [{ start: pen.x, end: pen.x }];
2950
+ let line = 0;
2951
+ const renderChars = (content, s) => {
2952
+ var _a2;
2953
+ const gf = glyphFontFor(s, glyphs, soleFont, warnings);
2954
+ const upm = (gf == null ? void 0 : gf.unitsPerEm) || 1e3;
2955
+ const scale = s.fontSize / upm;
2956
+ const ascent = ((_a2 = gf == null ? void 0 : gf.ascent) != null ? _a2 : 0.9 * upm) * scale;
2957
+ for (let i = 0; i < content.length; i++) {
2958
+ const ch = content.charAt(i);
2959
+ const g = gf == null ? void 0 : gf.glyphs[ch];
2960
+ const advance = (g ? g.width : 0) * scale + s.letterSpacing + (ch === " " ? s.wordSpacing : 0);
2961
+ boxes.push({ x: pen.x, y: pen.y, width: advance, ascent, fontSize: s.fontSize, line });
2962
+ pen.x += advance;
2963
+ lines[line].end = pen.x;
2964
+ }
2965
+ };
2966
+ const walk = (el, parentStyle) => {
2967
+ var _a2, _b2, _c2, _d2;
2968
+ const s = resolveStyle(el, parentStyle);
2969
+ const x = parseLen(el.x);
2970
+ const y = parseLen(el.y);
2971
+ if (x !== void 0) {
2972
+ pen.x = x;
2973
+ line = lines.length;
2974
+ lines.push({ start: pen.x, end: pen.x });
2975
+ }
2976
+ if (y !== void 0) pen.y = y;
2977
+ pen.x += (_a2 = parseLen(el.dx)) != null ? _a2 : 0;
2978
+ pen.y += (_b2 = parseLen(el.dy)) != null ? _b2 : 0;
2979
+ const content = (_c2 = str(el[TEXT_ATTR])) != null ? _c2 : str(el[TEXT_CONTENT_ATTR]);
2980
+ if (content && !((_d2 = el.children) == null ? void 0 : _d2.length)) renderChars(content, s);
2981
+ if (el.children) for (const ch of el.children) walk(ch, s);
2982
+ };
2983
+ const rootStyle = rootStyleOf(node);
2984
+ if (node.children) for (const ch of node.children) walk(ch, rootStyle);
2985
+ const rootContent = (_d = str(node[TEXT_ATTR])) != null ? _d : str(node[TEXT_CONTENT_ATTR]);
2986
+ if (rootContent && !((_e = node.children) == null ? void 0 : _e.length)) renderChars(rootContent, rootStyle);
2987
+ const anchor = str(node.textAnchor);
2988
+ if (anchor === "middle" || anchor === "end") {
2989
+ for (const b of boxes) {
2990
+ const w = lines[b.line].end - lines[b.line].start;
2991
+ b.x += anchor === "middle" ? -w / 2 : -w;
2992
+ }
2993
+ }
2994
+ return boxes.map((_f) => {
2995
+ var _g = _f, { line: _l } = _g, b = __objRest(_g, ["line"]);
2996
+ return b;
2997
+ });
2998
+ }
2999
+ function layoutGlyphTextCharsAlongPath(node, pathD, opts) {
3000
+ var _a;
3001
+ const { glyphs, warnings, alongPath } = opts;
3002
+ const sampler = createPathSampler(pathD);
3003
+ if (!sampler) {
3004
+ warnings == null ? void 0 : warnings.push("textGlyphs: unparsable along-path geometry (caret)");
3005
+ return [];
3006
+ }
3007
+ const soleFont = soleFontOf(glyphs);
3008
+ const chars = [];
3009
+ let adv = 0;
3010
+ const walk = (el, parentStyle) => {
3011
+ var _a2, _b, _c;
3012
+ const s = resolveStyle(el, parentStyle);
3013
+ const content = (_a2 = str(el[TEXT_ATTR])) != null ? _a2 : str(el[TEXT_CONTENT_ATTR]);
3014
+ if (content && !((_b = el.children) == null ? void 0 : _b.length)) {
3015
+ const gf = glyphFontFor(s, glyphs, soleFont, warnings);
3016
+ const upm = (gf == null ? void 0 : gf.unitsPerEm) || 1e3;
3017
+ const scale = s.fontSize / upm;
3018
+ const ascent = ((_c = gf == null ? void 0 : gf.ascent) != null ? _c : 0.9 * upm) * scale;
3019
+ for (let i = 0; i < content.length; i++) {
3020
+ const ch = content.charAt(i);
3021
+ const g = gf == null ? void 0 : gf.glyphs[ch];
3022
+ const glyphW = (g ? g.width : 0) * scale;
3023
+ const advance = glyphW + s.letterSpacing + (ch === " " ? s.wordSpacing : 0);
3024
+ chars.push({ advStart: adv, advEnd: adv + advance, glyphW, ascent, fontSize: s.fontSize });
3025
+ adv += advance;
3026
+ }
3027
+ }
3028
+ if (el.children) for (const ch of el.children) walk(ch, s);
3029
+ };
3030
+ walk(node, rootStyleOf(node));
3031
+ const width = adv;
3032
+ const k = (alongPath == null ? void 0 : alongPath.textLength) && alongPath.textLength > 0 && width > 0 ? alongPath.textLength / width : 1;
3033
+ const so = readAnimatable(alongPath == null ? void 0 : alongPath.startOffset);
3034
+ const { along: alongOffset, perp } = alongPathNodeOffsets(node);
3035
+ 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);
3036
+ const withPerp = (p) => ({
3037
+ x: p.x - perp * Math.sin(p.angle),
3038
+ y: p.y + perp * Math.cos(p.angle),
3039
+ angle: p.angle
3040
+ });
3041
+ return chars.map((c) => {
3042
+ const dStart = base + c.advStart * k;
3043
+ const dEnd = base + c.advEnd * k;
3044
+ const p0 = withPerp(sampler.sampleAtDistance(dStart));
3045
+ const p1 = withPerp(sampler.sampleAtDistance(dEnd));
3046
+ const glyphMid = sampler.sampleAtDistance(base + (c.advStart + c.glyphW / 2) * k);
3047
+ return {
3048
+ x: p0.x,
3049
+ y: p0.y,
3050
+ width: c.advEnd - c.advStart,
3051
+ ascent: c.ascent,
3052
+ fontSize: c.fontSize,
3053
+ endX: p1.x,
3054
+ endY: p1.y,
3055
+ rotation: glyphMid.angle * 180 / Math.PI
3056
+ };
3057
+ });
3058
+ }
2892
3059
  function collectAlongPathCells(node, glyphs, soleFont, warnings) {
2893
3060
  const cells = [];
2894
3061
  let adv = 0;
2895
3062
  const walk = (el, parentStyle) => {
2896
- var _a, _b;
3063
+ var _a, _b, _c;
2897
3064
  const s = resolveStyle(el, parentStyle);
2898
3065
  const content = (_a = str(el[TEXT_ATTR])) != null ? _a : str(el[TEXT_CONTENT_ATTR]);
2899
3066
  if (content && !((_b = el.children) == null ? void 0 : _b.length)) {
2900
3067
  const gf = glyphFontFor(s, glyphs, soleFont, warnings);
2901
3068
  if (gf) {
2902
3069
  const scale = s.fontSize / gf.unitsPerEm;
3070
+ const ascentEm = (_c = gf.ascent) != null ? _c : 0.9 * gf.unitsPerEm;
2903
3071
  const paint = paintOf(s);
2904
3072
  for (let i = 0; i < content.length; i++) {
2905
3073
  const ch = content.charAt(i);
2906
3074
  const g = gf.glyphs[ch];
2907
- const glyphAdv = (g ? g.width : 0) * scale;
2908
- if (g && g.d) cells.push({ glyphD: g.d, widthEm: g.width, scale, paint, midBase: adv + glyphAdv / 2 });
2909
- adv += glyphAdv + s.letterSpacing + (ch === " " ? s.wordSpacing : 0);
3075
+ if (g && g.d) {
3076
+ const glyphAdv = g.width * scale;
3077
+ cells.push({ glyphD: g.d, widthEm: g.width, scale, paint, midBase: adv + glyphAdv / 2 });
3078
+ adv += glyphAdv;
3079
+ } else if (/\S/.test(ch)) {
3080
+ const wEm = g && g.width > 0 ? g.width : MISSING_GLYPH_ADVANCE_EM * gf.unitsPerEm;
3081
+ const boxAdv = wEm * scale;
3082
+ cells.push({ glyphD: missingGlyphBoxEm(wEm, ascentEm), widthEm: wEm, scale, paint, midBase: adv + boxAdv / 2 });
3083
+ adv += boxAdv;
3084
+ } else {
3085
+ adv += (g ? g.width : 0) * scale;
3086
+ }
3087
+ adv += s.letterSpacing + (ch === " " ? s.wordSpacing : 0);
2910
3088
  }
2911
3089
  }
2912
3090
  }
@@ -2915,10 +3093,17 @@ function collectAlongPathCells(node, glyphs, soleFont, warnings) {
2915
3093
  walk(node, rootStyleOf(node));
2916
3094
  return { cells, width: adv };
2917
3095
  }
2918
- function alongAffine(sampler, dist, scale, widthEm) {
3096
+ function alongAffine(sampler, dist, scale, widthEm, perp = 0) {
2919
3097
  const { x, y, angle } = sampler.sampleAtDistance(dist);
2920
3098
  const cos = Math.cos(angle), sin = Math.sin(angle), hw = widthEm / 2;
2921
- return [scale * cos, scale * sin, -scale * sin, scale * cos, x - scale * cos * hw, y - scale * sin * hw];
3099
+ return [scale * cos, scale * sin, -scale * sin, scale * cos, x - scale * cos * hw - perp * sin, y - scale * sin * hw + perp * cos];
3100
+ }
3101
+ function alongPathNodeOffsets(node) {
3102
+ var _a, _b, _c;
3103
+ return {
3104
+ along: ((_a = parseLen(node.x)) != null ? _a : 0) + ((_b = parseLen(node.dx)) != null ? _b : 0),
3105
+ perp: (_c = parseLen(node.dy)) != null ? _c : 0
3106
+ };
2922
3107
  }
2923
3108
  function materialiseGlyphTextAlongPath(node, pathD, startOffset, opts, textLength, pathOverflow) {
2924
3109
  var _a;
@@ -2931,6 +3116,7 @@ function materialiseGlyphTextAlongPath(node, pathD, startOffset, opts, textLengt
2931
3116
  const soleFont = soleFontOf(glyphs);
2932
3117
  const { cells, width } = collectAlongPathCells(node, glyphs, soleFont, warnings);
2933
3118
  if (!cells.length) return toGroup(node, [], create);
3119
+ const { along: alongOffset, perp } = alongPathNodeOffsets(node);
2934
3120
  if (textLength && textLength > 0 && width > 0) {
2935
3121
  const k = textLength / width;
2936
3122
  for (const c of cells) c.midBase *= k;
@@ -2938,9 +3124,9 @@ function materialiseGlyphTextAlongPath(node, pathD, startOffset, opts, textLengt
2938
3124
  const isClip = pathOverflow === "clip" && !sampler.closed;
2939
3125
  const so = readAnimatable(startOffset);
2940
3126
  if (so.kind === "animated" /* Animated */ && so.keyframes.length >= 2) {
2941
- return toGroup(node, buildAnimatedAlongPath(cells, sampler, so.keyframes, so.loop, create, isClip), create);
3127
+ return toGroup(node, buildAnimatedAlongPath(cells, sampler, so.keyframes, so.loop, create, isClip, alongOffset, perp), create);
2942
3128
  }
2943
- 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;
3129
+ 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);
2944
3130
  const placeCells = isClip ? cells.filter((c) => {
2945
3131
  const d = base + c.midBase;
2946
3132
  return d >= 0 && d <= sampler.totalLength;
@@ -2948,7 +3134,7 @@ function materialiseGlyphTextAlongPath(node, pathD, startOffset, opts, textLengt
2948
3134
  const placements = placeCells.map((c) => ({
2949
3135
  glyphD: c.glyphD,
2950
3136
  paint: c.paint,
2951
- m: alongAffine(sampler, base + c.midBase, c.scale, c.widthEm)
3137
+ m: alongAffine(sampler, base + c.midBase, c.scale, c.widthEm, perp)
2952
3138
  }));
2953
3139
  return toGroup(node, buildPaths(placements, create, warnings), create);
2954
3140
  }
@@ -2958,10 +3144,10 @@ function roundN(v, n) {
2958
3144
  const f = __pow(10, n);
2959
3145
  return Math.round(v * f) / f;
2960
3146
  }
2961
- function buildAnimatedAlongPath(cells, sampler, sokfs, loop, create, isClip) {
3147
+ function buildAnimatedAlongPath(cells, sampler, sokfs, loop, create, isClip, alongOffset = 0, perp = 0) {
2962
3148
  const step = Math.max(sampler.totalLength / ALONG_PATH_MAX_STEPS, 0.5);
2963
3149
  const timeOf = (kf) => Number(kf.time) || 0;
2964
- const offOf = (kf) => Number(kf.value) || 0;
3150
+ const offOf = (kf) => alongOffset + (Number(kf.value) || 0);
2965
3151
  const onPath = (dist) => dist >= 0 && dist <= sampler.totalLength;
2966
3152
  const out = [];
2967
3153
  for (const c of cells) {
@@ -2969,10 +3155,11 @@ function buildAnimatedAlongPath(cells, sampler, sokfs, loop, create, isClip) {
2969
3155
  const d = transformPathData(c.glyphD, centred);
2970
3156
  const sampleKf = (dist, time) => {
2971
3157
  const { x, y, angle } = sampler.sampleAtDistance(dist);
3158
+ const cos = Math.cos(angle), sin = Math.sin(angle);
2972
3159
  return {
2973
3160
  time,
2974
3161
  value: {
2975
- ["translate" /* Translate */]: [roundN(x, 3), roundN(y, 3)],
3162
+ ["translate" /* Translate */]: [roundN(x - perp * sin, 3), roundN(y + perp * cos, 3)],
2976
3163
  ["rotate" /* Rotate */]: roundN(angle * 180 / Math.PI, 3)
2977
3164
  }
2978
3165
  };
@@ -3242,9 +3429,18 @@ function buildOutKfValue(prevV, nextV, p, translate, rotateDegFromAutoOrient, au
3242
3429
  if (pv === void 0 && nv === void 0) continue;
3243
3430
  value[k] = interpolatePart(pv, nv, p);
3244
3431
  }
3245
- if (rotateDegFromAutoOrient !== void 0) value.rotate = rotateDegFromAutoOrient;
3432
+ if (rotateDegFromAutoOrient !== void 0) {
3433
+ value.rotate = rotateDegFromAutoOrient + explicitRotateAt(prevV, nextV, p);
3434
+ }
3246
3435
  return value;
3247
3436
  }
3437
+ function explicitRotateAt(prevV, nextV, p) {
3438
+ const pv = typeof (prevV == null ? void 0 : prevV.rotate) === "number" ? prevV.rotate : void 0;
3439
+ const nv = typeof (nextV == null ? void 0 : nextV.rotate) === "number" ? nextV.rotate : void 0;
3440
+ if (pv === void 0 && nv === void 0) return 0;
3441
+ const r = interpolatePart(pv, nv, p);
3442
+ return typeof r === "number" ? r : 0;
3443
+ }
3248
3444
  function derivAngleForFirstKf(kf0, kf1) {
3249
3445
  const p0 = getKfTranslate(kf0);
3250
3446
  const p1 = getKfTranslate(kf1);
@@ -3265,10 +3461,12 @@ function insertSharpCornerStepKfIfNeeded(out, prevKf, nextKf, prevPos, nextPos,
3265
3461
  const lastV = (_a = lastKf.v) != null ? _a : lastKf.value;
3266
3462
  const prevExit = lastV == null ? void 0 : lastV.rotate;
3267
3463
  if (typeof prevExit !== "number") return;
3464
+ const boundaryV = getKfValueParts(prevKf);
3465
+ const prevExitTangent = prevExit - explicitRotateAt(boundaryV, boundaryV, 0);
3268
3466
  const seg = getSegmentCache(prevKf, nextKf, prevPos, nextPos);
3269
3467
  const tanAtStart = bezier2D_derivativeAt(seg.P0, seg.P1, seg.P2, seg.P3, 0);
3270
3468
  const nextEntry = Math.atan2(tanAtStart[1], tanAtStart[0]) * 180 / Math.PI;
3271
- const delta = wrappedAngleDelta(nextEntry, prevExit);
3469
+ const delta = wrappedAngleDelta(nextEntry, prevExitTangent);
3272
3470
  if (Math.abs(delta) <= rotationTol) return;
3273
3471
  const dupValue = buildOutKfValue(
3274
3472
  getKfValueParts(prevKf),
@@ -4467,7 +4665,7 @@ function applyPlayerEffects_exceptRetime(node, ctx) {
4467
4665
  const originalId = typeof node.id === "string" ? node.id : void 0;
4468
4666
  const innerIdForContentRef = originalId ? ctx.contentRefInnerIds.get(originalId) : void 0;
4469
4667
  if (!fx && !innerIdForContentRef) return node;
4470
- const { transformation, repeater, maskedBy, trimPath, clone: cloneFx, fillGradient, strokeGradient, textPath, text } = fx != null ? fx : {};
4668
+ const { transformation, repeater, maskedBy, clipPath, trimPath, clone: cloneFx, fillGradient, strokeGradient, textPath, text } = fx != null ? fx : {};
4471
4669
  const isCombinedShape = fx == null ? void 0 : fx.isCombinedShape;
4472
4670
  if (fx) delete node.effects;
4473
4671
  let n = node;
@@ -4493,6 +4691,7 @@ function applyPlayerEffects_exceptRetime(node, ctx) {
4493
4691
  n = applyTrimPathEffect(n, trimPath, isCombinedShape, ctx);
4494
4692
  n = applyRepeaterEffect(n, repeater, ctx);
4495
4693
  n = applyMaskedByEffect(n, maskedBy, transformation, ctx);
4694
+ n = applyClipPathEffect(n, clipPath, ctx);
4496
4695
  if (innerIdForContentRef) {
4497
4696
  applyRefHref(n, cloneFx, ctx);
4498
4697
  n = splitForContentRef(n, transformation, originalId, innerIdForContentRef, ctx);
@@ -4821,6 +5020,8 @@ function getNormalizedProps(props) {
4821
5020
  function renderNode(node, defs) {
4822
5021
  if (!node) return null;
4823
5022
  const _a = node, { type, children, style } = _a, props = __objRest(_a, ["type", "children", "style"]);
5023
+ const feFuncType = props.funcType;
5024
+ if (feFuncType !== void 0) delete props.funcType;
4824
5025
  const nodeDefs = getDefs(node) || defs;
4825
5026
  const resolvedStyle = resolveStyle2(style, nodeDefs);
4826
5027
  let childElements;
@@ -4833,13 +5034,15 @@ function renderNode(node, defs) {
4833
5034
  }
4834
5035
  }
4835
5036
  }
4836
- return createElement(
5037
+ const element = createElement(
4837
5038
  type || "g",
4838
5039
  getNormalizedProps(props),
4839
5040
  resolvedStyle,
4840
5041
  childElements,
4841
5042
  props[TEXT_ATTR] || props[TEXT_CONTENT_ATTR]
4842
5043
  );
5044
+ if (element && feFuncType !== void 0) element.setAttribute("type", feFuncType);
5045
+ return element;
4843
5046
  }
4844
5047
 
4845
5048
  // src/PxAnimatorTriggers.ts
@@ -4850,7 +5053,12 @@ function setupAnimationTriggers(api, config) {
4850
5053
  console.warn("setupAnimationTriggers: No root element found for animation.");
4851
5054
  return api;
4852
5055
  }
5056
+ let reversed = false;
4853
5057
  const start = () => {
5058
+ if (reversed) {
5059
+ reversed = false;
5060
+ api.setPlaybackRate(1);
5061
+ }
4854
5062
  api.play();
4855
5063
  };
4856
5064
  const handleEndAction = () => {
@@ -4862,6 +5070,8 @@ function setupAnimationTriggers(api, config) {
4862
5070
  api.cancel();
4863
5071
  break;
4864
5072
  case "reverse":
5073
+ reversed = true;
5074
+ api.setPlaybackRate(-1);
4865
5075
  api.play();
4866
5076
  break;
4867
5077
  case "continue":
@@ -4924,6 +5134,7 @@ function getSelector(id) {
4924
5134
  return "#" + id;
4925
5135
  }
4926
5136
  function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
5137
+ var _a;
4927
5138
  const config = getAnimatorConfig(doc) || {};
4928
5139
  const bindings = getNormalisedBindings(doc, PxAnimatorEngine.frames);
4929
5140
  const _iterations = config.iterations;
@@ -4934,18 +5145,24 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
4934
5145
  const duration = +(config.duration || DEFAULT_DURATION_MS);
4935
5146
  const totalDuration = duration && iterations ? duration * (iterations === Infinity ? Infinity : iterations) : duration ? (iterations != null ? iterations : 1) * duration : 0;
4936
5147
  const direction = config.direction || "normal";
5148
+ const fill = (_a = config.fill) != null ? _a : "forwards";
5149
+ const fillsForwards = fill === "forwards" || fill === "both";
5150
+ const fillsBackwards = fill === "backwards" || fill === "both";
4937
5151
  let timerId = null;
4938
5152
  let playing = false;
4939
- let timeBeforeLastStartMs = config.delay || 0;
5153
+ let timeBeforeLastStartMs = -(config.delay || 0);
4940
5154
  let lastStartedTs = 0;
4941
5155
  let playbackRate = 1;
4942
5156
  let finishCalled = false;
4943
5157
  const frameRate = config.frameRate;
4944
5158
  const minFrameIntervalMs = frameRate && frameRate > 0 ? 1e3 / frameRate : 0;
4945
5159
  let lastRenderTs = 0;
4946
- const getAnimCurrentTime = () => {
5160
+ const getRawAnimTime = () => {
4947
5161
  const runningElapsed = lastStartedTs ? (Date.now() - lastStartedTs) * playbackRate : 0;
4948
- let time = timeBeforeLastStartMs + runningElapsed;
5162
+ return timeBeforeLastStartMs + runningElapsed;
5163
+ };
5164
+ const getAnimCurrentTime = () => {
5165
+ let time = getRawAnimTime();
4949
5166
  if (Number.isFinite(totalDuration) && time > totalDuration) time = totalDuration;
4950
5167
  if (time < 0) time = 0;
4951
5168
  return time;
@@ -4990,40 +5207,59 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
4990
5207
  }
4991
5208
  }
4992
5209
  const tick = () => {
4993
- var _a;
5210
+ var _a2, _b;
4994
5211
  if (!adapter.isConnected()) {
4995
5212
  pauseAnim();
4996
5213
  return;
4997
5214
  }
4998
5215
  const currentTime = getAnimCurrentTime();
4999
- if (minFrameIntervalMs > 0) {
5000
- const now = Date.now();
5001
- if (lastRenderTs && now - lastRenderTs < minFrameIntervalMs) {
5002
- return;
5003
- }
5004
- lastRenderTs = now;
5005
- }
5006
- if (duration <= 0) {
5216
+ const rawTime = getRawAnimTime();
5217
+ if (rawTime < 0 && playbackRate > 0) {
5218
+ if (fillsBackwards) renderFrame(0);
5219
+ return;
5007
5220
  }
5008
- if (totalDuration && Number.isFinite(totalDuration) && currentTime >= totalDuration) {
5009
- renderFrame(totalDuration);
5221
+ if (playbackRate < 0 && rawTime <= 0) {
5222
+ pauseAnim();
5223
+ renderFrame(0);
5010
5224
  if (!finishCalled) {
5011
5225
  finishCalled = true;
5012
- (_a = callbacks == null ? void 0 : callbacks.onFinish) == null ? void 0 : _a.call(callbacks);
5226
+ (_a2 = callbacks == null ? void 0 : callbacks.onFinish) == null ? void 0 : _a2.call(callbacks);
5013
5227
  }
5228
+ return;
5229
+ }
5230
+ if (playbackRate > 0 && totalDuration && Number.isFinite(totalDuration) && currentTime >= totalDuration) {
5014
5231
  pauseAnim();
5232
+ renderFrame(fillsForwards ? totalDuration : 0);
5233
+ if (!finishCalled) {
5234
+ finishCalled = true;
5235
+ (_b = callbacks == null ? void 0 : callbacks.onFinish) == null ? void 0 : _b.call(callbacks);
5236
+ }
5015
5237
  return;
5016
5238
  }
5239
+ if (minFrameIntervalMs > 0) {
5240
+ const now = Date.now();
5241
+ if (lastRenderTs && now - lastRenderTs < minFrameIntervalMs) {
5242
+ return;
5243
+ }
5244
+ lastRenderTs = now;
5245
+ }
5017
5246
  renderFrame(currentTime);
5018
5247
  };
5019
5248
  if (config.delay) {
5020
- renderFrame(getAnimCurrentTime());
5249
+ if (config.delay < 0) {
5250
+ renderFrame(getAnimCurrentTime());
5251
+ } else if (fillsBackwards) {
5252
+ renderFrame(0);
5253
+ }
5021
5254
  }
5022
5255
  const _isPlaying = () => {
5023
5256
  if (!playing) return false;
5024
5257
  if (!adapter.isConnected()) {
5025
5258
  return false;
5026
5259
  }
5260
+ if (playbackRate < 0) {
5261
+ return getRawAnimTime() > 0;
5262
+ }
5027
5263
  if (Number.isFinite(totalDuration) && getAnimCurrentTime() >= totalDuration) return false;
5028
5264
  return true;
5029
5265
  };
@@ -5043,37 +5279,53 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
5043
5279
  };
5044
5280
  const startAnim = () => {
5045
5281
  if (playing) return;
5046
- if (Number.isFinite(totalDuration) && timeBeforeLastStartMs >= totalDuration) {
5047
- timeBeforeLastStartMs = 0;
5048
- finishCalled = false;
5282
+ if (playbackRate >= 0) {
5283
+ if (Number.isFinite(totalDuration) && timeBeforeLastStartMs >= totalDuration) {
5284
+ timeBeforeLastStartMs = 0;
5285
+ }
5286
+ } else {
5287
+ if (timeBeforeLastStartMs <= 0) {
5288
+ if (!Number.isFinite(totalDuration)) {
5289
+ console.warn("play: cannot start reverse playback of an infinite animation from time 0");
5290
+ return;
5291
+ }
5292
+ timeBeforeLastStartMs = totalDuration;
5293
+ }
5049
5294
  }
5295
+ finishCalled = false;
5050
5296
  playing = true;
5051
5297
  lastStartedTs = Date.now();
5052
5298
  loopAnim(true);
5053
5299
  };
5054
5300
  const pauseAnim = () => {
5055
5301
  if (!playing) return;
5056
- timeBeforeLastStartMs = getAnimCurrentTime();
5302
+ let raw = getRawAnimTime();
5303
+ if (Number.isFinite(totalDuration) && raw > totalDuration) raw = totalDuration;
5304
+ timeBeforeLastStartMs = raw;
5057
5305
  lastStartedTs = 0;
5058
5306
  playing = false;
5059
5307
  if (timerId !== null) {
5060
5308
  cancelAnimationFrame(timerId);
5061
5309
  timerId = null;
5062
5310
  }
5063
- renderFrame(timeBeforeLastStartMs);
5311
+ if (raw >= 0) {
5312
+ renderFrame(raw);
5313
+ } else if (fillsBackwards) {
5314
+ renderFrame(0);
5315
+ }
5064
5316
  };
5065
5317
  const cancelAnim = () => {
5066
- var _a;
5318
+ var _a2;
5067
5319
  pauseAnim();
5068
5320
  timeBeforeLastStartMs = 0;
5069
5321
  lastStartedTs = 0;
5070
5322
  playing = false;
5071
5323
  finishCalled = false;
5072
5324
  renderFrame(timeBeforeLastStartMs);
5073
- (_a = callbacks == null ? void 0 : callbacks.onCancel) == null ? void 0 : _a.call(callbacks);
5325
+ (_a2 = callbacks == null ? void 0 : callbacks.onCancel) == null ? void 0 : _a2.call(callbacks);
5074
5326
  };
5075
5327
  const finishAnim = (callOnFinish = true) => {
5076
- var _a;
5328
+ var _a2;
5077
5329
  if (Number.isFinite(totalDuration)) {
5078
5330
  timeBeforeLastStartMs = totalDuration;
5079
5331
  } else {
@@ -5081,10 +5333,14 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
5081
5333
  }
5082
5334
  lastStartedTs = 0;
5083
5335
  playing = false;
5084
- renderFrame(timeBeforeLastStartMs);
5336
+ if (timerId !== null) {
5337
+ cancelAnimationFrame(timerId);
5338
+ timerId = null;
5339
+ }
5340
+ renderFrame(fillsForwards ? timeBeforeLastStartMs : 0);
5085
5341
  if (callOnFinish && !finishCalled) {
5086
5342
  finishCalled = true;
5087
- (_a = callbacks == null ? void 0 : callbacks.onFinish) == null ? void 0 : _a.call(callbacks);
5343
+ (_a2 = callbacks == null ? void 0 : callbacks.onFinish) == null ? void 0 : _a2.call(callbacks);
5088
5344
  }
5089
5345
  };
5090
5346
  const api = {
@@ -5094,14 +5350,14 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
5094
5350
  return _isPlaying();
5095
5351
  },
5096
5352
  "play": () => {
5097
- var _a;
5353
+ var _a2;
5098
5354
  startAnim();
5099
- (_a = callbacks == null ? void 0 : callbacks.onPlay) == null ? void 0 : _a.call(callbacks);
5355
+ (_a2 = callbacks == null ? void 0 : callbacks.onPlay) == null ? void 0 : _a2.call(callbacks);
5100
5356
  },
5101
5357
  "pause": () => {
5102
- var _a;
5358
+ var _a2;
5103
5359
  pauseAnim();
5104
- (_a = callbacks == null ? void 0 : callbacks.onPause) == null ? void 0 : _a.call(callbacks);
5360
+ (_a2 = callbacks == null ? void 0 : callbacks.onPause) == null ? void 0 : _a2.call(callbacks);
5105
5361
  },
5106
5362
  "cancel": () => {
5107
5363
  cancelAnim();
@@ -5114,7 +5370,9 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
5114
5370
  console.warn("setPlaybackRate: rate must be finite and non-zero");
5115
5371
  return;
5116
5372
  }
5117
- const current = getAnimCurrentTime();
5373
+ let current = getRawAnimTime();
5374
+ if (Number.isFinite(totalDuration) && current > totalDuration) current = totalDuration;
5375
+ if (rate < 0 !== playbackRate < 0) finishCalled = false;
5118
5376
  playbackRate = rate;
5119
5377
  timeBeforeLastStartMs = current;
5120
5378
  if (playing) lastStartedTs = Date.now();
@@ -5127,10 +5385,13 @@ function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
5127
5385
  if (Number.isFinite(totalDuration) && newTime > totalDuration) newTime = totalDuration;
5128
5386
  timeBeforeLastStartMs = newTime;
5129
5387
  if (playing) lastStartedTs = Date.now();
5388
+ if (!Number.isFinite(totalDuration) || newTime < totalDuration) finishCalled = false;
5130
5389
  renderFrame(getAnimCurrentTime());
5131
5390
  },
5132
5391
  "destroy": () => {
5392
+ var _a2;
5133
5393
  api.cancel();
5394
+ (_a2 = callbacks == null ? void 0 : callbacks.onRemove) == null ? void 0 : _a2.call(callbacks);
5134
5395
  }
5135
5396
  };
5136
5397
  return api;
@@ -5295,6 +5556,8 @@ function createWebApiAnimator(doc, callbacks, rootElement, forceEvenIfHasUnsuppo
5295
5556
  if (typeof _iterations === "number") iterations = _iterations;
5296
5557
  if (_iterations === "infinite") iterations = Infinity;
5297
5558
  const unsupportedSet = /* @__PURE__ */ new Set();
5559
+ let finishNotified = false;
5560
+ let removeCalled = false;
5298
5561
  if (!(bindings == null ? void 0 : bindings.length)) {
5299
5562
  console.warn("createWebApiAnimator: No animation bindings defined");
5300
5563
  }
@@ -5311,7 +5574,11 @@ function createWebApiAnimator(doc, callbacks, rootElement, forceEvenIfHasUnsuppo
5311
5574
  }
5312
5575
  const keyframesMap = convertToWebApiKeyframes(animDef, unsupportedSet, config);
5313
5576
  const positiveDelay = config.delay && config.delay > 0 ? config.delay : void 0;
5314
- const seekPosition = config.delay && config.delay < 0 && config.duration ? -config.delay % config.duration : void 0;
5577
+ let seekPosition;
5578
+ if (config.delay && config.delay < 0 && config.duration) {
5579
+ const rawSeek = -config.delay;
5580
+ seekPosition = iterations === Infinity ? rawSeek % config.duration : Math.min(rawSeek, config.duration * (iterations != null ? iterations : 1));
5581
+ }
5315
5582
  const effectOptions = {
5316
5583
  duration: config.duration,
5317
5584
  delay: positiveDelay,
@@ -5332,13 +5599,17 @@ function createWebApiAnimator(doc, callbacks, rootElement, forceEvenIfHasUnsuppo
5332
5599
  const anim = new Animation(effect, document.timeline);
5333
5600
  if (callbacks == null ? void 0 : callbacks.onFinish) anim.onfinish = () => {
5334
5601
  var _a2;
5335
- return (_a2 = callbacks.onFinish) == null ? void 0 : _a2.call(callbacks);
5602
+ if (finishNotified) return;
5603
+ finishNotified = true;
5604
+ (_a2 = callbacks.onFinish) == null ? void 0 : _a2.call(callbacks);
5336
5605
  };
5337
5606
  if (callbacks == null ? void 0 : callbacks.onRemove) anim.onremove = () => {
5338
5607
  var _a2;
5339
- return (_a2 = callbacks.onRemove) == null ? void 0 : _a2.call(callbacks);
5608
+ if (removeCalled) return;
5609
+ removeCalled = true;
5610
+ (_a2 = callbacks.onRemove) == null ? void 0 : _a2.call(callbacks);
5340
5611
  };
5341
- if (seekPosition) {
5612
+ if (seekPosition !== void 0) {
5342
5613
  anim.currentTime = seekPosition;
5343
5614
  }
5344
5615
  animations.push(anim);
@@ -5362,6 +5633,7 @@ function createWebApiAnimator(doc, callbacks, rootElement, forceEvenIfHasUnsuppo
5362
5633
  },
5363
5634
  "play": () => {
5364
5635
  var _a2;
5636
+ finishNotified = false;
5365
5637
  animations.forEach((a) => a.play());
5366
5638
  (_a2 = callbacks == null ? void 0 : callbacks.onPlay) == null ? void 0 : _a2.call(callbacks);
5367
5639
  },
@@ -5372,6 +5644,7 @@ function createWebApiAnimator(doc, callbacks, rootElement, forceEvenIfHasUnsuppo
5372
5644
  },
5373
5645
  "cancel": () => {
5374
5646
  var _a2;
5647
+ finishNotified = false;
5375
5648
  animations.forEach((a) => a.cancel());
5376
5649
  (_a2 = callbacks == null ? void 0 : callbacks.onCancel) == null ? void 0 : _a2.call(callbacks);
5377
5650
  },
@@ -5401,13 +5674,19 @@ function createWebApiAnimator(doc, callbacks, rootElement, forceEvenIfHasUnsuppo
5401
5674
  return res !== null ? +res : null;
5402
5675
  },
5403
5676
  "setCurrentTime": (time) => {
5677
+ finishNotified = false;
5404
5678
  animations.forEach((a) => {
5405
5679
  a.currentTime = time;
5406
5680
  });
5407
5681
  },
5408
5682
  "destroy": () => {
5683
+ var _a2;
5409
5684
  api.cancel();
5410
5685
  animations.splice(0, animations.length);
5686
+ if (!removeCalled) {
5687
+ removeCalled = true;
5688
+ (_a2 = callbacks == null ? void 0 : callbacks.onRemove) == null ? void 0 : _a2.call(callbacks);
5689
+ }
5411
5690
  }
5412
5691
  };
5413
5692
  if (config.trigger) {
@@ -5551,7 +5830,6 @@ function createAnimatorImpl(doc, adapter, callbacks, containerElement) {
5551
5830
  const effectsWarnings = validateNodeEffects(doc);
5552
5831
  for (const w of effectsWarnings) console.warn("[PxAnimator] effects shape warning:", w);
5553
5832
  const animatorConfig = getAnimatorConfig(doc) || {};
5554
- animatorConfig.debug = true;
5555
5833
  const engine = animatorConfig.mode === PxAnimatorMode.frames ? PxAnimatorEngine.frames : PxAnimatorEngine.webapi;
5556
5834
  doc = materialiseAllInTree(doc, engine);
5557
5835
  let rootElement = null;
@@ -5580,37 +5858,55 @@ function createAnimator(options) {
5580
5858
  return createAnimatorImpl(data, adapter, callbacks, container);
5581
5859
  }
5582
5860
  let animator = null;
5861
+ let pending = [];
5862
+ let destroyed = false;
5863
+ const enqueue = (call) => {
5864
+ if (animator) {
5865
+ call(animator);
5866
+ } else if (pending) {
5867
+ pending.push(call);
5868
+ }
5869
+ };
5583
5870
  fetch(src).then((res) => res.json()).then((json) => {
5871
+ if (destroyed) return;
5584
5872
  if (isPxElementFileFormat(json)) {
5585
5873
  animator = createAnimatorImpl(json, adapter, callbacks, container);
5874
+ const queued = pending;
5875
+ pending = null;
5876
+ queued == null ? void 0 : queued.forEach((call) => call(animator));
5586
5877
  } else {
5587
- console.error("Invalid animation document format");
5878
+ console.error('createAnimator: invalid animation document format at "' + src + '"');
5588
5879
  }
5880
+ }).catch((err) => {
5881
+ pending = null;
5882
+ console.error('createAnimator: failed to load "' + src + '"', err);
5589
5883
  });
5590
5884
  return {
5591
5885
  "isReady": () => !!animator,
5592
5886
  "getRootElement": () => animator ? animator.getRootElement() : null,
5593
5887
  "isPlaying": () => (animator == null ? void 0 : animator.isPlaying()) || false,
5594
5888
  "play": () => {
5595
- animator == null ? void 0 : animator.play();
5889
+ enqueue((api) => api.play());
5596
5890
  },
5597
5891
  "pause": () => {
5598
- animator == null ? void 0 : animator.pause();
5892
+ enqueue((api) => api.pause());
5599
5893
  },
5600
5894
  "cancel": () => {
5601
- animator == null ? void 0 : animator.cancel();
5895
+ enqueue((api) => api.cancel());
5602
5896
  },
5603
5897
  "finish": () => {
5604
- animator == null ? void 0 : animator.finish();
5898
+ enqueue((api) => api.finish());
5605
5899
  },
5606
5900
  "setPlaybackRate": (rate) => {
5607
- animator == null ? void 0 : animator.setPlaybackRate(rate);
5901
+ enqueue((api) => api.setPlaybackRate(rate));
5608
5902
  },
5609
- "getCurrentTime": () => (animator == null ? void 0 : animator.getCurrentTime()) || 0,
5903
+ "getCurrentTime": () => animator ? animator.getCurrentTime() : null,
5610
5904
  "setCurrentTime": (time) => {
5611
- animator == null ? void 0 : animator.setCurrentTime(time);
5905
+ enqueue((api) => api.setCurrentTime(time));
5612
5906
  },
5613
5907
  "destroy": () => {
5908
+ destroyed = true;
5909
+ pending = null;
5614
5910
  animator == null ? void 0 : animator.destroy();
5615
5911
  }
5616
5912
  };
@@ -5892,6 +6188,7 @@ function subtractMultiset(a, b) {
5892
6188
  createAnimatorImpl,
5893
6189
  createBasicFrameLoopAnimator,
5894
6190
  createFrameLoopAnimator,
6191
+ createPathSampler,
5895
6192
  createWebApiAnimator,
5896
6193
  describeSchema,
5897
6194
  diffInEffect,
@@ -5906,6 +6203,7 @@ function subtractMultiset(a, b) {
5906
6203
  isPxElementFileFormat,
5907
6204
  isPxElementFileFormatDeep,
5908
6205
  jsonElementFactory,
6206
+ layoutGlyphTextChars,
5909
6207
  loadTagAnimators,
5910
6208
  materialiseAllInTree,
5911
6209
  materialiseAnimatedUseInstances,