pixi-effects 0.36.0 → 0.38.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.
- package/CHANGELOG.md +29 -0
- package/README.md +6 -5
- package/ai/chat-template.html +3 -3
- package/ai/tools/check.mjs +12 -2
- package/ai/tools/lookup.mjs +7 -3
- package/ai/tools/media-page.html +122 -0
- package/ai/tools/media.mjs +748 -0
- package/ai/tools/mediaBrowser.mjs +47 -0
- package/ai/tools/pixi-effects.mjs +11 -2
- package/dist/{Base-CmiFiwQM.d.cts → Base-BKKwxavW.d.cts} +1 -1
- package/dist/{Base-CdF7AJop.d.ts → Base-ioh_AjLB.d.ts} +1 -1
- package/dist/Composition-23KGIJX4.cjs +16 -0
- package/dist/{Composition-XRLYR6GL.cjs.map → Composition-23KGIJX4.cjs.map} +1 -1
- package/dist/Composition-5SQXSZNA.js +7 -0
- package/dist/{Composition-BMRCE5FH.js.map → Composition-5SQXSZNA.js.map} +1 -1
- package/dist/Controller.d.cts +3 -2
- package/dist/Controller.d.ts +3 -2
- package/dist/{Movie-D5WFfZdZ.d.ts → Movie-BtwFI2ne.d.ts} +23 -162
- package/dist/{Movie-Bh1HPdKw.d.cts → Movie-CSWUTnMd.d.cts} +23 -162
- package/dist/{Spans-MWP2FX3T.js → Spans-4IBQASGK.js} +6 -6
- package/dist/{Spans-MWP2FX3T.js.map → Spans-4IBQASGK.js.map} +1 -1
- package/dist/{Spans-4IRBSOLI.cjs → Spans-WJFPHMSQ.cjs} +11 -11
- package/dist/{Spans-4IRBSOLI.cjs.map → Spans-WJFPHMSQ.cjs.map} +1 -1
- package/dist/{blendModes-KU7XLV7U.cjs → blendModes-FD3THLNC.cjs} +5 -5
- package/dist/{blendModes-KU7XLV7U.cjs.map → blendModes-FD3THLNC.cjs.map} +1 -1
- package/dist/{blendModes-OOI3T6BE.js → blendModes-FMYO6SQN.js} +4 -4
- package/dist/{blendModes-OOI3T6BE.js.map → blendModes-FMYO6SQN.js.map} +1 -1
- package/dist/{chunk-2JFFKHXO.js → chunk-32MMNDDN.js} +4 -3
- package/dist/chunk-32MMNDDN.js.map +1 -0
- package/dist/{chunk-42ML5AKN.cjs → chunk-3SAS3ZE5.cjs} +4 -3
- package/dist/chunk-3SAS3ZE5.cjs.map +1 -0
- package/dist/{chunk-AZ6AINSW.js → chunk-4CSL5QSL.js} +6 -6
- package/dist/chunk-4CSL5QSL.js.map +1 -0
- package/dist/{chunk-KJSEQVBV.cjs → chunk-7NXKBRT7.cjs} +333 -26
- package/dist/chunk-7NXKBRT7.cjs.map +1 -0
- package/dist/{chunk-Y5UWFH6Y.cjs → chunk-FE42PKHP.cjs} +92 -92
- package/dist/chunk-FE42PKHP.cjs.map +1 -0
- package/dist/{chunk-NEUPEENI.cjs → chunk-JN7JHNZR.cjs} +5 -5
- package/dist/{chunk-NEUPEENI.cjs.map → chunk-JN7JHNZR.cjs.map} +1 -1
- package/dist/{chunk-CC7SUR7Q.cjs → chunk-KNMDDUA3.cjs} +129 -453
- package/dist/chunk-KNMDDUA3.cjs.map +1 -0
- package/dist/chunk-LQDDDIC4.cjs +431 -0
- package/dist/chunk-LQDDDIC4.cjs.map +1 -0
- package/dist/{chunk-G3DX65HO.js → chunk-UDTLYYGY.js} +311 -6
- package/dist/chunk-UDTLYYGY.js.map +1 -0
- package/dist/chunk-UHNSL2KJ.js +425 -0
- package/dist/chunk-UHNSL2KJ.js.map +1 -0
- package/dist/{chunk-WIIU42FH.js → chunk-VNP7QCJE.js} +4 -4
- package/dist/{chunk-WIIU42FH.js.map → chunk-VNP7QCJE.js.map} +1 -1
- package/dist/{chunk-VF56PRAA.js → chunk-XOCRS5MW.js} +92 -417
- package/dist/chunk-XOCRS5MW.js.map +1 -0
- package/dist/index.cjs +46 -33
- package/dist/index.d.cts +33 -6
- package/dist/index.d.ts +33 -6
- package/dist/index.js +6 -5
- package/dist/loader.css +1 -1
- package/dist/present.cjs +6 -5
- package/dist/present.cjs.map +1 -1
- package/dist/present.d.cts +3 -2
- package/dist/present.d.ts +3 -2
- package/dist/present.js +6 -5
- package/dist/present.js.map +1 -1
- package/dist/sound.cjs +12 -0
- package/dist/sound.cjs.map +1 -0
- package/dist/sound.d.cts +1 -0
- package/dist/sound.d.ts +1 -0
- package/dist/sound.js +3 -0
- package/dist/sound.js.map +1 -0
- package/dist/soundEntry-DT13DNt8.d.cts +191 -0
- package/dist/soundEntry-DT13DNt8.d.ts +191 -0
- package/dist/three.cjs +6 -6
- package/dist/three.d.cts +2 -2
- package/dist/three.d.ts +2 -2
- package/dist/three.js +2 -2
- package/dist/{types-B6zDTU2V.d.ts → types-BXi-0iZS.d.cts} +53 -2
- package/dist/{types-B6zDTU2V.d.cts → types-BXi-0iZS.d.ts} +53 -2
- package/docs/api.md +19 -0
- package/docs/dsl.md +35 -0
- package/docs/media.md +136 -0
- package/llms-full.txt +385 -6
- package/llms.txt +1 -0
- package/package.json +2 -1
- package/skills/pixi-effects/SKILL.md +7 -2
- package/skills/pixi-effects/reference/cheatsheet.md +2 -0
- package/skills/pixi-effects/reference/pitfalls.md +4 -0
- package/skills/pixi-effects/reference/recipes.md +177 -3
- package/skills/pixi-effects/template.html +6 -6
- package/dist/Composition-BMRCE5FH.js +0 -7
- package/dist/Composition-XRLYR6GL.cjs +0 -16
- package/dist/chunk-2JFFKHXO.js.map +0 -1
- package/dist/chunk-42ML5AKN.cjs.map +0 -1
- package/dist/chunk-AZ6AINSW.js.map +0 -1
- package/dist/chunk-CC7SUR7Q.cjs.map +0 -1
- package/dist/chunk-G3DX65HO.js.map +0 -1
- package/dist/chunk-KJSEQVBV.cjs.map +0 -1
- package/dist/chunk-VF56PRAA.js.map +0 -1
- package/dist/chunk-Y5UWFH6Y.cjs.map +0 -1
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// The browser engine of the media commands: the tool's local server, a headless Chrome (the one `check` and `render` use) and the page ai/tools/media-page.html.
|
|
2
|
+
// await withBrowser({ chrome, inputs: Map(id -> path or URL), outDir }, async ({ call }) => call('frames', { id, times, size, sheet }))
|
|
3
|
+
// `call` runs `window.media.<name>(args)` in the page and returns its JSON, or throws the sentence the page threw.
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
import os from 'node:os';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
8
|
+
|
|
9
|
+
const HERE = path.dirname(fileURLToPath(import.meta.url));
|
|
10
|
+
|
|
11
|
+
export async function withBrowser({ chrome, inputs, outDir, requestLog = null, timeoutSec = 180 }, fn) {
|
|
12
|
+
const check = await import(pathToFileURL(path.join(HERE, 'check.mjs')).href);
|
|
13
|
+
const { serveMedia } = await import(pathToFileURL(path.join(HERE, 'media.mjs')).href);
|
|
14
|
+
const chromePath = chrome ?? check.findChrome();
|
|
15
|
+
if (!chromePath || !fs.existsSync(chromePath)) throw new Error(`Chrome was not found${chromePath ? ` at ${chromePath}` : ''}: this command decodes video in a browser; install Chrome, or pass --chrome PATH (or set CHROME_PATH) with the right path`);
|
|
16
|
+
const srv = await serveMedia({ inputs, outDir, requestLog });
|
|
17
|
+
const userDataDir = fs.mkdtempSync(path.join(os.tmpdir(), 'pixi-effects-media-'));
|
|
18
|
+
let proc = null;
|
|
19
|
+
try {
|
|
20
|
+
const launched = await check.launchChrome(chromePath, userDataDir);
|
|
21
|
+
proc = launched.proc;
|
|
22
|
+
const cdp = launched.cdp;
|
|
23
|
+
await cdp.send('Runtime.enable');
|
|
24
|
+
await cdp.send('Page.enable');
|
|
25
|
+
await cdp.send('Page.navigate', { url: `http://127.0.0.1:${srv.port}/ai/tools/media-page.html` });
|
|
26
|
+
const deadline = Date.now() + timeoutSec * 1000;
|
|
27
|
+
while (!(await cdp.eval('window.__mediaReady === true').catch(() => false))) {
|
|
28
|
+
if (Date.now() > deadline) throw new Error('the media page did not start in the browser');
|
|
29
|
+
await check.sleep(100);
|
|
30
|
+
}
|
|
31
|
+
const call = async (name, args) => {
|
|
32
|
+
const run = cdp.eval(`(async () => { try { return { ok: await window.media.${name}(${JSON.stringify(args)}) }; } catch (e) { return { error: String(e && e.message || e) }; } })()`);
|
|
33
|
+
let timer;
|
|
34
|
+
const timeout = new Promise((_, bad) => { timer = setTimeout(() => bad(new Error(`timed out after ${timeoutSec} s`)), Math.max(1000, deadline - Date.now())); });
|
|
35
|
+
try {
|
|
36
|
+
const r = await Promise.race([run, timeout]);
|
|
37
|
+
if (r.error) throw new Error(r.error);
|
|
38
|
+
return r.ok;
|
|
39
|
+
} finally { clearTimeout(timer); }
|
|
40
|
+
};
|
|
41
|
+
return await fn({ call });
|
|
42
|
+
} finally {
|
|
43
|
+
try { proc?.kill(); } catch { /* gone */ }
|
|
44
|
+
await srv.close();
|
|
45
|
+
try { fs.rmSync(userDataDir, { recursive: true, force: true }); } catch { /* held a moment longer */ }
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -15,11 +15,19 @@ import { dirname, resolve } from 'node:path';
|
|
|
15
15
|
import { fileURLToPath } from 'node:url';
|
|
16
16
|
import { runLookup, LOOKUP_COMMANDS } from './lookup.mjs';
|
|
17
17
|
|
|
18
|
+
const MEDIA = ['probe', 'trim', 'frames', 'sound', 'audio', 'concat']; // footage tools: one file, `media.mjs`, which gets the command word too
|
|
19
|
+
|
|
18
20
|
const TOOLS = { check: 'check.mjs', render: 'render.mjs', view: 'view.mjs' };
|
|
19
21
|
const USAGE = `usage:
|
|
20
22
|
pixi-effects check <page.html> [--at 3,6] [--out dir] review a video page: warnings, layout, sound, contact sheet, real export
|
|
21
23
|
pixi-effects render <page.html> -o <file.mp4> export the video
|
|
22
24
|
pixi-effects view <page.html> look at it in a browser, with a timeline
|
|
25
|
+
pixi-effects probe <file|url> what is in a video or audio file (codecs, size, duration), with no ffmpeg
|
|
26
|
+
pixi-effects trim <file|url> <start> <end> -o <out> cut a file (by copy when it can) and say the real times
|
|
27
|
+
pixi-effects frames <file|url> [--at 1,50%,end] [--sheet] pictures of a video at those times
|
|
28
|
+
pixi-effects sound <file|url> [--waveform] loudness, peak, silences of a file's sound
|
|
29
|
+
pixi-effects audio <file|url> -o <out.m4a> the sound of a file, copied out
|
|
30
|
+
pixi-effects concat <a> <b> … -o <out> join clips by copy and say where each starts
|
|
23
31
|
pixi-effects new <name> [--size 1080x1920] [--duration 20] a page to start from (<name>.html), 1280x720 and 6 s unless asked
|
|
24
32
|
pixi-effects recipe [id] the tested recipes; with an id, one of them with its code
|
|
25
33
|
pixi-effects help <word> the docs about a word (mask, threeD, keyframes, music …)
|
|
@@ -28,7 +36,7 @@ const USAGE = `usage:
|
|
|
28
36
|
function nearest(word) {
|
|
29
37
|
const d = (a, b) => { const m = Array.from({ length: a.length + 1 }, (_, i) => [i, ...Array(b.length).fill(0)]); for (let j = 1; j <= b.length; j++) m[0][j] = j;
|
|
30
38
|
for (let i = 1; i <= a.length; i++) for (let j = 1; j <= b.length; j++) m[i][j] = Math.min(m[i - 1][j] + 1, m[i][j - 1] + 1, m[i - 1][j - 1] + (a[i - 1] === b[j - 1] ? 0 : 1)); return m[a.length][b.length]; };
|
|
31
|
-
const best = [...Object.keys(TOOLS), ...LOOKUP_COMMANDS].map(k => [k, d(word, k)]).sort((x, y) => x[1] - y[1])[0];
|
|
39
|
+
const best = [...Object.keys(TOOLS), ...MEDIA, ...LOOKUP_COMMANDS].map(k => [k, d(word, k)]).sort((x, y) => x[1] - y[1])[0];
|
|
32
40
|
return best[1] <= 2 ? best[0] : null;
|
|
33
41
|
}
|
|
34
42
|
|
|
@@ -37,9 +45,10 @@ export function route(argv) {
|
|
|
37
45
|
const [cmd, ...args] = argv;
|
|
38
46
|
if (!cmd || cmd === '--help' || cmd === '-h') return { usage: USAGE };
|
|
39
47
|
if (TOOLS[cmd]) return { tool: TOOLS[cmd], args };
|
|
48
|
+
if (MEDIA.includes(cmd)) return { tool: 'media.mjs', args: [cmd, ...args] };
|
|
40
49
|
if (LOOKUP_COMMANDS.includes(cmd)) return { inline: cmd, args };
|
|
41
50
|
const guess = /\.html?$/i.test(cmd) ? 'check' : nearest(cmd);
|
|
42
|
-
return { error: `pixi-effects: unknown command "${cmd}"${guess ? `; did you mean "${guess}"?` : ''} The commands are: ${[...Object.keys(TOOLS), ...LOOKUP_COMMANDS].join(', ')}.\n${USAGE}` };
|
|
51
|
+
return { error: `pixi-effects: unknown command "${cmd}"${guess ? `; did you mean "${guess}"?` : ''} The commands are: ${[...Object.keys(TOOLS), ...MEDIA, ...LOOKUP_COMMANDS].join(', ')}.\n${USAGE}` };
|
|
43
52
|
}
|
|
44
53
|
|
|
45
54
|
const self = fileURLToPath(import.meta.url);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Container } from 'pixi.js';
|
|
2
|
-
import {
|
|
2
|
+
import { a as SequenceSpec, C as CompositionShape } from './types-BXi-0iZS.cjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Resolves a routed keyframe path to a concrete tween target.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Container } from 'pixi.js';
|
|
2
|
-
import {
|
|
2
|
+
import { a as SequenceSpec, C as CompositionShape } from './types-BXi-0iZS.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Resolves a routed keyframe path to a concrete tween target.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkFE42PKHP_cjs = require('./chunk-FE42PKHP.cjs');
|
|
4
|
+
require('./chunk-7NXKBRT7.cjs');
|
|
5
|
+
require('./chunk-JN7JHNZR.cjs');
|
|
6
|
+
require('./chunk-3SAS3ZE5.cjs');
|
|
7
|
+
require('./chunk-TWZNOUM7.cjs');
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
Object.defineProperty(exports, "CompositionSequence", {
|
|
12
|
+
enumerable: true,
|
|
13
|
+
get: function () { return chunkFE42PKHP_cjs.CompositionSequence; }
|
|
14
|
+
});
|
|
15
|
+
//# sourceMappingURL=Composition-23KGIJX4.cjs.map
|
|
16
|
+
//# sourceMappingURL=Composition-23KGIJX4.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"Composition-
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"Composition-23KGIJX4.cjs"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { CompositionSequence } from './chunk-4CSL5QSL.js';
|
|
2
|
+
import './chunk-UDTLYYGY.js';
|
|
3
|
+
import './chunk-VNP7QCJE.js';
|
|
4
|
+
import './chunk-32MMNDDN.js';
|
|
5
|
+
import './chunk-BXOCEZ4U.js';
|
|
6
|
+
//# sourceMappingURL=Composition-5SQXSZNA.js.map
|
|
7
|
+
//# sourceMappingURL=Composition-5SQXSZNA.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"Composition-
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"Composition-5SQXSZNA.js"}
|
package/dist/Controller.d.cts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { M as Movie } from './Movie-CSWUTnMd.cjs';
|
|
2
2
|
import 'pixi.js';
|
|
3
|
-
import './
|
|
3
|
+
import './soundEntry-DT13DNt8.cjs';
|
|
4
|
+
import './types-BXi-0iZS.cjs';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* The look of the bar. Each key sets a CSS custom property on the bar (so you can also set `--mc-accent` … in your own CSS, on the
|
package/dist/Controller.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { M as Movie } from './Movie-BtwFI2ne.js';
|
|
2
2
|
import 'pixi.js';
|
|
3
|
-
import './
|
|
3
|
+
import './soundEntry-DT13DNt8.js';
|
|
4
|
+
import './types-BXi-0iZS.js';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* The look of the bar. Each key sets a CSS custom property on the bar (so you can also set `--mc-accent` … in your own CSS, on the
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Application } from 'pixi.js';
|
|
2
|
-
import {
|
|
2
|
+
import { A as AudioReport, a as AudioInspectOptions } from './soundEntry-DT13DNt8.js';
|
|
3
|
+
import { d as Stop, A as AssetSpec, c as CompositionSpec } from './types-BXi-0iZS.js';
|
|
3
4
|
|
|
4
5
|
type EaseFn = (p: number) => number;
|
|
5
6
|
|
|
@@ -126,165 +127,6 @@ declare class PureTimeline {
|
|
|
126
127
|
*/
|
|
127
128
|
type Timeline = PureTimeline;
|
|
128
129
|
|
|
129
|
-
/** One note or chord of a track, as a score reader sees it. */
|
|
130
|
-
interface MusicNote {
|
|
131
|
-
/** Where it starts: beats from the start, and the same moment in seconds (the tempo map applied; swing and humanize are not). */
|
|
132
|
-
beat: number;
|
|
133
|
-
time: number;
|
|
134
|
-
/** How long it is held, in beats and in seconds. */
|
|
135
|
-
duration: number;
|
|
136
|
-
seconds: number;
|
|
137
|
-
/** The bar it starts in (1-based, from `meter`) and its beat inside that bar (1 = the downbeat, 1.5 = the "and" of 1). */
|
|
138
|
-
bar: number;
|
|
139
|
-
beatInBar: number;
|
|
140
|
-
/** The audible MIDI notes (`music.transpose` and the track's `transpose` are in). */
|
|
141
|
-
midi: number[];
|
|
142
|
-
/** What the score called it: `Am7`, `c4`, `[c4 e4 g4]`. */
|
|
143
|
-
name: string;
|
|
144
|
-
/** More than one note at once. */
|
|
145
|
-
chord: boolean;
|
|
146
|
-
/** 0–1 (0.8 normal, 1 accented with `!`, 0.55 soft with `,`). */
|
|
147
|
-
velocity: number;
|
|
148
|
-
}
|
|
149
|
-
interface MusicTrackEvents {
|
|
150
|
-
inst: string;
|
|
151
|
-
/** The track's length in beats and in bars (not a whole number when a bar is short: that is what to look for). */
|
|
152
|
-
beats: number;
|
|
153
|
-
bars: number;
|
|
154
|
-
notes: MusicNote[];
|
|
155
|
-
}
|
|
156
|
-
interface MusicDrumHit {
|
|
157
|
-
beat: number;
|
|
158
|
-
time: number;
|
|
159
|
-
bar: number;
|
|
160
|
-
beatInBar: number;
|
|
161
|
-
velocity: number;
|
|
162
|
-
}
|
|
163
|
-
interface MusicDrumEvents {
|
|
164
|
-
kind: string;
|
|
165
|
-
hits: MusicDrumHit[];
|
|
166
|
-
}
|
|
167
|
-
interface MusicEvents {
|
|
168
|
-
/** The tempo at the start. */
|
|
169
|
-
bpm: number;
|
|
170
|
-
meter: number;
|
|
171
|
-
beats: number;
|
|
172
|
-
bars: number;
|
|
173
|
-
/** The music without its reverb tail. */
|
|
174
|
-
seconds: number;
|
|
175
|
-
tracks: MusicTrackEvents[];
|
|
176
|
-
/** Every drum that is hit, over all sections, with every hit written out. */
|
|
177
|
-
drums: MusicDrumEvents[];
|
|
178
|
-
}
|
|
179
|
-
/** What the `check` tool prints about a music layer: lengths in bars (a short track shows), what starts in each bar, where the drums play. */
|
|
180
|
-
interface MusicSummary {
|
|
181
|
-
bpm: number;
|
|
182
|
-
meter: number;
|
|
183
|
-
/** The score set `meter`; when false 4 is only assumed. */
|
|
184
|
-
meterSet: boolean;
|
|
185
|
-
beats: number;
|
|
186
|
-
bars: number;
|
|
187
|
-
seconds: number;
|
|
188
|
-
tail: number;
|
|
189
|
-
tracks: Array<{
|
|
190
|
-
inst: string;
|
|
191
|
-
beats: number;
|
|
192
|
-
bars: number;
|
|
193
|
-
events: number;
|
|
194
|
-
perBar: string[];
|
|
195
|
-
}>;
|
|
196
|
-
drums: Array<{
|
|
197
|
-
from: number;
|
|
198
|
-
to: number;
|
|
199
|
-
kinds: string[];
|
|
200
|
-
}>;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
interface AudioInspectOptions {
|
|
204
|
-
/** Width of each loudness window in seconds. Default 0.1. */
|
|
205
|
-
window?: number;
|
|
206
|
-
/** 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. */
|
|
207
|
-
scenes?: Array<{
|
|
208
|
-
name: string;
|
|
209
|
-
start: number;
|
|
210
|
-
end: number;
|
|
211
|
-
}>;
|
|
212
|
-
}
|
|
213
|
-
/** One sound measured ON ITS OWN (not mixed), so overlapping layers do not blur it. */
|
|
214
|
-
interface SoundMeasure {
|
|
215
|
-
/** Seconds of audio the source has (an sfx: its length; a file: the file's length). */
|
|
216
|
-
length: number;
|
|
217
|
-
/** Its own loudest sample, dBFS (before the layer's volume). */
|
|
218
|
-
peakDb: number;
|
|
219
|
-
/** Seconds from its start to its loudest sample — the moment to line up with the picture. */
|
|
220
|
-
loudestAt: number;
|
|
221
|
-
/** Spectral centroid in Hz: < 500 dark / boomy, 1–4 k mid, > 8 k airy / hissy. */
|
|
222
|
-
brightnessHz: number;
|
|
223
|
-
}
|
|
224
|
-
interface AudioSourceReport {
|
|
225
|
-
/** `layer "pop-1"` (or `unnamed audio layer`). */
|
|
226
|
-
layer: string;
|
|
227
|
-
/** `sfx "pop"`, `asset "bgm"`, `video "green"`. */
|
|
228
|
-
source: string;
|
|
229
|
-
/** Movie time, seconds. */
|
|
230
|
-
start: number;
|
|
231
|
-
end: number;
|
|
232
|
-
/** Loudest sample of the MIX while this source plays, dBFS (−120 = silence). */
|
|
233
|
-
peakDb: number;
|
|
234
|
-
sound: SoundMeasure;
|
|
235
|
-
/**
|
|
236
|
-
* How far below the loudest sample of the MIX around its own loudest moment this source is, dB (0 = it is the loudest thing there; 20 = the mix is 20 dB louder, so
|
|
237
|
-
* the source is hardly heard). Absent for a sound inside a remapped composition (its time is not the movie's).
|
|
238
|
-
*/
|
|
239
|
-
belowMixDb?: number;
|
|
240
|
-
/** For a `music` layer: its score read back (bars per track, what starts in each bar, the drum spans). */
|
|
241
|
-
music?: MusicSummary;
|
|
242
|
-
}
|
|
243
|
-
interface AudioReport {
|
|
244
|
-
duration: number;
|
|
245
|
-
sampleRate: number;
|
|
246
|
-
/** Loudest sample of the mix before limiting, dBFS. Above 0 the mix was limited. */
|
|
247
|
-
peakDb: number;
|
|
248
|
-
peakAt: number;
|
|
249
|
-
/** Every audio layer / video soundtrack in the mix, in start order. */
|
|
250
|
-
sources: AudioSourceReport[];
|
|
251
|
-
/** The mix over time: one row per window, `t` = window start. */
|
|
252
|
-
windows: Array<{
|
|
253
|
-
t: number;
|
|
254
|
-
rmsDb: number;
|
|
255
|
-
peakDb: number;
|
|
256
|
-
brightnessHz: number;
|
|
257
|
-
}>;
|
|
258
|
-
/** 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. */
|
|
259
|
-
issues: string[];
|
|
260
|
-
/** 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). */
|
|
261
|
-
loudness: {
|
|
262
|
-
integratedLufs: number | null;
|
|
263
|
-
truePeakDb: number;
|
|
264
|
-
clippedSamples: number;
|
|
265
|
-
silences: Array<{
|
|
266
|
-
from: number;
|
|
267
|
-
to: number;
|
|
268
|
-
}>;
|
|
269
|
-
};
|
|
270
|
-
/** The same measure for each scene (`silent`: nothing above −60 dBFS). */
|
|
271
|
-
scenes: Array<{
|
|
272
|
-
name: string;
|
|
273
|
-
from: number;
|
|
274
|
-
to: number;
|
|
275
|
-
lufs: number | null;
|
|
276
|
-
peakDb: number;
|
|
277
|
-
silent: boolean;
|
|
278
|
-
}>;
|
|
279
|
-
/** When each sound starts: what a waveform marks. */
|
|
280
|
-
cues: Array<{
|
|
281
|
-
t: number;
|
|
282
|
-
name: string;
|
|
283
|
-
}>;
|
|
284
|
-
/** Advice, not faults: a mix that is quiet or loud for web video, little headroom, silent stretches. */
|
|
285
|
-
notes: string[];
|
|
286
|
-
}
|
|
287
|
-
|
|
288
130
|
interface FontReport {
|
|
289
131
|
/** Text layers none of whose fonts is available here: they are drawn in a fallback. */
|
|
290
132
|
missing: Array<{
|
|
@@ -297,12 +139,25 @@ interface FontReport {
|
|
|
297
139
|
failedUnused: string[];
|
|
298
140
|
}
|
|
299
141
|
|
|
142
|
+
/** One canvas layer as the check saw it. */
|
|
143
|
+
interface CanvasRow {
|
|
144
|
+
name: string;
|
|
145
|
+
/** The moments (seconds of the layer's own time) it was drawn at, in two orders. */
|
|
146
|
+
moments: number[];
|
|
147
|
+
/** The usual time of one draw on the CPU canvas of the check (the browser's GPU may be faster or slower). */
|
|
148
|
+
drawMs: number;
|
|
149
|
+
ok: boolean;
|
|
150
|
+
/** Why not, in a sentence (empty when ok). */
|
|
151
|
+
problem: string;
|
|
152
|
+
}
|
|
153
|
+
|
|
300
154
|
/** One kind of issue, with how many frames it was seen in. Issues that differ only by numbers are one kind. */
|
|
301
155
|
interface IssueGroup {
|
|
302
156
|
message: string;
|
|
303
157
|
count: number;
|
|
304
158
|
firstFrame: number;
|
|
305
|
-
lastFrame: number;
|
|
159
|
+
lastFrame: number; /** `'canvas'`: a canvas layer that does not draw the same picture for the same time (not about the layout; `check` lists it under its own heading). */
|
|
160
|
+
kind?: 'canvas';
|
|
306
161
|
}
|
|
307
162
|
interface ReviewOptions {
|
|
308
163
|
/** Moments to resolve and report: `3.5`, `50%`, `f120`, `title@end` (comma-separated). */
|
|
@@ -317,6 +172,8 @@ interface ReviewReport {
|
|
|
317
172
|
problems: IssueGroup[];
|
|
318
173
|
/** Text overlaps and fonts that are not available: often intentional, look at them on the contact sheet. */
|
|
319
174
|
review: IssueGroup[];
|
|
175
|
+
/** Every canvas layer as the determinism check saw it (a failing one is also in `problems` with `kind: 'canvas'`). */
|
|
176
|
+
canvas: CanvasRow[];
|
|
320
177
|
fonts: FontReport;
|
|
321
178
|
/** The sound as numbers (`movie.inspectAudio()`), or null for a movie with no audio. */
|
|
322
179
|
audio: AudioReport | null;
|
|
@@ -817,6 +674,10 @@ declare class Movie {
|
|
|
817
674
|
* the canvas, cut by an edge, empty, or overlapping other text. Seeks there and stays there.
|
|
818
675
|
*/
|
|
819
676
|
inspect(frame?: number, opts?: InspectOptions): Promise<InspectReport>;
|
|
677
|
+
/** The canvas layers whose same frame is not the same picture (what `check` reports as a problem): one sentence each. */
|
|
678
|
+
canvasProblems(): string[];
|
|
679
|
+
/** 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). */
|
|
680
|
+
canvasReport(): CanvasRow[];
|
|
820
681
|
/**
|
|
821
682
|
* Every layer as a row with absolute start / end / keyframe times (seconds), plus the transition windows. Runs of
|
|
822
683
|
* similar layers (`pop-1` … `pop-12`) are one row with a `parts` span each. Read it, or draw it with `timelineChart()`.
|
|
@@ -902,4 +763,4 @@ declare class Movie {
|
|
|
902
763
|
destroy(): Promise<void>;
|
|
903
764
|
}
|
|
904
765
|
|
|
905
|
-
export { type
|
|
766
|
+
export { type ContactSheetOptions as C, type FontReport as F, type InspectOptions as I, type LayerInfo as L, Movie as M, type OnionSkinOptions as O, type ProgressEvent as P, type RebuildOptions as R, type SnapshotOptions as S, type ThumbnailOptions as T, type VolumeEvent as V, type MotionBlurSpec as a, type FrameEvent as b, type InspectReport as c, type IssueGroup as d, type LoadProgressState as e, type LoadStage as f, type LoaderOption as g, type LoopEvent as h, type MotionBlurOptions as i, type MovieErrorEvent as j, type MovieOptions as k, type RebuildReason as l, type RebuildReport as m, type RenderOptions as n, type ReviewOptions as o, type ReviewReport as p, type TimelineData as q, type TimelineHtmlOptions as r, type TimelineRow as s, type TimelineSvgOptions as t, type TimelineTransition as u, dismissLoader as v, failLoader as w, resolveLoader as x };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Application } from 'pixi.js';
|
|
2
|
-
import {
|
|
2
|
+
import { A as AudioReport, a as AudioInspectOptions } from './soundEntry-DT13DNt8.cjs';
|
|
3
|
+
import { d as Stop, A as AssetSpec, c as CompositionSpec } from './types-BXi-0iZS.cjs';
|
|
3
4
|
|
|
4
5
|
type EaseFn = (p: number) => number;
|
|
5
6
|
|
|
@@ -126,165 +127,6 @@ declare class PureTimeline {
|
|
|
126
127
|
*/
|
|
127
128
|
type Timeline = PureTimeline;
|
|
128
129
|
|
|
129
|
-
/** One note or chord of a track, as a score reader sees it. */
|
|
130
|
-
interface MusicNote {
|
|
131
|
-
/** Where it starts: beats from the start, and the same moment in seconds (the tempo map applied; swing and humanize are not). */
|
|
132
|
-
beat: number;
|
|
133
|
-
time: number;
|
|
134
|
-
/** How long it is held, in beats and in seconds. */
|
|
135
|
-
duration: number;
|
|
136
|
-
seconds: number;
|
|
137
|
-
/** The bar it starts in (1-based, from `meter`) and its beat inside that bar (1 = the downbeat, 1.5 = the "and" of 1). */
|
|
138
|
-
bar: number;
|
|
139
|
-
beatInBar: number;
|
|
140
|
-
/** The audible MIDI notes (`music.transpose` and the track's `transpose` are in). */
|
|
141
|
-
midi: number[];
|
|
142
|
-
/** What the score called it: `Am7`, `c4`, `[c4 e4 g4]`. */
|
|
143
|
-
name: string;
|
|
144
|
-
/** More than one note at once. */
|
|
145
|
-
chord: boolean;
|
|
146
|
-
/** 0–1 (0.8 normal, 1 accented with `!`, 0.55 soft with `,`). */
|
|
147
|
-
velocity: number;
|
|
148
|
-
}
|
|
149
|
-
interface MusicTrackEvents {
|
|
150
|
-
inst: string;
|
|
151
|
-
/** The track's length in beats and in bars (not a whole number when a bar is short: that is what to look for). */
|
|
152
|
-
beats: number;
|
|
153
|
-
bars: number;
|
|
154
|
-
notes: MusicNote[];
|
|
155
|
-
}
|
|
156
|
-
interface MusicDrumHit {
|
|
157
|
-
beat: number;
|
|
158
|
-
time: number;
|
|
159
|
-
bar: number;
|
|
160
|
-
beatInBar: number;
|
|
161
|
-
velocity: number;
|
|
162
|
-
}
|
|
163
|
-
interface MusicDrumEvents {
|
|
164
|
-
kind: string;
|
|
165
|
-
hits: MusicDrumHit[];
|
|
166
|
-
}
|
|
167
|
-
interface MusicEvents {
|
|
168
|
-
/** The tempo at the start. */
|
|
169
|
-
bpm: number;
|
|
170
|
-
meter: number;
|
|
171
|
-
beats: number;
|
|
172
|
-
bars: number;
|
|
173
|
-
/** The music without its reverb tail. */
|
|
174
|
-
seconds: number;
|
|
175
|
-
tracks: MusicTrackEvents[];
|
|
176
|
-
/** Every drum that is hit, over all sections, with every hit written out. */
|
|
177
|
-
drums: MusicDrumEvents[];
|
|
178
|
-
}
|
|
179
|
-
/** What the `check` tool prints about a music layer: lengths in bars (a short track shows), what starts in each bar, where the drums play. */
|
|
180
|
-
interface MusicSummary {
|
|
181
|
-
bpm: number;
|
|
182
|
-
meter: number;
|
|
183
|
-
/** The score set `meter`; when false 4 is only assumed. */
|
|
184
|
-
meterSet: boolean;
|
|
185
|
-
beats: number;
|
|
186
|
-
bars: number;
|
|
187
|
-
seconds: number;
|
|
188
|
-
tail: number;
|
|
189
|
-
tracks: Array<{
|
|
190
|
-
inst: string;
|
|
191
|
-
beats: number;
|
|
192
|
-
bars: number;
|
|
193
|
-
events: number;
|
|
194
|
-
perBar: string[];
|
|
195
|
-
}>;
|
|
196
|
-
drums: Array<{
|
|
197
|
-
from: number;
|
|
198
|
-
to: number;
|
|
199
|
-
kinds: string[];
|
|
200
|
-
}>;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
interface AudioInspectOptions {
|
|
204
|
-
/** Width of each loudness window in seconds. Default 0.1. */
|
|
205
|
-
window?: number;
|
|
206
|
-
/** 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. */
|
|
207
|
-
scenes?: Array<{
|
|
208
|
-
name: string;
|
|
209
|
-
start: number;
|
|
210
|
-
end: number;
|
|
211
|
-
}>;
|
|
212
|
-
}
|
|
213
|
-
/** One sound measured ON ITS OWN (not mixed), so overlapping layers do not blur it. */
|
|
214
|
-
interface SoundMeasure {
|
|
215
|
-
/** Seconds of audio the source has (an sfx: its length; a file: the file's length). */
|
|
216
|
-
length: number;
|
|
217
|
-
/** Its own loudest sample, dBFS (before the layer's volume). */
|
|
218
|
-
peakDb: number;
|
|
219
|
-
/** Seconds from its start to its loudest sample — the moment to line up with the picture. */
|
|
220
|
-
loudestAt: number;
|
|
221
|
-
/** Spectral centroid in Hz: < 500 dark / boomy, 1–4 k mid, > 8 k airy / hissy. */
|
|
222
|
-
brightnessHz: number;
|
|
223
|
-
}
|
|
224
|
-
interface AudioSourceReport {
|
|
225
|
-
/** `layer "pop-1"` (or `unnamed audio layer`). */
|
|
226
|
-
layer: string;
|
|
227
|
-
/** `sfx "pop"`, `asset "bgm"`, `video "green"`. */
|
|
228
|
-
source: string;
|
|
229
|
-
/** Movie time, seconds. */
|
|
230
|
-
start: number;
|
|
231
|
-
end: number;
|
|
232
|
-
/** Loudest sample of the MIX while this source plays, dBFS (−120 = silence). */
|
|
233
|
-
peakDb: number;
|
|
234
|
-
sound: SoundMeasure;
|
|
235
|
-
/**
|
|
236
|
-
* How far below the loudest sample of the MIX around its own loudest moment this source is, dB (0 = it is the loudest thing there; 20 = the mix is 20 dB louder, so
|
|
237
|
-
* the source is hardly heard). Absent for a sound inside a remapped composition (its time is not the movie's).
|
|
238
|
-
*/
|
|
239
|
-
belowMixDb?: number;
|
|
240
|
-
/** For a `music` layer: its score read back (bars per track, what starts in each bar, the drum spans). */
|
|
241
|
-
music?: MusicSummary;
|
|
242
|
-
}
|
|
243
|
-
interface AudioReport {
|
|
244
|
-
duration: number;
|
|
245
|
-
sampleRate: number;
|
|
246
|
-
/** Loudest sample of the mix before limiting, dBFS. Above 0 the mix was limited. */
|
|
247
|
-
peakDb: number;
|
|
248
|
-
peakAt: number;
|
|
249
|
-
/** Every audio layer / video soundtrack in the mix, in start order. */
|
|
250
|
-
sources: AudioSourceReport[];
|
|
251
|
-
/** The mix over time: one row per window, `t` = window start. */
|
|
252
|
-
windows: Array<{
|
|
253
|
-
t: number;
|
|
254
|
-
rmsDb: number;
|
|
255
|
-
peakDb: number;
|
|
256
|
-
brightnessHz: number;
|
|
257
|
-
}>;
|
|
258
|
-
/** 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. */
|
|
259
|
-
issues: string[];
|
|
260
|
-
/** 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). */
|
|
261
|
-
loudness: {
|
|
262
|
-
integratedLufs: number | null;
|
|
263
|
-
truePeakDb: number;
|
|
264
|
-
clippedSamples: number;
|
|
265
|
-
silences: Array<{
|
|
266
|
-
from: number;
|
|
267
|
-
to: number;
|
|
268
|
-
}>;
|
|
269
|
-
};
|
|
270
|
-
/** The same measure for each scene (`silent`: nothing above −60 dBFS). */
|
|
271
|
-
scenes: Array<{
|
|
272
|
-
name: string;
|
|
273
|
-
from: number;
|
|
274
|
-
to: number;
|
|
275
|
-
lufs: number | null;
|
|
276
|
-
peakDb: number;
|
|
277
|
-
silent: boolean;
|
|
278
|
-
}>;
|
|
279
|
-
/** When each sound starts: what a waveform marks. */
|
|
280
|
-
cues: Array<{
|
|
281
|
-
t: number;
|
|
282
|
-
name: string;
|
|
283
|
-
}>;
|
|
284
|
-
/** Advice, not faults: a mix that is quiet or loud for web video, little headroom, silent stretches. */
|
|
285
|
-
notes: string[];
|
|
286
|
-
}
|
|
287
|
-
|
|
288
130
|
interface FontReport {
|
|
289
131
|
/** Text layers none of whose fonts is available here: they are drawn in a fallback. */
|
|
290
132
|
missing: Array<{
|
|
@@ -297,12 +139,25 @@ interface FontReport {
|
|
|
297
139
|
failedUnused: string[];
|
|
298
140
|
}
|
|
299
141
|
|
|
142
|
+
/** One canvas layer as the check saw it. */
|
|
143
|
+
interface CanvasRow {
|
|
144
|
+
name: string;
|
|
145
|
+
/** The moments (seconds of the layer's own time) it was drawn at, in two orders. */
|
|
146
|
+
moments: number[];
|
|
147
|
+
/** The usual time of one draw on the CPU canvas of the check (the browser's GPU may be faster or slower). */
|
|
148
|
+
drawMs: number;
|
|
149
|
+
ok: boolean;
|
|
150
|
+
/** Why not, in a sentence (empty when ok). */
|
|
151
|
+
problem: string;
|
|
152
|
+
}
|
|
153
|
+
|
|
300
154
|
/** One kind of issue, with how many frames it was seen in. Issues that differ only by numbers are one kind. */
|
|
301
155
|
interface IssueGroup {
|
|
302
156
|
message: string;
|
|
303
157
|
count: number;
|
|
304
158
|
firstFrame: number;
|
|
305
|
-
lastFrame: number;
|
|
159
|
+
lastFrame: number; /** `'canvas'`: a canvas layer that does not draw the same picture for the same time (not about the layout; `check` lists it under its own heading). */
|
|
160
|
+
kind?: 'canvas';
|
|
306
161
|
}
|
|
307
162
|
interface ReviewOptions {
|
|
308
163
|
/** Moments to resolve and report: `3.5`, `50%`, `f120`, `title@end` (comma-separated). */
|
|
@@ -317,6 +172,8 @@ interface ReviewReport {
|
|
|
317
172
|
problems: IssueGroup[];
|
|
318
173
|
/** Text overlaps and fonts that are not available: often intentional, look at them on the contact sheet. */
|
|
319
174
|
review: IssueGroup[];
|
|
175
|
+
/** Every canvas layer as the determinism check saw it (a failing one is also in `problems` with `kind: 'canvas'`). */
|
|
176
|
+
canvas: CanvasRow[];
|
|
320
177
|
fonts: FontReport;
|
|
321
178
|
/** The sound as numbers (`movie.inspectAudio()`), or null for a movie with no audio. */
|
|
322
179
|
audio: AudioReport | null;
|
|
@@ -817,6 +674,10 @@ declare class Movie {
|
|
|
817
674
|
* the canvas, cut by an edge, empty, or overlapping other text. Seeks there and stays there.
|
|
818
675
|
*/
|
|
819
676
|
inspect(frame?: number, opts?: InspectOptions): Promise<InspectReport>;
|
|
677
|
+
/** The canvas layers whose same frame is not the same picture (what `check` reports as a problem): one sentence each. */
|
|
678
|
+
canvasProblems(): string[];
|
|
679
|
+
/** 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). */
|
|
680
|
+
canvasReport(): CanvasRow[];
|
|
820
681
|
/**
|
|
821
682
|
* Every layer as a row with absolute start / end / keyframe times (seconds), plus the transition windows. Runs of
|
|
822
683
|
* similar layers (`pop-1` … `pop-12`) are one row with a `parts` span each. Read it, or draw it with `timelineChart()`.
|
|
@@ -902,4 +763,4 @@ declare class Movie {
|
|
|
902
763
|
destroy(): Promise<void>;
|
|
903
764
|
}
|
|
904
765
|
|
|
905
|
-
export { type
|
|
766
|
+
export { type ContactSheetOptions as C, type FontReport as F, type InspectOptions as I, type LayerInfo as L, Movie as M, type OnionSkinOptions as O, type ProgressEvent as P, type RebuildOptions as R, type SnapshotOptions as S, type ThumbnailOptions as T, type VolumeEvent as V, type MotionBlurSpec as a, type FrameEvent as b, type InspectReport as c, type IssueGroup as d, type LoadProgressState as e, type LoadStage as f, type LoaderOption as g, type LoopEvent as h, type MotionBlurOptions as i, type MovieErrorEvent as j, type MovieOptions as k, type RebuildReason as l, type RebuildReport as m, type RenderOptions as n, type ReviewOptions as o, type ReviewReport as p, type TimelineData as q, type TimelineHtmlOptions as r, type TimelineRow as s, type TimelineSvgOptions as t, type TimelineTransition as u, dismissLoader as v, failLoader as w, resolveLoader as x };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { CompositionSequence } from './chunk-
|
|
2
|
-
import { spansMeta, resolveNumber, bindCounterKeyframes, TextSequence } from './chunk-
|
|
3
|
-
import './chunk-
|
|
4
|
-
import './chunk-
|
|
1
|
+
import { CompositionSequence } from './chunk-4CSL5QSL.js';
|
|
2
|
+
import { spansMeta, resolveNumber, bindCounterKeyframes, TextSequence } from './chunk-UDTLYYGY.js';
|
|
3
|
+
import './chunk-VNP7QCJE.js';
|
|
4
|
+
import './chunk-32MMNDDN.js';
|
|
5
5
|
import './chunk-BXOCEZ4U.js';
|
|
6
6
|
|
|
7
7
|
// src/sequences/Spans.ts
|
|
@@ -49,5 +49,5 @@ var SpansSequence = class extends CompositionSequence {
|
|
|
49
49
|
};
|
|
50
50
|
|
|
51
51
|
export { SpansSequence };
|
|
52
|
-
//# sourceMappingURL=Spans-
|
|
53
|
-
//# sourceMappingURL=Spans-
|
|
52
|
+
//# sourceMappingURL=Spans-4IBQASGK.js.map
|
|
53
|
+
//# sourceMappingURL=Spans-4IBQASGK.js.map
|