pixi-effects 0.32.0 → 0.34.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 (60) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +5 -5
  3. package/ai/chat-template.html +3 -3
  4. package/ai/tools/lookup.mjs +29 -6
  5. package/ai/tools/pixi-effects.mjs +1 -1
  6. package/dist/Composition-NDXKQHB4.js +7 -0
  7. package/dist/{Composition-RF7QOEXT.js.map → Composition-NDXKQHB4.js.map} +1 -1
  8. package/dist/Composition-OLH7RC5Z.cjs +16 -0
  9. package/dist/{Composition-LNMKWXSL.cjs.map → Composition-OLH7RC5Z.cjs.map} +1 -1
  10. package/dist/{Spans-SDXABOV6.js → Spans-QHHWC2PB.js} +6 -6
  11. package/dist/{Spans-SDXABOV6.js.map → Spans-QHHWC2PB.js.map} +1 -1
  12. package/dist/{Spans-NQGKVMR5.cjs → Spans-QRMN2EZO.cjs} +11 -11
  13. package/dist/{Spans-NQGKVMR5.cjs.map → Spans-QRMN2EZO.cjs.map} +1 -1
  14. package/dist/{blendModes-MVRLG3T7.js → blendModes-PP5NPBXY.js} +4 -4
  15. package/dist/{blendModes-MVRLG3T7.js.map → blendModes-PP5NPBXY.js.map} +1 -1
  16. package/dist/{blendModes-VTKDXWEN.cjs → blendModes-WIUCYIMC.cjs} +5 -5
  17. package/dist/{blendModes-VTKDXWEN.cjs.map → blendModes-WIUCYIMC.cjs.map} +1 -1
  18. package/dist/{chunk-CRUDOKSD.cjs → chunk-5IJENZOG.cjs} +91 -91
  19. package/dist/{chunk-CRUDOKSD.cjs.map → chunk-5IJENZOG.cjs.map} +1 -1
  20. package/dist/{chunk-FCMOREIS.js → chunk-67LG7MN5.js} +48 -15
  21. package/dist/chunk-67LG7MN5.js.map +1 -0
  22. package/dist/{chunk-K3MAEKFM.cjs → chunk-FVZEBYLW.cjs} +78 -45
  23. package/dist/chunk-FVZEBYLW.cjs.map +1 -0
  24. package/dist/{chunk-FCGYJCVO.cjs → chunk-GL2AQFLQ.cjs} +23 -5
  25. package/dist/chunk-GL2AQFLQ.cjs.map +1 -0
  26. package/dist/{chunk-Z437UWI4.cjs → chunk-IMQJVRMT.cjs} +5 -5
  27. package/dist/{chunk-Z437UWI4.cjs.map → chunk-IMQJVRMT.cjs.map} +1 -1
  28. package/dist/{chunk-C5BNHVKK.js → chunk-ITDYFBB6.js} +23 -5
  29. package/dist/chunk-ITDYFBB6.js.map +1 -0
  30. package/dist/{chunk-QHDN6TF5.cjs → chunk-LEECUCTG.cjs} +44 -25
  31. package/dist/chunk-LEECUCTG.cjs.map +1 -0
  32. package/dist/{chunk-QFNS6BFL.js → chunk-RTJD3ZSW.js} +4 -4
  33. package/dist/{chunk-QFNS6BFL.js.map → chunk-RTJD3ZSW.js.map} +1 -1
  34. package/dist/{chunk-D5BFQVKL.js → chunk-XV4L72FW.js} +5 -5
  35. package/dist/{chunk-D5BFQVKL.js.map → chunk-XV4L72FW.js.map} +1 -1
  36. package/dist/{chunk-AW5NPDE4.js → chunk-Y253JQOH.js} +24 -7
  37. package/dist/chunk-Y253JQOH.js.map +1 -0
  38. package/dist/index.cjs +33 -33
  39. package/dist/index.js +5 -5
  40. package/dist/loader.css +1 -1
  41. package/dist/present.cjs +5 -5
  42. package/dist/present.js +5 -5
  43. package/dist/three.cjs +6 -6
  44. package/dist/three.js +2 -2
  45. package/docs/dsl.md +9 -2
  46. package/llms-full.txt +19 -7
  47. package/package.json +1 -1
  48. package/skills/pixi-effects/SKILL.md +1 -1
  49. package/skills/pixi-effects/reference/pitfalls.md +5 -1
  50. package/skills/pixi-effects/reference/quickstart.md +3 -2
  51. package/skills/pixi-effects/reference/recipes.md +1 -1
  52. package/skills/pixi-effects/template.html +6 -6
  53. package/dist/Composition-LNMKWXSL.cjs +0 -16
  54. package/dist/Composition-RF7QOEXT.js +0 -7
  55. package/dist/chunk-AW5NPDE4.js.map +0 -1
  56. package/dist/chunk-C5BNHVKK.js.map +0 -1
  57. package/dist/chunk-FCGYJCVO.cjs.map +0 -1
  58. package/dist/chunk-FCMOREIS.js.map +0 -1
  59. package/dist/chunk-K3MAEKFM.cjs.map +0 -1
  60. package/dist/chunk-QHDN6TF5.cjs.map +0 -1
