@pixodesk/svg-animator-web 1.0.17 → 1.0.19

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
@@ -7,6 +7,7 @@ var __getOwnPropNames = Object.getOwnPropertyNames;
7
7
  var __getOwnPropSymbols = Object.getOwnPropertySymbols;
8
8
  var __hasOwnProp = Object.prototype.hasOwnProperty;
9
9
  var __propIsEnum = Object.prototype.propertyIsEnumerable;
10
+ var __pow = Math.pow;
10
11
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
11
12
  var __spreadValues = (a, b) => {
12
13
  for (var prop in b || (b = {}))
@@ -82,7 +83,8 @@ __export(index_exports, {
82
83
  PxRetimeEffectSchema: () => PxRetimeEffectSchema,
83
84
  PxStrokeGradientEffectSchema: () => PxStrokeGradientEffectSchema,
84
85
  PxSvgNodeExtra: () => PxSvgNodeExtra,
85
- PxTextAlongPathEffectSchema: () => PxTextAlongPathEffectSchema,
86
+ PxTextEffectSchema: () => PxTextEffectSchema,
87
+ PxTextPathEffectSchema: () => PxTextPathEffectSchema,
86
88
  PxTransformPartsSchema: () => PxTransformPartsSchema,
87
89
  PxTransformValueSchema: () => PxTransformValueSchema,
88
90
  PxTransformationEffectSchema: () => PxTransformationEffectSchema,
@@ -102,6 +104,7 @@ __export(index_exports, {
102
104
  describeSchema: () => describeSchema,
103
105
  diffInEffect: () => diffInEffect,
104
106
  evaluateMotionPathSegment: () => evaluateMotionPathSegment,
107
+ extendedPathForBrowser: () => extendedPathForBrowser,
105
108
  generateNewIds: () => generateNewIds,
106
109
  getAnimatorConfig: () => getAnimatorConfig,
107
110
  getBindings: () => getBindings,
@@ -110,9 +113,13 @@ __export(index_exports, {
110
113
  getNormalizedProps: () => getNormalizedProps,
111
114
  isPxElementFileFormat: () => isPxElementFileFormat,
112
115
  isPxElementFileFormatDeep: () => isPxElementFileFormatDeep,
116
+ jsonElementFactory: () => jsonElementFactory,
113
117
  loadTagAnimators: () => loadTagAnimators,
114
118
  materialiseAllInTree: () => materialiseAllInTree,
115
119
  materialiseAnimatedUseInstances: () => materialiseAnimatedUseInstances,
120
+ materialiseGlyphText: () => materialiseGlyphText,
121
+ materialiseGlyphTextAlongPath: () => materialiseGlyphTextAlongPath,
122
+ materialiseGlyphTextHorizontal: () => materialiseGlyphTextHorizontal,
116
123
  materialiseInternalLoopsInPropAnim: () => materialiseInternalLoopsInPropAnim,
117
124
  materialiseInternalLoopsInTree: () => materialiseInternalLoopsInTree,
118
125
  materialiseMotionPathInPropAnim: () => materialiseMotionPathInPropAnim,
@@ -123,6 +130,7 @@ __export(index_exports, {
123
130
  renderNode: () => renderNode,
124
131
  schemaKeys: () => schemaKeys,
125
132
  setupAnimationTriggers: () => setupAnimationTriggers,
133
+ shiftAnimatable: () => shiftAnimatable,
126
134
  toRGBA: () => toRGBA,
127
135
  validateNodeEffects: () => validateNodeEffects,
128
136
  visualModelAt: () => visualModelAt
@@ -1005,10 +1013,22 @@ var PxTriggerSchema = implementsInterface()(px.object({
1005
1013
  outAction: px.enum(["continue", "pause", "reset", "reverse"]).optional(),
1006
1014
  scrollIntoViewThreshold: px.number().optional()
1007
1015
  }));
1016
+ var PxGlyphSchema = implementsInterface()(px.object({
1017
+ width: px.number(),
1018
+ d: px.string()
1019
+ }));
1020
+ var PxGlyphFontSchema = implementsInterface()(px.object({
1021
+ fFamily: px.string(),
1022
+ style: px.string(),
1023
+ ascent: px.number(),
1024
+ unitsPerEm: px.number(),
1025
+ glyphs: px.record(PxGlyphSchema)
1026
+ }));
1008
1027
  var PxDefsSchema = implementsInterface()(px.object({
1009
1028
  easings: px.record(px.tuple([px.number(), px.number(), px.number(), px.number()])).optional(),
1010
1029
  animations: px.record(PxAnimationDefinitionSchema).optional(),
1011
- styles: px.record(px.any()).optional()
1030
+ styles: px.record(px.any()).optional(),
1031
+ glyphs: px.record(PxGlyphFontSchema).optional()
1012
1032
  }));
1013
1033
  var PxAnimatorConfigSchema = implementsInterface()(px.object({
1014
1034
  mode: px.enum([PxAnimatorMode.auto, PxAnimatorMode.webapi, PxAnimatorMode.frames]).optional(),
@@ -1121,14 +1141,18 @@ var PxFillGradientEffectSchema = implementsInterface()(px.object({
1121
1141
  gradientTransform: px.string().optional()
1122
1142
  }));
1123
1143
  var PxStrokeGradientEffectSchema = PxFillGradientEffectSchema;
1124
- var PxTextAlongPathEffectSchema = implementsInterface()(px.object({
1125
- href: px.string(),
1144
+ var PxTextPathEffectSchema = implementsInterface()(px.object({
1145
+ path: px.string(),
1146
+ pathOverflow: px.string().optional(),
1126
1147
  lengthAdjust: px.string().optional(),
1127
1148
  method: px.string().optional(),
1128
1149
  spacing: px.string().optional(),
1129
1150
  startOffset: PxAnimatableNumberSchema.optional(),
1130
1151
  textLength: PxAnimatableNumberSchema.optional()
1131
1152
  }));
1153
+ var PxTextEffectSchema = implementsInterface()(px.object({
1154
+ useGlyphs: px.boolean().optional()
1155
+ }));
1132
1156
  var PxEffectsSchema = implementsInterface()(px.object({
1133
1157
  transformation: PxTransformationEffectSchema.optional(),
1134
1158
  repeater: PxRepeaterEffectSchema.optional(),
@@ -1138,7 +1162,8 @@ var PxEffectsSchema = implementsInterface()(px.object({
1138
1162
  isCombinedShape: px.boolean().optional(),
1139
1163
  fillGradient: PxFillGradientEffectSchema.optional(),
1140
1164
  strokeGradient: PxStrokeGradientEffectSchema.optional(),
1141
- textAlongPath: PxTextAlongPathEffectSchema.optional()
1165
+ textPath: PxTextPathEffectSchema.optional(),
1166
+ text: PxTextEffectSchema.optional()
1142
1167
  }));
1143
1168
  function validateNodeEffects(root, opts) {
1144
1169
  const warnings = [];
@@ -2010,48 +2035,6 @@ function remapKeyframeTimesOnly(node, start, stretch) {
2010
2035
  }
2011
2036
  }
2012
2037
 
2013
- // src/effects/textAlongPathEffect.ts
2014
- function applyTextAlongPathEffect(node, fx, _ctx) {
2015
- var _a;
2016
- if (!fx) return node;
2017
- const href = typeof fx.href === "string" && !fx.href.startsWith("#") ? "#" + fx.href : fx.href;
2018
- const textPath = {
2019
- type: "textPath",
2020
- href,
2021
- children: (_a = node.children) != null ? _a : []
2022
- };
2023
- if (fx.lengthAdjust !== void 0) textPath.lengthAdjust = fx.lengthAdjust;
2024
- if (fx.method !== void 0) textPath.method = fx.method;
2025
- if (fx.spacing !== void 0) textPath.spacing = fx.spacing;
2026
- applyAnimatableNumber(textPath, "startOffset", fx.startOffset);
2027
- applyAnimatableNumber(textPath, "textLength", fx.textLength);
2028
- node.children = [textPath];
2029
- return node;
2030
- }
2031
- function applyAnimatableNumber(node, attrName, raw) {
2032
- if (raw === void 0 || raw === null) return;
2033
- if (typeof raw === "number") {
2034
- node[attrName] = String(raw);
2035
- return;
2036
- }
2037
- if (typeof raw === "object" && raw !== null) {
2038
- const obj = raw;
2039
- if (Array.isArray(obj.keyframes)) {
2040
- const prevAnimate = node.animate && typeof node.animate === "object" && !Array.isArray(node.animate) ? node.animate : void 0;
2041
- const animate = __spreadValues({}, prevAnimate || {});
2042
- const block = { keyframes: obj.keyframes };
2043
- if (obj.loop !== void 0) block.loop = obj.loop;
2044
- animate[attrName] = block;
2045
- node.animate = animate;
2046
- return;
2047
- }
2048
- if (typeof obj.value === "number") {
2049
- node[attrName] = String(obj.value);
2050
- return;
2051
- }
2052
- }
2053
- }
2054
-
2055
2038
  // src/PxAnimatorUtil.ts
2056
2039
  function bezierToSvgPath(path) {
2057
2040
  var _a, _b, _c, _d;
@@ -2424,6 +2407,24 @@ function bezier2D_arcLengthLUT(P0, P1, P2, P3, steps = 100) {
2424
2407
  }
2425
2408
  return { ts, ds };
2426
2409
  }
2410
+ function bezier2D_tForDistance(lut, distance) {
2411
+ const { ts, ds } = lut;
2412
+ const last = ds.length - 1;
2413
+ if (distance <= 0) return ts[0];
2414
+ if (distance >= ds[last]) return ts[last];
2415
+ let lo = 1;
2416
+ let hi = last;
2417
+ while (lo < hi) {
2418
+ const mid = lo + hi >>> 1;
2419
+ if (ds[mid] < distance) lo = mid + 1;
2420
+ else hi = mid;
2421
+ }
2422
+ const dPrev = ds[hi - 1];
2423
+ const dCur = ds[hi];
2424
+ const span = dCur - dPrev;
2425
+ const frac = span > 0 ? (distance - dPrev) / span : 0;
2426
+ return ts[hi - 1] + frac * (ts[hi] - ts[hi - 1]);
2427
+ }
2427
2428
  function bezier2D_arcAtT(lut, t) {
2428
2429
  const { ts, ds } = lut;
2429
2430
  const last = ts.length - 1;
@@ -2446,6 +2447,623 @@ function invertEasing(easing) {
2446
2447
  return cubicBezier(flipped);
2447
2448
  }
2448
2449
 
2450
+ // src/effects/pathSampler.ts
2451
+ var LUT_STEPS = 48;
2452
+ var CMD_RE = /[MmLlHhVvCcSsQqTtAaZz]/;
2453
+ function tokenize(d) {
2454
+ const tokens = [];
2455
+ const re = /([MmLlHhVvCcSsQqTtAaZz])|(-?\d*\.?\d+(?:[eE][-+]?\d+)?)/g;
2456
+ let m;
2457
+ while ((m = re.exec(d)) !== null) tokens.push(m[0]);
2458
+ return tokens;
2459
+ }
2460
+ function quadToCubic(P0, Qc, P3) {
2461
+ return {
2462
+ P1: [P0[0] + 2 / 3 * (Qc[0] - P0[0]), P0[1] + 2 / 3 * (Qc[1] - P0[1])],
2463
+ P2: [P3[0] + 2 / 3 * (Qc[0] - P3[0]), P3[1] + 2 / 3 * (Qc[1] - P3[1])]
2464
+ };
2465
+ }
2466
+ function parseCubics(d) {
2467
+ const tokens = tokenize(d);
2468
+ const segs = [];
2469
+ let i = 0;
2470
+ let cx = 0, cy = 0;
2471
+ let sx = 0, sy = 0;
2472
+ let pcx = 0, pcy = 0;
2473
+ let pqx = 0, pqy = 0;
2474
+ let prevCmd = "";
2475
+ const num2 = () => parseFloat(tokens[i++]);
2476
+ const push = (P1, P2, P3) => {
2477
+ const P0 = [cx, cy];
2478
+ const lut = bezier2D_arcLengthLUT(P0, P1, P2, P3, LUT_STEPS);
2479
+ segs.push({ P0, P1, P2, P3, lut, len: lut.ds[lut.ds.length - 1] });
2480
+ cx = P3[0];
2481
+ cy = P3[1];
2482
+ };
2483
+ const pushLine = (x, y) => {
2484
+ push(
2485
+ [cx + (x - cx) / 3, cy + (y - cy) / 3],
2486
+ [cx + 2 * (x - cx) / 3, cy + 2 * (y - cy) / 3],
2487
+ [x, y]
2488
+ );
2489
+ };
2490
+ while (i < tokens.length) {
2491
+ let cmd = tokens[i];
2492
+ if (CMD_RE.test(cmd)) i++;
2493
+ else cmd = prevCmd === "M" ? "L" : prevCmd === "m" ? "l" : prevCmd;
2494
+ const rel = cmd >= "a";
2495
+ const U = cmd.toUpperCase();
2496
+ if (U === "Z") {
2497
+ pushLine(sx, sy);
2498
+ cx = sx;
2499
+ cy = sy;
2500
+ prevCmd = cmd;
2501
+ continue;
2502
+ }
2503
+ if (U === "M") {
2504
+ const x = num2() + (rel ? cx : 0), y = num2() + (rel ? cy : 0);
2505
+ cx = x;
2506
+ cy = y;
2507
+ sx = x;
2508
+ sy = y;
2509
+ prevCmd = cmd;
2510
+ continue;
2511
+ }
2512
+ if (U === "L") {
2513
+ pushLine(num2() + (rel ? cx : 0), num2() + (rel ? cy : 0));
2514
+ } else if (U === "H") {
2515
+ pushLine(num2() + (rel ? cx : 0), cy);
2516
+ } else if (U === "V") {
2517
+ pushLine(cx, num2() + (rel ? cy : 0));
2518
+ } else if (U === "C") {
2519
+ const p1 = [num2() + (rel ? cx : 0), num2() + (rel ? cy : 0)];
2520
+ const p2 = [num2() + (rel ? cx : 0), num2() + (rel ? cy : 0)];
2521
+ const p3 = [num2() + (rel ? cx : 0), num2() + (rel ? cy : 0)];
2522
+ pcx = p2[0];
2523
+ pcy = p2[1];
2524
+ push(p1, p2, p3);
2525
+ } else if (U === "S") {
2526
+ const smooth = prevCmd.toUpperCase() === "C" || prevCmd.toUpperCase() === "S";
2527
+ const p1 = smooth ? [2 * cx - pcx, 2 * cy - pcy] : [cx, cy];
2528
+ const p2 = [num2() + (rel ? cx : 0), num2() + (rel ? cy : 0)];
2529
+ const p3 = [num2() + (rel ? cx : 0), num2() + (rel ? cy : 0)];
2530
+ pcx = p2[0];
2531
+ pcy = p2[1];
2532
+ push(p1, p2, p3);
2533
+ } else if (U === "Q") {
2534
+ const qc = [num2() + (rel ? cx : 0), num2() + (rel ? cy : 0)];
2535
+ const p3 = [num2() + (rel ? cx : 0), num2() + (rel ? cy : 0)];
2536
+ pqx = qc[0];
2537
+ pqy = qc[1];
2538
+ const { P1, P2 } = quadToCubic([cx, cy], qc, p3);
2539
+ push(P1, P2, p3);
2540
+ } else if (U === "T") {
2541
+ const smooth = prevCmd.toUpperCase() === "Q" || prevCmd.toUpperCase() === "T";
2542
+ const qc = smooth ? [2 * cx - pqx, 2 * cy - pqy] : [cx, cy];
2543
+ const p3 = [num2() + (rel ? cx : 0), num2() + (rel ? cy : 0)];
2544
+ pqx = qc[0];
2545
+ pqy = qc[1];
2546
+ const { P1, P2 } = quadToCubic([cx, cy], qc, p3);
2547
+ push(P1, P2, p3);
2548
+ } else if (U === "A") {
2549
+ i += 5;
2550
+ pushLine(num2() + (rel ? cx : 0), num2() + (rel ? cy : 0));
2551
+ } else {
2552
+ i++;
2553
+ continue;
2554
+ }
2555
+ prevCmd = cmd;
2556
+ }
2557
+ return segs.length ? segs : null;
2558
+ }
2559
+ function clamp2(v, lo, hi) {
2560
+ return v < lo ? lo : v > hi ? hi : v;
2561
+ }
2562
+ function createPathSampler(d) {
2563
+ const segs = parseCubics(d);
2564
+ if (!segs) return null;
2565
+ const cum = new Float64Array(segs.length + 1);
2566
+ for (let k = 0; k < segs.length; k++) cum[k + 1] = cum[k] + segs[k].len;
2567
+ const totalLength = cum[segs.length];
2568
+ const start = segs[0].P0, end = segs[segs.length - 1].P3;
2569
+ const closed = Math.hypot(end[0] - start[0], end[1] - start[1]) < 1e-3;
2570
+ const sampleOn = (dist) => {
2571
+ let k = 0;
2572
+ while (k < segs.length - 1 && dist > cum[k + 1]) k++;
2573
+ const seg = segs[k];
2574
+ const local = dist - cum[k];
2575
+ const t = seg.len > 0 ? bezier2D_tForDistance(seg.lut, local) : 0;
2576
+ const [x, y] = bezier2D_pointAt(seg.P0, seg.P1, seg.P2, seg.P3, t);
2577
+ const [dx, dy] = bezier2D_derivativeAt(seg.P0, seg.P1, seg.P2, seg.P3, t);
2578
+ return { x, y, angle: Math.atan2(dy, dx) };
2579
+ };
2580
+ return {
2581
+ totalLength,
2582
+ closed,
2583
+ sampleAtDistance(dist) {
2584
+ if (!closed && (dist < 0 || dist > totalLength)) {
2585
+ const edge = dist < 0 ? 0 : totalLength;
2586
+ const p = sampleOn(edge);
2587
+ const over = dist - edge;
2588
+ return { x: p.x + Math.cos(p.angle) * over, y: p.y + Math.sin(p.angle) * over, angle: p.angle };
2589
+ }
2590
+ return sampleOn(clamp2(dist, 0, totalLength));
2591
+ }
2592
+ };
2593
+ }
2594
+
2595
+ // src/effects/textPathEffect.ts
2596
+ var EXTEND_MARGIN_FRAC = 0.15;
2597
+ function numRange(v) {
2598
+ if (typeof v === "number") return { min: v, max: v };
2599
+ if (v && typeof v === "object") {
2600
+ const o = v;
2601
+ if (typeof o.value === "number") return { min: o.value, max: o.value };
2602
+ if (Array.isArray(o.keyframes) && o.keyframes.length) {
2603
+ const vals = o.keyframes.map((k) => Number(k.value) || 0);
2604
+ return { min: Math.min(...vals), max: Math.max(...vals) };
2605
+ }
2606
+ }
2607
+ return { min: 0, max: 0 };
2608
+ }
2609
+ function estimateTextAdvance(node) {
2610
+ let chars = 0, maxFont = 16;
2611
+ const walk = (el) => {
2612
+ var _a, _b;
2613
+ const fs = parseFloat(String((_a = el.fontSize) != null ? _a : "")) || 0;
2614
+ if (fs) maxFont = Math.max(maxFont, fs);
2615
+ const t = (_b = el.text) != null ? _b : el.textContent;
2616
+ if (typeof t === "string") chars += t.length;
2617
+ if (el.children) for (const c of el.children) walk(c);
2618
+ };
2619
+ walk(node);
2620
+ return chars * maxFont;
2621
+ }
2622
+ var r3 = (n) => Math.round(n * 1e3) / 1e3;
2623
+ function shiftAnimatable(v, by) {
2624
+ if (!by || v === void 0 || v === null) return v;
2625
+ if (typeof v === "number") return v + by;
2626
+ const o = v;
2627
+ if (typeof o.value === "number") return __spreadProps(__spreadValues({}, o), { value: o.value + by });
2628
+ if (Array.isArray(o.keyframes)) return __spreadProps(__spreadValues({}, o), { keyframes: o.keyframes.map((k) => __spreadProps(__spreadValues({}, k), { value: (Number(k.value) || 0) + by })) });
2629
+ return v;
2630
+ }
2631
+ function extendedPathForBrowser(pathD, opts) {
2632
+ var _a;
2633
+ if (opts.pathOverflow === "clip") return { d: pathD, startShift: 0 };
2634
+ const sampler = createPathSampler(pathD);
2635
+ if (!sampler || sampler.closed || sampler.totalLength <= 0) return { d: pathD, startShift: 0 };
2636
+ const L = sampler.totalLength;
2637
+ const margin = EXTEND_MARGIN_FRAC * L;
2638
+ const so = numRange(opts.startOffset);
2639
+ const runWidth = numRange(opts.textLength).max || ((_a = opts.advance) != null ? _a : 0);
2640
+ const startOverflow = Math.max(0, -so.min);
2641
+ const endOverflow = Math.max(0, so.max + runWidth - L);
2642
+ const startExt = startOverflow > 0 ? startOverflow + margin : 0;
2643
+ const endExt = endOverflow > 0 ? endOverflow + margin : 0;
2644
+ if (endExt <= 0 && startExt <= 0) return { d: pathD, startShift: 0 };
2645
+ const s = sampler.sampleAtDistance(0);
2646
+ const e = sampler.sampleAtDistance(L);
2647
+ let d = pathD;
2648
+ if (startExt > 0) {
2649
+ const sx = s.x - Math.cos(s.angle) * startExt, sy = s.y - Math.sin(s.angle) * startExt;
2650
+ const rest = pathD.replace(/^\s*[Mm]\s*-?[\d.]+[\s,]+-?[\d.]+/, "");
2651
+ d = "M" + r3(sx) + "," + r3(sy) + "L" + r3(s.x) + "," + r3(s.y) + rest;
2652
+ }
2653
+ if (endExt > 0) {
2654
+ const ex = e.x + Math.cos(e.angle) * endExt, ey = e.y + Math.sin(e.angle) * endExt;
2655
+ d += "L" + r3(ex) + "," + r3(ey);
2656
+ }
2657
+ return { d, startShift: startExt };
2658
+ }
2659
+ function applyTextPathEffect(node, fx, ctx) {
2660
+ var _a;
2661
+ if (!fx || typeof fx.path !== "string" || !fx.path) return node;
2662
+ const pathId = genId(ctx, "tpath");
2663
+ const { d, startShift } = extendedPathForBrowser(fx.path, {
2664
+ pathOverflow: fx.pathOverflow,
2665
+ startOffset: fx.startOffset,
2666
+ textLength: fx.textLength,
2667
+ advance: estimateTextAdvance(node)
2668
+ });
2669
+ ctx.defs.push({ type: "path", id: pathId, d });
2670
+ const textPath = {
2671
+ type: "textPath",
2672
+ href: "#" + pathId,
2673
+ children: (_a = node.children) != null ? _a : []
2674
+ };
2675
+ if (fx.lengthAdjust !== void 0) textPath.lengthAdjust = fx.lengthAdjust;
2676
+ if (fx.method !== void 0) textPath.method = fx.method;
2677
+ if (fx.spacing !== void 0) textPath.spacing = fx.spacing;
2678
+ applyAnimatableNumber(textPath, "startOffset", shiftAnimatable(fx.startOffset, startShift));
2679
+ applyAnimatableNumber(textPath, "textLength", fx.textLength);
2680
+ node.children = [textPath];
2681
+ return node;
2682
+ }
2683
+ function applyAnimatableNumber(node, attrName, raw) {
2684
+ if (raw === void 0 || raw === null) return;
2685
+ if (typeof raw === "number") {
2686
+ node[attrName] = String(raw);
2687
+ return;
2688
+ }
2689
+ if (typeof raw === "object" && raw !== null) {
2690
+ const obj = raw;
2691
+ if (Array.isArray(obj.keyframes)) {
2692
+ const prevAnimate = node.animate && typeof node.animate === "object" && !Array.isArray(node.animate) ? node.animate : void 0;
2693
+ const animate = __spreadValues({}, prevAnimate || {});
2694
+ const block = { keyframes: obj.keyframes };
2695
+ if (obj.loop !== void 0) block.loop = obj.loop;
2696
+ animate[attrName] = block;
2697
+ node.animate = animate;
2698
+ return;
2699
+ }
2700
+ if (typeof obj.value === "number") {
2701
+ node[attrName] = String(obj.value);
2702
+ return;
2703
+ }
2704
+ }
2705
+ }
2706
+
2707
+ // src/effects/elementFactory.ts
2708
+ var jsonElementFactory = (type, props, children) => {
2709
+ const node = { type };
2710
+ for (const k in props) if (props[k] !== void 0) node[k] = props[k];
2711
+ const arr = Array.isArray(children) ? children.filter((c) => c != null) : children != null ? [children] : [];
2712
+ if (arr.length) node.children = arr;
2713
+ return node;
2714
+ };
2715
+
2716
+ // src/effects/glyphPathBake.ts
2717
+ function fmt(v, decimals) {
2718
+ return Math.round(v) === v ? "" + Math.round(v) : v.toFixed(decimals);
2719
+ }
2720
+ function pack(nums, decimals) {
2721
+ let s = "";
2722
+ for (let i = 0; i < nums.length; i++) {
2723
+ const str2 = fmt(nums[i], decimals);
2724
+ if (i > 0 && str2.charCodeAt(0) !== 45) s += " ";
2725
+ s += str2;
2726
+ }
2727
+ return s;
2728
+ }
2729
+ function apply(m, x, y) {
2730
+ return [m[0] * x + m[2] * y + m[4], m[1] * x + m[3] * y + m[5]];
2731
+ }
2732
+ var TOKEN_RE = /([MLCQZ])|(-?\d*\.?\d+(?:e[-+]?\d+)?)/gi;
2733
+ function transformPathData(d, m, decimals = 2) {
2734
+ const tokens = [];
2735
+ let match;
2736
+ TOKEN_RE.lastIndex = 0;
2737
+ while ((match = TOKEN_RE.exec(d)) !== null) tokens.push(match[0]);
2738
+ let out = "";
2739
+ let i = 0;
2740
+ const num2 = () => parseFloat(tokens[i++]);
2741
+ while (i < tokens.length) {
2742
+ const cmd = tokens[i++];
2743
+ if (cmd === "M" || cmd === "L") {
2744
+ const [x, y] = apply(m, num2(), num2());
2745
+ out += cmd + pack([x, y], decimals);
2746
+ } else if (cmd === "C") {
2747
+ const [x1, y1] = apply(m, num2(), num2());
2748
+ const [x2, y2] = apply(m, num2(), num2());
2749
+ const [x, y] = apply(m, num2(), num2());
2750
+ out += "C" + pack([x1, y1, x2, y2, x, y], decimals);
2751
+ } else if (cmd === "Q") {
2752
+ const [x1, y1] = apply(m, num2(), num2());
2753
+ const [x, y] = apply(m, num2(), num2());
2754
+ out += "Q" + pack([x1, y1, x, y], decimals);
2755
+ } else if (cmd === "Z" || cmd === "z") {
2756
+ out += "Z";
2757
+ }
2758
+ }
2759
+ return out;
2760
+ }
2761
+
2762
+ // src/effects/textGlyphsEffect.ts
2763
+ var DEFAULT_FONT_SIZE = 16;
2764
+ var TEXT_ATTR_KEYS = [
2765
+ "fontFamily",
2766
+ "fontSize",
2767
+ "fontWeight",
2768
+ "fontStyle",
2769
+ "textAnchor",
2770
+ "letterSpacing",
2771
+ "wordSpacing",
2772
+ "textDecoration",
2773
+ "textTransform",
2774
+ "whiteSpace",
2775
+ "x",
2776
+ "y",
2777
+ "dx",
2778
+ "dy",
2779
+ "lengthAdjust",
2780
+ "fill",
2781
+ "stroke",
2782
+ "strokeWidth",
2783
+ "effects",
2784
+ TEXT_ATTR,
2785
+ TEXT_CONTENT_ATTR,
2786
+ "xml:space"
2787
+ ];
2788
+ function parseLen(v) {
2789
+ if (typeof v === "number") return v;
2790
+ if (typeof v === "string") {
2791
+ const n = parseFloat(v);
2792
+ return isNaN(n) ? void 0 : n;
2793
+ }
2794
+ return void 0;
2795
+ }
2796
+ function str(v) {
2797
+ return typeof v === "string" ? v : void 0;
2798
+ }
2799
+ function resolveStyle(node, parent) {
2800
+ var _a, _b, _c, _d, _e, _f, _g;
2801
+ return {
2802
+ fontFamily: (_a = str(node.fontFamily)) != null ? _a : parent.fontFamily,
2803
+ fontSize: (_b = parseLen(node.fontSize)) != null ? _b : parent.fontSize,
2804
+ fill: (_c = node.fill) != null ? _c : parent.fill,
2805
+ stroke: (_d = node.stroke) != null ? _d : parent.stroke,
2806
+ strokeWidth: (_e = node.strokeWidth) != null ? _e : parent.strokeWidth,
2807
+ letterSpacing: (_f = parseLen(node.letterSpacing)) != null ? _f : parent.letterSpacing,
2808
+ wordSpacing: (_g = parseLen(node.wordSpacing)) != null ? _g : parent.wordSpacing
2809
+ };
2810
+ }
2811
+ function rootStyleOf(node) {
2812
+ var _a, _b, _c;
2813
+ return {
2814
+ fontFamily: str(node.fontFamily),
2815
+ fontSize: (_a = parseLen(node.fontSize)) != null ? _a : DEFAULT_FONT_SIZE,
2816
+ fill: node.fill,
2817
+ stroke: node.stroke,
2818
+ strokeWidth: node.strokeWidth,
2819
+ letterSpacing: (_b = parseLen(node.letterSpacing)) != null ? _b : 0,
2820
+ wordSpacing: (_c = parseLen(node.wordSpacing)) != null ? _c : 0
2821
+ };
2822
+ }
2823
+ function paintOf(s) {
2824
+ const p = {};
2825
+ if (s.fill !== void 0) p.fill = s.fill;
2826
+ if (s.stroke !== void 0) p.stroke = s.stroke;
2827
+ if (s.strokeWidth !== void 0) p.strokeWidth = s.strokeWidth;
2828
+ return p;
2829
+ }
2830
+ function glyphFontFor(s, glyphs, soleFont, warnings) {
2831
+ var _a;
2832
+ const gf = s.fontFamily ? glyphs[s.fontFamily] : soleFont;
2833
+ if (!gf) warnings == null ? void 0 : warnings.push('textGlyphs: no glyphs for font "' + ((_a = s.fontFamily) != null ? _a : "") + '"');
2834
+ return gf;
2835
+ }
2836
+ function soleFontOf(glyphs) {
2837
+ const names = Object.keys(glyphs);
2838
+ return names.length === 1 ? glyphs[names[0]] : void 0;
2839
+ }
2840
+ function materialiseGlyphTextHorizontal(node, opts) {
2841
+ var _a, _b, _c, _d;
2842
+ const { glyphs, create = jsonElementFactory, warnings } = opts;
2843
+ const soleFont = soleFontOf(glyphs);
2844
+ const pen = { x: (_a = parseLen(node.x)) != null ? _a : 0, y: (_b = parseLen(node.y)) != null ? _b : 0 };
2845
+ const placements = [];
2846
+ const lines = [{ start: pen.x, end: pen.x }];
2847
+ let line = 0;
2848
+ const renderChars = (content, s) => {
2849
+ const gf = glyphFontFor(s, glyphs, soleFont, warnings);
2850
+ if (!gf) return;
2851
+ const scale = s.fontSize / gf.unitsPerEm;
2852
+ const paint = paintOf(s);
2853
+ for (let i = 0; i < content.length; i++) {
2854
+ 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);
2858
+ lines[line].end = pen.x;
2859
+ }
2860
+ };
2861
+ const walk = (el, parentStyle) => {
2862
+ var _a2, _b2, _c2, _d2;
2863
+ const s = resolveStyle(el, parentStyle);
2864
+ const x = parseLen(el.x);
2865
+ const y = parseLen(el.y);
2866
+ if (x !== void 0) {
2867
+ pen.x = x;
2868
+ line = lines.length;
2869
+ lines.push({ start: pen.x, end: pen.x });
2870
+ }
2871
+ if (y !== void 0) pen.y = y;
2872
+ pen.x += (_a2 = parseLen(el.dx)) != null ? _a2 : 0;
2873
+ pen.y += (_b2 = parseLen(el.dy)) != null ? _b2 : 0;
2874
+ const content = (_c2 = str(el[TEXT_ATTR])) != null ? _c2 : str(el[TEXT_CONTENT_ATTR]);
2875
+ if (content && !((_d2 = el.children) == null ? void 0 : _d2.length)) renderChars(content, s);
2876
+ if (el.children) for (const ch of el.children) walk(ch, s);
2877
+ };
2878
+ const rootStyle = rootStyleOf(node);
2879
+ if (node.children) for (const ch of node.children) walk(ch, rootStyle);
2880
+ const rootContent = (_c = str(node[TEXT_ATTR])) != null ? _c : str(node[TEXT_CONTENT_ATTR]);
2881
+ if (rootContent && !((_d = node.children) == null ? void 0 : _d.length)) renderChars(rootContent, rootStyle);
2882
+ const anchor = str(node.textAnchor);
2883
+ if (anchor === "middle" || anchor === "end") {
2884
+ for (const p of placements) {
2885
+ const w = lines[p.line].end - lines[p.line].start;
2886
+ const shift = anchor === "middle" ? -w / 2 : -w;
2887
+ p.m = [p.scale, 0, 0, p.scale, p.x + shift, p.y];
2888
+ }
2889
+ }
2890
+ return toGroup(node, buildPaths(placements, create, warnings), create);
2891
+ }
2892
+ function collectAlongPathCells(node, glyphs, soleFont, warnings) {
2893
+ const cells = [];
2894
+ let adv = 0;
2895
+ const walk = (el, parentStyle) => {
2896
+ var _a, _b;
2897
+ const s = resolveStyle(el, parentStyle);
2898
+ const content = (_a = str(el[TEXT_ATTR])) != null ? _a : str(el[TEXT_CONTENT_ATTR]);
2899
+ if (content && !((_b = el.children) == null ? void 0 : _b.length)) {
2900
+ const gf = glyphFontFor(s, glyphs, soleFont, warnings);
2901
+ if (gf) {
2902
+ const scale = s.fontSize / gf.unitsPerEm;
2903
+ const paint = paintOf(s);
2904
+ for (let i = 0; i < content.length; i++) {
2905
+ const ch = content.charAt(i);
2906
+ 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);
2910
+ }
2911
+ }
2912
+ }
2913
+ if (el.children) for (const ch of el.children) walk(ch, s);
2914
+ };
2915
+ walk(node, rootStyleOf(node));
2916
+ return { cells, width: adv };
2917
+ }
2918
+ function alongAffine(sampler, dist, scale, widthEm) {
2919
+ const { x, y, angle } = sampler.sampleAtDistance(dist);
2920
+ 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];
2922
+ }
2923
+ function materialiseGlyphTextAlongPath(node, pathD, startOffset, opts, textLength, pathOverflow) {
2924
+ var _a;
2925
+ const { glyphs, create = jsonElementFactory, warnings } = opts;
2926
+ const sampler = pathD ? createPathSampler(pathD) : null;
2927
+ if (!sampler) {
2928
+ warnings == null ? void 0 : warnings.push("textGlyphs: unparsable along-path geometry");
2929
+ return null;
2930
+ }
2931
+ const soleFont = soleFontOf(glyphs);
2932
+ const { cells, width } = collectAlongPathCells(node, glyphs, soleFont, warnings);
2933
+ if (!cells.length) return toGroup(node, [], create);
2934
+ if (textLength && textLength > 0 && width > 0) {
2935
+ const k = textLength / width;
2936
+ for (const c of cells) c.midBase *= k;
2937
+ }
2938
+ const isClip = pathOverflow === "clip" && !sampler.closed;
2939
+ const so = readAnimatable(startOffset);
2940
+ if (so.kind === "animated" /* Animated */ && so.keyframes.length >= 2) {
2941
+ return toGroup(node, buildAnimatedAlongPath(cells, sampler, so.keyframes, so.loop, create, isClip), create);
2942
+ }
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;
2944
+ const placeCells = isClip ? cells.filter((c) => {
2945
+ const d = base + c.midBase;
2946
+ return d >= 0 && d <= sampler.totalLength;
2947
+ }) : cells;
2948
+ const placements = placeCells.map((c) => ({
2949
+ glyphD: c.glyphD,
2950
+ paint: c.paint,
2951
+ m: alongAffine(sampler, base + c.midBase, c.scale, c.widthEm)
2952
+ }));
2953
+ return toGroup(node, buildPaths(placements, create, warnings), create);
2954
+ }
2955
+ var ALONG_PATH_MAX_STEPS = 48;
2956
+ var ALONG_PATH_MAX_STEPS_PER_SEGMENT = 64;
2957
+ function roundN(v, n) {
2958
+ const f = __pow(10, n);
2959
+ return Math.round(v * f) / f;
2960
+ }
2961
+ function buildAnimatedAlongPath(cells, sampler, sokfs, loop, create, isClip) {
2962
+ const step = Math.max(sampler.totalLength / ALONG_PATH_MAX_STEPS, 0.5);
2963
+ const timeOf = (kf) => Number(kf.time) || 0;
2964
+ const offOf = (kf) => Number(kf.value) || 0;
2965
+ const onPath = (dist) => dist >= 0 && dist <= sampler.totalLength;
2966
+ const out = [];
2967
+ for (const c of cells) {
2968
+ const centred = [c.scale, 0, 0, c.scale, -c.scale * (c.widthEm / 2), 0];
2969
+ const d = transformPathData(c.glyphD, centred);
2970
+ const sampleKf = (dist, time) => {
2971
+ const { x, y, angle } = sampler.sampleAtDistance(dist);
2972
+ return {
2973
+ time,
2974
+ value: {
2975
+ ["translate" /* Translate */]: [roundN(x, 3), roundN(y, 3)],
2976
+ ["rotate" /* Rotate */]: roundN(angle * 180 / Math.PI, 3)
2977
+ }
2978
+ };
2979
+ };
2980
+ const kfs = [];
2981
+ const opKfs = [];
2982
+ const pushKf = (dist, time) => {
2983
+ kfs.push(sampleKf(dist, time));
2984
+ if (isClip) opKfs.push({ time, value: onPath(dist) ? 1 : 0 });
2985
+ };
2986
+ pushKf(offOf(sokfs[0]) + c.midBase, timeOf(sokfs[0]));
2987
+ for (let k = 1; k < sokfs.length; k++) {
2988
+ const t0 = timeOf(sokfs[k - 1]), t1 = timeOf(sokfs[k]);
2989
+ const o0 = offOf(sokfs[k - 1]), o1 = offOf(sokfs[k]);
2990
+ const n = Math.min(ALONG_PATH_MAX_STEPS_PER_SEGMENT, Math.max(1, Math.ceil(Math.abs(o1 - o0) / step)));
2991
+ for (let s = 1; s <= n; s++) {
2992
+ const f = s / n;
2993
+ pushKf(o0 + f * (o1 - o0) + c.midBase, t0 + f * (t1 - t0));
2994
+ }
2995
+ }
2996
+ const transform = { keyframes: kfs };
2997
+ if (loop !== void 0) transform.loop = loop;
2998
+ const animate = { transform };
2999
+ if (isClip && opKfs.some((k) => k.value === 0)) {
3000
+ const op = { keyframes: opKfs };
3001
+ if (loop !== void 0) op.loop = loop;
3002
+ animate.opacity = op;
3003
+ }
3004
+ out.push(create("path", __spreadProps(__spreadValues({ d }, paintProps(c.paint)), { animate }), []));
3005
+ }
3006
+ return out;
3007
+ }
3008
+ function paintProps(paint) {
3009
+ const p = {};
3010
+ if (paint.fill !== void 0) p.fill = paint.fill;
3011
+ if (paint.stroke !== void 0) p.stroke = paint.stroke;
3012
+ if (paint.strokeWidth !== void 0) p.strokeWidth = paint.strokeWidth;
3013
+ return p;
3014
+ }
3015
+ function buildPaths(placements, create, warnings) {
3016
+ var _a, _b, _c;
3017
+ if (!placements.length) {
3018
+ warnings == null ? void 0 : warnings.push("textGlyphs: nothing to render");
3019
+ return [];
3020
+ }
3021
+ const byPaint = /* @__PURE__ */ new Map();
3022
+ for (const p of placements) {
3023
+ const key = JSON.stringify([(_a = p.paint.fill) != null ? _a : null, (_b = p.paint.stroke) != null ? _b : null, (_c = p.paint.strokeWidth) != null ? _c : null]);
3024
+ const baked = transformPathData(p.glyphD, p.m);
3025
+ const entry = byPaint.get(key);
3026
+ if (entry) entry.d += baked;
3027
+ else byPaint.set(key, { paint: p.paint, d: baked });
3028
+ }
3029
+ const out = [];
3030
+ for (const { paint, d } of byPaint.values()) out.push(create("path", __spreadValues({ d }, paintProps(paint)), []));
3031
+ return out;
3032
+ }
3033
+ function toGroup(node, children, create) {
3034
+ const gProps = {};
3035
+ for (const k of Object.keys(node)) {
3036
+ if (k === "type" || k === "children" || TEXT_ATTR_KEYS.indexOf(k) !== -1) continue;
3037
+ gProps[k] = node[k];
3038
+ }
3039
+ if (gProps.style && typeof gProps.style === "object") {
3040
+ const style = __spreadValues({}, gProps.style);
3041
+ delete style["white-space"];
3042
+ if (Object.keys(style).length) gProps.style = style;
3043
+ else delete gProps.style;
3044
+ }
3045
+ return create("g", gProps, children);
3046
+ }
3047
+ function materialiseGlyphText(node, opts) {
3048
+ if (opts.alongPath) return materialiseGlyphTextAlongPath(node, opts.alongPath.pathD, opts.alongPath.startOffset, opts, opts.alongPath.textLength, opts.alongPath.pathOverflow);
3049
+ return materialiseGlyphTextHorizontal(node, opts);
3050
+ }
3051
+ function applyTextGlyphsEffect(node, fx, ctx) {
3052
+ if (!(fx == null ? void 0 : fx.useGlyphs)) return node;
3053
+ if (!ctx.glyphs) {
3054
+ ctx.warnings.push("textGlyphs: no definitions.glyphs \u2014 left as native <text>");
3055
+ return node;
3056
+ }
3057
+ return materialiseGlyphTextHorizontal(node, { glyphs: ctx.glyphs, warnings: ctx.warnings });
3058
+ }
3059
+ function applyTextGlyphsAlongPath(node, ctx, pathD, startOffset, textLength, pathOverflow) {
3060
+ if (!ctx.glyphs) {
3061
+ ctx.warnings.push("textGlyphs: no definitions.glyphs");
3062
+ return null;
3063
+ }
3064
+ return materialiseGlyphTextAlongPath(node, pathD, startOffset, { glyphs: ctx.glyphs, warnings: ctx.warnings }, textLength, pathOverflow);
3065
+ }
3066
+
2449
3067
  // src/PxMotionPath.ts
2450
3068
  function getKfTranslate(kf) {
2451
3069
  var _a;
@@ -2889,12 +3507,12 @@ function parseSvgPathToBezier(d) {
2889
3507
  }
2890
3508
  return res;
2891
3509
  }
2892
- function extractPathData(str) {
2893
- if (str.startsWith("path(") && str.endsWith(")")) {
2894
- return str.slice(5, -1);
3510
+ function extractPathData(str2) {
3511
+ if (str2.startsWith("path(") && str2.endsWith(")")) {
3512
+ return str2.slice(5, -1);
2895
3513
  }
2896
- if (/^[MmZzLlHhVvCcSsQqTtAa]/.test(str)) {
2897
- return str;
3514
+ if (/^[MmZzLlHhVvCcSsQqTtAa]/.test(str2)) {
3515
+ return str2;
2898
3516
  }
2899
3517
  return void 0;
2900
3518
  }
@@ -3819,7 +4437,7 @@ function rectToPathD(node) {
3819
4437
 
3820
4438
  // src/effects/PlayerEffectsUtil.ts
3821
4439
  function applyPlayerEffects(root) {
3822
- var _a;
4440
+ var _a, _b;
3823
4441
  const ctx = {
3824
4442
  defs: [],
3825
4443
  warnings: [],
@@ -3830,7 +4448,8 @@ function applyPlayerEffects(root) {
3830
4448
  maskAncestorChains: /* @__PURE__ */ new Map(),
3831
4449
  // Resolved engine: `frames` ONLY when explicitly set; auto/webapi/unset →
3832
4450
  // webapi (we're not 100% sure it's frames, and CSS/WAAPI need the inline form).
3833
- engine: ((_a = getAnimatorConfig(root)) == null ? void 0 : _a.mode) === PxAnimatorMode.frames ? PxAnimatorEngine.frames : PxAnimatorEngine.webapi
4451
+ engine: ((_a = getAnimatorConfig(root)) == null ? void 0 : _a.mode) === PxAnimatorMode.frames ? PxAnimatorEngine.frames : PxAnimatorEngine.webapi,
4452
+ glyphs: (_b = getDefs(root)) == null ? void 0 : _b.glyphs
3834
4453
  };
3835
4454
  const working = clone(root);
3836
4455
  indexById(working, ctx.idMap);
@@ -3842,16 +4461,33 @@ function applyPlayerEffects(root) {
3842
4461
  return { root: out, defs: ctx.defs, warnings: ctx.warnings, errors: ctx.errors };
3843
4462
  }
3844
4463
  function applyPlayerEffects_exceptRetime(node, ctx) {
4464
+ var _a;
3845
4465
  if (node.children) node.children = node.children.map((child) => applyPlayerEffects_exceptRetime(child, ctx));
3846
4466
  const fx = node.effects;
3847
4467
  const originalId = typeof node.id === "string" ? node.id : void 0;
3848
4468
  const innerIdForContentRef = originalId ? ctx.contentRefInnerIds.get(originalId) : void 0;
3849
4469
  if (!fx && !innerIdForContentRef) return node;
3850
- const { transformation, repeater, maskedBy, trimPath, clone: cloneFx, fillGradient, strokeGradient, textAlongPath } = fx != null ? fx : {};
4470
+ const { transformation, repeater, maskedBy, trimPath, clone: cloneFx, fillGradient, strokeGradient, textPath, text } = fx != null ? fx : {};
3851
4471
  const isCombinedShape = fx == null ? void 0 : fx.isCombinedShape;
3852
4472
  if (fx) delete node.effects;
3853
4473
  let n = node;
3854
- n = applyTextAlongPathEffect(n, textAlongPath, ctx);
4474
+ let consumedByGlyphs = false;
4475
+ if (text == null ? void 0 : text.useGlyphs) {
4476
+ if (textPath) {
4477
+ const pathD = typeof textPath.path === "string" ? textPath.path : void 0;
4478
+ const rawTL = textPath.textLength;
4479
+ const textLength = typeof rawTL === "number" ? rawTL : rawTL && typeof rawTL === "object" ? typeof rawTL.value === "number" ? rawTL.value : Array.isArray(rawTL.keyframes) && rawTL.keyframes.length ? Number((_a = rawTL.keyframes[0]) == null ? void 0 : _a.value) : void 0 : void 0;
4480
+ const glyphed = applyTextGlyphsAlongPath(n, ctx, pathD, textPath.startOffset, textLength, textPath.pathOverflow);
4481
+ if (glyphed) {
4482
+ n = glyphed;
4483
+ consumedByGlyphs = true;
4484
+ }
4485
+ } else {
4486
+ n = applyTextGlyphsEffect(n, text, ctx);
4487
+ consumedByGlyphs = true;
4488
+ }
4489
+ }
4490
+ if (!consumedByGlyphs) n = applyTextPathEffect(n, textPath, ctx);
3855
4491
  n = applyFillGradientEffect(n, fillGradient, ctx);
3856
4492
  n = applyStrokeGradientEffect(n, strokeGradient, ctx);
3857
4493
  n = applyTrimPathEffect(n, trimPath, isCombinedShape, ctx);
@@ -4094,8 +4730,8 @@ var DATA_RASTER_IMAGE_RE = /^data:image\/(?:png|jpe?g|gif|webp|bmp);base64,/i;
4094
4730
  var DATA_SVG_IMAGE_RE = /^data:image\/svg\+xml(?:;[^,]*)?,/i;
4095
4731
  var DATA_IMAGE_BASE64_PAYLOAD_RE = /^data:image\/[^;,]*;base64,([A-Za-z0-9+/]{8})/i;
4096
4732
  var BASE64_RASTER_MAGICS = ["iVBORw0K", "/9j/", "R0lGOD", "UklGR", "Qk"];
4097
- function isContentSniffedRasterImage(str) {
4098
- const m = DATA_IMAGE_BASE64_PAYLOAD_RE.exec(str);
4733
+ function isContentSniffedRasterImage(str2) {
4734
+ const m = DATA_IMAGE_BASE64_PAYLOAD_RE.exec(str2);
4099
4735
  return !!m && BASE64_RASTER_MAGICS.some((magic) => m[1].startsWith(magic));
4100
4736
  }
4101
4737
  function isDangerousAttrName(nameLower) {
@@ -4109,18 +4745,18 @@ function sanitiseAttributeValue(name, value) {
4109
4745
  return void 0;
4110
4746
  }
4111
4747
  if (nameLower === "fill" || nameLower === "stroke" || nameLower === "stopcolor") {
4112
- const str = String(value);
4113
- if (str.includes("url(") && !/^url\(#[^)]+\)$/.test(str)) {
4748
+ const str2 = String(value);
4749
+ if (str2.includes("url(") && !/^url\(#[^)]+\)$/.test(str2)) {
4114
4750
  console.warn('Attribute "' + nameLower + '" blocked: url() must be internal url(#id), got:', value);
4115
4751
  return void 0;
4116
4752
  }
4117
4753
  return value;
4118
4754
  }
4119
4755
  if (URL_VALUE_ATTRS_LOWER.has(nameLower)) {
4120
- const str = String(value);
4121
- if (str.startsWith("#")) return value;
4122
- if (/^url\(#[^)]+\)$/.test(str)) return value;
4123
- if (IMAGE_REF_ATTRS_LOWER.has(nameLower) && (DATA_RASTER_IMAGE_RE.test(str) || DATA_SVG_IMAGE_RE.test(str) || isContentSniffedRasterImage(str))) return value;
4756
+ const str2 = String(value);
4757
+ if (str2.startsWith("#")) return value;
4758
+ if (/^url\(#[^)]+\)$/.test(str2)) return value;
4759
+ if (IMAGE_REF_ATTRS_LOWER.has(nameLower) && (DATA_RASTER_IMAGE_RE.test(str2) || DATA_SVG_IMAGE_RE.test(str2) || isContentSniffedRasterImage(str2))) return value;
4124
4760
  console.warn('Attribute "' + nameLower + '" blocked: must be #id, url(#id), or data:image/\u2026 URI, got:', value);
4125
4761
  return void 0;
4126
4762
  }
@@ -4150,7 +4786,7 @@ function createElement(tagName, normalisedProps, style, children, textContent) {
4150
4786
  if (textContent) element.textContent = textContent;
4151
4787
  return element;
4152
4788
  }
4153
- function resolveStyle(style, defs) {
4789
+ function resolveStyle2(style, defs) {
4154
4790
  var _a;
4155
4791
  if (!style) return void 0;
4156
4792
  if (typeof style === "string") {
@@ -4186,7 +4822,7 @@ function renderNode(node, defs) {
4186
4822
  if (!node) return null;
4187
4823
  const _a = node, { type, children, style } = _a, props = __objRest(_a, ["type", "children", "style"]);
4188
4824
  const nodeDefs = getDefs(node) || defs;
4189
- const resolvedStyle = resolveStyle(style, nodeDefs);
4825
+ const resolvedStyle = resolveStyle2(style, nodeDefs);
4190
4826
  let childElements;
4191
4827
  if (children) {
4192
4828
  for (const ch of children) {
@@ -5239,7 +5875,8 @@ function subtractMultiset(a, b) {
5239
5875
  PxRetimeEffectSchema,
5240
5876
  PxStrokeGradientEffectSchema,
5241
5877
  PxSvgNodeExtra,
5242
- PxTextAlongPathEffectSchema,
5878
+ PxTextEffectSchema,
5879
+ PxTextPathEffectSchema,
5243
5880
  PxTransformPartsSchema,
5244
5881
  PxTransformValueSchema,
5245
5882
  PxTransformationEffectSchema,
@@ -5259,6 +5896,7 @@ function subtractMultiset(a, b) {
5259
5896
  describeSchema,
5260
5897
  diffInEffect,
5261
5898
  evaluateMotionPathSegment,
5899
+ extendedPathForBrowser,
5262
5900
  generateNewIds,
5263
5901
  getAnimatorConfig,
5264
5902
  getBindings,
@@ -5267,9 +5905,13 @@ function subtractMultiset(a, b) {
5267
5905
  getNormalizedProps,
5268
5906
  isPxElementFileFormat,
5269
5907
  isPxElementFileFormatDeep,
5908
+ jsonElementFactory,
5270
5909
  loadTagAnimators,
5271
5910
  materialiseAllInTree,
5272
5911
  materialiseAnimatedUseInstances,
5912
+ materialiseGlyphText,
5913
+ materialiseGlyphTextAlongPath,
5914
+ materialiseGlyphTextHorizontal,
5273
5915
  materialiseInternalLoopsInPropAnim,
5274
5916
  materialiseInternalLoopsInTree,
5275
5917
  materialiseMotionPathInPropAnim,
@@ -5280,6 +5922,7 @@ function subtractMultiset(a, b) {
5280
5922
  renderNode,
5281
5923
  schemaKeys,
5282
5924
  setupAnimationTriggers,
5925
+ shiftAnimatable,
5283
5926
  toRGBA,
5284
5927
  validateNodeEffects,
5285
5928
  visualModelAt