pixi-effects 0.27.2 → 0.28.1

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 (66) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +6 -6
  3. package/ai/chat-template.html +3 -3
  4. package/ai/tools/check.mjs +30 -0
  5. package/dist/{Base-CKGl6jCo.d.ts → Base-C6f0fE8j.d.ts} +1 -1
  6. package/dist/{Base-DjhdL8B1.d.cts → Base-DI1FCGcH.d.cts} +1 -1
  7. package/dist/Composition-HFEVIYHN.js +7 -0
  8. package/dist/{Composition-TZHVYIGH.js.map → Composition-HFEVIYHN.js.map} +1 -1
  9. package/dist/Composition-NI74UJT3.cjs +16 -0
  10. package/dist/{Composition-DRCTWIYH.cjs.map → Composition-NI74UJT3.cjs.map} +1 -1
  11. package/dist/Controller.d.cts +2 -2
  12. package/dist/Controller.d.ts +2 -2
  13. package/dist/{Movie-CbYwTs6U.d.cts → Movie-CHcM8HNB.d.ts} +3 -1
  14. package/dist/{Movie-ILKq2fw_.d.ts → Movie-Cx5ozUGb.d.cts} +3 -1
  15. package/dist/Presenter.d.cts +2 -2
  16. package/dist/Presenter.d.ts +2 -2
  17. package/dist/chunk-4LEX3G3M.cjs +259 -0
  18. package/dist/chunk-4LEX3G3M.cjs.map +1 -0
  19. package/dist/{chunk-BQNNZEAX.js → chunk-AK54FIWM.js} +7 -4
  20. package/dist/chunk-AK54FIWM.js.map +1 -0
  21. package/dist/{chunk-YOV6MEXH.cjs → chunk-MZCDBRTY.cjs} +7 -4
  22. package/dist/chunk-MZCDBRTY.cjs.map +1 -0
  23. package/dist/{chunk-C7HJJ7MZ.cjs → chunk-SBOVUZZY.cjs} +61 -61
  24. package/dist/{chunk-C7HJJ7MZ.cjs.map → chunk-SBOVUZZY.cjs.map} +1 -1
  25. package/dist/{chunk-K3F2YKL4.js → chunk-WEJAQAFX.js} +3 -3
  26. package/dist/{chunk-K3F2YKL4.js.map → chunk-WEJAQAFX.js.map} +1 -1
  27. package/dist/chunk-ZHUUIF6A.js +250 -0
  28. package/dist/chunk-ZHUUIF6A.js.map +1 -0
  29. package/dist/events-EE3SM5LM.cjs +16 -0
  30. package/dist/events-EE3SM5LM.cjs.map +1 -0
  31. package/dist/events-KXBWR4IV.js +3 -0
  32. package/dist/events-KXBWR4IV.js.map +1 -0
  33. package/dist/index.cjs +49 -33
  34. package/dist/index.cjs.map +1 -1
  35. package/dist/index.d.cts +19 -5
  36. package/dist/index.d.ts +19 -5
  37. package/dist/index.js +18 -7
  38. package/dist/index.js.map +1 -1
  39. package/dist/loader.css +1 -1
  40. package/dist/{music-6MTHQEXS.cjs → music-6WFTPVHU.cjs} +43 -202
  41. package/dist/music-6WFTPVHU.cjs.map +1 -0
  42. package/dist/{music-72YJAMXH.js → music-JKOM5YK6.js} +8 -192
  43. package/dist/music-JKOM5YK6.js.map +1 -0
  44. package/dist/three.cjs +5 -5
  45. package/dist/three.d.cts +2 -2
  46. package/dist/three.d.ts +2 -2
  47. package/dist/three.js +1 -1
  48. package/dist/{types-BNVsBBZf.d.ts → types-DpK1vwcl.d.cts} +79 -1
  49. package/dist/{types-BNVsBBZf.d.cts → types-DpK1vwcl.d.ts} +79 -1
  50. package/docs/api.md +28 -0
  51. package/docs/dsl.md +8 -4
  52. package/llms-full.txt +216 -6
  53. package/llms.txt +1 -0
  54. package/package.json +1 -1
  55. package/skills/pixi-effects/SKILL.md +11 -1
  56. package/skills/pixi-effects/reference/cheatsheet.md +1 -1
  57. package/skills/pixi-effects/reference/direction.md +136 -0
  58. package/skills/pixi-effects/reference/pitfalls.md +3 -0
  59. package/skills/pixi-effects/reference/recipes.md +25 -0
  60. package/skills/pixi-effects/template.html +6 -6
  61. package/dist/Composition-DRCTWIYH.cjs +0 -16
  62. package/dist/Composition-TZHVYIGH.js +0 -7
  63. package/dist/chunk-BQNNZEAX.js.map +0 -1
  64. package/dist/chunk-YOV6MEXH.cjs.map +0 -1
  65. package/dist/music-6MTHQEXS.cjs.map +0 -1
  66. package/dist/music-72YJAMXH.js.map +0 -1
