pixi-effects 0.36.0 → 0.37.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 (76) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +5 -5
  3. package/ai/chat-template.html +3 -3
  4. package/ai/tools/check.mjs +12 -2
  5. package/ai/tools/lookup.mjs +2 -1
  6. package/dist/{Base-CmiFiwQM.d.cts → Base-BlA6SeqJ.d.cts} +1 -1
  7. package/dist/{Base-CdF7AJop.d.ts → Base-YqM0Ljvp.d.ts} +1 -1
  8. package/dist/Composition-5KZETM4J.js +7 -0
  9. package/dist/{Composition-BMRCE5FH.js.map → Composition-5KZETM4J.js.map} +1 -1
  10. package/dist/Composition-MHDI7UNZ.cjs +16 -0
  11. package/dist/{Composition-XRLYR6GL.cjs.map → Composition-MHDI7UNZ.cjs.map} +1 -1
  12. package/dist/Controller.d.cts +2 -2
  13. package/dist/Controller.d.ts +2 -2
  14. package/dist/{Movie-D5WFfZdZ.d.ts → Movie-CJN_gvLB.d.cts} +21 -2
  15. package/dist/{Movie-Bh1HPdKw.d.cts → Movie-CfHaGmUP.d.ts} +21 -2
  16. package/dist/{Spans-MWP2FX3T.js → Spans-FSSO2HGX.js} +6 -6
  17. package/dist/{Spans-MWP2FX3T.js.map → Spans-FSSO2HGX.js.map} +1 -1
  18. package/dist/{Spans-4IRBSOLI.cjs → Spans-WVJH77BW.cjs} +11 -11
  19. package/dist/{Spans-4IRBSOLI.cjs.map → Spans-WVJH77BW.cjs.map} +1 -1
  20. package/dist/{blendModes-KU7XLV7U.cjs → blendModes-FD3THLNC.cjs} +5 -5
  21. package/dist/{blendModes-KU7XLV7U.cjs.map → blendModes-FD3THLNC.cjs.map} +1 -1
  22. package/dist/{blendModes-OOI3T6BE.js → blendModes-FMYO6SQN.js} +4 -4
  23. package/dist/{blendModes-OOI3T6BE.js.map → blendModes-FMYO6SQN.js.map} +1 -1
  24. package/dist/{chunk-2JFFKHXO.js → chunk-32MMNDDN.js} +4 -3
  25. package/dist/chunk-32MMNDDN.js.map +1 -0
  26. package/dist/{chunk-42ML5AKN.cjs → chunk-3SAS3ZE5.cjs} +4 -3
  27. package/dist/chunk-3SAS3ZE5.cjs.map +1 -0
  28. package/dist/{chunk-CC7SUR7Q.cjs → chunk-E26M4NTL.cjs} +122 -41
  29. package/dist/chunk-E26M4NTL.cjs.map +1 -0
  30. package/dist/{chunk-AZ6AINSW.js → chunk-IPQNT65V.js} +6 -6
  31. package/dist/chunk-IPQNT65V.js.map +1 -0
  32. package/dist/{chunk-NEUPEENI.cjs → chunk-JN7JHNZR.cjs} +5 -5
  33. package/dist/{chunk-NEUPEENI.cjs.map → chunk-JN7JHNZR.cjs.map} +1 -1
  34. package/dist/{chunk-VF56PRAA.js → chunk-KNDEKWQO.js} +89 -9
  35. package/dist/chunk-KNDEKWQO.js.map +1 -0
  36. package/dist/{chunk-Y5UWFH6Y.cjs → chunk-MJMOPWMK.cjs} +92 -92
  37. package/dist/chunk-MJMOPWMK.cjs.map +1 -0
  38. package/dist/{chunk-KJSEQVBV.cjs → chunk-QHIOOK5S.cjs} +333 -26
  39. package/dist/chunk-QHIOOK5S.cjs.map +1 -0
  40. package/dist/{chunk-G3DX65HO.js → chunk-SBR75G73.js} +311 -6
  41. package/dist/chunk-SBR75G73.js.map +1 -0
  42. package/dist/{chunk-WIIU42FH.js → chunk-VNP7QCJE.js} +4 -4
  43. package/dist/{chunk-WIIU42FH.js.map → chunk-VNP7QCJE.js.map} +1 -1
  44. package/dist/index.cjs +41 -33
  45. package/dist/index.d.cts +32 -6
  46. package/dist/index.d.ts +32 -6
  47. package/dist/index.js +5 -5
  48. package/dist/loader.css +1 -1
  49. package/dist/present.cjs +5 -5
  50. package/dist/present.d.cts +2 -2
  51. package/dist/present.d.ts +2 -2
  52. package/dist/present.js +5 -5
  53. package/dist/three.cjs +6 -6
  54. package/dist/three.d.cts +2 -2
  55. package/dist/three.d.ts +2 -2
  56. package/dist/three.js +2 -2
  57. package/dist/{types-B6zDTU2V.d.ts → types-DvnXXm33.d.cts} +53 -2
  58. package/dist/{types-B6zDTU2V.d.cts → types-DvnXXm33.d.ts} +53 -2
  59. package/docs/dsl.md +35 -0
  60. package/llms-full.txt +221 -5
  61. package/package.json +1 -1
  62. package/skills/pixi-effects/SKILL.md +3 -2
  63. package/skills/pixi-effects/reference/cheatsheet.md +2 -0
  64. package/skills/pixi-effects/reference/pitfalls.md +4 -0
  65. package/skills/pixi-effects/reference/recipes.md +177 -3
  66. package/skills/pixi-effects/template.html +6 -6
  67. package/dist/Composition-BMRCE5FH.js +0 -7
  68. package/dist/Composition-XRLYR6GL.cjs +0 -16
  69. package/dist/chunk-2JFFKHXO.js.map +0 -1
  70. package/dist/chunk-42ML5AKN.cjs.map +0 -1
  71. package/dist/chunk-AZ6AINSW.js.map +0 -1
  72. package/dist/chunk-CC7SUR7Q.cjs.map +0 -1
  73. package/dist/chunk-G3DX65HO.js.map +0 -1
  74. package/dist/chunk-KJSEQVBV.cjs.map +0 -1
  75. package/dist/chunk-VF56PRAA.js.map +0 -1
  76. package/dist/chunk-Y5UWFH6Y.cjs.map +0 -1
