pixi-effects 0.16.3 → 0.18.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 (48) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/README.md +7 -7
  3. package/ai/CHAT.md +7 -0
  4. package/ai/SKILL.md +3 -2
  5. package/ai/chat-template.html +8 -4
  6. package/ai/reference/cheatsheet.md +6 -2
  7. package/ai/reference/pitfalls.md +3 -0
  8. package/ai/reference/recipes.md +67 -0
  9. package/ai/template.html +5 -5
  10. package/ai/tools/check.mjs +119 -59
  11. package/ai/tools/render.mjs +22 -7
  12. package/dist/Composition-6JMXWNVV.cjs +14 -0
  13. package/dist/{Composition-3WWNVRR5.cjs.map → Composition-6JMXWNVV.cjs.map} +1 -1
  14. package/dist/Composition-MLBHYYFF.js +5 -0
  15. package/dist/{Composition-VJWY2NDL.js.map → Composition-MLBHYYFF.js.map} +1 -1
  16. package/dist/Controller.d.cts +1 -1
  17. package/dist/Controller.d.ts +1 -1
  18. package/dist/{Movie-DilBC348.d.ts → Movie-DlHQ9C02.d.ts} +126 -2
  19. package/dist/{Movie-oA0SUAyb.d.cts → Movie-K2YuVAdg.d.cts} +126 -2
  20. package/dist/Presenter.d.cts +1 -1
  21. package/dist/Presenter.d.ts +1 -1
  22. package/dist/{chunk-FJA5VUOF.cjs → chunk-ANO5R2E6.cjs} +25 -3
  23. package/dist/chunk-ANO5R2E6.cjs.map +1 -0
  24. package/dist/{chunk-2ROVCPSL.cjs → chunk-JW67MDHQ.cjs} +32 -27
  25. package/dist/chunk-JW67MDHQ.cjs.map +1 -0
  26. package/dist/{chunk-ZNKQH356.js → chunk-SG3Y66FN.js} +25 -4
  27. package/dist/chunk-SG3Y66FN.js.map +1 -0
  28. package/dist/{chunk-XTIHKODH.js → chunk-UXDR3ZDU.js} +10 -5
  29. package/dist/chunk-UXDR3ZDU.js.map +1 -0
  30. package/dist/index.cjs +464 -43
  31. package/dist/index.cjs.map +1 -1
  32. package/dist/index.d.cts +1 -1
  33. package/dist/index.d.ts +1 -1
  34. package/dist/index.js +442 -21
  35. package/dist/index.js.map +1 -1
  36. package/dist/loader.css +1 -1
  37. package/dist/three.cjs +5 -5
  38. package/dist/three.js +1 -1
  39. package/docs/dsl.md +2 -1
  40. package/llms-full.txt +81 -5
  41. package/llms.txt +1 -1
  42. package/package.json +6 -3
  43. package/dist/Composition-3WWNVRR5.cjs +0 -14
  44. package/dist/Composition-VJWY2NDL.js +0 -5
  45. package/dist/chunk-2ROVCPSL.cjs.map +0 -1
  46. package/dist/chunk-FJA5VUOF.cjs.map +0 -1
  47. package/dist/chunk-XTIHKODH.js.map +0 -1
  48. package/dist/chunk-ZNKQH356.js.map +0 -1
@@ -5,6 +5,12 @@ import { U as Stop, e as AssetSpec, c as CompositionSpec } from './types-SS51lP6
5
5
  interface AudioInspectOptions {
6
6
  /** Width of each loudness window in seconds. Default 0.1. */
7
7
  window?: number;
8
+ /** The scenes to measure one by one (`movie.inspectAudio()` fills this from the movie's named top-level compositions). Default: the whole movie as one. */
9
+ scenes?: Array<{
10
+ name: string;
11
+ start: number;
12
+ end: number;
13
+ }>;
8
14
  }
9
15
  /** One sound measured ON ITS OWN (not mixed), so overlapping layers do not blur it. */