@@ -0,0 +1,136 @@
1
+ # Directing a film (for any AI that makes video with code)
2
+
3
+ Read this before you write a composition for anything longer than a title card: a product film, a company introduction, a launch, a data story. It is about the decisions around the renderer, so it names no tool; `SKILL.md` has the pixi-effects commands.
4
+
5
+ A one-line prompt makes the model fill every missing decision with its safest default: large text in the middle, a gradient behind it, everything fading in, the logo last. The fix is not a cleverer prompt. It is to remove the missing decisions before anything is drawn, and to judge what was drawn with evidence.
6
+
7
+ ## The five layers (do not collapse them into one step)
8
+
9
+ | Layer | The question | Where the answer lives |
10
+ |---|---|---|
11
+ | Director | What is the film trying to say, to whom? | `brief.md` |
12
+ | Reference | What should it look and feel like? | `style-guide.md` |
13
+ | Timeline | What changes at each beat, and why? | `shotlist.md` |
14
+ | Renderer | How is every frame produced? | `src/` (seekable code) |
15
+ | Critic | What failed, exactly where, and why? | `reviews/` |
16
+
17
+ ## Keep the decisions in files, not in the chat
18
+
19
+ A film whose only record is a conversation is a lucky session. Put the decisions where the next run can read them:
20
+
21
+ ```
22
+ film/
23
+ brief.md the one-sentence goal, the audience, the product facts, the real assets
24
+ style-guide.md palette, type, motion rules, banned defaults
25
+ shotlist.md beats, states, timestamps, purpose
26
+ assets/ approved logos, photos, screens, footage, sound
27
+ src/ the composition and its code
28
+ reviews/ contact sheets and defect notes
29
+ out/ exports
30
+ ```
31
+
32
+ The next film swaps the brief and the assets and keeps the rest. A run that stops can resume from the last file it finished and say which one is missing; "the last command exited 0" is never the definition of done.
33
+
34
+ ## brief.md: facts about the product, choices about the film
35
+
36
+ Separate what is true (it comes from the product) from what is chosen (it comes from you). The model may invent a camera move or a stronger opening. It may not invent a dashboard, a figure, a logo or a client.
37
+
38
+ ```
39
+ FILM
40
+ One sentence: what the viewer should remember
41
+ Audience: who it is for
42
+ Duration: seconds
43
+ Formats: ask the human; one format unless they name more (see "Formats" below)
44
+
45
+ ASSETS (paths; everything on screen comes from here)
46
+ Logo · photos · screens · copy and numbers · brand type and colours · sound reference
47
+
48
+ VISUAL RULES
49
+ Keep: traits taken from the reference
50
+ Avoid: the clichés you will not use
51
+ Never: invent a product screen, a metric, a claim or a logo
52
+
53
+ DELIVERABLES
54
+ Final video, poster frame, contact sheets, source, an asset list, a note on what a human still has to check
55
+ ```
56
+
57
+ **Collect the assets first, list them, and read the list before building.** If the brief needs an asset that is missing, stop and ask. A convincing fake (a drawn logo, an invented dashboard, a guessed number) is the one failure that cannot be repaired afterwards. Words and numbers on screen are the source's own; take colours and type from the source itself (a site's CSS, a brand sheet), never from an adjective such as "premium".
58
+
59
+ ## style-guide.md: a visual grammar written down
60
+
61
+ Without one the model supplies its own, which is why unrelated one-prompt films look related. Give it a frame, a film or the real site, and make it write what it saw:
62
+
63
+ ```
64
+ REFERENCE ANALYSIS
65
+ Palette: the actual colours (hex), not an adjective
66
+ Typography: family, weight, scale
67
+ Composition: where the eye goes first
68
+ Pacing: average time between meaningful changes
69
+ Motion: snap, glide, overshoot, cut or hold
70
+ Texture: grain, paper, glass, flat
71
+ DO NOT COPY: the reference's subjects, logos, copy or product imagery
72
+ ```
73
+
74
+ The result is a style guide, not a collage of borrowed shots. Add a **motion rule per class of object**, because "motion with weight" is the difference between decoration and direction: small controls snap, large panels settle, the camera is almost invisible, headlines enter strongly and then hold long enough to read, one playful object is allowed to overshoot. If everything overshoots, nothing feels precise. After each move ask: does the viewer know where to look?
75
+
76
+ ## shotlist.md: states and beats, not effects
77
+
78
+ "Zoom in, then morph, then add particles" lists activity. A plan says what the viewer knows at each moment:
79
+
80
+ ```
81
+ 00-02 HOOK one image that earns attention
82
+ 02-05 PROBLEM the friction, shown, not described in a paragraph
83
+ 05-09 REVEAL the product enters through a real interaction
84
+ 09-13 PROOF one screen or number that demonstrates the claim
85
+ 13-16 CLOSE a clean final state and a readable call to action
86
+ ```
87
+
88
+ Each row has an entry state, an exit state and a reason to exist. For a UI film write the state list first (SEARCH → RESULT → DETAIL → ACTION → CONFIRMATION) so one component can change size, colour and content while staying recognisably the same object. The shot list is a contract: a shot nobody can justify is cut.
89
+
90
+ ## Seekable and deterministic, or it cannot be reviewed
91
+
92
+ Frame 240 must render directly, without replaying frames 0 to 239: no hidden clock, no unseeded randomness, nothing that only works after eight seconds of running. Think of a frame as a query: `frame = render(time, shotlist, assets, style, seed)`. Then a revision is local (change one time value, one curve, one asset) and a reviewed frame stays reviewed. Two renders of the same moment must give the same pixels; check it.
93
+
94
+ ## Sound is on the same timeline
95
+
96
+ Many AI films look finished with the sound off; then the click lands after the button, the cut misses the beat, the logo arrives before the music resolves. Write a beat grid and drive picture and sound from it: choose a tempo whose bar is a round number of seconds, put every cut on a bar line and every cue on the beat it belongs to. With a licensed or original track, measure its beats and cut against them. Test: close your eyes and listen; if the film has no shape without the picture, the sound is not finished.
97
+
98
+ ## Review the rendered frames, not your intent
99
+
100
+ Do not start by watching a full export ten times, and do not describe what you meant to make. Ask the renderer for a contact sheet: one frame at every beat, a short strip around the fastest transitions, and a frame from the middle of each cut taken from the exported file. Look cold, then write the **three largest defects**, each with a **timestamp**, the **evidence** (what you see) and a **local fix**; patch only those, render those frames again. Ask for a second pair of eyes on the sheet whenever one is available: the author reads their own intent into it.
101
+
102
+ ```
103
+ [ ] text readable at phone size (about 34 px or more on a 1080p frame)
104
+ [ ] nothing in the outer 5 % of the frame
105
+ [ ] real assets only, none redrawn or invented
106
+ [ ] one type and colour system across scenes
107
+ [ ] no awkward half-transition frame
108
+ [ ] cuts and sound cues land together
109
+ [ ] the first two seconds are a real hook
110
+ [ ] the last frame works as a poster
111
+ ```
112
+
113
+ "The agent made a video" stops when the file exists. "The agent directed a video" stops when the evidence says the film works.
114
+
115
+ ## Formats
116
+
117
+ A 16:9 film and a 9:16 cut are different compositions: the vertical one needs larger type, fewer things at once, another layout, sometimes a tighter story. Never crop the middle of the wide one. **Do not make a format nobody asked for:** ask which formats are wanted, make one if the answer is "whatever", and offer the others. When more than one is wanted, keep the same assets, timeline and states, define the layout per format, and look at a contact sheet of each: an export is correct because the composition survived the format, not because the encoder finished.
118
+
119
+ ## Gates, and what to do when no human is there
120
+
121
+ Long runs need places to stop. With a human present:
122
+
123
+ 1. approve the references and the asset list
124
+ 2. approve the style guide and the shot list
125
+ 3. look at representative stills
126
+ 4. look at a rough cut and its contact sheet
127
+ 5. repair the three highest-impact defects
128
+ 6. check sound, formats and deliverables
129
+
130
+ Between gates the agent may work for hours; it never makes an irreversible brand decision (logo, claim, number) for the human, and a missing real asset is a blocker, not an invitation to invent one. If the reference is unclear, the right output is a question or one small test frame, not nine hundred polished wrong ones. With nobody to ask, record each decision you took as a "ruling" in the review notes, with what it costs if wrong, and finish with a short note of what still needs a human.
131
+
132
+ ## The loop
133
+
134
+ PROMPT → CLIP is a demo. BRIEF → SYSTEM → FILM → REVIEW → BETTER SYSTEM is a studio: every stage leaves evidence the next one can use, and the tenth film can be better than the first.
135
+
136
+ *The shape of this guide follows a published breakdown of building a code-rendered video studio around an AI model ("Motion Engineering", @0xwhrrari, September 2026); the wording and the checklist are rewritten for this library's users.*
@@ -127,3 +127,6 @@ A good habit that catches most of these: after `init`, read `window.__logs` (see
127
127
  97. **A deck inside your own composition loses its `transitions` and `stops`** unless you take them across: `const d = deck({ width: 1920, height: 1080, pages })`, then `{ type: 'composition', sequences: d.composition.sequences, transitions: d.composition.transitions }`. Pass `width` / `height` yourself for a page that is not the movie's own size.
128
128
  98. **A matte layer needs a fill.** A named matte (`mask: 'glass'`) that is a shape with no `fillColor` / `fillGradient` (or a text with no fill) cuts everything away and nothing warns: the layers it should show simply vanish. Give the matte a fill (white for `alpha`, a gradient for `luma`).
129
129
  99. **In a `music` score a capital letter is a chord and a lowercase one a note.** `G7` is G dominant seventh, `C5` a power chord, `C6` a sixth chord; `g7`, `c5`, `c6` are notes (octave 7 is a very high note: it used to be what `G7` meant, silently). A bare note in capitals (`Bb2`) is refused with the lowercase spelling (`bb2`); inside brackets (`[C4 E4 G4]`) any case is a note. An unknown chord kind suggests the nearest (`Cmin7` → `Cm7`, `Csus` → `Csus4`, `CM7` → `Cmaj7`).
130
+ 100. **Read the score back before you trust it.** `check` prints a `music` block: every track's length in bars (a track that ends early or has a short bar is named), the names that start in each bar with their beat (`Am(2)` starts on beat 2; no mark = the downbeat; the first four names of a bar are shown, `musicEvents()` lists everything), and the drum span. Count bars by the read-back, not by hand: a bar of 3 beats in a score with no `meter` is shown as bars of 4, so set `meter: 3` for a waltz. Drums repeat by themselves and `from` / `to` are beats; `swing` only moves notes that start off the beat, so a comp on beats 2 and 4 stays straight.
131
+ 101. **A film built from one adjective looks like every other one.** Read `reference/direction.md` and write `brief.md` / `style-guide.md` / `shotlist.md` first: real assets with paths, the one sentence to remember, a row per beat with entry and exit state. If a real asset is missing, ask: a drawn fake (a logo, a dashboard, a figure) is the failure that matters. Judge the contact sheet cold: three defects, each with a timestamp, evidence and a local fix.
132
+ 102. **A vertical cut is a second composition, not a crop, and only when someone asked for it.** One source, a layout function, `?f=9x16`; `check` and `render` take `--query f=9x16` (recipe `two-formats`). Look at a contact sheet of each format: type that fits wide is tiny tall. Ask which formats are wanted; make one if the answer is open. In a 1080p film keep every line of text at 34 px or more; if you cannot read it in a sheet tile, a phone cannot.
@@ -1103,6 +1103,31 @@ return [
1103
1103
  ];
1104
1104
  ```
1105
1105
 
1106
+ ## One source, two formats (16:9 and 9:16), and a photo inside a region
1107
+
1108
+ Only when a vertical cut is wanted (ask first). It is not a crop of the wide one: write each scene as a function of a layout, switch with a query (`?f=9x16`), and render each format on its own: `npx pixi-effects check film.html --query f=9x16`, `npx pixi-effects render film.html --query f=9x16 -o film-9x16.mp4`. `photo()` fits a picture into any rectangle like CSS `cover` (scale from the image's own size, a mask for the rectangle); `scale: 'cover'` only fits the PARENT.
1109
+
1110
+ ```js
1111
+ // @docs-only two-formats
1112
+ const PORTRAIT = new URLSearchParams(location.search).get('f') === '9x16';
1113
+ const W = PORTRAIT ? 1080 : 1920, H = PORTRAIT ? 1920 : 1080, MX = PORTRAIT ? 76 : 150; // margins: nothing important in the outer 5 %
1114
+ const IMG = { hero: [1920, 1280] }; // each photo's size (assets: [{ name: 'hero', src: '...' }])
1115
+ const photo = (key, x, y, w, h, duration) => {
1116
+ const cover = Math.max(w / IMG[key][0], h / IMG[key][1]);
1117
+ return { type: 'image', asset: key, duration,
1118
+ mask: { type: 'shape', shape: 'rect', width: w, height: h, initial: { x: x + w / 2, y: y + h / 2, fillColor: '#fff' } }, // the mask lives in the parent's coordinates
1119
+ initial: { x: x + w / 2, y: y + h / 2, anchorX: 0.5, anchorY: 0.5, scale: cover }, // image anchors go in `initial`
1120
+ keyframes: [{ at: 0, to: { scale: cover * 1.1 }, duration, ease: 'sine.inOut' }] }; // a slow push
1121
+ };
1122
+ const scene = { type: 'composition', name: 'hook', at: 0, duration: 5.5, width: W, height: H, sequences: [
1123
+ photo('hero', 0, 0, W, H, 5.5),
1124
+ { type: 'text', text: 'Headline', initial: { x: MX, y: PORTRAIT ? 1150 : 620 }, style: { fontSize: PORTRAIT ? 100 : 112, fill: '#fff' } }, // wide: lower left; tall: lower third
1125
+ ] };
1126
+ // movie.init({ width: W, height: H, composition: { sequences: [scene] } })
1127
+ ```
1128
+
1129
+ ---
1130
+
1106
1131
  ## A batch of videos from a table (one video per row)
1107
1132
 
1108
1133
  A batch of videos is a loop outside the video. The page reads what changes from its address (`new URLSearchParams(location.search)`), and `pixi-effects-render --query "name=Aiko&score=92"` opens it with those values. Names with spaces or non-Latin letters must be URL-encoded (`jq -sRr @uri` as below, or `encodeURIComponent` in Node). Each video starts its own browser, so N videos cost N start-ups: try one with `--draft` (half size, fast), then render the real ones. To make the pieces of one row differ in more than text, use the same values to pick colours or an image name.
@@ -4,7 +4,7 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1" />
6
6
  <title>pixi-effects video</title>
7
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/pixi-effects@0.27.2/dist/loader.css" /> <!-- the loader: HTML + CSS only, so it is on screen at once and keeps moving while the page builds the video -->
7
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/pixi-effects@0.28.1/dist/loader.css" /> <!-- the loader: HTML + CSS only, so it is on screen at once and keeps moving while the page builds the video -->
8
8
  <style>
9
9
  body { background: #0d1220; margin: 0; padding: 16px; }
10
10
  .stage { position: relative; width: min(960px, 100%); } /* the player and the loader both sit inside this box */
@@ -37,16 +37,16 @@
37
37
  "imports": {
38
38
  "pixi.js": "https://esm.sh/pixi.js@8.22.0?bundle-deps",
39
39
  "mediabunny": "https://esm.sh/mediabunny",
40
- "pixi-effects": "https://cdn.jsdelivr.net/npm/pixi-effects@0.27.2/dist/index.js",
41
- "pixi-effects/controller": "https://cdn.jsdelivr.net/npm/pixi-effects@0.27.2/dist/Controller.js",
42
- "pixi-effects/presenter": "https://cdn.jsdelivr.net/npm/pixi-effects@0.27.2/dist/Presenter.js",
43
- "pixi-effects/three": "https://cdn.jsdelivr.net/npm/pixi-effects@0.27.2/dist/three.js",
40
+ "pixi-effects": "https://cdn.jsdelivr.net/npm/pixi-effects@0.28.1/dist/index.js",
41
+ "pixi-effects/controller": "https://cdn.jsdelivr.net/npm/pixi-effects@0.28.1/dist/Controller.js",
42
+ "pixi-effects/presenter": "https://cdn.jsdelivr.net/npm/pixi-effects@0.28.1/dist/Presenter.js",
43
+ "pixi-effects/three": "https://cdn.jsdelivr.net/npm/pixi-effects@0.28.1/dist/three.js",
44
44
  "pixi-filters": "https://esm.sh/pixi-filters@6.1.5?external=pixi.js",
45
45
  "three": "https://esm.sh/three@0.178.0"
46
46
  }
47
47
  }
48
48
  </script>
49
- <link rel="modulepreload" href="https://cdn.jsdelivr.net/npm/pixi-effects@0.27.2/dist/index.js" /> <!-- after the import map: the library downloads while the page is parsed -->
49
+ <link rel="modulepreload" href="https://cdn.jsdelivr.net/npm/pixi-effects@0.28.1/dist/index.js" /> <!-- after the import map: the library downloads while the page is parsed -->
50
50
 
51
51
  <script type="module">
52
52
  import { Movie, kenBurns, withFade } from 'pixi-effects';
@@ -1,16 +0,0 @@
1
- 'use strict';
2
-
3
- var chunkC7HJJ7MZ_cjs = require('./chunk-C7HJJ7MZ.cjs');
4
- require('./chunk-YOV6MEXH.cjs');
5
- require('./chunk-P4GY3Z4G.cjs');
6
- require('./chunk-ZMAD3KJU.cjs');
7
- require('./chunk-TWZNOUM7.cjs');
8
-
9
-
10
-
11
- Object.defineProperty(exports, "CompositionSequence", {
12
- enumerable: true,
13
- get: function () { return chunkC7HJJ7MZ_cjs.CompositionSequence; }
14
- });
15
- //# sourceMappingURL=Composition-DRCTWIYH.cjs.map
16
- //# sourceMappingURL=Composition-DRCTWIYH.cjs.map
@@ -1,7 +0,0 @@
1
- export { CompositionSequence } from './chunk-K3F2YKL4.js';
2
- import './chunk-BQNNZEAX.js';
3
- import './chunk-TYWFKCPY.js';
4
- import './chunk-45QKLD6M.js';
5
- import './chunk-BXOCEZ4U.js';
6
- //# sourceMappingURL=Composition-TZHVYIGH.js.map
7
- //# sourceMappingURL=Composition-TZHVYIGH.js.map