@@ -1,8 +1,9 @@
1
1
  'use strict';
2
2
 
3
- var chunkY5UWFH6Y_cjs = require('./chunk-Y5UWFH6Y.cjs');
4
- var chunkKJSEQVBV_cjs = require('./chunk-KJSEQVBV.cjs');
5
- var chunkNEUPEENI_cjs = require('./chunk-NEUPEENI.cjs');
3
+ var chunkMJMOPWMK_cjs = require('./chunk-MJMOPWMK.cjs');
4
+ var chunkQHIOOK5S_cjs = require('./chunk-QHIOOK5S.cjs');
5
+ var chunkJN7JHNZR_cjs = require('./chunk-JN7JHNZR.cjs');
6
+ var chunk3SAS3ZE5_cjs = require('./chunk-3SAS3ZE5.cjs');
6
7
  var chunkTWZNOUM7_cjs = require('./chunk-TWZNOUM7.cjs');
7
8
  var pixi_js = require('pixi.js');
8
9
  var mediabunny = require('mediabunny');
@@ -519,8 +520,8 @@ function analyzeAudio(mix, sources, stats, movieDuration, opts = {}) {
519
520
  });
520
521
  if (buried.length > 0) {
521
522
  const worst = buried.reduce((a, b) => b.belowMixDb > a.belowMixDb ? b : a);
522
- const names = new Set(buried.map((x) => x.layer + x.source));
523
- scoreNotes.push(`${names.size === 1 ? "1 sound effect is" : `${names.size} sound effects are`} buried (${BURIED_DB} dB or more under the loudest sample of the mix around its loudest moment${buried.length > names.size ? `, ${buried.length} times in all` : ""}): the worst is ${worst.layer} (${worst.source}), its own peak ${worst.ownDb} dBFS at volume ${worst.topVolume} against ${worst.around} dBFS at ${worst.at} s, ${worst.belowMixDb} dB louder. If it is meant to be heard, raise its volume (an accent over music needs 2 to 3) or lower what plays there; every source's belowMixDb has its own number`);
523
+ const distinct = new Set(buried.map((x) => (x.layer === "an audio layer" ? `#${buried.indexOf(x)}` : x.layer) + x.source)).size;
524
+ scoreNotes.push(`${distinct === 1 ? "1 sound effect is" : `${distinct} sound effects are`} buried (${BURIED_DB} dB or more under the loudest sample of the mix around its loudest moment${buried.length > distinct ? `, ${buried.length} times in all` : ""}): the worst is ${worst.layer} (${worst.source}), its own peak ${worst.ownDb} dBFS at volume ${Math.round(worst.topVolume * 100) / 100} against ${worst.around} dBFS at ${worst.at} s, ${worst.belowMixDb} dB louder. If it is meant to be heard, raise its volume (an accent over music needs 2 to 3) or lower what plays there; every source's belowMixDb has its own number`);
524
525
  }
525
526
  const whole = measureLoudness(chans, sr);
526
527
  const silences = findSilences(chans, sr, { minLength: 1 });
