pixi-effects 0.48.2 → 0.50.0

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.
Files changed (88) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +53 -8
  3. package/ai/chat-template.html +8 -4
  4. package/ai/tools/check.mjs +6 -6
  5. package/dist/3d.cjs +967 -0
  6. package/dist/3d.cjs.map +1 -0
  7. package/dist/3d.d.cts +305 -0
  8. package/dist/3d.d.ts +305 -0
  9. package/dist/3d.js +960 -0
  10. package/dist/3d.js.map +1 -0
  11. package/dist/Canvas-BfZkAFJm.d.cts +12 -0
  12. package/dist/Canvas-BfZkAFJm.d.ts +12 -0
  13. package/dist/Composition-47U5U637.cjs +16 -0
  14. package/dist/{Composition-TJ5D7Z63.cjs.map → Composition-47U5U637.cjs.map} +1 -1
  15. package/dist/Composition-GVWWLFDL.js +7 -0
  16. package/dist/{Composition-5FKV2IBP.js.map → Composition-GVWWLFDL.js.map} +1 -1
  17. package/dist/Controller.d.cts +2 -2
  18. package/dist/Controller.d.ts +2 -2
  19. package/dist/{Movie-svZQF-9Z.d.cts → Movie-DogzDBuW.d.cts} +36 -5
  20. package/dist/{Movie--qSYKgAQ.d.ts → Movie-Y7iHg2V8.d.ts} +36 -5
  21. package/dist/{Spans-6A3VLHRH.js → Spans-3SEZSTQV.js} +6 -6
  22. package/dist/{Spans-6A3VLHRH.js.map → Spans-3SEZSTQV.js.map} +1 -1
  23. package/dist/{Spans-5ENZ3XGS.cjs → Spans-R426NVY3.cjs} +11 -11
  24. package/dist/{Spans-5ENZ3XGS.cjs.map → Spans-R426NVY3.cjs.map} +1 -1
  25. package/dist/{blendModes-V5XHC7U4.cjs → blendModes-2IDILRN6.cjs} +5 -5
  26. package/dist/{blendModes-V5XHC7U4.cjs.map → blendModes-2IDILRN6.cjs.map} +1 -1
  27. package/dist/{blendModes-535EMYGK.js → blendModes-4QH44GOL.js} +4 -4
  28. package/dist/{blendModes-535EMYGK.js.map → blendModes-4QH44GOL.js.map} +1 -1
  29. package/dist/{chunk-NGJXVJB7.cjs → chunk-3FCDRLW3.cjs} +5 -3
  30. package/dist/chunk-3FCDRLW3.cjs.map +1 -0
  31. package/dist/{chunk-JBDBICS2.js → chunk-C2HL5236.js} +4 -4
  32. package/dist/{chunk-JBDBICS2.js.map → chunk-C2HL5236.js.map} +1 -1
  33. package/dist/{chunk-WYR2AU4W.cjs → chunk-GXGIISFS.cjs} +5 -5
  34. package/dist/{chunk-WYR2AU4W.cjs.map → chunk-GXGIISFS.cjs.map} +1 -1
  35. package/dist/{chunk-BFRWSV3R.js → chunk-J4ZP76IL.js} +5 -4
  36. package/dist/chunk-J4ZP76IL.js.map +1 -0
  37. package/dist/{chunk-CCPJD76D.cjs → chunk-O2MD3L4J.cjs} +93 -93
  38. package/dist/chunk-O2MD3L4J.cjs.map +1 -0
  39. package/dist/{chunk-IVKI6CPH.js → chunk-SSVHAF3Q.js} +483 -20
  40. package/dist/chunk-SSVHAF3Q.js.map +1 -0
  41. package/dist/{chunk-6D4W2KZQ.js → chunk-TXNQLMRT.js} +6 -6
  42. package/dist/chunk-TXNQLMRT.js.map +1 -0
  43. package/dist/{chunk-RCKLUCB7.js → chunk-UTUUOQ47.js} +46 -20
  44. package/dist/chunk-UTUUOQ47.js.map +1 -0
  45. package/dist/{chunk-Z3DM4ETD.cjs → chunk-VVUSZVP7.cjs} +507 -42
  46. package/dist/chunk-VVUSZVP7.cjs.map +1 -0
  47. package/dist/{chunk-45ALIMAF.cjs → chunk-YOKRPAKA.cjs} +89 -63
  48. package/dist/chunk-YOKRPAKA.cjs.map +1 -0
  49. package/dist/index.cjs +35 -35
  50. package/dist/index.d.cts +3 -3
  51. package/dist/index.d.ts +3 -3
  52. package/dist/index.js +5 -5
  53. package/dist/loader.css +1 -1
  54. package/dist/{music-P4JRT73P.js → music-ATX22VAT.js} +3 -3
  55. package/dist/{music-P4JRT73P.js.map → music-ATX22VAT.js.map} +1 -1
  56. package/dist/{music-XQEPBIDT.cjs → music-OFVM3PYH.cjs} +3 -3
  57. package/dist/{music-XQEPBIDT.cjs.map → music-OFVM3PYH.cjs.map} +1 -1
  58. package/dist/present.cjs +5 -5
  59. package/dist/present.d.cts +2 -2
  60. package/dist/present.d.ts +2 -2
  61. package/dist/present.js +5 -5
  62. package/dist/three.cjs +13 -10
  63. package/dist/three.cjs.map +1 -1
  64. package/dist/three.d.cts +4 -12
  65. package/dist/three.d.ts +4 -12
  66. package/dist/three.js +8 -5
  67. package/dist/three.js.map +1 -1
  68. package/dist/{types-CTSrPvY3.d.cts → types-BZngm4nT.d.cts} +48 -5
  69. package/dist/{types-CTSrPvY3.d.ts → types-BZngm4nT.d.ts} +48 -5
  70. package/docs/api.md +45 -2
  71. package/docs/dsl.md +115 -1
  72. package/llms-full.txt +307 -6
  73. package/package.json +19 -3
  74. package/skills/pixi-effects/SKILL.md +4 -2
  75. package/skills/pixi-effects/reference/cheatsheet.md +4 -0
  76. package/skills/pixi-effects/reference/pitfalls.md +20 -0
  77. package/skills/pixi-effects/reference/recipes.md +119 -1
  78. package/skills/pixi-effects/template.html +14 -8
  79. package/dist/Composition-5FKV2IBP.js +0 -7
  80. package/dist/Composition-TJ5D7Z63.cjs +0 -16
  81. package/dist/chunk-45ALIMAF.cjs.map +0 -1
  82. package/dist/chunk-6D4W2KZQ.js.map +0 -1
  83. package/dist/chunk-BFRWSV3R.js.map +0 -1
  84. package/dist/chunk-CCPJD76D.cjs.map +0 -1
  85. package/dist/chunk-IVKI6CPH.js.map +0 -1
  86. package/dist/chunk-NGJXVJB7.cjs.map +0 -1
  87. package/dist/chunk-RCKLUCB7.js.map +0 -1
  88. package/dist/chunk-Z3DM4ETD.cjs.map +0 -1
