@pixodesk/svg-animator-core 1.0.24 → 1.0.26

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
@@ -55,6 +55,8 @@ __export(index_exports, {
55
55
  DEFAULT_DURATION_MS: () => DEFAULT_DURATION_MS,
56
56
  DISALLOWED_SVG_TAGS_LOWER: () => DISALLOWED_SVG_TAGS_LOWER,
57
57
  INTERNAL_ATTRS: () => INTERNAL_ATTRS,
58
+ LOOP_JUMP_SHIFT_MS: () => LOOP_JUMP_SHIFT_MS,
59
+ PCT_BASED_ATTR_NAMES: () => PCT_BASED_ATTR_NAMES,
58
60
  PX_ANIM_ATTR_NAME: () => PX_ANIM_ATTR_NAME,
59
61
  PX_ANIM_SRC_ATTR_NAME: () => PX_ANIM_SRC_ATTR_NAME,
60
62
  PX_TRANSFORM_PART_KEYS: () => PX_TRANSFORM_PART_KEYS,
@@ -1005,8 +1007,10 @@ var PxNodeSchema = px.openObject(__spreadProps(__spreadValues({}, PxNodeBase._sh
1005
1007
  children: px.lazy(() => px.array(PxNodeSchema), []).optional()
1006
1008
  }), PxAttrValueSchema);
1007
1009
  var PxSvgNodeExtra = px.object({
1008
- width: px.number().optional(),
1009
- height: px.number().optional(),
1010
+ // `"100%"` and other SVG length strings are legal here — a number-only slot rejected
1011
+ // real documents (e.g. apple-store-look-14-main.json) at the root <svg>.
1012
+ width: px.union([px.number(), px.string()]).optional(),
1013
+ height: px.union([px.number(), px.string()]).optional(),
1010
1014
  viewBox: px.string().optional(),
1011
1015
  animator: PxAnimatorConfigSchema.optional()
1012
1016
  });
@@ -2049,7 +2053,7 @@ function walkAndMaterialise(node, opts) {
2049
2053
  }
2050
2054
 
2051
2055
  // src/PxDefinitions.ts
2052
- var LOOP_JUMP_SHIFT_MS = 10;
2056
+ var LOOP_JUMP_SHIFT_MS = 1;
2053
2057
  function deepEqualValue(a, b) {
2054
2058
  if (a === b) return true;
2055
2059
  if (typeof a !== typeof b || a === null || b === null || typeof a !== "object") return false;
@@ -2298,6 +2302,8 @@ function expandLoopKeyframes(propName, keyframes, loop, duration) {
2298
2302
  const looped = [];
2299
2303
  const separateBoundary = loop.extend !== PxLoopExtend.before;
2300
2304
  const originalTerminalKf = keyframes[keyframes.length - 1];
2305
+ let terminalEasingOverride;
2306
+ let hasTerminalEasingOverride = false;
2301
2307
  function appendRep(repStart, isReversed, partial) {
2302
2308
  var _a2;
2303
2309
  let entries;
@@ -2338,7 +2344,16 @@ function expandLoopKeyframes(propName, keyframes, loop, duration) {
2338
2344
  const prevKf = looped.length > 0 ? looped[looped.length - 1] : originalTerminalKf;
2339
2345
  const isBoundary = separateBoundary && i === 0 && prevKf !== void 0 && Math.abs(((_a2 = prevKf.t) != null ? _a2 : 0) - (repStart + entry.relT * segDuration)) < 1e-9;
2340
2346
  if (isBoundary) {
2341
- if (deepEqualValue(prevKf.v, entry.v)) continue;
2347
+ if (deepEqualValue(prevKf.v, entry.v)) {
2348
+ if (looped.length > 0) {
2349
+ prevKf.e = entry.e;
2350
+ prevKf.tangentOut = entry.tangentOut;
2351
+ } else {
2352
+ terminalEasingOverride = entry.e;
2353
+ hasTerminalEasingOverride = true;
2354
+ }
2355
+ continue;
2356
+ }
2342
2357
  if (looped.length > 0) {
2343
2358
  delete prevKf.tangentIn;
2344
2359
  delete prevKf.tangentOut;
@@ -2419,6 +2434,11 @@ function expandLoopKeyframes(propName, keyframes, loop, duration) {
2419
2434
  if (loop.extend === PxLoopExtend.before) {
2420
2435
  return [...looped, ...keyframes];
2421
2436
  } else {
2437
+ if (hasTerminalEasingOverride && keyframes.length > 0) {
2438
+ const head = keyframes.slice(0, -1);
2439
+ const tail = __spreadProps(__spreadValues({}, keyframes[keyframes.length - 1]), { e: terminalEasingOverride });
2440
+ return [...head, tail, ...looped];
2441
+ }
2422
2442
  return [...keyframes, ...looped];
2423
2443
  }
2424
2444
  }
@@ -2535,6 +2555,9 @@ function generateElementId() {
2535
2555
  function normalizeAnimationDefinition(animDef, duration, defs, engine = PxAnimatorEngine.waapi) {
2536
2556
  const normalized = {};
2537
2557
  for (const [propName, propAnim] of Object.entries(animDef)) {
2558
+ if (propName === "transform" && propAnim.alongPathMode === "offsetPath" && animDef["offsetDistance"] !== void 0) {
2559
+ continue;
2560
+ }
2538
2561
  const normalizedKfs = normalizeKeyframes(propName, propAnim, duration, defs);
2539
2562
  if (normalizedKfs.length > 0) {
2540
2563
  const out = { kfs: normalizedKfs };
@@ -5376,10 +5399,141 @@ function applyPlayerEffects_retime(node, ctx) {
5376
5399
  return node;
5377
5400
  }
5378
5401
 
5402
+ // src/PxOffsetPathMaterialiser.ts
5403
+ var kfTime = (kf) => {
5404
+ var _a, _b;
5405
+ return (_b = (_a = kf.t) != null ? _a : kf.time) != null ? _b : 0;
5406
+ };
5407
+ var kfValue = (kf) => {
5408
+ var _a;
5409
+ return (_a = kf.v) != null ? _a : kf.value;
5410
+ };
5411
+ var kfEasing = (kf) => {
5412
+ var _a;
5413
+ return (_a = kf.e) != null ? _a : kf.easing;
5414
+ };
5415
+ var kfTangentIn = (kf) => {
5416
+ var _a;
5417
+ return (_a = kf.tangentIn) != null ? _a : kf.ti;
5418
+ };
5419
+ var kfTangentOut = (kf) => {
5420
+ var _a;
5421
+ return (_a = kf.tangentOut) != null ? _a : kf.to;
5422
+ };
5423
+ function cubicAt(p0, c1, c2, p1, t) {
5424
+ const u = 1 - t;
5425
+ const a = u * u * u, b = 3 * u * u * t, c = 3 * u * t * t, d = t * t * t;
5426
+ return [
5427
+ a * p0[0] + b * c1[0] + c * c2[0] + d * p1[0],
5428
+ a * p0[1] + b * c1[1] + c * c2[1] + d * p1[1]
5429
+ ];
5430
+ }
5431
+ function cubicLength(p0, c1, c2, p1, steps = 64) {
5432
+ let len = 0;
5433
+ let prev = p0;
5434
+ for (let i = 1; i <= steps; i++) {
5435
+ const pt = cubicAt(p0, c1, c2, p1, i / steps);
5436
+ len += Math.hypot(pt[0] - prev[0], pt[1] - prev[1]);
5437
+ prev = pt;
5438
+ }
5439
+ return len;
5440
+ }
5441
+ var fmt2 = (n) => {
5442
+ const r = Math.round(n * 1e4) / 1e4;
5443
+ return Object.is(r, -0) ? "0" : String(r);
5444
+ };
5445
+ function buildOffsetPath(propAnim) {
5446
+ var _a, _b, _c, _d;
5447
+ if (propAnim.alongPathMode !== "offsetPath") return void 0;
5448
+ const kfs = (_a = propAnim.keyframes) != null ? _a : propAnim.kfs;
5449
+ if (!kfs || kfs.length < 2) return void 0;
5450
+ const first = kfValue(kfs[0]);
5451
+ const anchor = (first == null ? void 0 : first.origin) && first.origin.length >= 2 ? [first.origin[0], first.origin[1]] : [0, 0];
5452
+ const points = [];
5453
+ for (const kf of kfs) {
5454
+ const v = kfValue(kf);
5455
+ const tr = v == null ? void 0 : v.translate;
5456
+ if (!tr || tr.length < 2) return void 0;
5457
+ const parts = Object.keys(v);
5458
+ if (parts.some((p) => p !== "translate" && p !== "origin")) return void 0;
5459
+ const o = (_b = v == null ? void 0 : v.origin) != null ? _b : [0, 0];
5460
+ if (o[0] !== anchor[0] || o[1] !== anchor[1]) return void 0;
5461
+ points.push([tr[0] + anchor[0], tr[1] + anchor[1]]);
5462
+ }
5463
+ if (!kfs.some((kf) => kfTangentIn(kf) || kfTangentOut(kf))) return void 0;
5464
+ let d = "M" + fmt2(points[0][0]) + "," + fmt2(points[0][1]);
5465
+ const segLens = [];
5466
+ for (let i = 0; i < points.length - 1; i++) {
5467
+ const p0 = points[i], p1 = points[i + 1];
5468
+ const to = (_c = kfTangentOut(kfs[i])) != null ? _c : [0, 0];
5469
+ const ti = (_d = kfTangentIn(kfs[i + 1])) != null ? _d : [0, 0];
5470
+ const c1 = [p0[0] + to[0], p0[1] + to[1]];
5471
+ const c2 = [p1[0] + ti[0], p1[1] + ti[1]];
5472
+ d += "C" + fmt2(c1[0]) + "," + fmt2(c1[1]) + "," + fmt2(c2[0]) + "," + fmt2(c2[1]) + "," + fmt2(p1[0]) + "," + fmt2(p1[1]);
5473
+ segLens.push(cubicLength(p0, c1, c2, p1));
5474
+ }
5475
+ const total = segLens.reduce((a, b) => a + b, 0);
5476
+ if (!(total > 0)) return void 0;
5477
+ const distanceKfs = [];
5478
+ let cum = 0;
5479
+ for (let i = 0; i < kfs.length; i++) {
5480
+ if (i > 0) cum += segLens[i - 1];
5481
+ const out = { t: kfTime(kfs[i]), v: cum / total };
5482
+ const e = kfEasing(kfs[i]);
5483
+ if (e !== void 0) out.e = e;
5484
+ distanceKfs.push(out);
5485
+ }
5486
+ return { pathStr: d, distanceKfs, autoOrient: !!propAnim.autoOrient, anchor };
5487
+ }
5488
+ function materialiseOffsetPathsInTree(root) {
5489
+ const walk = (node) => {
5490
+ var _a;
5491
+ let out = node;
5492
+ const anim = node.animate;
5493
+ const transform = anim == null ? void 0 : anim["transform"];
5494
+ if (transform) {
5495
+ const built = buildOffsetPath(transform);
5496
+ if (built) {
5497
+ const newAnimate = __spreadValues({}, anim);
5498
+ delete newAnimate["transform"];
5499
+ const distance = { keyframes: built.distanceKfs };
5500
+ if (transform.loop !== void 0) distance.loop = transform.loop;
5501
+ newAnimate["offsetDistance"] = distance;
5502
+ const staticTr = node.transform;
5503
+ let newTransform = staticTr;
5504
+ if (staticTr && typeof staticTr === "object") {
5505
+ const t = __spreadValues({}, staticTr);
5506
+ delete t["translate"];
5507
+ delete t["origin"];
5508
+ newTransform = Object.keys(t).length ? t : void 0;
5509
+ }
5510
+ out = __spreadProps(__spreadValues({}, node), {
5511
+ animate: newAnimate,
5512
+ style: __spreadProps(__spreadValues({}, node.style), {
5513
+ offsetPath: "path('" + built.pathStr + "')",
5514
+ offsetAnchor: fmt2(built.anchor[0]) + "px " + fmt2(built.anchor[1]) + "px",
5515
+ offsetRotate: built.autoOrient ? "auto" : "0deg",
5516
+ offsetDistance: "0%"
5517
+ })
5518
+ });
5519
+ if (newTransform !== void 0) out.transform = newTransform;
5520
+ else delete out.transform;
5521
+ }
5522
+ }
5523
+ if ((_a = out.children) == null ? void 0 : _a.length) {
5524
+ const children = out.children.map(walk);
5525
+ if (children.some((c, i) => c !== out.children[i])) out = __spreadProps(__spreadValues({}, out), { children });
5526
+ }
5527
+ return out;
5528
+ };
5529
+ return walk(root);
5530
+ }
5531
+
5379
5532
  // src/PxAnimatorMaterialiseAll.ts
5380
5533
  function materialiseAllInTree(doc, engine, opts) {
5381
5534
  var _a, _b;
5382
5535
  let root = applyPlayerEffects(doc).root;
5536
+ root = materialiseOffsetPathsInTree(root);
5383
5537
  const duration = (_b = (_a = getAnimatorConfig(root)) == null ? void 0 : _a.duration) != null ? _b : DEFAULT_DURATION_MS;
5384
5538
  root = materialiseInternalLoopsInTree(root, duration);
5385
5539
  if (engine === PxAnimatorEngine.waapi) {
@@ -5912,6 +6066,8 @@ function subtractMultiset(a, b) {
5912
6066
  DEFAULT_DURATION_MS,
5913
6067
  DISALLOWED_SVG_TAGS_LOWER,
5914
6068
  INTERNAL_ATTRS,
6069
+ LOOP_JUMP_SHIFT_MS,
6070
+ PCT_BASED_ATTR_NAMES,
5915
6071
  PX_ANIM_ATTR_NAME,
5916
6072
  PX_ANIM_SRC_ATTR_NAME,
5917
6073
  PX_TRANSFORM_PART_KEYS,