@@ -695,12 +696,14 @@ async function reviewMovie(movie, opts = {}) {
695
696
  if (r.issues.length) perFrame.push({ frame, issues: r.issues });
696
697
  }
697
698
  const grouped = splitIssues(groupIssues(perFrame), !!opts.strict);
699
+ const canvas = movie.canvasReport();
700
+ for (const r of canvas) if (!r.ok) grouped.problems.push({ message: r.problem, count: 1, firstFrame: 0, lastFrame: 0, kind: "canvas" });
698
701
  const fonts = movie.inspectFonts();
699
702
  for (const f of fonts.failedUnused) grouped.review.push({ message: `web font "${f}" failed to load, but no text layer uses it (a broken or unused @font-face)`, count: 1, firstFrame: 0, lastFrame: 0 });
700
703
  for (const m of fonts.missing) {
701
704
  (opts.strict ? grouped.problems : grouped.review).push({ message: `layer "${m.layer}": none of the fonts "${m.family}" is available here (it is drawn in a fallback font)`, count: 1, firstFrame: 0, lastFrame: 0 });
702
705
  }
703
- return { frames: frames.length, problems: grouped.problems, review: grouped.review, fonts, audio: movie.audioBuffer ? movie.inspectAudio() : null, at };
706
+ return { frames: frames.length, problems: grouped.problems, review: grouped.review, canvas, fonts, audio: movie.audioBuffer ? movie.inspectAudio() : null, at };
704
707
  }
705
708
 
706
709
  // src/core/onion.ts
@@ -1506,8 +1509,8 @@ function expandTransitions(spec) {
1506
1509
  }
1507
1510
  const transitions = out.transitions;
1508
1511
  const sequences = out.sequences ?? [];
1509
- const remap = out.duration !== void 0 ? chunkKJSEQVBV_cjs.timeRemapOf(out) : null;
1510
- const parentDuration = remap ? chunkKJSEQVBV_cjs.contentLength(remap, out.duration) : out.duration ?? Infinity;
1512
+ const remap = out.duration !== void 0 ? chunkQHIOOK5S_cjs.timeRemapOf(out) : null;
1513
+ const parentDuration = remap ? chunkQHIOOK5S_cjs.contentLength(remap, out.duration) : out.duration ?? Infinity;
1511
1514
  const compW = out.width;
1512
1515
  const compH = out.height;
1513
1516
  const threeDByName = new Set(sequences.filter((s) => s.name && s.threeD).map((s) => s.name));