@@ -1,11 +1,11 @@
1
1
  'use strict';
2
2
 
3
- var chunkCCPJD76D_cjs = require('./chunk-CCPJD76D.cjs');
3
+ var chunkO2MD3L4J_cjs = require('./chunk-O2MD3L4J.cjs');
4
4
  var chunkVQXZ2NOI_cjs = require('./chunk-VQXZ2NOI.cjs');
5
- var chunkZ3DM4ETD_cjs = require('./chunk-Z3DM4ETD.cjs');
5
+ var chunkVVUSZVP7_cjs = require('./chunk-VVUSZVP7.cjs');
6
6
  var chunkZAHCGFGC_cjs = require('./chunk-ZAHCGFGC.cjs');
7
- var chunkWYR2AU4W_cjs = require('./chunk-WYR2AU4W.cjs');
8
- var chunkNGJXVJB7_cjs = require('./chunk-NGJXVJB7.cjs');
7
+ var chunkGXGIISFS_cjs = require('./chunk-GXGIISFS.cjs');
8
+ var chunk3FCDRLW3_cjs = require('./chunk-3FCDRLW3.cjs');
9
9
  var chunkDOLTCXCL_cjs = require('./chunk-DOLTCXCL.cjs');
10
10
  var pixi_js = require('pixi.js');
11
11
 
@@ -1268,8 +1268,8 @@ function expandTransitions(spec) {
1268
1268
  }
1269
1269
  const transitions = out.transitions;
1270
1270
  const sequences = out.sequences ?? [];
1271
- const remap = out.duration !== void 0 ? chunkZ3DM4ETD_cjs.timeRemapOf(out) : null;
1272
- const parentDuration = remap ? chunkZ3DM4ETD_cjs.contentLength(remap, out.duration) : out.duration ?? Infinity;
1271
+ const remap = out.duration !== void 0 ? chunkVVUSZVP7_cjs.timeRemapOf(out) : null;
1272
+ const parentDuration = remap ? chunkVVUSZVP7_cjs.contentLength(remap, out.duration) : out.duration ?? Infinity;
1273
1273
  const compW = out.width;
1274
1274
  const compH = out.height;
1275
1275
  const threeDByName = new Set(sequences.filter((s) => s.name && s.threeD).map((s) => s.name));