@@ -1,7 +1,6 @@
1
- import { CompositionSequence, maskSourceOf } from './chunk-D5BFQVKL.js';
2
- import { EXPRESSION_NAMES, createTimeline, lengthen, ensureFilterLibrary, checkEase, parseEase, homeDistance, DEFAULT_FOV, random, noise, flattenSvgPath, rand, DEG, timeRemapOf, contentLength, resolveAt, spansMeta } from './chunk-AW5NPDE4.js';
3
- import { usesAdvancedBlend, enableAdvancedBlend } from './chunk-QFNS6BFL.js';
4
- import { collectPropKeys } from './chunk-C5BNHVKK.js';
1
+ import { CompositionSequence, maskSourceOf } from './chunk-XV4L72FW.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-Y253JQOH.js';
3
+ import { usesAdvancedBlend, enableAdvancedBlend } from './chunk-RTJD3ZSW.js';
5
4
  import { warnUnknownOptions, suggestName } from './chunk-BXOCEZ4U.js';
6
5
  import { extensions, CullerPlugin, Application, Container, Rectangle, Culler, CanvasTextMetrics, TextStyle, Assets, ExtensionType, Filter, Texture, UniformGroup, GpuProgram, GlProgram, defaultFilterVert } from 'pixi.js';
7
6
  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';
@@ -475,6 +474,7 @@ function analyzeAudio(mix, sources, stats, movieDuration, opts = {}) {
475
474
  const b = s.buffer;
476
475
  return measure(Array.from({ length: b.numberOfChannels }, (_, c) => b.getChannelData(c)), b.sampleRate);
477
476
  };
477
+ const scoreNotes = [];
478
478
  const list = [...sources].sort((a, b) => a.start - b.start).map((s) => {
479
479
  const layer = s.layer ?? "an audio layer";
480
480
  const source = s.source ?? "audio";
@@ -497,13 +497,18 @@ function analyzeAudio(mix, sources, stats, movieDuration, opts = {}) {
497
497
  issues.push(`${layer} (${source}) is cut off by the end of the movie at ${movieDuration}s (it runs to ${s.end.toFixed(2)}s)`);
498
498
  }
499
499
  }
500
+ if (s.music && !s.loop && s.start < movieDuration && !clock) {
501
+ const plays = Math.min(s.end, movieDuration) - s.start;
502
+ const over = s.music.seconds - plays;
503
+ if (over > 2 && over / s.music.seconds > 0.15) scoreNotes.push(`${layer} (${source}): the score is ${Math.round(s.music.seconds * 10) / 10}s long but only ${Math.round(plays * 100) / 100}s of it play, so it is cut off mid-phrase. Write fewer bars (or a faster tempo) so it ends with the movie`);
504
+ }
500
505
  return { layer, source, start: s.start, end: s.end, peakDb, sound, ...s.music ? { music: s.music } : {} };
501
506
  });
502
507
  const whole = measureLoudness(chans, sr);
503
508
  const silences = findSilences(chans, sr, { minLength: 1 });
504
509
  if (whole.clippedSamples > 0) issues.push(`${whole.clippedSamples} sample(s) of the mix are at full scale (clipped) \u2014 lower the volume of the layers that play loudest`);
