pixi-effects 0.26.1 → 0.26.3
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.
- package/CHANGELOG.md +22 -0
- package/README.md +6 -6
- package/ai/chat-template.html +3 -3
- package/ai/tools/render.mjs +16 -11
- package/dist/Composition-3O7L2VL5.js +7 -0
- package/dist/{Composition-Z2VY3KWZ.js.map → Composition-3O7L2VL5.js.map} +1 -1
- package/dist/Composition-EE3KEE2L.cjs +16 -0
- package/dist/{Composition-THQPG4E5.cjs.map → Composition-EE3KEE2L.cjs.map} +1 -1
- package/dist/Controller.d.cts +1 -1
- package/dist/Controller.d.ts +1 -1
- package/dist/{Movie-i05Oh9mJ.d.cts → Movie-BWLLWRRe.d.cts} +10 -3
- package/dist/{Movie-DVeDTdnc.d.ts → Movie-BkP82KXS.d.ts} +10 -3
- package/dist/Presenter.d.cts +1 -1
- package/dist/Presenter.d.ts +1 -1
- package/dist/{chunk-EABL3UKJ.cjs → chunk-A225HYSY.cjs} +351 -20
- package/dist/chunk-A225HYSY.cjs.map +1 -0
- package/dist/{chunk-JHJNEIDI.js → chunk-FXAHNPBP.js} +351 -20
- package/dist/chunk-FXAHNPBP.js.map +1 -0
- package/dist/{chunk-H3RHEH5W.cjs → chunk-IIDBEYQH.cjs} +59 -59
- package/dist/{chunk-H3RHEH5W.cjs.map → chunk-IIDBEYQH.cjs.map} +1 -1
- package/dist/{chunk-YEVAUQ6Y.js → chunk-WMMZDPWK.js} +3 -3
- package/dist/{chunk-YEVAUQ6Y.js.map → chunk-WMMZDPWK.js.map} +1 -1
- package/dist/index.cjs +144 -50
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +121 -27
- package/dist/index.js.map +1 -1
- package/dist/loader.css +1 -1
- package/dist/{music-AF4VTFAF.js → music-3O5MDQXY.js} +52 -6
- package/dist/music-3O5MDQXY.js.map +1 -0
- package/dist/{music-KB7YZLHP.cjs → music-4O367SPR.cjs} +52 -6
- package/dist/music-4O367SPR.cjs.map +1 -0
- package/dist/three.cjs +5 -5
- package/dist/three.js +1 -1
- package/docs/api.md +11 -5
- package/docs/dsl.md +4 -2
- package/llms-full.txt +21 -12
- package/package.json +1 -1
- package/skills/pixi-effects/SKILL.md +1 -1
- package/skills/pixi-effects/reference/cheatsheet.md +4 -4
- package/skills/pixi-effects/reference/pitfalls.md +1 -0
- package/skills/pixi-effects/template.html +6 -6
- package/dist/Composition-THQPG4E5.cjs +0 -16
- package/dist/Composition-Z2VY3KWZ.js +0 -7
- package/dist/chunk-EABL3UKJ.cjs.map +0 -1
- package/dist/chunk-JHJNEIDI.js.map +0 -1
- package/dist/music-AF4VTFAF.js.map +0 -1
- package/dist/music-KB7YZLHP.cjs.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.26.3
|
|
4
|
+
|
|
5
|
+
**Added**
|
|
6
|
+
|
|
7
|
+
- **Sound-only export.** `render({ format: 'wav' })` (16-bit PCM) and `render({ format: 'ogg' })` (Opus) write the movie's mixed sound without drawing a frame, with `range` cutting it; `pixi-effects render page.html -o mix.wav` does it from a script. A movie with no sound says so instead of writing an empty file.
|
|
8
|
+
- **Video codec and bitrate options.** `render({ video: { codec, bitrate, hardware, keyFrameInterval } })`: `codec` is `avc`, `hevc`, `vp9`, `av1` or `vp8` (checked against the container and against what this browser can encode: the usual one falls back to the next that works with a warning, a codec you name is used or the error names the one that would work, and `h264` gets a did-you-mean); `bitrate` is a quality name or bits a second (`8_000_000`, `'8M'`, `'800k'`); `hardware` picks the encoder; `keyFrameInterval` (seconds, default 2). The render command gains `--video-bitrate`.
|
|
9
|
+
- **Relative keyframe values.** `to`, `from` and `set` accept `'+=36'` / `'-=36'`, measured from where the layer stands, with an expression on the right (`'-=GW*0.1'`): `from: { x: '-=36' }` is the usual slide-in, `to: { y: '+=40' }` a nudge, and keyframes one after another stack in any order of seeking. Until now `'+=36'` was evaluated as an expression and became **0 with no warning**; in `initial`, a style or the start of a `from` + `to` it now warns and is read as the number. (GSAP supported relative values all along; the keyframe pipeline did not let them through.)
|
|
10
|
+
|
|
11
|
+
**Changed**
|
|
12
|
+
|
|
13
|
+
- **Video: the pauses of reverse play and of a loop are read ahead.** A looping layer reads the first frames of the file (and a pass behind them) before the end comes, so the wrap shows no pause (a 30 s loop of two heavy layers: 0 pauses, it had 3). Reverse play reads the next window in the background while the held frames last, and each window now just fits what is held: one heavy layer played backwards shows 29.3 distinct frames a second with 1 pause in 6 s (24.8 and 6 pauses without the read-ahead, 14.1 and 31 before 0.26.2); four heavy layers, each reading its own window, reach 18 a second. Frames are now let go by where the playhead is (the ones it has passed first), not by age. Measured with the on-screen frame-number method of 0.26.2, on an M1 Pro.
|
|
14
|
+
|
|
15
|
+
## 0.26.2
|
|
16
|
+
|
|
17
|
+
**Fixed**
|
|
18
|
+
|
|
19
|
+
- **`music`: `G7`, `A7`, `E7`, `Bb7`, `C6`, `C5`, `D9` were read as single notes** (`G7` = the note G in octave 7, about 3 kHz) instead of chords, with no warning, and the documented example `G7:4` had the bug. The rule is now one line: **a capital letter starts a chord, a lowercase one is a note** (`G7` the chord, `g7` the note). A bare note in capitals (`Bb2`) is refused with its lowercase spelling (`bb2`), inside brackets any case is a note, and an unknown chord kind suggests the nearest (`Cmin7` → `Cm7`, `Csus` → `Csus4`). Scores that wrote notes in capitals (the gallery's spring-marquee did) need lowercase.
|
|
20
|
+
|
|
21
|
+
**Changed**
|
|
22
|
+
|
|
23
|
+
- **Video layers read frames in one decoder pass, not one seek per frame.** A render with a video layer is much faster: 1080p, 8 s, one layer 10.6 s → 6.1 s (the same as no video), four layers of one file 22.5 s → 6.8 s, reverse playback 11 s → 6.7 s (measured on an M1 Pro; a `getSample` per frame cost 19-25 ms, a pass under 1 ms). The pictures are the same (a snapshot of 125 frames in order, out of order, at speed 2 / 0.5 / -1 and looped matched the old reader byte for byte). Live playback is smoother too (measured by reading which frame is on screen every animation frame, 1080p, 6 s): the old reader fell behind as soon as the footage was heavy or there were several layers (one heavy layer: 79 % of the frames late, 14.5 distinct frames a second; four heavy layers: 95 % late, 6.6 a second); the new one keeps 30 a second in every case tried (0 to 0.3 % late), and a 30 s loop with two heavy layers showed no warning. Dragging the playhead forward costs about 4 ms a step instead of 62 ms; a far jump (a seek) is one frame as before (about 65 ms on heavy footage); reverse play and dragging backwards are much faster on average but still pause for 0.1-0.2 s about every 30 frames and at each loop wrap. A video layer now holds decoded frames up to about 96 MB (never fewer than 3) instead of 30 whatever the size, so a 4K layer no longer holds hundreds of MB.
|
|
24
|
+
|
|
3
25
|
## 0.26.1
|
|
4
26
|
|
|
5
27
|
**Fixed**
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# pixi-effects
|
|
2
2
|
|
|
3
|
-
> **Status**: experimental — current release `0.26.
|
|
3
|
+
> **Status**: experimental — current release `0.26.3`. The API may still change between minor versions; see the [CHANGELOG](./CHANGELOG.md) for what each release changed.
|
|
4
4
|
|
|
5
5
|
**[Guide →](https://yjmtmtk.github.io/pixi-effects/guide/)** · **[Gallery →](https://yjmtmtk.github.io/pixi-effects/examples/gallery/)** · 50 portfolio pieces written as plain data by AI models · **[Examples →](https://yjmtmtk.github.io/pixi-effects/examples/)** · 15 numbered examples, a music lab + an in-browser playground.
|
|
6
6
|
|
|
@@ -51,8 +51,8 @@ Drop the imports into an [importmap](https://developer.mozilla.org/docs/Web/HTML
|
|
|
51
51
|
"gsap": "https://esm.sh/gsap@3.12.5",
|
|
52
52
|
"gsap/PixiPlugin": "https://esm.sh/gsap@3.12.5/PixiPlugin",
|
|
53
53
|
"mediabunny": "https://esm.sh/mediabunny",
|
|
54
|
-
"pixi-effects": "https://cdn.jsdelivr.net/npm/pixi-effects@0.26.
|
|
55
|
-
"pixi-effects/controller": "https://cdn.jsdelivr.net/npm/pixi-effects@0.26.
|
|
54
|
+
"pixi-effects": "https://cdn.jsdelivr.net/npm/pixi-effects@0.26.3/dist/index.js",
|
|
55
|
+
"pixi-effects/controller": "https://cdn.jsdelivr.net/npm/pixi-effects@0.26.3/dist/Controller.js"
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
</script>
|
|
@@ -63,7 +63,7 @@ Drop the imports into an [importmap](https://developer.mozilla.org/docs/Web/HTML
|
|
|
63
63
|
</script>
|
|
64
64
|
```
|
|
65
65
|
|
|
66
|
-
Load the `dist/` files **as they are** (jsDelivr's `/npm/…/dist/…`, or unpkg's `https://unpkg.com/pixi-effects@0.26.
|
|
66
|
+
Load the `dist/` files **as they are** (jsDelivr's `/npm/…/dist/…`, or unpkg's `https://unpkg.com/pixi-effects@0.26.3/dist/index.js`) rather than a CDN-rebundled build such as `esm.sh/pixi-effects` or jsDelivr's `+esm`: the entries (`pixi-effects`, `…/controller`, `…/three`) share internal chunks, which only works when each file is served untouched.
|
|
67
67
|
|
|
68
68
|
> **Using three.js?** Add two more entries (`three` and `pixi-effects/three`) to this importmap — see [Adding three.js](#adding-threejs-optional) below.
|
|
69
69
|
>
|
|
@@ -79,7 +79,7 @@ Add two more entries to the importmap above: three.js itself, and the `pixi-effe
|
|
|
79
79
|
"imports": {
|
|
80
80
|
"...": "(everything from the importmap above)",
|
|
81
81
|
"three": "https://esm.sh/three@0.178.0",
|
|
82
|
-
"pixi-effects/three": "https://cdn.jsdelivr.net/npm/pixi-effects@0.26.
|
|
82
|
+
"pixi-effects/three": "https://cdn.jsdelivr.net/npm/pixi-effects@0.26.3/dist/three.js"
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
85
|
</script>
|
|
@@ -173,7 +173,7 @@ sequences: [
|
|
|
173
173
|
This library is designed to be written by AI: a video is plain data, and every mistake we found while having AI sessions build test animations is either warned about at runtime or written down.
|
|
174
174
|
|
|
175
175
|
- [`llms.txt`](./llms.txt) / [`llms-full.txt`](./llms-full.txt) — index and full text for LLM tooling (generated from the files below).
|
|
176
|
-
- [`skills/pixi-effects/SKILL.md`](./skills/pixi-effects/SKILL.md) — a [skill](https://docs.claude.com/en/docs/claude-code/skills) (workflow, rules, verification loop).
|
|
176
|
+
- [`skills/pixi-effects/SKILL.md`](./skills/pixi-effects/SKILL.md) — a [skill](https://docs.claude.com/en/docs/claude-code/skills) (workflow, rules, verification loop). Install it with `npx skills add yjmtmtk/pixi-effects` (or copy the `skills/pixi-effects/` folder to `~/.claude/skills/pixi-effects/` or your project's `.claude/skills/`) and your agent loads it by itself when you ask for a video.
|
|
177
177
|
- [`skills/pixi-effects/reference/cheatsheet.md`](./skills/pixi-effects/reference/cheatsheet.md), [`recipes.md`](./skills/pixi-effects/reference/recipes.md) (tested), [`pitfalls.md`](./skills/pixi-effects/reference/pitfalls.md), and a starter [`skills/pixi-effects/template.html`](./skills/pixi-effects/template.html).
|
|
178
178
|
|
|
179
179
|
- **Look at a page with its timeline, and scrub one with the other:** `npx pixi-effects view my-video.html` (or `node ai/tools/view.mjs …`) opens your browser on a viewer: the page on top, the timeline of every layer under it with a playhead that follows the movie. Click or drag the timeline to seek, click a layer's name to jump to where it starts, Space plays, ← / → step a frame, + / − (or Ctrl/⌘ + wheel) zoom, the names stay in place. For the human who wants to see what the AI made.
|
package/ai/chat-template.html
CHANGED
|
@@ -61,9 +61,9 @@
|
|
|
61
61
|
"gsap": "https://cdn.jsdelivr.net/npm/gsap@3.12.5/+esm",
|
|
62
62
|
"gsap/PixiPlugin": "https://cdn.jsdelivr.net/npm/gsap@3.12.5/PixiPlugin/+esm",
|
|
63
63
|
"mediabunny": "https://cdn.jsdelivr.net/npm/mediabunny@1.61.3/+esm",
|
|
64
|
-
"pixi-effects": "https://cdn.jsdelivr.net/npm/pixi-effects@0.26.
|
|
65
|
-
"pixi-effects/controller": "https://cdn.jsdelivr.net/npm/pixi-effects@0.26.
|
|
66
|
-
"pixi-effects/presenter": "https://cdn.jsdelivr.net/npm/pixi-effects@0.26.
|
|
64
|
+
"pixi-effects": "https://cdn.jsdelivr.net/npm/pixi-effects@0.26.3/dist/index.js",
|
|
65
|
+
"pixi-effects/controller": "https://cdn.jsdelivr.net/npm/pixi-effects@0.26.3/dist/Controller.js",
|
|
66
|
+
"pixi-effects/presenter": "https://cdn.jsdelivr.net/npm/pixi-effects@0.26.3/dist/Presenter.js"
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
69
|
</script>
|
package/ai/tools/render.mjs
CHANGED
|
@@ -12,12 +12,12 @@
|
|
|
12
12
|
* Exit code: 0 = the file was written, 1 = the page or the render failed (no file), 2 = bad usage.
|
|
13
13
|
*
|
|
14
14
|
* Options: -o, --out FILE (default ./<page name>.<format>; the container follows the extension: mp4 webm mov mkv) ·
|
|
15
|
-
* --format mp4|webm|mov|mkv|pdf (a .pdf is the deck as pages: one picture per page of a movie with `stops`; --all-stops makes a page of every stop) · --quality very-low|low|medium|high|very-high (video and audio bitrate, default high) ·
|
|
15
|
+
* --format mp4|webm|mov|mkv|wav|ogg|pdf (wav / ogg: only the movie's sound, no picture; a .pdf is the deck as pages: one picture per page of a movie with `stops`; --all-stops makes a page of every stop) · --quality very-low|low|medium|high|very-high (video and audio bitrate, default high) ·
|
|
16
16
|
* --range A:B (only seconds A to B; 2: runs to the end, :5 starts at the beginning) · --scene NAME (the span of a top-level layer: a movie's scene) · --scale S (output size, 0 < S <= 1: smaller picture, smaller file) ·
|
|
17
17
|
* --draft (for looking: half size, low quality, no motion blur; a --quality you give still wins) ·
|
|
18
18
|
* --motion-blur SAMPLES (2-64: each frame is drawn that many times over the shutter and averaged; overrides the page's own motionBlur) ·
|
|
19
19
|
* --shutter FRACTION (with --motion-blur: how long the shutter is open, 0-1 of a frame, default 0.5) ·
|
|
20
|
-
* --video-codec C · --audio-codec C · --query "a=1&b=2" (added to the page URL) · --fail-on-warn (exit 1 when the page
|
|
20
|
+
* --video-codec C (avc hevc vp9 av1 vp8) · --video-bitrate B (a quality or bits a second: 8M, 800k) · --audio-codec C · --query "a=1&b=2" (added to the page URL) · --fail-on-warn (exit 1 when the page
|
|
21
21
|
* logged a warning; the file is still written) · --quiet (no progress line) · --timeout SECONDS (default 900) ·
|
|
22
22
|
* --root DIR (static server root; default: the nearest folder above the page with dist/) · --chrome PATH
|
|
23
23
|
*/
|
|
@@ -27,14 +27,15 @@ import path from 'node:path';
|
|
|
27
27
|
import { pathToFileURL } from 'node:url';
|
|
28
28
|
import { findChrome, findRoot, serve, launchChrome, shown, sleep } from './check.mjs';
|
|
29
29
|
|
|
30
|
-
const FORMATS = ['mp4', 'webm', 'mov', 'mkv', 'pdf'];
|
|
30
|
+
const FORMATS = ['mp4', 'webm', 'mov', 'mkv', 'wav', 'ogg', 'pdf'];
|
|
31
|
+
const SOUND_ONLY = ['wav', 'ogg'];
|
|
31
32
|
const QUALITIES = ['very-low', 'low', 'medium', 'high', 'very-high'];
|
|
32
33
|
|
|
33
34
|
/** 'clip.WEBM' → 'webm'; no extension → null; any other extension is an error. */
|
|
34
35
|
export function formatFromPath(file) {
|
|
35
36
|
const ext = path.extname(file).slice(1).toLowerCase();
|
|
36
37
|
if (!ext) return null;
|
|
37
|
-
if (!FORMATS.includes(ext)) throw new Error(`cannot tell the container from ".${ext}": use an output ending in mp4, webm, mov, mkv or pdf (or --format)`);
|
|
38
|
+
if (!FORMATS.includes(ext)) throw new Error(`cannot tell the container from ".${ext}": use an output ending in mp4, webm, mov, mkv, wav, ogg or pdf (or --format)`);
|
|
38
39
|
return ext;
|
|
39
40
|
}
|
|
40
41
|
|
|
@@ -43,18 +44,21 @@ export function defaultOutput(page, format) {
|
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
export function parseRenderArgs(argv) {
|
|
46
|
-
const o = { range: null, scene: null, scale: null, draft: false, qualityGiven: false, page: null, out: null, format: null, quality: 'high', videoCodec: null, audioCodec: null, allStops: false, motionBlur: null, shutter: null, query: null, failOnWarn: false, quiet: false, timeout: 900, root: null, chrome: null };
|
|
47
|
+
const o = { range: null, scene: null, scale: null, draft: false, qualityGiven: false, page: null, out: null, format: null, quality: 'high', videoCodec: null, videoBitrate: null, audioCodec: null, allStops: false, motionBlur: null, shutter: null, query: null, failOnWarn: false, quiet: false, timeout: 900, root: null, chrome: null };
|
|
47
48
|
const need = (i, name) => { if (i + 1 >= argv.length) throw new Error(`${name} needs a value`); return argv[i + 1]; };
|
|
48
49
|
for (let i = 0; i < argv.length; i++) {
|
|
49
50
|
const a = argv[i];
|
|
50
51
|
if (a === '-o' || a === '--out') o.out = need(i++, a);
|
|
51
52
|
else if (a === '--format') {
|
|
52
53
|
o.format = need(i++, a).toLowerCase();
|
|
53
|
-
if (!FORMATS.includes(o.format)) throw new Error(`--format must be mp4, webm, mov, mkv or pdf (got "${o.format}")`);
|
|
54
|
+
if (!FORMATS.includes(o.format)) throw new Error(`--format must be mp4, webm, mov, mkv, wav, ogg or pdf (got "${o.format}")`);
|
|
54
55
|
} else if (a === '--quality') {
|
|
55
56
|
o.qualityGiven = true;
|
|
56
57
|
o.quality = need(i++, a);
|
|
57
58
|
if (!QUALITIES.includes(o.quality)) throw new Error(`--quality must be very-low, low, medium, high or very-high (got "${o.quality}")`);
|
|
59
|
+
} else if (a === '--video-bitrate') {
|
|
60
|
+
o.videoBitrate = need(i++, a);
|
|
61
|
+
if (!/^(very-low|low|medium|high|very-high|\d+(\.\d+)?\s*[kKmM]?)$/.test(o.videoBitrate)) throw new Error(`--video-bitrate must be a quality (very-low, low, medium, high, very-high) or bits a second (8000000, 8M, 800k), got "${o.videoBitrate}"`);
|
|
58
62
|
} else if (a === '--video-codec') o.videoCodec = need(i++, a);
|
|
59
63
|
else if (a === '--audio-codec') o.audioCodec = need(i++, a);
|
|
60
64
|
else if (a === '--motion-blur') {
|
|
@@ -88,6 +92,7 @@ export function parseRenderArgs(argv) {
|
|
|
88
92
|
if (o.allStops && o.format !== 'pdf' && !(o.out && formatFromPath(o.out) === 'pdf')) throw new Error('--all-stops goes with a PDF (-o deck.pdf)');
|
|
89
93
|
o.format ??= (o.out ? formatFromPath(o.out) : null) ?? 'mp4';
|
|
90
94
|
if (o.range && o.scene !== null) throw new Error('--range and --scene cannot be used together: a scene is a range');
|
|
95
|
+
if (SOUND_ONLY.includes(o.format) && (o.scale !== null || o.draft || o.motionBlur !== null || o.videoCodec || o.videoBitrate)) throw new Error(`--scale, --draft, --motion-blur, --video-codec and --video-bitrate are for a picture: ${o.format} writes only the sound`);
|
|
91
96
|
if (o.format === 'pdf' && (o.range || o.scene !== null || o.scale !== null || o.draft)) throw new Error('--range, --scene, --scale and --draft are not for a PDF (a PDF is the pages of a deck)');
|
|
92
97
|
return o;
|
|
93
98
|
}
|
|
@@ -96,16 +101,16 @@ const UPLOAD = '/__pixi_effects_out';
|
|
|
96
101
|
const kb = n => (n >= 1048576 ? `${(n / 1048576).toFixed(2)} MB` : `${Math.max(1, Math.round(n / 1024))} KB`);
|
|
97
102
|
|
|
98
103
|
/** The page's side: render, and PUT the Blob to our server (so a long video never goes through base64). */
|
|
99
|
-
const renderScript = (format, quality, videoCodec, audioCodec, motionBlur, shutter, allStops, part = {}) => `(() => {
|
|
104
|
+
const renderScript = (format, quality, videoCodec, audioCodec, motionBlur, shutter, allStops, part = {}, videoBitrate = null) => `(() => {
|
|
100
105
|
window.__r = { state: 'running', progress: 0 };
|
|
101
106
|
movie.on('progress', e => { window.__r.progress = e.progress; });
|
|
102
107
|
(async () => {
|
|
103
108
|
try {
|
|
104
|
-
const video = { ${[part.draft && !part.qualityGiven ? null : `bitrate: ${JSON.stringify(quality)}`, videoCodec ? `codec: ${JSON.stringify(videoCodec)}` : null].filter(Boolean).join(', ')} };
|
|
109
|
+
const video = { ${[videoBitrate ? `bitrate: ${JSON.stringify(/^\d+(\.\d+)?$/.test(videoBitrate) ? Number(videoBitrate) : videoBitrate)}` : part.draft && !part.qualityGiven ? null : `bitrate: ${JSON.stringify(quality)}`, videoCodec ? `codec: ${JSON.stringify(videoCodec)}` : null].filter(Boolean).join(', ')} };
|
|
105
110
|
const audio = { bitrate: ${JSON.stringify(quality)}${audioCodec ? `, codec: ${JSON.stringify(audioCodec)}` : ''} };
|
|
106
111
|
const blob = ${JSON.stringify(format)} === 'pdf'
|
|
107
112
|
? await movie.exportPDF({ which: ${allStops ? "'stops'" : "'pages'"}, title: document.title })
|
|
108
|
-
: await movie.render({ format: ${JSON.stringify(format)}, video, audio${part.range ? `, range: [${part.range[0] ?? 0}, ${part.range[1] ?? 'movie.duration'}]` : ''}${part.scene ? `, range: ${JSON.stringify(part.scene)}` : ''}${part.scale ? `, scale: ${part.scale}` : ''}${part.draft ? ', draft: true' : ''}${motionBlur ? `, motionBlur: { samples: ${motionBlur}${shutter ? `, shutter: ${shutter}` : ''} }` : ''} });
|
|
113
|
+
: await movie.render({ format: ${JSON.stringify(format)}, ${SOUND_ONLY.includes(format) ? '' : 'video, '}audio${part.range ? `, range: [${part.range[0] ?? 0}, ${part.range[1] ?? 'movie.duration'}]` : ''}${part.scene ? `, range: ${JSON.stringify(part.scene)}` : ''}${part.scale ? `, scale: ${part.scale}` : ''}${part.draft ? ', draft: true' : ''}${motionBlur ? `, motionBlur: { samples: ${motionBlur}${shutter ? `, shutter: ${shutter}` : ''} }` : ''} });
|
|
109
114
|
const res = await fetch(${JSON.stringify(UPLOAD)}, { method: 'PUT', body: blob });
|
|
110
115
|
if (!res.ok) throw new Error('could not hand the file to the command (' + res.status + ')');
|
|
111
116
|
window.__r = { state: 'done', bytes: blob.size, type: blob.type };
|
|
@@ -171,7 +176,7 @@ export async function runRender(opts, log = console.log, progress = () => {}) {
|
|
|
171
176
|
}
|
|
172
177
|
Object.assign(result, { duration: info.duration, frames: info.totalFrames, width: info.width, height: info.height, frameRate: info.frameRate });
|
|
173
178
|
|
|
174
|
-
await cdp.eval(renderScript(opts.format, opts.quality, opts.videoCodec, opts.audioCodec, opts.motionBlur, opts.shutter, opts.allStops, { range: opts.range, scene: opts.scene, scale: opts.scale, draft: opts.draft, qualityGiven: opts.qualityGiven }));
|
|
179
|
+
await cdp.eval(renderScript(opts.format, opts.quality, opts.videoCodec, opts.audioCodec, opts.motionBlur, opts.shutter, opts.allStops, { range: opts.range, scene: opts.scene, scale: opts.scale, draft: opts.draft, qualityGiven: opts.qualityGiven }, opts.videoBitrate));
|
|
175
180
|
let state;
|
|
176
181
|
for (;;) {
|
|
177
182
|
left();
|
|
@@ -221,7 +226,7 @@ if (process.argv[1] && import.meta.url === pathToFileURL(fs.realpathSync(process
|
|
|
221
226
|
console.error(`pixi-effects render failed: ${r.problems.join('; ') || 'no file written'}`);
|
|
222
227
|
process.exit(1);
|
|
223
228
|
}
|
|
224
|
-
console.log(`${shown(r.file)} ${kb(r.bytes)} · ${r.duration} s · ${r.width}×${r.height} @ ${r.frameRate} fps · ${opts.format} · rendered in ${r.seconds} s`);
|
|
229
|
+
console.log(`${shown(r.file)} ${kb(r.bytes)} · ${r.duration} s · ${SOUND_ONLY.includes(opts.format) ? 'sound only' : `${r.width}×${r.height} @ ${r.frameRate} fps`} · ${opts.format} · rendered in ${r.seconds} s`);
|
|
225
230
|
process.exit(opts.failOnWarn && r.logs.length ? 1 : 0);
|
|
226
231
|
} catch (e) {
|
|
227
232
|
console.error(`pixi-effects render failed: ${e.message}`);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { CompositionSequence } from './chunk-WMMZDPWK.js';
|
|
2
|
+
import './chunk-FXAHNPBP.js';
|
|
3
|
+
import './chunk-AXZUKNXF.js';
|
|
4
|
+
import './chunk-TLYTYBWX.js';
|
|
5
|
+
import './chunk-BXOCEZ4U.js';
|
|
6
|
+
//# sourceMappingURL=Composition-3O7L2VL5.js.map
|
|
7
|
+
//# sourceMappingURL=Composition-3O7L2VL5.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"Composition-
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"Composition-3O7L2VL5.js"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkIIDBEYQH_cjs = require('./chunk-IIDBEYQH.cjs');
|
|
4
|
+
require('./chunk-A225HYSY.cjs');
|
|
5
|
+
require('./chunk-3DLYAPK7.cjs');
|
|
6
|
+
require('./chunk-ECA2WNRX.cjs');
|
|
7
|
+
require('./chunk-TWZNOUM7.cjs');
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
Object.defineProperty(exports, "CompositionSequence", {
|
|
12
|
+
enumerable: true,
|
|
13
|
+
get: function () { return chunkIIDBEYQH_cjs.CompositionSequence; }
|
|
14
|
+
});
|
|
15
|
+
//# sourceMappingURL=Composition-EE3KEE2L.cjs.map
|
|
16
|
+
//# sourceMappingURL=Composition-EE3KEE2L.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"Composition-
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"Composition-EE3KEE2L.cjs"}
|
package/dist/Controller.d.cts
CHANGED
package/dist/Controller.d.ts
CHANGED
|
@@ -289,14 +289,21 @@ interface MovieOptions {
|
|
|
289
289
|
interface RenderOptions {
|
|
290
290
|
/** Motion blur for this export (see `MovieOptions.motionBlur`); overrides the movie's own setting, `false` turns it off. */
|
|
291
291
|
motionBlur?: MotionBlurSpec;
|
|
292
|
-
|
|
292
|
+
/** `mp4`, `mov`, `webm`, `mkv`: the picture with its sound. `wav`, `ogg`: only the sound of the movie (an error when it has none). */
|
|
293
|
+
format?: 'mp4' | 'mov' | 'webm' | 'mkv' | 'wav' | 'ogg';
|
|
293
294
|
video?: {
|
|
295
|
+
/** `'avc'` (H.264), `'hevc'`, `'vp9'`, `'av1'`, `'vp8'`: default the usual one for the format, the next that works if this browser cannot encode it; a name you give is never swapped. */
|
|
294
296
|
codec?: string;
|
|
295
|
-
|
|
297
|
+
/** A quality name, or bits a second: `8_000_000` or `'8M'`, `'800k'`. */
|
|
298
|
+
bitrate?: 'very-low' | 'low' | 'medium' | 'high' | 'very-high' | number | string;
|
|
299
|
+
/** Where to encode: `'prefer-hardware'`, `'prefer-software'` or `'no-preference'` (default). */
|
|
300
|
+
hardware?: 'no-preference' | 'prefer-hardware' | 'prefer-software';
|
|
301
|
+
/** Seconds between keyframes (default 2): shorter seeks faster and makes a bigger file. */
|
|
302
|
+
keyFrameInterval?: number;
|
|
296
303
|
};
|
|
297
304
|
audio?: {
|
|
298
305
|
codec?: string;
|
|
299
|
-
bitrate?: 'very-low' | 'low' | 'medium' | 'high' | 'very-high';
|
|
306
|
+
bitrate?: 'very-low' | 'low' | 'medium' | 'high' | 'very-high' | number | string;
|
|
300
307
|
};
|
|
301
308
|
/**
|
|
302
309
|
* 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
|
|
@@ -289,14 +289,21 @@ interface MovieOptions {
|
|
|
289
289
|
interface RenderOptions {
|
|
290
290
|
/** Motion blur for this export (see `MovieOptions.motionBlur`); overrides the movie's own setting, `false` turns it off. */
|
|
291
291
|
motionBlur?: MotionBlurSpec;
|
|
292
|
-
|
|
292
|
+
/** `mp4`, `mov`, `webm`, `mkv`: the picture with its sound. `wav`, `ogg`: only the sound of the movie (an error when it has none). */
|
|
293
|
+
format?: 'mp4' | 'mov' | 'webm' | 'mkv' | 'wav' | 'ogg';
|
|
293
294
|
video?: {
|
|
295
|
+
/** `'avc'` (H.264), `'hevc'`, `'vp9'`, `'av1'`, `'vp8'`: default the usual one for the format, the next that works if this browser cannot encode it; a name you give is never swapped. */
|
|
294
296
|
codec?: string;
|
|
295
|
-
|
|
297
|
+
/** A quality name, or bits a second: `8_000_000` or `'8M'`, `'800k'`. */
|
|
298
|
+
bitrate?: 'very-low' | 'low' | 'medium' | 'high' | 'very-high' | number | string;
|
|
299
|
+
/** Where to encode: `'prefer-hardware'`, `'prefer-software'` or `'no-preference'` (default). */
|
|
300
|
+
hardware?: 'no-preference' | 'prefer-hardware' | 'prefer-software';
|
|
301
|
+
/** Seconds between keyframes (default 2): shorter seeks faster and makes a bigger file. */
|
|
302
|
+
keyFrameInterval?: number;
|
|
296
303
|
};
|
|
297
304
|
audio?: {
|
|
298
305
|
codec?: string;
|
|
299
|
-
bitrate?: 'very-low' | 'low' | 'medium' | 'high' | 'very-high';
|
|
306
|
+
bitrate?: 'very-low' | 'low' | 'medium' | 'high' | 'very-high' | number | string;
|
|
300
307
|
};
|
|
301
308
|
/**
|
|
302
309
|
* 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
|
package/dist/Presenter.d.cts
CHANGED
package/dist/Presenter.d.ts
CHANGED