@@ -1575,16 +1578,16 @@ function expandTransitions(spec) {
1575
1578
  if (toUses > 1) {
1576
1579
  throw new Error(`pixi-effects: ${tag} sequence "${t.to}" is used as \`to\` in more than one transition`);
1577
1580
  }
1578
- const tStart = chunkKJSEQVBV_cjs.resolveAt(t.at, parentDuration);
1581
+ const tStart = chunkQHIOOK5S_cjs.resolveAt(t.at, parentDuration);
1579
1582
  const tEnd = tStart + t.duration;
1580
1583
  const fromSeq = fromEntry.seq;
1581
- const fromStart = chunkKJSEQVBV_cjs.resolveAt(fromSeq.at, parentDuration);
1584
+ const fromStart = chunkQHIOOK5S_cjs.resolveAt(fromSeq.at, parentDuration);
1582
1585
  const fromEnd = fromStart + (fromSeq.duration ?? parentDuration);
1583
1586
  if (tStart < fromStart - EPS || tEnd > fromEnd + EPS) {
1584
1587
  throw new Error(`pixi-effects: ${tag} window [${tStart}, ${tEnd}] is not covered by \`from\` "${t.from}" (lives [${fromStart}, ${fromEnd}], so it ends at ${fromEnd})`);
1585
1588
  }
1586
1589
  const toSeq = toEntry.seq;
1587
- const toStart = chunkKJSEQVBV_cjs.resolveAt(toSeq.at, parentDuration);
1590
+ const toStart = chunkQHIOOK5S_cjs.resolveAt(toSeq.at, parentDuration);
1588
1591
  const toEnd = toStart + (toSeq.duration ?? parentDuration);
1589
1592
  if (tStart < toStart - EPS || tEnd > toEnd + EPS) {
1590
1593
  throw new Error(`pixi-effects: ${tag} window [${tStart}, ${tEnd}] is not covered by \`to\` "${t.to}" (lives [${toStart}, ${toEnd}], so it starts at ${toStart})`);
@@ -1644,7 +1647,7 @@ function wrapAsFullComposition(seq, compW, compH) {
1644
1647
  delete inner.at;
1645
1648
  delete inner.duration;
1646
1649
  const m = inner.mask;
1647
- const carriesMatte = m !== void 0 && chunkY5UWFH6Y_cjs.maskSourceOf(m).kind === "refs";
1650
+ const carriesMatte = m !== void 0 && chunkMJMOPWMK_cjs.maskSourceOf(m).kind === "refs";
1648
1651
  if (carriesMatte) delete inner.mask;
1649
1652
  return {
1650
1653
  ...carriesMatte ? { mask: m } : {},
@@ -1899,6 +1902,34 @@ function rejectReservedNameCollision(filters, seqName) {
1899
1902
  }
1900
1903
  }
1901
1904
 
1905
+ // src/core/canvasCheck.ts
1906
+ var isCanvas = (s) => typeof s.checkDeterminism === "function";
1907
+ var describeDiff = (d) => `${d.t} s${d.pixels >= 0 ? ` (${d.pixels} channel values differ, by up to ${d.maxDiff} of 255)` : ""}`;
1908
+ function canvasReport(root) {
1909
+ const out = [];
1910
+ const visit = (seq) => {
1911
+ if (isCanvas(seq)) {
1912
+ const length = seq.duration ?? 0;
1913
+ const moments = [0.15, 0.4, 0.65, 0.9].map((f) => Math.round(f * length * 1e3) / 1e3);
1914
+ const { differs, drawMs, threw } = seq.checkDeterminism(moments);
1915
+ const name = chunk3SAS3ZE5_cjs.describeLayer(seq.spec);
1916
+ const problem = threw.length ? `${name} could not draw at ${threw.map((t) => `${t} s`).join(", ")} (its draw threw, or the layer failed to build): 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): 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` : "";
1917
+ out.push({ name: seq.spec.name ?? name, moments, drawMs, ok: !differs.length && !threw.length, problem });
1918
+ }
1919
+ if (seq instanceof chunkMJMOPWMK_cjs.CompositionSequence) walk2(seq);
1920
+ };
1921
+ const walk2 = (comp) => {
1922
+ for (const { seq } of comp.layers()) {
1923
+ visit(seq);
1924
+ const mask = seq.maskSequence;
1925
+ if (mask) visit(mask);
1926
+ }
1927
+ };
1928
+ walk2(root);
1929
+ return out;
1930
+ }
1931
+ var canvasProblems = (root) => canvasReport(root).filter((r) => !r.ok).map((r) => r.problem);
1932
+
1902
1933
  // src/core/inspect.ts
1903
1934
  function chainOf(node) {
1904
1935
  const chain = [];
@@ -1937,8 +1968,8 @@ function motionOf(keyframes, local, lives, keys = (k) => GEOMETRY.has(k)) {
1937
1968
  let length = 0;
1938
1969
  if (typeof kf.duration === "number") length = kf.duration;
1939
1970
  else if (kf.duration === "auto") {
1940
- const sp = chunkKJSEQVBV_cjs.parseSpring(kf.ease);
1941
- length = sp ? Math.round(chunkKJSEQVBV_cjs.springDuration(sp) * 1e3) / 1e3 : 0.5;
1971
+ const sp = chunkQHIOOK5S_cjs.parseSpring(kf.ease);
1972
+ length = sp ? Math.round(chunkQHIOOK5S_cjs.springDuration(sp) * 1e3) / 1e3 : 0.5;
1942
1973
  }
1943
1974
  if (!(length > 0)) continue;
1944
1975
  const kat = kf.at ?? 0;
@@ -2012,7 +2043,7 @@ function inspectScene(root, frame, time, canvas, opts = {}) {
2012
2043
  if (motion.ever) hasMotion.add(info);
2013
2044
  let shown = bounds ? clip(bounds, view) : null;
2014
2045
  const maskTarget = seq.maskSequence?.target;
2015
- const maskSrc = chunkY5UWFH6Y_cjs.maskSourceOf(seq.spec.mask);
2046
+ const maskSrc = chunkMJMOPWMK_cjs.maskSourceOf(seq.spec.mask);
2016
2047
  if (shown && maskTarget && !(maskSrc.kind === "inline" && maskSrc.invert)) {
2017
2048
  const m = maskTarget.getBounds();
2018
2049
  shown = clip(shown, { x: m.x, y: m.y, width: m.width, height: m.height });
@@ -2021,7 +2052,7 @@ function inspectScene(root, frame, time, canvas, opts = {}) {
2021
2052
  const group = parentScene ?? (name !== void 0 && blending.has(name) ? name : void 0);
2022
2053
  if (group) scene.set(info, group);
2023
2054
  if (zero || seq.showsNothingYet) scaledToNothing.add(info);
2024
- if (seq instanceof chunkY5UWFH6Y_cjs.CompositionSequence) walk2(seq, prefix + label + "/", insideThreeD || threeD, visible, group, motion, zero, parentAlpha * alpha);
2055
+ if (seq instanceof chunkMJMOPWMK_cjs.CompositionSequence) walk2(seq, prefix + label + "/", insideThreeD || threeD, visible, group, motion, zero, parentAlpha * alpha);
2025
2056
  });
2026
2057
  };
2027
2058
  walk2(root, "", false, true);
@@ -2105,7 +2136,7 @@ var round = (n) => Math.round(n * 1e6) / 1e6;
2105
2136
  var family = (name) => name.replace(/\d+/g, "#");
2106
2137
  function detailOf(seq) {
2107
2138
  const s = seq.spec;
2108
- const spans = chunkKJSEQVBV_cjs.spansMeta.get(seq.spec)?.preview;
2139
+ const spans = chunkQHIOOK5S_cjs.spansMeta.get(seq.spec)?.preview;
2109
2140
  if (spans) return spans.length > 60 ? spans.slice(0, 57) + "\u2026" : spans;
2110
2141
  if (typeof s.text === "string") return s.text.length > 60 ? s.text.slice(0, 57) + "\u2026" : s.text;
2111
2142
  if (typeof s.asset === "string") return `asset \u201C${s.asset}\u201D`;
@@ -2121,10 +2152,10 @@ function walk(comp, parentStart, parentEnd, depth, prefix, rows, transitions, lo
2121
2152
  const start = parentStart + (seq.at ?? 0);
2122
2153
  const end = Math.min(parentEnd, seq.duration !== void 0 ? start + seq.duration : parentEnd);
2123
2154
  const span = end - start;
2124
- const keys = (seq.spec.keyframes ?? []).map((kf) => round(start + chunkKJSEQVBV_cjs.resolveAt(kf.at, span))).sort((a, b) => a - b).slice(0, MAX_KEYS);
2155
+ const keys = (seq.spec.keyframes ?? []).map((kf) => round(start + chunkQHIOOK5S_cjs.resolveAt(kf.at, span))).sort((a, b) => a - b).slice(0, MAX_KEYS);
2125
2156
  const row = { path: prefix + name, name, type: seq.spec.type, depth, start: round(start), end: round(end), keys, detail: detailOf(seq), ...local ? { local } : {} };
2126
2157
  const inner = [];
2127
- const isComp = seq instanceof chunkY5UWFH6Y_cjs.CompositionSequence;
2158
+ const isComp = seq instanceof chunkMJMOPWMK_cjs.CompositionSequence;
2128
2159
  if (isComp) {
2129
2160
  const label = seq.remapLabel();
2130
2161
  walk(seq, label ? 0 : start, label ? seq.contentSpan : end, depth + 1, prefix + name + "/", inner, transitions, label ? `${name} ${label}` : local);
@@ -2283,7 +2314,7 @@ function sheetLayout(n, columns, cellW, srcW, srcH, labelH) {
2283
2314
  }
2284
2315
 
2285
2316
  // src/core/vars.ts
2286
- var RESERVED_NAMES = ["w", "h", "W", "H", "GW", "GH", "t", "d", "T", "contain", "cover", "value", ...chunkKJSEQVBV_cjs.EXPRESSION_NAMES];
2317
+ var RESERVED_NAMES = ["w", "h", "W", "H", "GW", "GH", "t", "d", "T", "contain", "cover", "value", ...chunkQHIOOK5S_cjs.EXPRESSION_NAMES];
2287
2318
  var NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;
2288
2319
  var isPlain = (v) => !!v && typeof v === "object" && (Object.getPrototypeOf(v) === Object.prototype || Object.getPrototypeOf(v) === null);
2289
2320
  function normalizeVars(raw, where, warn = (m) => console.warn(m)) {
@@ -2822,8 +2853,8 @@ var Movie = class {
2822
2853
  this.stops = normalizeStops(applyVars(options.composition, this._vars)?.stops, this.duration, this.frameRate);
2823
2854
  this._posterFrame = poster.frame;
2824
2855
  this.background = options.background ?? "#000000";
2825
- this.timeline = chunkKJSEQVBV_cjs.createTimeline({ paused: true, defaults: { ease: "none" } });
2826
- chunkKJSEQVBV_cjs.lengthen(this.timeline, this.duration);
2856
+ this.timeline = chunkQHIOOK5S_cjs.createTimeline({ paused: true, defaults: { ease: "none" } });
2857
+ chunkQHIOOK5S_cjs.lengthen(this.timeline, this.duration);
2827
2858
  const baseAppOptions = {
2828
2859
  width: this.width,
2829
2860
  height: this.height,
@@ -2917,8 +2948,8 @@ var Movie = class {
2917
2948
  height: sizeWins ? height : spec.height ?? height,
2918
2949
  duration: spec.duration ?? this.duration
2919
2950
  } : void 0;
2920
- await chunkKJSEQVBV_cjs.ensureFilterLibrary(seededComposition);
2921
- if (chunkNEUPEENI_cjs.usesAdvancedBlend(seededComposition)) await chunkNEUPEENI_cjs.enableAdvancedBlend(this.app.renderer);
2951
+ await chunkQHIOOK5S_cjs.ensureFilterLibrary(seededComposition);
2952
+ if (chunkJN7JHNZR_cjs.usesAdvancedBlend(seededComposition)) await chunkJN7JHNZR_cjs.enableAdvancedBlend(this.app.renderer);
2922
2953
  const userComposition = seededComposition ? expandTransitions(seededComposition) : void 0;
2923
2954
  const rootSeqSpec = {
2924
2955
  type: "composition",
@@ -2928,7 +2959,7 @@ var Movie = class {
2928
2959
  ...userComposition
2929
2960
  };
2930
2961
  if (userComposition) carryTransitionWindows(userComposition, rootSeqSpec);
2931
- const sequence = new chunkY5UWFH6Y_cjs.CompositionSequence(rootSeqSpec, null, rootShape);
2962
+ const sequence = new chunkMJMOPWMK_cjs.CompositionSequence(rootSeqSpec, null, rootShape);
2932
2963
  lp?.begin("build", countLayers(rootSeqSpec));
2933
2964
  try {
2934
2965
  await sequence.build();
@@ -3064,8 +3095,8 @@ var Movie = class {
3064
3095
  if (!changed) return { reason, ms: 0, audio: "none", frame: this.currentFrame, playing: this.isPlaying, unchanged: true };
3065
3096
  sequence = await this._construct(composition, vars, width, height, void 0, this._resized || sizeChanged);
3066
3097
  alive();
3067
- const timeline = chunkKJSEQVBV_cjs.createTimeline({ paused: true, defaults: { ease: "none" } });
3068
- chunkKJSEQVBV_cjs.lengthen(timeline, this.duration);
3098
+ const timeline = chunkQHIOOK5S_cjs.createTimeline({ paused: true, defaults: { ease: "none" } });
3099
+ chunkQHIOOK5S_cjs.lengthen(timeline, this.duration);
3069
3100
  sequence.bindTimeline(timeline);
3070
3101
  const hadSound = this.audioBuffer !== null;
3071
3102
  const audio = await this._mixSound(sequence, this._ensureAudioContext());
@@ -3362,6 +3393,16 @@ var Movie = class {
3362
3393
  await this.gotoFrame(f, true);
3363
3394
  return inspectScene(this._rootSequence, f, f / this.frameRate, { width: this.width, height: this.height }, opts);
3364
3395
  }
3396
+ /** The canvas layers whose same frame is not the same picture (what `check` reports as a problem): one sentence each. */
3397
+ canvasProblems() {
3398
+ this._requireReady("canvasProblems");
3399
+ return canvasProblems(this._rootSequence);
3400
+ }
3401
+ /** Every canvas layer as the determinism check saw it: the moments drawn, the usual time of a draw in ms, and whether the same time gave the same picture (`check` prints it even when all pass). */
3402
+ canvasReport() {
3403
+ this._requireReady("canvasReport");
3404
+ return canvasReport(this._rootSequence);
3405
+ }
3365
3406
  /**
3366
3407
  * Every layer as a row with absolute start / end / keyframe times (seconds), plus the transition windows. Runs of
3367
3408
  * similar layers (`pop-1` … `pop-12`) are one row with a `parts` span each. Read it, or draw it with `timelineChart()`.
@@ -3779,7 +3820,7 @@ function countLayers(spec) {
3779
3820
  n += 1 + countLayers(s);
3780
3821
  const spans = s.spans;
3781
3822
  if (Array.isArray(spans)) n += spans.length;
3782
- const src = chunkY5UWFH6Y_cjs.maskSourceOf(mask);
3823
+ const src = chunkMJMOPWMK_cjs.maskSourceOf(mask);
3783
3824
  if (src.kind === "inline") n += 1 + countLayers(src.spec);
3784
3825
  }
3785
3826
  return n;
@@ -3868,8 +3909,8 @@ function splitVertical(text, style, ts, right, top, align, by) {
3868
3909
 
3869
3910
  // src/presets/_ease.ts
3870
3911
  function parseEase2(name) {
3871
- chunkKJSEQVBV_cjs.checkEase(name, "a preset");
3872
- return chunkKJSEQVBV_cjs.parseEase(name);
3912
+ chunkQHIOOK5S_cjs.checkEase(name, "a preset");
3913
+ return chunkQHIOOK5S_cjs.parseEase(name);
3873
3914
  }
3874
3915
 
3875
3916
  // src/presets/kenBurns.ts
@@ -4004,17 +4045,17 @@ function orbit(opts) {
4004
4045
  throw new Error("pixi-effects: orbit() cannot combine `radius` with `dollyZoom` \u2014 the radius follows the animated fov");
4005
4046
  }
4006
4047
  const [cx, cy] = opts.center ?? [width / 2, height / 2];
4007
- const fixedR = opts.radius ?? chunkKJSEQVBV_cjs.homeDistance(height, fov ?? chunkKJSEQVBV_cjs.DEFAULT_FOV);
4048
+ const fixedR = opts.radius ?? chunkQHIOOK5S_cjs.homeDistance(height, fov ?? chunkQHIOOK5S_cjs.DEFAULT_FOV);
4008
4049
  const start = opts.start ?? -degrees / 2;
4009
4050
  const steps = Math.max(1, Math.round(duration * stepsPerSecond));
4010
4051
  const easeFn = parseEase2(ease);
4011
4052
  const dollyEase = dolly ? parseEase2(dolly.ease ?? ease) : null;
4012
4053
  const pos = (i) => {
4013
4054
  const p = i / steps;
4014
- const a = (start + degrees * easeFn(p)) * chunkKJSEQVBV_cjs.DEG;
4055
+ const a = (start + degrees * easeFn(p)) * chunkQHIOOK5S_cjs.DEG;
4015
4056
  if (!dolly) return { x: cx + fixedR * Math.sin(a), z: fixedR * Math.cos(a) };
4016
4057
  const f = dolly.from + (dolly.to - dolly.from) * dollyEase(p);
4017
- const R = chunkKJSEQVBV_cjs.homeDistance(height, f);
4058
+ const R = chunkQHIOOK5S_cjs.homeDistance(height, f);
4018
4059
  return { x: cx + R * Math.sin(a), z: R * Math.cos(a), fov: f };
4019
4060
  };
4020
4061
  const keyframes = [];
@@ -4069,7 +4110,7 @@ function particles(opts) {
4069
4110
  const round2 = (v) => Math.round(v * 1e6) / 1e6;
4070
4111
  const out = [];
4071
4112
  for (let i = 0; i < count; i++) {
4072
- const r = chunkKJSEQVBV_cjs.random(seed * 1000003 + i * 7919 + 17);
4113
+ const r = chunkQHIOOK5S_cjs.random(seed * 1000003 + i * 7919 + 17);
4073
4114
  const pick = ([a2, b]) => a2 + r() * (b - a2);
4074
4115
  const born = at + r() * emit;
4075
4116
  const lifetime = pick(life);
@@ -4082,7 +4123,7 @@ function particles(opts) {
4082
4123
  const turn = spin ? pick(spin) : 0;
4083
4124
  const startAngle = spin ? r() * 360 : 0;
4084
4125
  const swayAmp = sway?.amp ?? 0, swayFreq = sway?.freq ?? 1;
4085
- const n0 = sway ? chunkKJSEQVBV_cjs.noise(0, seed * 1000003 + i) : 0;
4126
+ const n0 = sway ? chunkQHIOOK5S_cjs.noise(0, seed * 1000003 + i) : 0;
4086
4127
  const at_ = (t) => {
4087
4128
  const axis = (p0, v0, acc) => {
4088
4129
  if (drag > 0) {
@@ -4091,7 +4132,7 @@ function particles(opts) {
4091
4132
  }
4092
4133
  return p0 + v0 * t + 0.5 * acc * t * t;
4093
4134
  };
4094
- const sw = sway ? swayAmp * (chunkKJSEQVBV_cjs.noise(t * swayFreq, seed * 1000003 + i) - n0) : 0;
4135
+ const sw = sway ? swayAmp * (chunkQHIOOK5S_cjs.noise(t * swayFreq, seed * 1000003 + i) - n0) : 0;
4095
4136
  return { x: axis(x0, vx, wind) + sw, y: axis(y0, vy, gravity) };
4096
4137
  };
4097
4138
  const kfs = [];
@@ -4153,7 +4194,7 @@ function followPath(opts) {
4153
4194
  if (steps > MAX_STEPS) throw new Error(`followPath(): ${steps} samples is too many (max ${MAX_STEPS}); lower frameRate or duration`);
4154
4195
  const segments = [];
4155
4196
  let total = 0;
4156
- for (const line of chunkKJSEQVBV_cjs.flattenSvgPath(d)) {
4197
+ for (const line of chunkQHIOOK5S_cjs.flattenSvgPath(d)) {
4157
4198
  const p = line.closed ? [...line.pts, line.pts[0], line.pts[1]] : line.pts;
4158
4199
  for (let i = 2; i < p.length; i += 2) {
4159
4200
  const len = Math.hypot(p[i] - p[i - 2], p[i + 1] - p[i - 1]);
@@ -4203,6 +4244,45 @@ function followPath(opts) {
4203
4244
  return out;
4204
4245
  }
4205
4246
 
4247
+ // src/core/pathSample.ts
4248
+ function samplePath(d) {
4249
+ 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"');
4250
+ const lines = chunkQHIOOK5S_cjs.flattenSvgPath(d);
4251
+ const segments = [];
4252
+ let length = 0;
4253
+ for (const line of lines) {
4254
+ const p = line.closed ? [...line.pts, line.pts[0], line.pts[1]] : line.pts;
4255
+ for (let i = 2; i < p.length; i += 2) {
4256
+ const len = Math.hypot(p[i] - p[i - 2], p[i + 1] - p[i - 1]);
4257
+ if (len === 0) continue;
4258
+ segments.push({ x0: p[i - 2], y0: p[i - 1], x1: p[i], y1: p[i + 1], start: length, len });
4259
+ length += len;
4260
+ }
4261
+ }
4262
+ if (!(length > 0)) throw new Error(`samplePath(): the path "${d}" has no length (it needs at least two different points)`);
4263
+ const find = (s) => {
4264
+ let lo = 0, hi = segments.length - 1;
4265
+ while (lo < hi) {
4266
+ const mid = lo + hi >> 1;
4267
+ if (segments[mid].start + segments[mid].len < s) lo = mid + 1;
4268
+ else hi = mid;
4269
+ }
4270
+ return segments[lo];
4271
+ };
4272
+ return {
4273
+ length,
4274
+ at(u) {
4275
+ const s = Math.min(Math.max(Number.isFinite(u) ? u : 0, 0), 1) * length;
4276
+ const g = find(s);
4277
+ const t = Math.min(Math.max((s - g.start) / g.len, 0), 1);
4278
+ 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) };
4279
+ },
4280
+ trim(start = 0, end = 1) {
4281
+ return chunkQHIOOK5S_cjs.trimPolylines(lines, start, end).map((l) => l.closed ? [...l.pts, l.pts[0], l.pts[1]] : l.pts);
4282
+ }
4283
+ };
4284
+ }
4285
+
4206
4286
  // src/presets/cameraPath.ts
4207
4287
  var KEYS4 = ["points", "at", "duration", "ease", "look", "lookAhead", "smooth", "from", "to", "frameRate"];
4208
4288
  var MAX_STEPS2 = 4e3;
@@ -4307,7 +4387,7 @@ function distances(n, from, grid, seed) {
4307
4387
  if (n === 0) return [];
4308
4388
  if (from === "random") {
4309
4389
  const order = Array.from({ length: n }, (_, i) => i);
4310
- const r = chunkKJSEQVBV_cjs.random(seed);
4390
+ const r = chunkQHIOOK5S_cjs.random(seed);
4311
4391
  for (let i = n - 1; i > 0; i--) {
4312
4392
  const j = Math.floor(r() * (i + 1));
4313
4393
  [order[i], order[j]] = [order[j], order[i]];
@@ -4369,7 +4449,7 @@ function wiggle(opts) {
4369
4449
  to[n] = p.around;
4370
4450
  return;
4371
4451
  }
4372
- const off = (chunkKJSEQVBV_cjs.rand(seed * 7919 + pi * 104729 + s * 31 + 1) * 2 - 1) * p.amp;
4452
+ const off = (chunkQHIOOK5S_cjs.rand(seed * 7919 + pi * 104729 + s * 31 + 1) * 2 - 1) * p.amp;
4373
4453
  to[n] = typeof p.around === "number" ? p.around + off : `(${p.around}) ${off < 0 ? "-" : "+"} ${Math.abs(off)}`;
4374
4454
  });
4375
4455
  out.push({ at: at + s * stepLen, to, duration: stepLen, ease });
@@ -4823,9 +4903,10 @@ exports.parseEase = parseEase2;
4823
4903
  exports.particles = particles;
4824
4904
  exports.react = react;
4825
4905
  exports.resolveLoader = resolveLoader;
4906
+ exports.samplePath = samplePath;
4826
4907
  exports.splitText = splitText;
4827
4908
  exports.stagger = stagger;
4828
4909
  exports.wiggle = wiggle;
4829
4910
  exports.withFade = withFade;
4830
- //# sourceMappingURL=chunk-CC7SUR7Q.cjs.map
4831
- //# sourceMappingURL=chunk-CC7SUR7Q.cjs.map
4911
+ //# sourceMappingURL=chunk-E26M4NTL.cjs.map
4912
+ //# sourceMappingURL=chunk-E26M4NTL.cjs.map