505
510
  if (whole.truePeakDb > 0) issues.push(`the mix's true peak is ${whole.truePeakDb} dBTP: it will distort when the video is encoded \u2014 lower the volume`);
506
- const notes = [];
511
+ const notes = [...scoreNotes];
507
512
  if (whole.integratedLufs !== null) {
508
513
  if (whole.integratedLufs < LOUDNESS_NOTES.quietBelow) notes.push(`the mix is quiet for web video: ${whole.integratedLufs} LUFS (typical \u221214 to \u221216); raise the volume if that is not on purpose`);
509
514
  else if (whole.integratedLufs > LOUDNESS_NOTES.loudAbove) notes.push(`the mix is loud: ${whole.integratedLufs} LUFS (typical web video \u221214 to \u221216)`);
@@ -1888,15 +1893,42 @@ var clip = (a, b) => {
1888
1893
  const w = Math.min(a.x + a.width, b.x + b.width) - x, h = Math.min(a.y + a.height, b.y + b.height) - y;
1889
1894
  return w > 0 && h > 0 ? { x, y, width: w, height: h } : null;
1890
1895
  };
1896
+ var GEOMETRY = /* @__PURE__ */ new Set(["x", "y", "z", "scale", "scaleX", "scaleY", "rotation", "rotationX", "rotationY", "skewX", "skewY", "positionX", "positionY", "pivotX", "pivotY", "anchorX", "anchorY"]);
1897
+ var NO_MOTION = { running: false, ever: false };
1898
+ var either = (a, b) => ({ running: a.running || b.running, ever: a.ever || b.ever });
1899
+ var TRANSLATION = /* @__PURE__ */ new Set(["x", "y", "z", "positionX", "positionY"]);
1900
+ function motionOf(keyframes, local, lives, keys = (k) => GEOMETRY.has(k)) {
1901
+ let running = false, ever = false;
1902
+ for (const kf of keyframes ?? []) {
1903
+ const names = [kf.set, kf.to, kf.from].flatMap((bag) => bag ? Object.keys(bag) : []);
1904
+ if (!names.some(keys)) continue;
1905
+ let length = 0;
1906
+ if (typeof kf.duration === "number") length = kf.duration;
1907
+ else if (kf.duration === "auto") {
1908
+ const sp = parseSpring(kf.ease);
1909
+ length = sp ? Math.round(springDuration(sp) * 1e3) / 1e3 : 0.5;
1910
+ }
1911
+ if (!(length > 0)) continue;
1912
+ const kat = kf.at ?? 0;
1913
+ const start = kat < 0 ? lives + kat : kat;
1914
+ const repeats = kf.repeat ?? 0;
1915
+ const end = start + length * (repeats + 1) + (kf.repeatDelay ?? 0) * repeats;
1916
+ if (names.some((k) => TRANSLATION.has(k))) ever = true;
1917
+ if (local >= start - 1e-6 && local <= end + 1e-6) running = true;
1918
+ }
1919
+ return { running, ever };
1920
+ }
1891
1921
  function inspectScene(root, frame, time, canvas, opts = {}) {
1892
1922
  const layers = [];
1893
1923
  const view = { x: 0, y: 0, width: canvas.width, height: canvas.height };
1894
1924
  const seen = /* @__PURE__ */ new Map();
1895
1925
  const scene = /* @__PURE__ */ new Map();
1896
1926
  const scaledToNothing = /* @__PURE__ */ new Set();
1897
- const walk2 = (comp, prefix, insideThreeD, parentVisible, parentScene, parentMoving = false, parentZero = false) => {
1927
+ const hasMotion = /* @__PURE__ */ new Set();
1928
+ const walk2 = (comp, prefix, insideThreeD, parentVisible, parentScene, parentMotion = NO_MOTION, parentZero = false) => {
1898
1929
  const blending = /* @__PURE__ */ new Set();
1899
1930
  const now = comp.childTime(time);
1931
+ const cameraMotion = (comp.spec.sequences ?? []).filter((q) => q.type === "camera").reduce((m, q) => either(m, motionOf(q.keyframes, now - comp.childBase - (q.at ?? 0), q.duration ?? comp.duration ?? Infinity, () => true)), NO_MOTION);
1900
1932
  for (const w of transitionWindowsOf(comp.spec)) {
1901
1933
  const start = comp.childBase + w.start, end = comp.childBase + w.end;
1902
1934
  if (now >= start - 1e-9 && now <= end + 1e-9) {
@@ -1923,12 +1955,11 @@ function inspectScene(root, frame, time, canvas, opts = {}) {
1923
1955
  onCanvas = inter === 0 && area > 0 ? "none" : inter >= area - 1e-6 ? "full" : "partial";
1924
1956
  if (area === 0) onCanvas = "none";
1925
1957
  }
1926
- const keys = collectPropKeys(seq.spec);
1927
- const carried = carriers.some((c) => {
1928
- const k = collectPropKeys(c.spec);
1929
- return (c.spec.keyframes ?? []).length > 0 && (k.has("x") || k.has("y") || k.has("rotation") || k.has("scale"));
1930
- });
1931
- const moving = parentMoving || carried || (seq.spec.keyframes ?? []).length > 0 && (keys.has("x") || keys.has("y"));
1958
+ const localOf = (q) => now - comp.childBase - q.at;
1959
+ let motion = either(parentMotion, motionOf(seq.spec.keyframes, localOf(seq), seq.duration ?? Infinity));
1960
+ for (const c of carriers) motion = either(motion, motionOf(c.spec.keyframes, localOf(c), c.duration ?? Infinity));
1961
+ if (threeD) motion = either(motion, cameraMotion);
1962
+ const moving = motion.running;
1932
1963
  const zeroScale = (o) => {
1933
1964
  const s = o?.scale;
1934
1965
  return !!s && (s.x === 0 || s.y === 0);
@@ -1938,6 +1969,7 @@ function inspectScene(root, frame, time, canvas, opts = {}) {
1938
1969
  if (threeD) info.depthBlur = Number(depthBlur.toFixed(2));
1939
1970
  if (threeD && light !== void 0) info.light = Number(light.toFixed(2));
1940
1971
  layers.push(info);
1972
+ if (motion.ever) hasMotion.add(info);
1941
1973
  let shown = bounds ? clip(bounds, view) : null;
1942
1974
  const maskTarget = seq.maskSequence?.target;
1943
1975
  const maskSrc = maskSourceOf(seq.spec.mask);
@@ -1949,7 +1981,7 @@ function inspectScene(root, frame, time, canvas, opts = {}) {
1949
1981
  const group = parentScene ?? (name !== void 0 && blending.has(name) ? name : void 0);
1950
1982
  if (group) scene.set(info, group);
1951
1983
  if (zero || seq.showsNothingYet) scaledToNothing.add(info);
1952
- if (seq instanceof CompositionSequence) walk2(seq, prefix + label + "/", insideThreeD || threeD, visible, group, moving, zero);
1984
+ if (seq instanceof CompositionSequence) walk2(seq, prefix + label + "/", insideThreeD || threeD, visible, group, motion, zero);
1953
1985
  });
1954
1986
  };
1955
1987
  walk2(root, "", false, true);
@@ -1962,6 +1994,7 @@ function inspectScene(root, frame, time, canvas, opts = {}) {
1962
1994
  if (scaledToNothing.has(l)) continue;
1963
1995
  issues.push(`${who} has no size (empty text, or not drawn yet)`);
1964
1996
  } else if (l.moving || scene.has(l)) ; else if (l.onCanvas === "none") {
1997
+ if (hasMotion.has(l)) continue;
1965
1998
  issues.push(`${who} is entirely outside the canvas (at ${Math.round(b.x)},${Math.round(b.y)}, ${Math.round(b.width)}\xD7${Math.round(b.height)})`);
1966
1999
  } else if (l.onCanvas === "partial") {
1967
2000
  const over = [];
@@ -4587,5 +4620,5 @@ function withFade(spec, opts) {
4587
4620
  }
4588
4621
 
4589
4622
  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 };
4590
- //# sourceMappingURL=chunk-FCMOREIS.js.map
4591
- //# sourceMappingURL=chunk-FCMOREIS.js.map
4623
+ //# sourceMappingURL=chunk-67LG7MN5.js.map
4624
+ //# sourceMappingURL=chunk-67LG7MN5.js.map