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,6 +1,7 @@
1
- import { CompositionSequence, maskSourceOf } from './chunk-AZ6AINSW.js';
2
- import { EXPRESSION_NAMES, createTimeline, lengthen, ensureFilterLibrary, checkEase, parseEase, homeDistance, DEFAULT_FOV, random, noise, flattenSvgPath, rand, DEG, timeRemapOf, contentLength, resolveAt, parseSpring, springDuration, spansMeta } from './chunk-G3DX65HO.js';
3
- import { usesAdvancedBlend, enableAdvancedBlend } from './chunk-WIIU42FH.js';
1
+ import { CompositionSequence, maskSourceOf } from './chunk-IPQNT65V.js';
2
+ import { EXPRESSION_NAMES, createTimeline, lengthen, ensureFilterLibrary, checkEase, parseEase, homeDistance, DEFAULT_FOV, random, noise, flattenSvgPath, trimPolylines, rand, DEG, timeRemapOf, contentLength, resolveAt, parseSpring, springDuration, spansMeta } from './chunk-SBR75G73.js';
3
+ import { usesAdvancedBlend, enableAdvancedBlend } from './chunk-VNP7QCJE.js';
4
+ import { describeLayer } from './chunk-32MMNDDN.js';
4
5
  import { warnUnknownOptions, suggestName } from './chunk-BXOCEZ4U.js';
5
6
  import { extensions, CullerPlugin, Application, Container, Rectangle, Culler, CanvasTextMetrics, TextStyle, Assets, ExtensionType, Filter, Texture, UniformGroup, GpuProgram, GlProgram, defaultFilterVert } from 'pixi.js';
6
7
  import { Output, BufferTarget, CanvasSource, AudioBufferSource, Input, ALL_FORMATS, BlobSource, WavOutputFormat, Conversion, VideoSampleSink, OggOutputFormat, QUALITY_VERY_HIGH, QUALITY_HIGH, QUALITY_MEDIUM, QUALITY_LOW, QUALITY_VERY_LOW, MkvOutputFormat, WebMOutputFormat, MovOutputFormat, Mp4OutputFormat, canEncodeVideo, getFirstEncodableAudioCodec } from 'mediabunny';
@@ -517,8 +518,8 @@ function analyzeAudio(mix, sources, stats, movieDuration, opts = {}) {
517
518
  });
518
519
  if (buried.length > 0) {
519
520
  const worst = buried.reduce((a, b) => b.belowMixDb > a.belowMixDb ? b : a);
520
- const names = new Set(buried.map((x) => x.layer + x.source));
521
- 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`);
521
+ const distinct = new Set(buried.map((x) => (x.layer === "an audio layer" ? `#${buried.indexOf(x)}` : x.layer) + x.source)).size;
522
+ 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`);
522
523
  }
523
524
  const whole = measureLoudness(chans, sr);
524
525
  const silences = findSilences(chans, sr, { minLength: 1 });
@@ -693,12 +694,14 @@ async function reviewMovie(movie, opts = {}) {
693
694
  if (r.issues.length) perFrame.push({ frame, issues: r.issues });
694
695
  }
695
696
  const grouped = splitIssues(groupIssues(perFrame), !!opts.strict);
697
+ const canvas = movie.canvasReport();
698
+ for (const r of canvas) if (!r.ok) grouped.problems.push({ message: r.problem, count: 1, firstFrame: 0, lastFrame: 0, kind: "canvas" });
696
699
  const fonts = movie.inspectFonts();
697
700
  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 });
698
701
  for (const m of fonts.missing) {
699
702
  (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 });
700
703
  }
701
- return { frames: frames.length, problems: grouped.problems, review: grouped.review, fonts, audio: movie.audioBuffer ? movie.inspectAudio() : null, at };
704
+ return { frames: frames.length, problems: grouped.problems, review: grouped.review, canvas, fonts, audio: movie.audioBuffer ? movie.inspectAudio() : null, at };
702
705
  }
703
706
 
704
707
  // src/core/onion.ts
@@ -1897,6 +1900,34 @@ function rejectReservedNameCollision(filters, seqName) {
1897
1900
  }
1898
1901
  }
1899
1902
 
1903
+ // src/core/canvasCheck.ts
1904
+ var isCanvas = (s) => typeof s.checkDeterminism === "function";
1905
+ var describeDiff = (d) => `${d.t} s${d.pixels >= 0 ? ` (${d.pixels} channel values differ, by up to ${d.maxDiff} of 255)` : ""}`;
1906
+ function canvasReport(root) {
1907
+ const out = [];
1908
+ const visit = (seq) => {
1909
+ if (isCanvas(seq)) {
1910
+ const length = seq.duration ?? 0;
1911
+ const moments = [0.15, 0.4, 0.65, 0.9].map((f) => Math.round(f * length * 1e3) / 1e3);
1912
+ const { differs, drawMs, threw } = seq.checkDeterminism(moments);
1913
+ const name = describeLayer(seq.spec);
1914
+ 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` : "";
1915
+ out.push({ name: seq.spec.name ?? name, moments, drawMs, ok: !differs.length && !threw.length, problem });
1916
+ }
1917
+ if (seq instanceof CompositionSequence) walk2(seq);
1918
+ };
1919
+ const walk2 = (comp) => {
1920
+ for (const { seq } of comp.layers()) {
1921
+ visit(seq);
1922
+ const mask = seq.maskSequence;
1923
+ if (mask) visit(mask);
1924
+ }
1925
+ };
1926
+ walk2(root);
1927
+ return out;
1928
+ }
1929
+ var canvasProblems = (root) => canvasReport(root).filter((r) => !r.ok).map((r) => r.problem);
1930
+
1900
1931
  // src/core/inspect.ts