10
16
  interface SoundMeasure {
@@ -44,8 +50,76 @@ interface AudioReport {
44
50
  peakDb: number;
45
51
  brightnessHz: number;
46
52
  }>;
47
- /** Problems worth fixing: limiting, inaudible layers, sounds cut off by the end of the movie. Read this first. */
53
+ /** Problems worth fixing: limiting, clipping, a true peak above 0 dBTP, inaudible layers, sounds cut off by the end of the movie. Read this first. */
48
54
  issues: string[];
55
+ /** The mix as a whole (ITU-R BS.1770 loudness; `integratedLufs` is null for a mix shorter than 0.4 s or with nothing above −70 LUFS). */
56
+ loudness: {
57
+ integratedLufs: number | null;
58
+ truePeakDb: number;
59
+ clippedSamples: number;
60
+ silences: Array<{
61
+ from: number;
62
+ to: number;
63
+ }>;
64
+ };
65
+ /** The same measure for each scene (`silent`: nothing above −60 dBFS). */
66
+ scenes: Array<{
67
+ name: string;
68
+ from: number;
69
+ to: number;
70
+ lufs: number | null;
71
+ peakDb: number;
72
+ silent: boolean;
73
+ }>;
74
+ /** When each sound starts: what a waveform marks. */
75
+ cues: Array<{
76
+ t: number;
77
+ name: string;
78
+ }>;
79
+ /** Advice, not faults: a mix that is quiet or loud for web video, little headroom, silent stretches. */
80
+ notes: string[];
81
+ }
82
+
83
+ interface FontReport {
84
+ /** Text layers none of whose fonts is available here: they are drawn in a fallback. */
85
+ missing: Array<{
86
+ layer: string;
87
+ family: string;
88
+ }>;
89
+ /** Web fonts (`@font-face`) whose file could not be loaded and that a text layer uses. */
90
+ failed: string[];
91
+ /** Web fonts whose file could not be loaded but no text layer uses (an unused face: worth a look, not a fault). */
92
+ failedUnused: string[];
93
+ }
94
+
95
+ /** One kind of issue, with how many frames it was seen in. Issues that differ only by numbers are one kind. */
96
+ interface IssueGroup {
97
+ message: string;
98
+ count: number;
99
+ firstFrame: number;
100
+ lastFrame: number;
101
+ }
102
+ interface ReviewOptions {
103
+ /** Moments to resolve and report: `3.5`, `50%`, `f120`, `title@end` (comma-separated). */
104
+ at?: string;
105
+ /** Every layout issue is a problem (by default text overlaps are only listed for review). */
106
+ strict?: boolean;
107
+ }
108
+ interface ReviewReport {
109
+ /** How many frames were inspected. */
110
+ frames: number;
111
+ /** Text cut off by an edge, outside the canvas, or with no size (with `strict`: every issue). */
112
+ problems: IssueGroup[];
113
+ /** Text overlaps and fonts that are not available: often intentional, look at them on the contact sheet. */
114
+ review: IssueGroup[];
115
+ fonts: FontReport;
116
+ /** The sound as numbers (`movie.inspectAudio()`), or null for a movie with no audio. */
117
+ audio: AudioReport | null;
118
+ /** The moments of `at`, as frames with a label that is safe as a file name. */
119
+ at: Array<{
120
+ label: string;
121
+ frame: number;
122
+ }>;
49
123
  }
50
124
 
51
125
  interface Rect {
@@ -107,6 +181,8 @@ interface TimelineRow {
107
181
  start: number;
108
182
  end: number;
109
183
  }>;
184
+ /** With `parts`: the name of each layer the row stands for, in the same order (so `render({ range: 'pop-3' })` can find it). */
185
+ partNames?: string[];
110
186
  /** A short text for the tooltip (a text layer's words, an asset name). */
111
187
  detail?: string;
112
188
  }
@@ -196,6 +272,15 @@ interface RenderOptions {
196
272
  codec?: string;
197
273
  bitrate?: 'very-low' | 'low' | 'medium' | 'high' | 'very-high';
198
274
  };
275
+ /**
276
+ * Only part of the movie: `[from, to]` in seconds, or the name of a top-level layer (its start to its end). The file starts at 0
277
+ * and its sound is cut the same way (with a 10 ms fade on a cut edge). Past the end, backwards or an unknown name is an error.
278
+ */
279
+ range?: [number, number] | string;
280
+ /** Output size relative to the canvas, above 0 and at most 1. Each frame is drawn at full size and copied smaller before it is encoded: the file and the encoding get smaller, the drawing is not faster. */
281
+ scale?: number;
282
+ /** For looking, not for delivering: `scale: 0.5`, `video.bitrate: 'low'` and no motion blur. Anything you set yourself wins. */
283
+ draft?: boolean;
199
284
  }