@@ -1337,16 +1337,16 @@ function expandTransitions(spec) {
1337
1337
  if (toUses > 1) {
1338
1338
  throw new Error(`pixi-effects: ${tag} sequence "${t.to}" is used as \`to\` in more than one transition`);
1339
1339
  }
1340
- const tStart = chunkZ3DM4ETD_cjs.resolveAt(t.at, parentDuration);
1340
+ const tStart = chunkVVUSZVP7_cjs.resolveAt(t.at, parentDuration);
1341
1341
  const tEnd = tStart + t.duration;
1342
1342
  const fromSeq = fromEntry.seq;
1343
- const fromStart = chunkZ3DM4ETD_cjs.resolveAt(fromSeq.at, parentDuration);
1343
+ const fromStart = chunkVVUSZVP7_cjs.resolveAt(fromSeq.at, parentDuration);
1344
1344
  const fromEnd = fromStart + (fromSeq.duration ?? parentDuration);
1345
1345
  if (tStart < fromStart - EPS || tEnd > fromEnd + EPS) {
1346
1346
  throw new Error(`pixi-effects: ${tag} window [${tStart}, ${tEnd}] is not covered by \`from\` "${t.from}" (lives [${fromStart}, ${fromEnd}], so it ends at ${fromEnd})`);
1347
1347
  }
1348
1348
  const toSeq = toEntry.seq;
1349
- const toStart = chunkZ3DM4ETD_cjs.resolveAt(toSeq.at, parentDuration);
1349
+ const toStart = chunkVVUSZVP7_cjs.resolveAt(toSeq.at, parentDuration);
1350
1350
  const toEnd = toStart + (toSeq.duration ?? parentDuration);
1351
1351
  if (tStart < toStart - EPS || tEnd > toEnd + EPS) {
1352
1352
  throw new Error(`pixi-effects: ${tag} window [${tStart}, ${tEnd}] is not covered by \`to\` "${t.to}" (lives [${toStart}, ${toEnd}], so it starts at ${toStart})`);
@@ -1406,7 +1406,7 @@ function wrapAsFullComposition(seq, compW, compH) {
1406
1406
  delete inner.at;
1407
1407
  delete inner.duration;
1408
1408
  const m = inner.mask;
1409
- const carriesMatte = m !== void 0 && chunkCCPJD76D_cjs.maskSourceOf(m).kind === "refs";
1409
+ const carriesMatte = m !== void 0 && chunkO2MD3L4J_cjs.maskSourceOf(m).kind === "refs";
1410
1410
  if (carriesMatte) delete inner.mask;
1411
1411
  return {
1412
1412
  ...carriesMatte ? { mask: m } : {},
@@ -1671,12 +1671,14 @@ function canvasReport(root) {
1671
1671
  const length = seq.duration ?? 0;
1672
1672
  const moments = [0.15, 0.4, 0.65, 0.9].map((f) => Math.round(f * length * 1e3) / 1e3);
1673
1673
  const { differs, drawMs, threw } = seq.checkDeterminism(moments);
1674
- const name = chunkNGJXVJB7_cjs.describeLayer(seq.spec);
1675
- const kind = seq.spec.type === "three" ? "three" : "canvas";
1676
- const problem = threw.length ? `${name} could not draw at ${threw.map((t) => `${t} s`).join(", ")} (its ${kind === "three" ? "update or render threw" : "draw threw"}, or the layer failed to build): ${kind === "three" ? "the warning above says why" : "it shows a magenta checkerboard there; the warning above says why"}, so the layer cannot be called deterministic` : differs.length ? `${name} does not draw the same picture for the same time (checked at ${differs.map(describeDiff).join(", ")}; drawn in two orders after one draw that was thrown away): ` + (kind === "three" ? "usually its update uses Math.random, Date.now, a clock, or state that builds up from call to call: a mixer advanced with mixer.update(dt) is one (pose a clip with mixer.setTime(t), or threeGltf(url).pose(t)), and so is a value moved by the time since the last call. A skinned model of your own (not loaded by threeGltf) that moves and casts a shadow does it too: three culls a skinned mesh by a bounding sphere that does not follow it, so set mesh.frustumCulled = false. Set every object from t, so playback, a seek and an export agree" : "usually its draw uses Math.random, Date.now or state that outlives the call (a value it keeps from the last call), so playback, a seek and an export would not agree: use info.random() (seeded) and derive everything from t. If it uses none of these, look at the canvases it draws from: make sprites and masks with info.canvas(w, h) (not document.createElement) and draw them into the picture before the strokes that depend on them") : "";
1674
+ const name = chunk3FCDRLW3_cjs.describeLayer(seq.spec);
1675
+ const type = seq.spec.type;
1676
+ const kind = type === "three" ? "three" : type === "scene3d" ? "scene3d" : type === "scene2d" ? "scene2d" : "canvas";
1677
+ const drawn = kind === "canvas" ? "draw threw" : "update or render threw";
1678
+ const problem = threw.length ? `${name} could not draw at ${threw.map((t) => `${t} s`).join(", ")} (its ${drawn}, or the layer failed to build): ${kind === "canvas" ? "it shows a magenta checkerboard there; the warning above says why" : "the warning above says why"}, so the layer cannot be called deterministic` : differs.length ? `${name} does not draw the same picture for the same time (checked at ${differs.map(describeDiff).join(", ")}; drawn in two orders after one draw that was thrown away): ` + (kind === "three" ? "usually its update uses Math.random, Date.now, a clock, or state that builds up from call to call: a mixer advanced with mixer.update(dt) is one (pose a clip with mixer.setTime(t), or threeGltf(url).pose(t)), and so is a value moved by the time since the last call. A skinned model of your own (not loaded by threeGltf) that moves and casts a shadow does it too: three culls a skinned mesh by a bounding sphere that does not follow it, so set mesh.frustumCulled = false. Set every object from t, so playback, a seek and an export agree" : kind === "scene3d" ? "usually its update keeps state from call to call (a value moved by the time since the last call), uses Math.random or a clock, or a model's player or a particle system runs on its own clock (pose a clip with model.player.getState(name).gotoAndStop(t)), or a MotionBlurEffect reads the camera of the frame drawn before. Set every object from t, so playback, a seek and an export agree" : kind === "scene2d" ? "usually its update keeps state from call to call (a value moved by the time since the last call, a position added to instead of set), uses Math.random or a clock, or something runs on PixiJS's ticker (a Ticker.shared.add of your own, a video texture). Set every object from t, so playback, a seek and an export agree" : "usually its draw uses Math.random, Date.now or state that outlives the call (a value it keeps from the last call), so playback, a seek and an export would not agree: use info.random() (seeded) and derive everything from t. If it uses none of these, look at the canvases it draws from: make sprites and masks with info.canvas(w, h) (not document.createElement) and draw them into the picture before the strokes that depend on them") : "";
1677
1679
  out.push({ name: seq.spec.name ?? name, moments, drawMs, ok: !differs.length && !threw.length, problem, kind });
1678
1680
  }
1679
- if (seq instanceof chunkCCPJD76D_cjs.CompositionSequence) walk3(seq);
1681
+ if (seq instanceof chunkO2MD3L4J_cjs.CompositionSequence) walk3(seq);
1680
1682
  };
1681
1683
  const walk3 = (comp) => {
1682
1684
  for (const { seq } of comp.layers()) {
@@ -1728,8 +1730,8 @@ function motionOf(keyframes, local, lives, keys = (k) => GEOMETRY.has(k)) {
1728
1730
  let length = 0;
1729
1731
  if (typeof kf.duration === "number") length = kf.duration;
1730
1732
  else if (kf.duration === "auto") {
1731
- const sp = chunkZ3DM4ETD_cjs.parseSpring(kf.ease);
1732
- length = sp ? Math.round(chunkZ3DM4ETD_cjs.springDuration(sp) * 1e3) / 1e3 : 0.5;
1733
+ const sp = chunkVVUSZVP7_cjs.parseSpring(kf.ease);
1734
+ length = sp ? Math.round(chunkVVUSZVP7_cjs.springDuration(sp) * 1e3) / 1e3 : 0.5;
1733
1735
  }
1734
1736
  if (!(length > 0)) continue;
1735
1737
  const kat = kf.at ?? 0;
@@ -1809,7 +1811,7 @@ function inspectScene(root, frame, time, canvas, opts = {}) {
1809
1811
  if (motion.ever) hasMotion.add(info);
1810
1812
  let shown = bounds ? clip(bounds, view) : null;
1811
1813
  const maskTarget = seq.maskSequence?.target;
1812
- const maskSrc = chunkCCPJD76D_cjs.maskSourceOf(seq.spec.mask);
1814
+ const maskSrc = chunkO2MD3L4J_cjs.maskSourceOf(seq.spec.mask);
1813
1815
  if (shown && maskTarget && !(maskSrc.kind === "inline" && maskSrc.invert)) {
1814
1816
  const m = maskTarget.getBounds();
1815
1817
  shown = clip(shown, { x: m.x, y: m.y, width: m.width, height: m.height });
@@ -1818,7 +1820,7 @@ function inspectScene(root, frame, time, canvas, opts = {}) {
1818
1820
  const group = parentScene ?? (name !== void 0 && blending.has(name) ? name : void 0);
1819
1821
  if (group) scene.set(info, group);
1820
1822
  if (zero || seq.showsNothingYet) scaledToNothing.add(info);
1821
- if (seq instanceof chunkCCPJD76D_cjs.CompositionSequence) walk3(seq, prefix + label + "/", insideThreeD || threeD, visible, group, motion, zero, parentAlpha * alpha);
1823
+ if (seq instanceof chunkO2MD3L4J_cjs.CompositionSequence) walk3(seq, prefix + label + "/", insideThreeD || threeD, visible, group, motion, zero, parentAlpha * alpha);
1822
1824
  });
1823
1825
  };
1824
1826
  walk3(root, "", false, true);
@@ -1990,12 +1992,12 @@ function pickScene(root, x, y, opts = {}, deps = {}) {
1990
1992
  const alive = (threeD ? d.visible : (t?.renderable ?? true) && t?.visible !== false) && carriers.every((c) => c.target?.renderable ?? true);
1991
1993
  const visible = parentVisible && alive && alpha > 0;
1992
1994
  if (!visible) {
1993
- if (seq instanceof chunkCCPJD76D_cjs.CompositionSequence && !threeD && parentVisible && alpha > 0 && t?.visible === false && (t?.renderable ?? true) && carriers.every((c) => c.target?.renderable ?? true)) hiddenSources.set(seq, path);
1995
+ if (seq instanceof chunkO2MD3L4J_cjs.CompositionSequence && !threeD && parentVisible && alpha > 0 && t?.visible === false && (t?.renderable ?? true) && carriers.every((c) => c.target?.renderable ?? true)) hiddenSources.set(seq, path);
1994
1996
  return;
1995
1997
  }
1996
- const isComposition = seq instanceof chunkCCPJD76D_cjs.CompositionSequence;
1998
+ const isComposition = seq instanceof chunkO2MD3L4J_cjs.CompositionSequence;
1997
1999
  if (isComposition && !threeD) {
1998
- const gm = seq.maskSequence?.target, gs = chunkCCPJD76D_cjs.maskSourceOf(seq.spec.mask);
2000
+ const gm = seq.maskSequence?.target, gs = chunkO2MD3L4J_cjs.maskSourceOf(seq.spec.mask);
1999
2001
  if (gm && gs.kind === "inline" && !gs.invert && !inMask(gm, at)) return;
2000
2002
  walk3(seq, path + "/", visible, at, orderBase, via);
2001
2003
  return;
@@ -2009,7 +2011,14 @@ function pickScene(root, x, y, opts = {}, deps = {}) {
2009
2011
  }
2010
2012
  const point = at;
2011
2013
  let hit = null;
2012
- if (threeD) {
2014
+ const scene2d = seq.pick2d;
2015
+ if (typeof scene2d === "function" && !threeD) {
2016
+ const found2 = scene2d.call(seq, point);
2017
+ if (found2) {
2018
+ const s2 = seq;
2019
+ hit = { name, path, type: seq.spec.type, kind: "scene2d", point, scene2d: { object: found2.object, node: found2.node, point: found2.point, grab: () => ({ move: s2.dragFrom(found2.node, point) }) } };
2020
+ }
2021
+ } else if (threeD) {
2013
2022
  if (quad && pointInQuad(quad, d.toLocal(point).x, d.toLocal(point).y)) hit = { name, path, type: seq.spec.type, kind: "card", point };
2014
2023
  } else {
2015
2024
  const local = d.toLocal(point);
@@ -2031,7 +2040,8 @@ function pickScene(root, x, y, opts = {}, deps = {}) {
2031
2040
  } };
2032
2041
  };
2033
2042
  }
2034
- hit = { name, path, type: seq.spec.type, kind: "three", point, three };
2043
+ const type = seq.spec.type;
2044
+ hit = type === "scene3d" ? { name, path, type, kind: "scene3d", point, scene3d: { object: String(three.object), point: three.point, distance: three.distance, node: three.object3d, ...three.grab ? { grab: three.grab } : {} } } : { name, path, type, kind: "three", point, three };
2035
2045
  } else if (three === void 0 && (typeof d.containsPoint !== "function" || d.containsPoint(local))) {
2036
2046
  let opaque = true;
2037
2047
  const tex = opts.alpha !== void 0 && seq.spec.type !== "shader" ? d.texture ?? deps.textureOf?.(d) : void 0;
@@ -2051,7 +2061,7 @@ function pickScene(root, x, y, opts = {}, deps = {}) {
2051
2061
  }
2052
2062
  if (!hit) return;
2053
2063
  const maskTarget = seq.maskSequence?.target;
2054
- const maskSrc = chunkCCPJD76D_cjs.maskSourceOf(seq.spec.mask);
2064
+ const maskSrc = chunkO2MD3L4J_cjs.maskSourceOf(seq.spec.mask);
2055
2065
  if (maskTarget && !(maskSrc.kind === "inline" && maskSrc.invert) && !(maskSrc.kind === "inline" ? inMask(maskTarget, point) : inside(maskTarget.getBounds(), point))) return;
2056
2066
  found.push({ hit: via ? { ...hit, point: { x, y }, via } : hit, order: orderBase ? [...orderBase, ...orderOf(d)] : orderOf(d) });
2057
2067
  });
@@ -2061,7 +2071,7 @@ function pickScene(root, x, y, opts = {}, deps = {}) {
2061
2071
  const path = hiddenSources.get(f.source);
2062
2072
  if (path === void 0) continue;
2063
2073
  const g = f.source.target.toGlobal({ x: f.at.x * f.source.intrinsicWidth, y: f.at.y * f.source.intrinsicHeight });
2064
- const sm = f.source.maskSequence?.target, ss = chunkCCPJD76D_cjs.maskSourceOf(f.source.spec.mask);
2074
+ const sm = f.source.maskSequence?.target, ss = chunkO2MD3L4J_cjs.maskSourceOf(f.source.spec.mask);
2065
2075
  if (sm && ss.kind === "inline" && !ss.invert && !inMask(sm, g)) continue;
2066
2076
  walk3(f.source, path + "/", true, g, f.order, f.via);
2067
2077
  }
@@ -2097,7 +2107,7 @@ function walk(root, visit) {
2097
2107
  visit(seq);
2098
2108
  const mask = seq.maskSequence;
2099
2109
  if (mask) visit(mask);
2100
- if (seq instanceof chunkCCPJD76D_cjs.CompositionSequence) walk(seq, visit);
2110
+ if (seq instanceof chunkO2MD3L4J_cjs.CompositionSequence) walk(seq, visit);
2101
2111
  }
2102
2112
  }
2103
2113
  function reusePoolOf(old) {
@@ -2107,12 +2117,26 @@ function reusePoolOf(old) {
2107
2117
  const key = seq.reuseKey();
2108
2118
  if (key !== null) free.set(key, [...free.get(key) ?? [], seq]);
2109
2119
  });
2110
- return { claim: (key) => free.get(key)?.shift() ?? null };
2120
+ const borrowers = [];
2121
+ return {
2122
+ claim: (key, by) => {
2123
+ const d = free.get(key)?.shift() ?? null;
2124
+ if (d && by) borrowers.push(by);
2125
+ return d;
2126
+ },
2127
+ borrowers
2128
+ };
2111
2129
  }
2112
- function commitReuse(root) {
2113
- walk(root, (seq) => {
2114
- if (borrower(seq)) seq.commitReuse();
2115
- });
2130
+ function commitReuse(root, pool) {
2131
+ const done = /* @__PURE__ */ new Set();
2132
+ const commit = (seq) => {
2133
+ if (!done.has(seq) && borrower(seq)) {
2134
+ done.add(seq);
2135
+ seq.commitReuse();
2136
+ }
2137
+ };
2138
+ walk(root, commit);
2139
+ for (const seq of pool?.borrowers ?? []) commit(seq);
2116
2140
  }
2117
2141
 
2118
2142
  // src/core/hover.ts
@@ -2198,7 +2222,7 @@ var round = (n) => Math.round(n * 1e6) / 1e6;
2198
2222
  var family = (name) => name.replace(/\d+/g, "#");
2199
2223
  function detailOf(seq) {
2200
2224
  const s = seq.spec;
2201
- const spans = chunkZ3DM4ETD_cjs.spansMeta.get(seq.spec)?.preview;
2225
+ const spans = chunkVVUSZVP7_cjs.spansMeta.get(seq.spec)?.preview;
2202
2226
  if (spans) return spans.length > 60 ? spans.slice(0, 57) + "\u2026" : spans;
2203
2227
  if (typeof s.text === "string") return s.text.length > 60 ? s.text.slice(0, 57) + "\u2026" : s.text;
2204
2228
  if (typeof s.asset === "string") return `asset \u201C${s.asset}\u201D`;
@@ -2214,10 +2238,10 @@ function walk2(comp, parentStart, parentEnd, depth, prefix, rows, transitions, l
2214
2238
  const start = parentStart + (seq.at ?? 0);
2215
2239
  const end = Math.min(parentEnd, seq.duration !== void 0 ? start + seq.duration : parentEnd);
2216
2240
  const span = end - start;
2217
- const keys = (seq.spec.keyframes ?? []).map((kf) => round(start + chunkZ3DM4ETD_cjs.resolveAt(kf.at, span))).sort((a, b) => a - b).slice(0, MAX_KEYS);
2241
+ const keys = (seq.spec.keyframes ?? []).map((kf) => round(start + chunkVVUSZVP7_cjs.resolveAt(kf.at, span))).sort((a, b) => a - b).slice(0, MAX_KEYS);
2218
2242
  const row = { path: prefix + name, name, type: seq.spec.type, depth, start: round(start), end: round(end), keys, detail: detailOf(seq), ...local ? { local } : {} };
2219
2243
  const inner = [];
2220
- const isComp = seq instanceof chunkCCPJD76D_cjs.CompositionSequence;
2244
+ const isComp = seq instanceof chunkO2MD3L4J_cjs.CompositionSequence;
2221
2245
  if (isComp) {
2222
2246
  const label = seq.remapLabel();
2223
2247
  walk2(seq, label ? 0 : start, label ? seq.contentSpan : end, depth + 1, prefix + name + "/", inner, transitions, label ? `${name} ${label}` : local);
@@ -2376,7 +2400,7 @@ function sheetLayout(n, columns, cellW, srcW, srcH, labelH) {
2376
2400
  }
2377
2401
 
2378
2402
  // src/core/vars.ts
2379
- var RESERVED_NAMES = ["w", "h", "W", "H", "GW", "GH", "t", "d", "T", "contain", "cover", "value", ...chunkZ3DM4ETD_cjs.EXPRESSION_NAMES];
2403
+ var RESERVED_NAMES = ["w", "h", "W", "H", "GW", "GH", "t", "d", "T", "contain", "cover", "value", ...chunkVVUSZVP7_cjs.EXPRESSION_NAMES];
2380
2404
  var NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;
2381
2405
  var isPlain = (v) => !!v && typeof v === "object" && (Object.getPrototypeOf(v) === Object.prototype || Object.getPrototypeOf(v) === null);
2382
2406
  function normalizeVars(raw, where, warn = (m) => console.warn(m)) {
@@ -2920,8 +2944,8 @@ var Movie = class {
2920
2944
  this.stops = normalizeStops(applyVars(options.composition, this._vars)?.stops, this.duration, this.frameRate);
2921
2945
  this._posterFrame = poster.frame;
2922
2946
  this.background = options.background ?? "#000000";
2923
- this.timeline = chunkZ3DM4ETD_cjs.createTimeline({ paused: true, defaults: { ease: "none" } });
2924
- chunkZ3DM4ETD_cjs.lengthen(this.timeline, this.duration);
2947
+ this.timeline = chunkVVUSZVP7_cjs.createTimeline({ paused: true, defaults: { ease: "none" } });
2948
+ chunkVVUSZVP7_cjs.lengthen(this.timeline, this.duration);
2925
2949
  const baseAppOptions = {
2926
2950
  width: this.width,
2927
2951
  height: this.height,
@@ -3021,8 +3045,8 @@ var Movie = class {
3021
3045
  height: sizeWins ? height : spec.height ?? height,
3022
3046
  duration: spec.duration ?? this.duration
3023
3047
  } : void 0;
3024
- await chunkZ3DM4ETD_cjs.ensureFilterLibrary(seededComposition);
3025
- if (chunkWYR2AU4W_cjs.usesAdvancedBlend(seededComposition)) await chunkWYR2AU4W_cjs.enableAdvancedBlend(this.app.renderer);
3048
+ await chunkVVUSZVP7_cjs.ensureFilterLibrary(seededComposition);
3049
+ if (chunkGXGIISFS_cjs.usesAdvancedBlend(seededComposition)) await chunkGXGIISFS_cjs.enableAdvancedBlend(this.app.renderer);
3026
3050
  const userComposition = seededComposition ? expandTransitions(seededComposition) : void 0;
3027
3051
  const rootSeqSpec = {
3028
3052
  type: "composition",
@@ -3032,7 +3056,7 @@ var Movie = class {
3032
3056
  ...userComposition
3033
3057
  };
3034
3058
  if (userComposition) carryTransitionWindows(userComposition, rootSeqSpec);
3035
- const sequence = new chunkCCPJD76D_cjs.CompositionSequence(rootSeqSpec, null, rootShape);
3059
+ const sequence = new chunkO2MD3L4J_cjs.CompositionSequence(rootSeqSpec, null, rootShape);
3036
3060
  lp?.begin("build", countLayers(rootSeqSpec));
3037
3061
  try {
3038
3062
  await sequence.build();
@@ -3140,6 +3164,7 @@ var Movie = class {
3140
3164
  if (!root || !app) throw new Error("pixi-effects: movie.rebuild() needs a ready movie \u2014 await movie.init(...) first");
3141
3165
  const who = `movie.${reason === "vars" ? "setVars" : "rebuild"}()`;
3142
3166
  let sequence = null;
3167
+ let reusePool = null;
3143
3168
  const alive = () => {
3144
3169
  if (this._initState !== "ready") throw new Error("pixi-effects: the movie was destroyed while it was being rebuilt");
3145
3170
  };
@@ -3169,10 +3194,11 @@ var Movie = class {
3169
3194
  if (change.composition !== void 0) for (const w of lintVars(change.composition, vars)) console.warn(w);
3170
3195
  changed = changed || sizeChanged || change.composition !== void 0 || reason === "rebuild";
3171
3196
  if (!changed) return { reason, ms: 0, audio: "none", frame: this.currentFrame, playing: this.isPlaying, unchanged: true };
3172
- sequence = await this._construct(composition, vars, width, height, void 0, this._resized || sizeChanged, reusePoolOf(this._rootSequence));
3197
+ reusePool = reusePoolOf(this._rootSequence);
3198
+ sequence = await this._construct(composition, vars, width, height, void 0, this._resized || sizeChanged, reusePool);
3173
3199
  alive();
3174
- const timeline = chunkZ3DM4ETD_cjs.createTimeline({ paused: true, defaults: { ease: "none" } });
3175
- chunkZ3DM4ETD_cjs.lengthen(timeline, this.duration);
3200
+ const timeline = chunkVVUSZVP7_cjs.createTimeline({ paused: true, defaults: { ease: "none" } });
3201
+ chunkVVUSZVP7_cjs.lengthen(timeline, this.duration);
3176
3202
  sequence.bindTimeline(timeline);
3177
3203
  const hadSound = this.audioBuffer !== null;
3178
3204
  const audio = await this._mixSound(sequence, this._ensureAudioContext());
@@ -3209,7 +3235,7 @@ var Movie = class {
3209
3235
  if (old?.target) root.removeChild(old.target);
3210
3236
  if (sequence.target) root.addChild(sequence.target);
3211
3237
  this._rootSequence = sequence;
3212
- commitReuse(sequence);
3238
+ commitReuse(sequence, reusePool);
3213
3239
  this.timeline = timeline;
3214
3240
  this._timeFilters = collectTimeFilters(sequence);
3215
3241
  const loud = quietUnbind();
@@ -3971,7 +3997,7 @@ function countLayers(spec) {
3971
3997
  n += 1 + countLayers(s);
3972
3998
  const spans = s.spans;
3973
3999
  if (Array.isArray(spans)) n += spans.length;
3974
- const src = chunkCCPJD76D_cjs.maskSourceOf(mask);
4000
+ const src = chunkO2MD3L4J_cjs.maskSourceOf(mask);
3975
4001
  if (src.kind === "inline") n += 1 + countLayers(src.spec);
3976
4002
  }
3977
4003
  return n;
@@ -4060,8 +4086,8 @@ function splitVertical(text, style, ts, right, top, align, by) {
4060
4086
 
4061
4087
  // src/presets/_ease.ts
4062
4088
  function parseEase2(name) {
4063
- chunkZ3DM4ETD_cjs.checkEase(name, "a preset");
4064
- return chunkZ3DM4ETD_cjs.parseEase(name);
4089
+ chunkVVUSZVP7_cjs.checkEase(name, "a preset");
4090
+ return chunkVVUSZVP7_cjs.parseEase(name);
4065
4091
  }
4066
4092
 
4067
4093
  // src/presets/kenBurns.ts
@@ -4196,17 +4222,17 @@ function orbit(opts) {
4196
4222
  throw new Error("pixi-effects: orbit() cannot combine `radius` with `dollyZoom` \u2014 the radius follows the animated fov");
4197
4223
  }
4198
4224
  const [cx, cy] = opts.center ?? [width / 2, height / 2];
4199
- const fixedR = opts.radius ?? chunkZ3DM4ETD_cjs.homeDistance(height, fov ?? chunkZ3DM4ETD_cjs.DEFAULT_FOV);
4225
+ const fixedR = opts.radius ?? chunkVVUSZVP7_cjs.homeDistance(height, fov ?? chunkVVUSZVP7_cjs.DEFAULT_FOV);
4200
4226
  const start = opts.start ?? -degrees / 2;
4201
4227
  const steps = Math.max(1, Math.round(duration * stepsPerSecond));
4202
4228
  const easeFn = parseEase2(ease);
4203
4229
  const dollyEase = dolly ? parseEase2(dolly.ease ?? ease) : null;
4204
4230
  const pos = (i) => {
4205
4231
  const p = i / steps;
4206
- const a = (start + degrees * easeFn(p)) * chunkZ3DM4ETD_cjs.DEG;
4232
+ const a = (start + degrees * easeFn(p)) * chunkVVUSZVP7_cjs.DEG;
4207
4233
  if (!dolly) return { x: cx + fixedR * Math.sin(a), z: fixedR * Math.cos(a) };
4208
4234
  const f = dolly.from + (dolly.to - dolly.from) * dollyEase(p);
4209
- const R = chunkZ3DM4ETD_cjs.homeDistance(height, f);
4235
+ const R = chunkVVUSZVP7_cjs.homeDistance(height, f);
4210
4236
  return { x: cx + R * Math.sin(a), z: R * Math.cos(a), fov: f };
4211
4237
  };
4212
4238
  const keyframes = [];
@@ -4261,7 +4287,7 @@ function particles(opts) {
4261
4287
  const round2 = (v) => Math.round(v * 1e6) / 1e6;
4262
4288
  const out = [];
4263
4289
  for (let i = 0; i < count; i++) {
4264
- const r = chunkZ3DM4ETD_cjs.random(seed * 1000003 + i * 7919 + 17);
4290
+ const r = chunkVVUSZVP7_cjs.random(seed * 1000003 + i * 7919 + 17);
4265
4291
  const pick = ([a2, b]) => a2 + r() * (b - a2);
4266
4292
  const born = at + r() * emit;
4267
4293
  const lifetime = pick(life);
@@ -4274,7 +4300,7 @@ function particles(opts) {
4274
4300
  const turn = spin ? pick(spin) : 0;
4275
4301
  const startAngle = spin ? r() * 360 : 0;
4276
4302
  const swayAmp = sway?.amp ?? 0, swayFreq = sway?.freq ?? 1;
4277
- const n0 = sway ? chunkZ3DM4ETD_cjs.noise(0, seed * 1000003 + i) : 0;
4303
+ const n0 = sway ? chunkVVUSZVP7_cjs.noise(0, seed * 1000003 + i) : 0;
4278
4304
  const at_ = (t) => {
4279
4305
  const axis = (p0, v0, acc) => {
4280
4306
  if (drag > 0) {
@@ -4283,7 +4309,7 @@ function particles(opts) {
4283
4309
  }
4284
4310
  return p0 + v0 * t + 0.5 * acc * t * t;
4285
4311
  };
4286
- const sw = sway ? swayAmp * (chunkZ3DM4ETD_cjs.noise(t * swayFreq, seed * 1000003 + i) - n0) : 0;
4312
+ const sw = sway ? swayAmp * (chunkVVUSZVP7_cjs.noise(t * swayFreq, seed * 1000003 + i) - n0) : 0;
4287
4313
  return { x: axis(x0, vx, wind) + sw, y: axis(y0, vy, gravity) };
4288
4314
  };
4289
4315
  const kfs = [];
@@ -4345,7 +4371,7 @@ function followPath(opts) {
4345
4371
  if (steps > MAX_STEPS) throw new Error(`followPath(): ${steps} samples is too many (max ${MAX_STEPS}); lower frameRate or duration`);
4346
4372
  const segments = [];
4347
4373
  let total = 0;
4348
- for (const line of chunkZ3DM4ETD_cjs.flattenSvgPath(d)) {
4374
+ for (const line of chunkVVUSZVP7_cjs.flattenSvgPath(d)) {
4349
4375
  const p = line.closed ? [...line.pts, line.pts[0], line.pts[1]] : line.pts;
4350
4376
  for (let i = 2; i < p.length; i += 2) {
4351
4377
  const len = Math.hypot(p[i] - p[i - 2], p[i + 1] - p[i - 1]);
@@ -4398,7 +4424,7 @@ function followPath(opts) {
4398
4424
  // src/core/pathSample.ts
4399
4425
  function samplePath(d) {
4400
4426
  if (typeof d !== "string" || d.trim() === "") throw new Error('samplePath(): d must be SVG path data, e.g. "M 40 300 C 200 20 400 20 560 300"');
4401
- const lines = chunkZ3DM4ETD_cjs.flattenSvgPath(d);
4427
+ const lines = chunkVVUSZVP7_cjs.flattenSvgPath(d);
4402
4428
  const segments = [];
4403
4429
  let length = 0;
4404
4430
  for (const line of lines) {
@@ -4429,7 +4455,7 @@ function samplePath(d) {
4429
4455
  return { x: g.x0 + (g.x1 - g.x0) * t, y: g.y0 + (g.y1 - g.y0) * t, angle: Math.atan2(g.y1 - g.y0, g.x1 - g.x0) };
4430
4456
  },
4431
4457
  trim(start = 0, end = 1) {
4432
- return chunkZ3DM4ETD_cjs.trimPolylines(lines, start, end).map((l) => l.closed ? [...l.pts, l.pts[0], l.pts[1]] : l.pts);
4458
+ return chunkVVUSZVP7_cjs.trimPolylines(lines, start, end).map((l) => l.closed ? [...l.pts, l.pts[0], l.pts[1]] : l.pts);
4433
4459
  }
4434
4460
  };
4435
4461
  }
@@ -4540,7 +4566,7 @@ function distances(n, from, grid, seed) {
4540
4566
  if (n === 0) return [];
4541
4567
  if (from === "random") {
4542
4568
  const order = Array.from({ length: n }, (_, i) => i);
4543
- const r = chunkZ3DM4ETD_cjs.random(seed);
4569
+ const r = chunkVVUSZVP7_cjs.random(seed);
4544
4570
  for (let i = n - 1; i > 0; i--) {
4545
4571
  const j = Math.floor(r() * (i + 1));
4546
4572
  [order[i], order[j]] = [order[j], order[i]];
@@ -4602,7 +4628,7 @@ function wiggle(opts) {
4602
4628
  to[n] = p.around;
4603
4629
  return;
4604
4630
  }
4605
- const off = (chunkZ3DM4ETD_cjs.rand(seed * 7919 + pi * 104729 + s * 31 + 1) * 2 - 1) * p.amp;
4631
+ const off = (chunkVVUSZVP7_cjs.rand(seed * 7919 + pi * 104729 + s * 31 + 1) * 2 - 1) * p.amp;
4606
4632
  to[n] = typeof p.around === "number" ? p.around + off : `(${p.around}) ${off < 0 ? "-" : "+"} ${Math.abs(off)}`;
4607
4633
  });
4608
4634
  out.push({ at: at + s * stepLen, to, duration: stepLen, ease });
@@ -4990,7 +5016,7 @@ async function audioEnvelope(source, options = {}) {
4990
5016
 
4991
5017
  // src/audio/musicEnvelope.ts
4992
5018
  async function musicEnvelope(music, options = {}) {
4993
- const { resolveMusic, renderMusic, musicLength, musicBeatTimes, TempoMap } = await import('./music-XQEPBIDT.cjs');
5019
+ const { resolveMusic, renderMusic, musicLength, musicBeatTimes, TempoMap } = await import('./music-OFVM3PYH.cjs');
4994
5020
  const messages = [];
4995
5021
  const m = resolveMusic(music, "musicEnvelope()", (msg) => messages.push(msg));
4996
5022
  if (!m) throw new Error(`pixi-effects: musicEnvelope(): ${messages.join(" ") || "the music has nothing to play"}`);
@@ -5003,7 +5029,7 @@ async function musicEnvelope(music, options = {}) {
5003
5029
 
5004
5030
  // src/audio/musicBuffer.ts
5005
5031
  async function musicBuffer(music, options = {}) {
5006
- const { resolveMusic, renderMusic, musicLength } = await import('./music-XQEPBIDT.cjs');
5032
+ const { resolveMusic, renderMusic, musicLength } = await import('./music-OFVM3PYH.cjs');
5007
5033
  const messages = [];
5008
5034
  const m = resolveMusic(music, "musicBuffer()", (msg) => messages.push(msg));
5009
5035
  if (!m) throw new Error(`pixi-effects: musicBuffer(): ${messages.join(" ") || "the music has nothing to play"}`);
@@ -5020,7 +5046,7 @@ async function musicBuffer(music, options = {}) {
5020
5046
 
5021
5047
  // src/audio/musicEvents.ts
5022
5048
  async function musicEvents(music) {
5023
- const { resolveMusic } = await import('./music-XQEPBIDT.cjs');
5049
+ const { resolveMusic } = await import('./music-OFVM3PYH.cjs');
5024
5050
  const { describeEvents } = await import('./events-EE3SM5LM.cjs');
5025
5051
  const messages = [];
5026
5052
  const m = resolveMusic(music, "musicEvents()", (msg) => messages.push(msg));
@@ -5073,5 +5099,5 @@ exports.splitText = splitText;
5073
5099
  exports.stagger = stagger;
5074
5100
  exports.wiggle = wiggle;
5075
5101
  exports.withFade = withFade;
5076
- //# sourceMappingURL=chunk-45ALIMAF.cjs.map
5077
- //# sourceMappingURL=chunk-45ALIMAF.cjs.map
5102
+ //# sourceMappingURL=chunk-YOKRPAKA.cjs.map
5103
+ //# sourceMappingURL=chunk-YOKRPAKA.cjs.map