pixi-effects 0.5.0 → 0.7.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 +30 -0
- package/README.md +17 -10
- package/ai/SKILL.md +1 -1
- package/ai/reference/cheatsheet.md +8 -2
- package/ai/reference/pitfalls.md +1 -0
- package/ai/reference/recipes.md +36 -1
- package/ai/template.html +4 -3
- package/ai/tools/check.mjs +14 -5
- package/ai/tools/render.mjs +202 -0
- package/ai/tools/view.mjs +269 -0
- package/dist/{Base-DnRAxroQ.d.cts → Base-CSIulyIq.d.cts} +1 -1
- package/dist/{Base-CPSFBkPm.d.ts → Base-DVgwyIUj.d.ts} +1 -1
- package/dist/Composition-3KHQPRBA.cjs +14 -0
- package/dist/{Composition-63EXHNJJ.cjs.map → Composition-3KHQPRBA.cjs.map} +1 -1
- package/dist/Composition-DT657FO5.js +5 -0
- package/dist/{Composition-TUCRSMJU.js.map → Composition-DT657FO5.js.map} +1 -1
- package/dist/Controller.cjs +77 -2
- package/dist/Controller.cjs.map +1 -1
- package/dist/Controller.d.cts +16 -2
- package/dist/Controller.d.ts +16 -2
- package/dist/Controller.js +77 -2
- package/dist/Controller.js.map +1 -1
- package/dist/{Movie-CuU_aaCm.d.cts → Movie-B0OUKlZI.d.ts} +54 -2
- package/dist/{Movie-VyDiUYOj.d.ts → Movie-BK9daiTt.d.cts} +54 -2
- package/dist/{chunk-5Q5XZG7Z.js → chunk-36Z4RIRK.js} +3 -3
- package/dist/{chunk-5Q5XZG7Z.js.map → chunk-36Z4RIRK.js.map} +1 -1
- package/dist/{chunk-UBPZLGLU.js → chunk-4O2NYDJG.js} +365 -44
- package/dist/chunk-4O2NYDJG.js.map +1 -0
- package/dist/{chunk-23M5QTWW.cjs → chunk-4VSIJLU3.cjs} +21 -21
- package/dist/{chunk-23M5QTWW.cjs.map → chunk-4VSIJLU3.cjs.map} +1 -1
- package/dist/{chunk-2RR43OIN.cjs → chunk-6I55T4OH.cjs} +403 -62
- package/dist/chunk-6I55T4OH.cjs.map +1 -0
- package/dist/index.cjs +234 -24
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +226 -16
- package/dist/index.js.map +1 -1
- package/dist/three.cjs +6 -5
- package/dist/three.cjs.map +1 -1
- package/dist/three.d.cts +2 -2
- package/dist/three.d.ts +2 -2
- package/dist/three.js +2 -1
- package/dist/three.js.map +1 -1
- package/dist/{types-7VtTEKUW.d.ts → types-oJijbn-K.d.cts} +36 -7
- package/dist/{types-7VtTEKUW.d.cts → types-oJijbn-K.d.ts} +36 -7
- package/docs/api.md +7 -0
- package/docs/dsl.md +74 -8
- package/llms-full.txt +127 -12
- package/package.json +7 -4
- package/dist/Composition-63EXHNJJ.cjs +0 -13
- package/dist/Composition-TUCRSMJU.js +0 -4
- package/dist/chunk-2RR43OIN.cjs.map +0 -1
- package/dist/chunk-UBPZLGLU.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var chunk4VSIJLU3_cjs = require('./chunk-4VSIJLU3.cjs');
|
|
4
|
+
var chunk6I55T4OH_cjs = require('./chunk-6I55T4OH.cjs');
|
|
3
5
|
var chunkUQBGW5DO_cjs = require('./chunk-UQBGW5DO.cjs');
|
|
4
|
-
var chunk23M5QTWW_cjs = require('./chunk-23M5QTWW.cjs');
|
|
5
|
-
var chunk2RR43OIN_cjs = require('./chunk-2RR43OIN.cjs');
|
|
6
6
|
var PIXI = require('pixi.js');
|
|
7
7
|
var gsap = require('gsap');
|
|
8
8
|
var PixiPlugin = require('gsap/PixiPlugin');
|
|
@@ -181,7 +181,7 @@ function fft(re, im) {
|
|
|
181
181
|
}
|
|
182
182
|
var FRAME = 2048;
|
|
183
183
|
function spectralCentroid(samples, sampleRate, from = 0, to = samples.length) {
|
|
184
|
-
let
|
|
184
|
+
let num2 = 0;
|
|
185
185
|
let den = 0;
|
|
186
186
|
const re = new Float64Array(FRAME);
|
|
187
187
|
const im = new Float64Array(FRAME);
|
|
@@ -196,11 +196,11 @@ function spectralCentroid(samples, sampleRate, from = 0, to = samples.length) {
|
|
|
196
196
|
fft(re, im);
|
|
197
197
|
for (let b = 1; b < FRAME / 2; b++) {
|
|
198
198
|
const power = re[b] * re[b] + im[b] * im[b];
|
|
199
|
-
|
|
199
|
+
num2 += power * (b * sampleRate / FRAME);
|
|
200
200
|
den += power;
|
|
201
201
|
}
|
|
202
202
|
}
|
|
203
|
-
return den > 1e-9 ? Math.round(
|
|
203
|
+
return den > 1e-9 ? Math.round(num2 / den / 10) * 10 : 0;
|
|
204
204
|
}
|
|
205
205
|
|
|
206
206
|
// src/core/inspectAudio.ts
|
|
@@ -819,16 +819,16 @@ function expandTransitions(spec) {
|
|
|
819
819
|
if (toUses > 1) {
|
|
820
820
|
throw new Error(`pixi-effects: ${tag} sequence "${t.to}" is used as \`to\` in more than one transition`);
|
|
821
821
|
}
|
|
822
|
-
const tStart =
|
|
822
|
+
const tStart = chunk6I55T4OH_cjs.resolveAt(t.at, parentDuration);
|
|
823
823
|
const tEnd = tStart + t.duration;
|
|
824
824
|
const fromSeq = fromEntry.seq;
|
|
825
|
-
const fromStart =
|
|
825
|
+
const fromStart = chunk6I55T4OH_cjs.resolveAt(fromSeq.at, parentDuration);
|
|
826
826
|
const fromEnd = fromStart + (fromSeq.duration ?? parentDuration);
|
|
827
827
|
if (tStart < fromStart || tEnd > fromEnd) {
|
|
828
828
|
throw new Error(`pixi-effects: ${tag} window [${tStart}, ${tEnd}] is not covered by \`from\` "${t.from}" (lives [${fromStart}, ${fromEnd}], so it ends at ${fromEnd})`);
|
|
829
829
|
}
|
|
830
830
|
const toSeq = toEntry.seq;
|
|
831
|
-
const toStart =
|
|
831
|
+
const toStart = chunk6I55T4OH_cjs.resolveAt(toSeq.at, parentDuration);
|
|
832
832
|
const toEnd = toStart + (toSeq.duration ?? parentDuration);
|
|
833
833
|
if (tStart < toStart || tEnd > toEnd) {
|
|
834
834
|
throw new Error(`pixi-effects: ${tag} window [${tStart}, ${tEnd}] is not covered by \`to\` "${t.to}" (lives [${toStart}, ${toEnd}], so it starts at ${toStart})`);
|
|
@@ -1140,7 +1140,7 @@ function inspectScene(root, frame, time, canvas, opts = {}) {
|
|
|
1140
1140
|
const seen = /* @__PURE__ */ new Map();
|
|
1141
1141
|
const scene = /* @__PURE__ */ new Map();
|
|
1142
1142
|
const scaledToNothing = /* @__PURE__ */ new Set();
|
|
1143
|
-
const
|
|
1143
|
+
const walk2 = (comp, prefix, insideThreeD, parentVisible, parentScene, parentMoving = false, parentZero = false) => {
|
|
1144
1144
|
const blending = /* @__PURE__ */ new Set();
|
|
1145
1145
|
for (const w of transitionWindowsOf(comp.spec)) {
|
|
1146
1146
|
const start = (comp.absoluteStart ?? 0) + w.start, end = (comp.absoluteStart ?? 0) + w.end;
|
|
@@ -1168,7 +1168,7 @@ function inspectScene(root, frame, time, canvas, opts = {}) {
|
|
|
1168
1168
|
onCanvas = inter === 0 && area > 0 ? "none" : inter >= area - 1e-6 ? "full" : "partial";
|
|
1169
1169
|
if (area === 0) onCanvas = "none";
|
|
1170
1170
|
}
|
|
1171
|
-
const keys =
|
|
1171
|
+
const keys = chunk6I55T4OH_cjs.collectPropKeys(seq.spec);
|
|
1172
1172
|
const moving = parentMoving || (seq.spec.keyframes ?? []).length > 0 && (keys.has("x") || keys.has("y"));
|
|
1173
1173
|
const scale = t?.scale;
|
|
1174
1174
|
const zero = parentZero || !!scale && (scale.x === 0 || scale.y === 0);
|
|
@@ -1183,11 +1183,11 @@ function inspectScene(root, frame, time, canvas, opts = {}) {
|
|
|
1183
1183
|
seen.set(info, shown);
|
|
1184
1184
|
const group = parentScene ?? (name !== void 0 && blending.has(name) ? name : void 0);
|
|
1185
1185
|
if (group) scene.set(info, group);
|
|
1186
|
-
if (zero) scaledToNothing.add(info);
|
|
1187
|
-
if (seq instanceof
|
|
1186
|
+
if (zero || seq.showsNothingYet) scaledToNothing.add(info);
|
|
1187
|
+
if (seq instanceof chunk4VSIJLU3_cjs.CompositionSequence) walk2(seq, prefix + label + "/", insideThreeD || threeD, visible, group, moving, zero);
|
|
1188
1188
|
});
|
|
1189
1189
|
};
|
|
1190
|
-
|
|
1190
|
+
walk2(root, "", false, true);
|
|
1191
1191
|
const issues = [];
|
|
1192
1192
|
const texts = layers.filter((l) => l.type === "text" && l.visible && l.alpha >= FAINT && l.bounds);
|
|
1193
1193
|
for (const l of texts) {
|
|
@@ -1224,6 +1224,158 @@ function inspectScene(root, frame, time, canvas, opts = {}) {
|
|
|
1224
1224
|
return { frame, time, canvas, summary: { layers: layers.length, visible: layers.filter((l) => l.visible).length }, issues, layers: listed };
|
|
1225
1225
|
}
|
|
1226
1226
|
|
|
1227
|
+
// src/core/timelineChart.ts
|
|
1228
|
+
var GROUP_MIN = 4;
|
|
1229
|
+
var MAX_KEYS = 200;
|
|
1230
|
+
var round = (n) => Math.round(n * 1e6) / 1e6;
|
|
1231
|
+
var family = (name) => name.replace(/\d+/g, "#");
|
|
1232
|
+
function detailOf(seq) {
|
|
1233
|
+
const s = seq.spec;
|
|
1234
|
+
if (typeof s.text === "string") return s.text.length > 60 ? s.text.slice(0, 57) + "\u2026" : s.text;
|
|
1235
|
+
if (typeof s.asset === "string") return `asset \u201C${s.asset}\u201D`;
|
|
1236
|
+
if (typeof s.sfx === "string") return `sfx \u201C${s.sfx}\u201D`;
|
|
1237
|
+
if (s.sfx && typeof s.sfx === "object") return "sfx (custom)";
|
|
1238
|
+
return void 0;
|
|
1239
|
+
}
|
|
1240
|
+
function walk(comp, parentStart, parentEnd, depth, prefix, rows, transitions) {
|
|
1241
|
+
const entries = [];
|
|
1242
|
+
comp._children.forEach((seq, i) => {
|
|
1243
|
+
const name = seq.spec.name ?? `${seq.spec.type}#${i}`;
|
|
1244
|
+
const start = parentStart + (seq.at ?? 0);
|
|
1245
|
+
const end = Math.min(parentEnd, seq.duration !== void 0 ? start + seq.duration : parentEnd);
|
|
1246
|
+
const span = end - start;
|
|
1247
|
+
const keys = (seq.spec.keyframes ?? []).map((kf) => round(start + chunk6I55T4OH_cjs.resolveAt(kf.at, span))).sort((a, b) => a - b).slice(0, MAX_KEYS);
|
|
1248
|
+
const row = { path: prefix + name, name, type: seq.spec.type, depth, start: round(start), end: round(end), keys, detail: detailOf(seq) };
|
|
1249
|
+
const inner = [];
|
|
1250
|
+
const isComp = seq instanceof chunk4VSIJLU3_cjs.CompositionSequence;
|
|
1251
|
+
if (isComp) walk(seq, start, end, depth + 1, prefix + name + "/", inner, transitions);
|
|
1252
|
+
entries.push({ row, inner, groupable: !isComp });
|
|
1253
|
+
});
|
|
1254
|
+
rows.push(...groupFamilies(entries));
|
|
1255
|
+
for (const w of transitionWindowsOf(comp.spec)) {
|
|
1256
|
+
transitions.push({ from: prefix + w.from, to: prefix + w.to, start: round(parentStart + w.start), end: round(parentStart + w.end) });
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
function groupFamilies(entries) {
|
|
1260
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
1261
|
+
for (const e of entries) {
|
|
1262
|
+
if (!e.groupable) continue;
|
|
1263
|
+
const key = e.row.type + "|" + family(e.row.name);
|
|
1264
|
+
(buckets.get(key) ?? buckets.set(key, []).get(key)).push(e.row);
|
|
1265
|
+
}
|
|
1266
|
+
const out = [];
|
|
1267
|
+
const done = /* @__PURE__ */ new Set();
|
|
1268
|
+
for (const e of entries) {
|
|
1269
|
+
const key = e.row.type + "|" + family(e.row.name);
|
|
1270
|
+
const members = e.groupable ? buckets.get(key) : null;
|
|
1271
|
+
if (members && members.length >= GROUP_MIN) {
|
|
1272
|
+
if (done.has(key)) continue;
|
|
1273
|
+
done.add(key);
|
|
1274
|
+
const label = `${family(e.row.name)} \xD7${members.length}`;
|
|
1275
|
+
out.push({
|
|
1276
|
+
path: e.row.path.slice(0, e.row.path.length - e.row.name.length) + label,
|
|
1277
|
+
name: label,
|
|
1278
|
+
type: e.row.type,
|
|
1279
|
+
depth: e.row.depth,
|
|
1280
|
+
start: Math.min(...members.map((x) => x.start)),
|
|
1281
|
+
end: Math.max(...members.map((x) => x.end)),
|
|
1282
|
+
keys: members.flatMap((x) => x.keys).sort((a, b) => a - b).slice(0, MAX_KEYS),
|
|
1283
|
+
parts: members.map((x) => ({ start: x.start, end: x.end }))
|
|
1284
|
+
});
|
|
1285
|
+
} else {
|
|
1286
|
+
out.push(e.row, ...e.inner);
|
|
1287
|
+
continue;
|
|
1288
|
+
}
|
|
1289
|
+
out.push(...e.inner);
|
|
1290
|
+
}
|
|
1291
|
+
return out;
|
|
1292
|
+
}
|
|
1293
|
+
function collectTimeline(root, duration) {
|
|
1294
|
+
const rows = [];
|
|
1295
|
+
const transitions = [];
|
|
1296
|
+
walk(root, 0, duration, 0, "", rows, transitions);
|
|
1297
|
+
return { duration, rows, transitions };
|
|
1298
|
+
}
|
|
1299
|
+
var COLORS = {
|
|
1300
|
+
text: "#4cc9f0",
|
|
1301
|
+
shape: "#ffd166",
|
|
1302
|
+
image: "#7bd88f",
|
|
1303
|
+
video: "#c77dff",
|
|
1304
|
+
audio: "#ff7aa8",
|
|
1305
|
+
composition: "#8ea4c8",
|
|
1306
|
+
three: "#ff9f68",
|
|
1307
|
+
camera: "#b0b0b0"
|
|
1308
|
+
};
|
|
1309
|
+
var esc = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
1310
|
+
var num = (n) => String(Math.round(n * 100) / 100);
|
|
1311
|
+
function tickStep(duration, chartWidth) {
|
|
1312
|
+
for (const s of [0.04, 0.1, 0.2, 0.5, 1, 2, 5, 10, 15, 30, 60, 120, 300, 600, 1200, 3600]) if (s / duration * chartWidth >= 70) return s;
|
|
1313
|
+
return 7200;
|
|
1314
|
+
}
|
|
1315
|
+
function timelineSvg(data, opts = {}) {
|
|
1316
|
+
const CHART = Math.max(100, opts.chartWidth ?? 950), withLabels = opts.labels !== false;
|
|
1317
|
+
const LABEL = withLabels ? 250 : 0, ROW = 22, TOP = 34, PAD = 16;
|
|
1318
|
+
const W = LABEL + CHART + PAD * 2, H = TOP + data.rows.length * ROW + PAD;
|
|
1319
|
+
const x = (t) => PAD + LABEL + Math.max(0, Math.min(data.duration, t)) / data.duration * CHART;
|
|
1320
|
+
const step = tickStep(data.duration, CHART);
|
|
1321
|
+
const out = [];
|
|
1322
|
+
for (let t = 0; t <= data.duration + 1e-9; t += step) {
|
|
1323
|
+
out.push(`<line class="grid" x1="${num(x(t))}" y1="${TOP - 6}" x2="${num(x(t))}" y2="${H - PAD}"/>`);
|
|
1324
|
+
out.push(`<text class="tick" x="${num(x(t))}" y="${TOP - 12}" text-anchor="middle">${num(t)}${t === 0 || Math.abs(t - data.duration) < 1e-9 ? " s" : ""}</text>`);
|
|
1325
|
+
}
|
|
1326
|
+
if (Math.abs(data.duration % step) > 1e-9) out.push(`<text class="tick" x="${num(x(data.duration))}" y="${TOP - 12}" text-anchor="middle">${num(data.duration)} s</text>`);
|
|
1327
|
+
for (const t of data.transitions) {
|
|
1328
|
+
out.push(`<g><title>transition ${esc(t.from)} \u2192 ${esc(t.to)} (${num(t.start)}\u2013${num(t.end)} s)</title><rect class="transition" x="${num(x(t.start))}" y="${TOP - 4}" width="${num(Math.max(2, x(t.end) - x(t.start)))}" height="${H - TOP - PAD + 4}"/></g>`);
|
|
1329
|
+
}
|
|
1330
|
+
data.rows.forEach((r, i) => {
|
|
1331
|
+
const y = TOP + i * ROW;
|
|
1332
|
+
const color = COLORS[r.type] ?? "#9aa7b8";
|
|
1333
|
+
const tip = `${r.path} \xB7 ${r.type} \xB7 ${num(r.start)}\u2013${num(r.end)} s (${num(r.end - r.start)} s)${r.keys.length ? ` \xB7 ${r.keys.length} keyframe${r.keys.length > 1 ? "s" : ""}` : ""}${r.detail ? ` \xB7 ${r.detail}` : ""}`;
|
|
1334
|
+
out.push(`<g class="row" data-start="${num(r.start)}"><title>${esc(tip)}</title>`);
|
|
1335
|
+
out.push(`<rect class="band" x="${PAD}" y="${y}" width="${LABEL + CHART}" height="${ROW}" ${i % 2 ? 'fill-opacity=".05"' : 'fill-opacity="0"'}/>`);
|
|
1336
|
+
if (withLabels) out.push(`<text class="label" x="${PAD + 6 + r.depth * 14}" y="${y + 15}">${esc(r.name)}</text>`);
|
|
1337
|
+
for (const p of r.parts ?? [{ start: r.start, end: r.end }]) {
|
|
1338
|
+
out.push(`<rect class="bar" x="${num(x(p.start))}" y="${y + 4}" width="${num(Math.max(2, x(p.end) - x(p.start)))}" height="${ROW - 8}" rx="3" fill="${color}"/>`);
|
|
1339
|
+
}
|
|
1340
|
+
for (const k of r.keys) out.push(`<path class="key" d="M ${num(x(k))} ${y + 7} l 3 4 l -3 4 l -3 -4 z"/>`);
|
|
1341
|
+
out.push("</g>");
|
|
1342
|
+
});
|
|
1343
|
+
const legend = Object.entries(COLORS).map(([type, c], i) => `<g transform="translate(${PAD + i * 108},${H + 10})"><rect width="12" height="12" rx="3" fill="${c}"/><text x="18" y="10" class="tick">${type}</text></g>`).join("");
|
|
1344
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" width="${W}" height="${H + 32}" viewBox="0 0 ${W} ${H + 32}" role="img" aria-label="Timeline of ${data.rows.length} rows" data-duration="${num(data.duration)}" data-x0="${num(x(0))}" data-x1="${num(x(data.duration))}" data-top="${TOP - 6}" data-bottom="${H - PAD}" data-row="${ROW}">
|
|
1345
|
+
${out.join("\n")}
|
|
1346
|
+
${legend}
|
|
1347
|
+
</svg>`;
|
|
1348
|
+
}
|
|
1349
|
+
function timelineHtml(data, opts = {}) {
|
|
1350
|
+
const W = 250 + 950 + 32;
|
|
1351
|
+
const title = esc(opts.title ?? "Timeline");
|
|
1352
|
+
return `<!doctype html>
|
|
1353
|
+
<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>${title} \u2014 timeline</title>
|
|
1354
|
+
<style>
|
|
1355
|
+
:root { --bg: #f7f5f1; --ink: #1d2433; --dim: #6b7587; --grid: #d9d5cc; --key: #1d2433; --trans: #4cc9f0; }
|
|
1356
|
+
@media (prefers-color-scheme: dark) { :root { --bg: #0e1320; --ink: #e8eefc; --dim: #8fa0bf; --grid: #26304a; --key: #ffffff; --trans: #4cc9f0; } }
|
|
1357
|
+
body { margin: 0; background: var(--bg); color: var(--ink); font: 14px system-ui, sans-serif; }
|
|
1358
|
+
main { padding: 20px 16px 32px; max-width: ${W + 32}px; margin: 0 auto; overflow-x: auto; }
|
|
1359
|
+
h1 { font-size: 18px; font-weight: 600; margin: 0 0 4px; }
|
|
1360
|
+
p { margin: 0 0 14px; color: var(--dim); font-size: 13px; }
|
|
1361
|
+
svg { display: block; }
|
|
1362
|
+
.grid { stroke: var(--grid); stroke-width: 1; }
|
|
1363
|
+
.tick { fill: var(--dim); font-size: 11px; }
|
|
1364
|
+
.label { fill: var(--ink); font-size: 12px; font-family: ui-monospace, Menlo, monospace; }
|
|
1365
|
+
.band { fill: var(--ink); }
|
|
1366
|
+
.key { fill: var(--key); opacity: .85; }
|
|
1367
|
+
.transition { fill: var(--trans); opacity: .16; }
|
|
1368
|
+
.bar { opacity: .88; }
|
|
1369
|
+
.row:hover .bar { opacity: 1; }
|
|
1370
|
+
</style></head>
|
|
1371
|
+
<body><main>
|
|
1372
|
+
<h1>${title}</h1>
|
|
1373
|
+
<p>${data.rows.length} row${data.rows.length === 1 ? "" : "s"} \xB7 ${num(data.duration)} s \xB7 \u25C6 keyframe start \xB7 shaded band: a transition \xB7 hover a bar for details</p>
|
|
1374
|
+
${timelineSvg(data)}
|
|
1375
|
+
</main></body></html>
|
|
1376
|
+
`;
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1227
1379
|
// src/core/frames.ts
|
|
1228
1380
|
function pickFrames(lastFrame, count) {
|
|
1229
1381
|
const last = Math.max(0, Math.floor(lastFrame));
|
|
@@ -1244,6 +1396,35 @@ function sheetLayout(n, columns, cellW, srcW, srcH, labelH) {
|
|
|
1244
1396
|
return { cols, rows, cellW, cellH, width: cols * cellW, height: rows * (cellH + labelH), positions };
|
|
1245
1397
|
}
|
|
1246
1398
|
|
|
1399
|
+
// src/core/startWhenRunning.ts
|
|
1400
|
+
function startWhenRunning(ctx, start, gesture) {
|
|
1401
|
+
if (ctx.state === "running") {
|
|
1402
|
+
start();
|
|
1403
|
+
return () => {
|
|
1404
|
+
};
|
|
1405
|
+
}
|
|
1406
|
+
let done = false;
|
|
1407
|
+
const resume = () => {
|
|
1408
|
+
ctx.resume?.()?.catch(() => {
|
|
1409
|
+
});
|
|
1410
|
+
};
|
|
1411
|
+
const stop = () => {
|
|
1412
|
+
done = true;
|
|
1413
|
+
ctx.removeEventListener("statechange", onState);
|
|
1414
|
+
for (const e of GESTURES) gesture?.removeEventListener(e, resume, true);
|
|
1415
|
+
};
|
|
1416
|
+
const onState = () => {
|
|
1417
|
+
if (done || ctx.state !== "running") return;
|
|
1418
|
+
stop();
|
|
1419
|
+
start();
|
|
1420
|
+
};
|
|
1421
|
+
ctx.addEventListener("statechange", onState);
|
|
1422
|
+
for (const e of GESTURES) gesture?.addEventListener(e, resume, true);
|
|
1423
|
+
resume();
|
|
1424
|
+
return stop;
|
|
1425
|
+
}
|
|
1426
|
+
var GESTURES = ["pointerdown", "mousedown", "touchend", "keydown"];
|
|
1427
|
+
|
|
1247
1428
|
// src/core/Movie.ts
|
|
1248
1429
|
PIXI.extensions.add(PIXI.CullerPlugin);
|
|
1249
1430
|
gsap.gsap.registerPlugin(PixiPlugin.PixiPlugin);
|
|
@@ -1256,6 +1437,7 @@ var Movie = class {
|
|
|
1256
1437
|
audioBuffer = null;
|
|
1257
1438
|
audioSource = null;
|
|
1258
1439
|
gainNode = null;
|
|
1440
|
+
_cancelAudioStart = null;
|
|
1259
1441
|
_volume = 1;
|
|
1260
1442
|
_muted = false;
|
|
1261
1443
|
isPlaying = false;
|
|
@@ -1349,6 +1531,7 @@ var Movie = class {
|
|
|
1349
1531
|
height: options.composition.height ?? this.height,
|
|
1350
1532
|
duration: options.composition.duration ?? this.duration
|
|
1351
1533
|
} : void 0;
|
|
1534
|
+
await chunk6I55T4OH_cjs.ensureFilterLibrary(seededComposition);
|
|
1352
1535
|
const userComposition = seededComposition ? expandTransitions(seededComposition) : void 0;
|
|
1353
1536
|
const rootSeqSpec = {
|
|
1354
1537
|
type: "composition",
|
|
@@ -1358,7 +1541,7 @@ var Movie = class {
|
|
|
1358
1541
|
...userComposition
|
|
1359
1542
|
};
|
|
1360
1543
|
if (userComposition) carryTransitionWindows(userComposition, rootSeqSpec);
|
|
1361
|
-
const composition = new
|
|
1544
|
+
const composition = new chunk4VSIJLU3_cjs.CompositionSequence(rootSeqSpec, null, rootShape);
|
|
1362
1545
|
await composition.build();
|
|
1363
1546
|
this._rootSequence = composition;
|
|
1364
1547
|
if (composition.target) root.addChild(composition.target);
|
|
@@ -1457,6 +1640,24 @@ var Movie = class {
|
|
|
1457
1640
|
await this.gotoFrame(f, true);
|
|
1458
1641
|
return inspectScene(this._rootSequence, f, f / this.frameRate, { width: this.width, height: this.height }, opts);
|
|
1459
1642
|
}
|
|
1643
|
+
/**
|
|
1644
|
+
* Every layer as a row with absolute start / end / keyframe times (seconds), plus the transition windows. Runs of
|
|
1645
|
+
* similar layers (`pop-1` … `pop-12`) are one row with a `parts` span each. Read it, or draw it with `timelineChart()`.
|
|
1646
|
+
*/
|
|
1647
|
+
timelineData() {
|
|
1648
|
+
this._requireReady("timelineData");
|
|
1649
|
+
return collectTimeline(this._rootSequence, this.duration);
|
|
1650
|
+
}
|
|
1651
|
+
/** The timeline as one self-contained HTML page (an inline SVG, no scripts): layers as bars on a time axis, ◆ keyframes, transition bands. Open it in a browser. */
|
|
1652
|
+
timelineChart(opts = {}) {
|
|
1653
|
+
chunkUQBGW5DO_cjs.warnUnknownOptions("movie.timelineChart()", opts, ["title"]);
|
|
1654
|
+
return timelineHtml(this.timelineData(), opts);
|
|
1655
|
+
}
|
|
1656
|
+
/** Just the chart: one `<svg>` whose geometry is in `data-*` attributes (a viewer puts a playhead on it: `pixi-effects-view`). */
|
|
1657
|
+
timelineSvg(opts = {}) {
|
|
1658
|
+
chunkUQBGW5DO_cjs.warnUnknownOptions("movie.timelineSvg()", opts, ["chartWidth", "labels"]);
|
|
1659
|
+
return timelineSvg(this.timelineData(), opts);
|
|
1660
|
+
}
|
|
1460
1661
|
/**
|
|
1461
1662
|
* The soundtrack, measured: when every audio layer plays, how loud the mix is over time, and `issues`
|
|
1462
1663
|
* (limiting, inaudible layers, sounds cut off by the end). Use it to CHECK sound you cannot hear.
|
|
@@ -1493,6 +1694,7 @@ var Movie = class {
|
|
|
1493
1694
|
play() {
|
|
1494
1695
|
if (this._initState !== "ready") return;
|
|
1495
1696
|
if (this.currentFrame >= this.totalFrames) this.currentFrame = 0;
|
|
1697
|
+
const wasPlaying = this.isPlaying;
|
|
1496
1698
|
this.isPlaying = true;
|
|
1497
1699
|
const startTime = performance.now() - this.currentFrame / this.frameRate * 1e3;
|
|
1498
1700
|
let inFlight = false;
|
|
@@ -1522,17 +1724,25 @@ var Movie = class {
|
|
|
1522
1724
|
this._raf = requestAnimationFrame(tick);
|
|
1523
1725
|
if (this.audioBuffer) {
|
|
1524
1726
|
const ctx = this._ensureAudioContext();
|
|
1525
|
-
|
|
1526
|
-
this.
|
|
1527
|
-
this.
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1727
|
+
const buffer = this.audioBuffer;
|
|
1728
|
+
this._cancelAudioStart?.();
|
|
1729
|
+
this._cancelAudioStart = startWhenRunning(ctx, () => {
|
|
1730
|
+
if (!this.isPlaying) return;
|
|
1731
|
+
this.audioSource = ctx.createBufferSource();
|
|
1732
|
+
this.audioSource.buffer = buffer;
|
|
1733
|
+
this.gainNode = ctx.createGain();
|
|
1734
|
+
this.gainNode.gain.value = this._muted ? 0 : this._volume;
|
|
1735
|
+
this.audioSource.connect(this.gainNode).connect(ctx.destination);
|
|
1736
|
+
this.audioSource.start(0, Math.min(this.currentFrame / this.frameRate, buffer.duration));
|
|
1737
|
+
}, typeof window !== "undefined" ? window : void 0);
|
|
1531
1738
|
}
|
|
1739
|
+
if (!wasPlaying) this.emit("play");
|
|
1532
1740
|
}
|
|
1533
1741
|
pause() {
|
|
1534
1742
|
const wasPlaying = this.isPlaying;
|
|
1535
1743
|
this.isPlaying = false;
|
|
1744
|
+
this._cancelAudioStart?.();
|
|
1745
|
+
this._cancelAudioStart = null;
|
|
1536
1746
|
if (this._raf) {
|
|
1537
1747
|
cancelAnimationFrame(this._raf);
|
|
1538
1748
|
this._raf = null;
|
|
@@ -1794,17 +2004,17 @@ function orbit(opts) {
|
|
|
1794
2004
|
throw new Error("pixi-effects: orbit() cannot combine `radius` with `dollyZoom` \u2014 the radius follows the animated fov");
|
|
1795
2005
|
}
|
|
1796
2006
|
const [cx, cy] = opts.center ?? [width / 2, height / 2];
|
|
1797
|
-
const fixedR = opts.radius ??
|
|
2007
|
+
const fixedR = opts.radius ?? chunk6I55T4OH_cjs.homeDistance(height, fov ?? chunk6I55T4OH_cjs.DEFAULT_FOV);
|
|
1798
2008
|
const start = opts.start ?? -degrees / 2;
|
|
1799
2009
|
const steps = Math.max(1, Math.round(duration * stepsPerSecond));
|
|
1800
2010
|
const easeFn = parseEase(ease);
|
|
1801
2011
|
const dollyEase = dolly ? parseEase(dolly.ease ?? ease) : null;
|
|
1802
2012
|
const pos = (i) => {
|
|
1803
2013
|
const p = i / steps;
|
|
1804
|
-
const a = (start + degrees * easeFn(p)) *
|
|
2014
|
+
const a = (start + degrees * easeFn(p)) * chunk6I55T4OH_cjs.DEG;
|
|
1805
2015
|
if (!dolly) return { x: cx + fixedR * Math.sin(a), z: fixedR * Math.cos(a) };
|
|
1806
2016
|
const f = dolly.from + (dolly.to - dolly.from) * dollyEase(p);
|
|
1807
|
-
const R =
|
|
2017
|
+
const R = chunk6I55T4OH_cjs.homeDistance(height, f);
|
|
1808
2018
|
return { x: cx + R * Math.sin(a), z: R * Math.cos(a), fov: f };
|
|
1809
2019
|
};
|
|
1810
2020
|
const keyframes = [];
|
|
@@ -1853,7 +2063,7 @@ function withFade(spec, opts) {
|
|
|
1853
2063
|
|
|
1854
2064
|
Object.defineProperty(exports, "registerSequenceType", {
|
|
1855
2065
|
enumerable: true,
|
|
1856
|
-
get: function () { return
|
|
2066
|
+
get: function () { return chunk6I55T4OH_cjs.registerSequenceType; }
|
|
1857
2067
|
});
|
|
1858
2068
|
exports.Movie = Movie;
|
|
1859
2069
|
exports.kenBurns = kenBurns;
|