200
285
  interface SnapshotOptions {
201
286
  /** Motion blur for this picture (see `MovieOptions.motionBlur`); overrides the movie's own setting, `false` turns it off. */
@@ -248,6 +333,19 @@ interface ContactSheetOptions {
248
333
  cellWidth?: number;
249
334
  as?: 'blob' | 'dataURL';
250
335
  }
336
+ interface OnionSkinOptions {
337
+ /** Where the movement starts, in seconds. Default 0. */
338
+ from?: number;
339
+ /** Where it ends, in seconds. Default: the end of the movie. */
340
+ to?: number;
341
+ /** How many frames are overlaid, 1–64, spread evenly from `from` to `to`. Default 8. */
342
+ count?: number;
343
+ /** Output size relative to the canvas, above 0 and at most 4. Default 1. */
344
+ scale?: number;
345
+ /** Motion blur for these pictures (see `MovieOptions.motionBlur`); overrides the movie's own setting, `false` turns it off. */
346
+ motionBlur?: MotionBlurSpec;
347
+ as?: 'blob' | 'dataURL';
348
+ }
251
349
  interface FrameEvent {
252
350
  frame: number;
253
351
  totalFrames: number;
@@ -419,6 +517,17 @@ declare class Movie {
419
517
  motionBlur?: MotionBlurSpec;
420
518
  onImage?: (image: StopImage) => void;
421
519
  }): Promise<Blob>;
520
+ /**
521
+ * One picture of a movement: `count` frames from `from` to `to` drawn one over the other, each later one stronger, so a thing that
522
+ * moves leaves a trail (its path and its easing: even steps = constant speed, bunched = slow) and what stays still stays itself.
523
+ * The movie is left where it was.
524
+ */
525
+ onionSkin(opts?: OnionSkinOptions & {
526
+ as?: 'blob';
527
+ }): Promise<Blob>;
528
+ onionSkin(opts: OnionSkinOptions & {
529
+ as: 'dataURL';
530
+ }): Promise<string>;
422
531
  /**
423
532
  * Several frames on ONE image, each labelled with its frame number and time — the cheapest way to
424
533
  * check a whole animation by eye. Restores the current frame afterwards.
@@ -447,6 +556,21 @@ declare class Movie {
447
556
  * The soundtrack, measured: when every audio layer plays, how loud the mix is over time, and `issues`
448
557
  * (limiting, inaudible layers, sounds cut off by the end). Use it to CHECK sound you cannot hear.
449
558
  */
559
+ /** The pictures to look at for moments such as `3.5`, `50%`, `f120`, `title@end` (comma-separated). A mistake says what could not be read. */
560
+ resolveAt(list: string): Array<{
561
+ label: string;
562
+ frame: number;
563
+ }>;
564
+ /**
565
+ * One call that looks at everything `pixi-effects-check` looks at inside the page: layout issues over the whole timeline (every
566
+ * scene's first and last frame and a frame every 0.25 s), fonts and the sound. See `ReviewReport`. Page warnings are in `window.__logs`. The movie is left as it was.
567
+ */
568
+ review(opts?: ReviewOptions): Promise<ReviewReport>;
569
+ /**
570
+ * The fonts of the text layers: `missing` lists layers none of whose `fontFamily` entries is available in this browser (they are
571
+ * drawn in a fallback font), `failed` lists web fonts (`@font-face`) whose file could not be loaded.
572
+ */
573
+ inspectFonts(): FontReport;
450
574
  inspectAudio(opts?: AudioInspectOptions): AudioReport;
451
575
  /**
452
576
  * Draw the stage now. PixiJS's CullerPlugin only culls inside `app.render()` (the ticker), and we render
@@ -509,4 +633,4 @@ declare class Movie {
509
633
  destroy(): Promise<void>;
510
634
  }
511
635
 
512
- export { type AudioInspectOptions as A, type ContactSheetOptions as C, type FrameEvent as F, type InspectOptions as I, type LayerInfo as L, type MotionBlurOptions as M, type ProgressEvent as P, type RenderOptions as R, type SnapshotOptions as S, type TimelineData as T, type VolumeEvent as V, type AudioReport as a, type AudioSourceReport as b, type InspectReport as c, type LoaderOption as d, type MotionBlurSpec as e, Movie as f, type MovieErrorEvent as g, type MovieOptions as h, type SoundMeasure as i, type StopEvent as j, type StopImage as k, type StopImagesOptions as l, type TimelineHtmlOptions as m, type TimelineRow as n, type TimelineSvgOptions as o, type TimelineTransition as p, dismissLoader as q, failLoader as r, resolveLoader as s };
636
+ export { type AudioInspectOptions as A, type ContactSheetOptions as C, type FontReport as F, type InspectOptions as I, type LayerInfo as L, type MotionBlurOptions as M, type OnionSkinOptions as O, type ProgressEvent as P, type RenderOptions as R, type SnapshotOptions as S, type TimelineData as T, type VolumeEvent as V, type AudioReport as a, type AudioSourceReport as b, type FrameEvent as c, type InspectReport as d, type IssueGroup as e, type LoaderOption as f, type MotionBlurSpec as g, Movie as h, type MovieErrorEvent as i, type MovieOptions as j, type ReviewOptions as k, type ReviewReport as l, type SoundMeasure as m, type StopEvent as n, type StopImage as o, type StopImagesOptions as p, type TimelineHtmlOptions as q, type TimelineRow as r, type TimelineSvgOptions as s, type TimelineTransition as t, dismissLoader as u, failLoader as v, resolveLoader as w };
@@ -1,4 +1,4 @@
1
- import { f as Movie } from './Movie-oA0SUAyb.cjs';
1
+ import { h as Movie } from './Movie-K2YuVAdg.cjs';
2
2
  import 'pixi.js';
3
3
  import 'gsap';
4
4
  import './types-SS51lP6O.cjs';
@@ -1,4 +1,4 @@
1
- import { f as Movie } from './Movie-DilBC348.js';
1
+ import { h as Movie } from './Movie-DlHQ9C02.js';
2
2
  import 'pixi.js';
3
3
  import 'gsap';
4
4
  import './types-SS51lP6O.js';
@@ -310,6 +310,26 @@ function looksLikeColorString(s) {
310
310
  if (s.charCodeAt(0) === 35) return true;
311
311
  return /^(rgb|hsl|oklab|oklch|lab|lch)\b/i.test(s);
312
312
  }
313
+ var FAMILIES = ["power1", "power2", "power3", "power4", "back", "elastic", "bounce", "circ", "expo", "sine"];
314
+ var EASE_NAMES = ["none", ...FAMILIES.flatMap((f) => [`${f}.in`, `${f}.out`, `${f}.inOut`])];
315
+ var warned = /* @__PURE__ */ new Set();
316
+ function checkEase(ease, where) {
317
+ if (typeof ease !== "string") return;
318
+ const found = gsap.gsap.parseEase(ease);
319
+ if (typeof found === "function") return;
320
+ if (warned.has(ease)) return;
321
+ warned.add(ease);
322
+ if (ease === "") {
323
+ console.warn(`pixi-effects: ${where}: an empty ease (GSAP would run its default, power1.out): write 'none' for no easing, or a name such as 'power2.out'`);
324
+ return;
325
+ }
326
+ if (found && /^power[1-4]$/i.test(ease)) {
327
+ console.warn(`pixi-effects: ${where}: "${ease}" is a family, not an ease \u2014 write ${ease.toLowerCase()}.out, ${ease.toLowerCase()}.in or ${ease.toLowerCase()}.inOut`);
328
+ return;
329
+ }
330
+ const guess = chunkUQBGW5DO_cjs.suggestName(ease, EASE_NAMES);
331
+ console.warn(`pixi-effects: ${where}: unknown ease "${ease}"${guess ? ` \u2014 did you mean "${guess}"?` : ""} (GSAP would run it as its default ease, power1.out). Examples: ${EASE_NAMES.slice(0, 7).join(", ")}, back.out(1.7), elastic.out(1, 0.3), steps(8)`);
332
+ }
313
333
 
314
334
  // src/core/Timeline.ts
315
335
  function loopVars(kf) {
@@ -337,6 +357,7 @@ function normalizeKeyframe(kf, parentDuration) {
337
357
  const at = resolveAt(kf.at, parentDuration);
338
358
  const duration = kf.duration ?? 0;
339
359
  const ease = kf.ease ?? "none";
360
+ checkEase(ease, "a keyframe");
340
361
  const hasSet = !!kf.set;
341
362
  const hasFrom = !!kf.from;
342
363
  const hasTo = !!kf.to;
@@ -2754,7 +2775,7 @@ function numOrZero(v, scope) {
2754
2775
  var _CompositionSequence = null;
2755
2776
  async function getCompositionSequence() {
2756
2777
  if (!_CompositionSequence) {
2757
- _CompositionSequence = (await import('./Composition-3WWNVRR5.cjs')).CompositionSequence;
2778
+ _CompositionSequence = (await import('./Composition-6JMXWNVV.cjs')).CompositionSequence;
2758
2779
  }
2759
2780
  return _CompositionSequence;
2760
2781
  }
@@ -2801,6 +2822,7 @@ exports.Sequence = Sequence;
2801
2822
  exports.buildScope = buildScope;
2802
2823
  exports.buildSequenceTree = buildSequenceTree;
2803
2824
  exports.cameraBasis = cameraBasis;
2825
+ exports.checkEase = checkEase;
2804
2826
  exports.collectPropKeys = collectPropKeys;
2805
2827
  exports.describeLayer = describeLayer;
2806
2828
  exports.ensureFilterLibrary = ensureFilterLibrary;
@@ -2817,5 +2839,5 @@ exports.random = random;
2817
2839
  exports.registerSequenceType = registerSequenceType;
2818
2840
  exports.resolveAt = resolveAt;
2819
2841
  exports.summarizeWarnings = summarizeWarnings;
2820
- //# sourceMappingURL=chunk-FJA5VUOF.cjs.map
2821
- //# sourceMappingURL=chunk-FJA5VUOF.cjs.map
2842
+ //# sourceMappingURL=chunk-ANO5R2E6.cjs.map
2843
+ //# sourceMappingURL=chunk-ANO5R2E6.cjs.map