1901
1932
  function chainOf(node) {
1902
1933
  const chain = [];
@@ -3360,6 +3391,16 @@ var Movie = class {
3360
3391
  await this.gotoFrame(f, true);
3361
3392
  return inspectScene(this._rootSequence, f, f / this.frameRate, { width: this.width, height: this.height }, opts);
3362
3393
  }
3394
+ /** The canvas layers whose same frame is not the same picture (what `check` reports as a problem): one sentence each. */
3395
+ canvasProblems() {
3396
+ this._requireReady("canvasProblems");
3397
+ return canvasProblems(this._rootSequence);
3398
+ }
3399
+ /** 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). */
3400
+ canvasReport() {
3401
+ this._requireReady("canvasReport");
3402
+ return canvasReport(this._rootSequence);
3403
+ }
3363
3404
  /**
3364
3405
  * Every layer as a row with absolute start / end / keyframe times (seconds), plus the transition windows. Runs of
3365
3406
  * similar layers (`pop-1` … `pop-12`) are one row with a `parts` span each. Read it, or draw it with `timelineChart()`.
@@ -4201,6 +4242,45 @@ function followPath(opts) {
4201
4242
  return out;
4202
4243
  }
4203
4244
 
4245
+ // src/core/pathSample.ts
4246
+ function samplePath(d) {
4247
+ 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"');
4248
+ const lines = flattenSvgPath(d);
4249
+ const segments = [];
4250
+ let length = 0;
4251
+ for (const line of lines) {
4252
+ const p = line.closed ? [...line.pts, line.pts[0], line.pts[1]] : line.pts;
4253
+ for (let i = 2; i < p.length; i += 2) {
4254
+ const len = Math.hypot(p[i] - p[i - 2], p[i + 1] - p[i - 1]);
4255
+ if (len === 0) continue;
4256
+ segments.push({ x0: p[i - 2], y0: p[i - 1], x1: p[i], y1: p[i + 1], start: length, len });
4257
+ length += len;
4258
+ }
4259
+ }
4260
+ if (!(length > 0)) throw new Error(`samplePath(): the path "${d}" has no length (it needs at least two different points)`);
4261
+ const find = (s) => {
4262
+ let lo = 0, hi = segments.length - 1;
4263
+ while (lo < hi) {
4264
+ const mid = lo + hi >> 1;
4265
+ if (segments[mid].start + segments[mid].len < s) lo = mid + 1;
4266
+ else hi = mid;
4267
+ }
4268
+ return segments[lo];
4269
+ };
4270
+ return {
4271
+ length,
4272
+ at(u) {
4273
+ const s = Math.min(Math.max(Number.isFinite(u) ? u : 0, 0), 1) * length;
4274
+ const g = find(s);
4275
+ const t = Math.min(Math.max((s - g.start) / g.len, 0), 1);
4276
+ 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) };
4277
+ },
4278
+ trim(start = 0, end = 1) {
4279
+ return trimPolylines(lines, start, end).map((l) => l.closed ? [...l.pts, l.pts[0], l.pts[1]] : l.pts);
4280
+ }
4281
+ };
4282
+ }
4283
+
4204
4284
  // src/presets/cameraPath.ts
4205
4285
  var KEYS4 = ["points", "at", "duration", "ease", "look", "lookAhead", "smooth", "from", "to", "frameRate"];
4206
4286
  var MAX_STEPS2 = 4e3;
@@ -4802,6 +4882,6 @@ function withFade(spec, opts) {
4802
4882
  return spec;
4803
4883
  }
4804
4884
 
4805
- export { Movie, animateText, audioEnvelope, bpmEnvelope, cameraPath, computeEnvelope, dismissLoader, failLoader, followPath, kenBurns, measureText, musicBuffer, musicEnvelope, musicEvents, orbit, parseEase2 as parseEase, particles, react, resolveLoader, splitText, stagger, wiggle, withFade };
4806
- //# sourceMappingURL=chunk-VF56PRAA.js.map
4807
- //# sourceMappingURL=chunk-VF56PRAA.js.map
4885
+ export { Movie, animateText, audioEnvelope, bpmEnvelope, cameraPath, computeEnvelope, dismissLoader, failLoader, followPath, kenBurns, measureText, musicBuffer, musicEnvelope, musicEvents, orbit, parseEase2 as parseEase, particles, react, resolveLoader, samplePath, splitText, stagger, wiggle, withFade };
4886
+ //# sourceMappingURL=chunk-KNDEKWQO.js.map
4887
+ //# sourceMappingURL=chunk-KNDEKWQO.js.map