pixi-effects 0.19.0 → 0.20.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 +31 -0
- package/README.md +6 -6
- package/ai/SKILL.md +1 -0
- package/ai/chat-template.html +3 -3
- package/ai/reference/cheatsheet.md +7 -6
- package/ai/reference/pitfalls.md +5 -0
- package/ai/reference/recipes.md +52 -0
- package/ai/template.html +5 -5
- package/ai/tools/check.mjs +15 -3
- package/dist/{Base-B4WbUJO2.d.ts → Base-CzfLGoDr.d.ts} +9 -1
- package/dist/{Base-i88XXaiP.d.cts → Base-wYJQ2g5Q.d.cts} +9 -1
- package/dist/Composition-6PA4C4TV.js +5 -0
- package/dist/{Composition-QBKEEJBV.js.map → Composition-6PA4C4TV.js.map} +1 -1
- package/dist/Composition-LL2XXU5N.cjs +14 -0
- package/dist/{Composition-KYNPRWK3.cjs.map → Composition-LL2XXU5N.cjs.map} +1 -1
- package/dist/Controller.cjs +2 -2
- package/dist/Controller.d.cts +2 -2
- package/dist/Controller.d.ts +2 -2
- package/dist/Controller.js +1 -1
- package/dist/{Movie-8IrqL3kO.d.ts → Movie-CBxGH5ms.d.ts} +8 -2
- package/dist/{Movie-CpmdNadg.d.cts → Movie-CzzJw8A-.d.cts} +8 -2
- package/dist/Presenter.cjs +2 -2
- package/dist/Presenter.d.cts +2 -2
- package/dist/Presenter.d.ts +2 -2
- package/dist/Presenter.js +1 -1
- package/dist/{chunk-YRXTKOV5.js → chunk-DQHXVNOI.js} +282 -23
- package/dist/chunk-DQHXVNOI.js.map +1 -0
- package/dist/{chunk-CTZRFSVU.cjs → chunk-FFYA3UBU.cjs} +144 -37
- package/dist/chunk-FFYA3UBU.cjs.map +1 -0
- package/dist/{chunk-DKGG7WD4.js → chunk-MNM56B3X.js} +6 -3
- package/dist/chunk-MNM56B3X.js.map +1 -0
- package/dist/{chunk-VTBT6NNE.cjs → chunk-NO26HWR7.cjs} +294 -30
- package/dist/chunk-NO26HWR7.cjs.map +1 -0
- package/dist/{chunk-B3YB2TNY.js → chunk-TSPMKV2F.js} +120 -13
- package/dist/chunk-TSPMKV2F.js.map +1 -0
- package/dist/{chunk-UQBGW5DO.cjs → chunk-WTRKDIKH.cjs} +6 -3
- package/dist/chunk-WTRKDIKH.cjs.map +1 -0
- package/dist/index.cjs +213 -90
- 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 +154 -31
- package/dist/index.js.map +1 -1
- package/dist/loader.css +1 -1
- package/dist/{music-4HDFULNR.js → music-CFEC7HKL.js} +3 -3
- package/dist/{music-4HDFULNR.js.map → music-CFEC7HKL.js.map} +1 -1
- package/dist/{music-3OF5C6X5.cjs → music-UAN7DXK4.cjs} +7 -7
- package/dist/{music-3OF5C6X5.cjs.map → music-UAN7DXK4.cjs.map} +1 -1
- package/dist/{sfx-MZJZXYY3.cjs → sfx-EX4PUBMV.cjs} +8 -8
- package/dist/{sfx-MZJZXYY3.cjs.map → sfx-EX4PUBMV.cjs.map} +1 -1
- package/dist/{sfx-S37DDC66.js → sfx-U3GM2MED.js} +3 -3
- package/dist/{sfx-S37DDC66.js.map → sfx-U3GM2MED.js.map} +1 -1
- 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-bzLJ7aUx.d.ts → types-YmUaViL1.d.cts} +24 -0
- package/dist/{types-bzLJ7aUx.d.cts → types-YmUaViL1.d.ts} +24 -0
- package/docs/dsl.md +22 -0
- package/llms-full.txt +87 -6
- package/package.json +3 -1
- package/dist/Composition-KYNPRWK3.cjs +0 -14
- package/dist/Composition-QBKEEJBV.js +0 -5
- package/dist/chunk-B3YB2TNY.js.map +0 -1
- package/dist/chunk-CTZRFSVU.cjs.map +0 -1
- package/dist/chunk-DKGG7WD4.js.map +0 -1
- package/dist/chunk-UQBGW5DO.cjs.map +0 -1
- package/dist/chunk-VTBT6NNE.cjs.map +0 -1
- package/dist/chunk-YRXTKOV5.js.map +0 -1
package/dist/Presenter.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { suggestName, warnUnknownOptions } from './chunk-
|
|
1
|
+
import { suggestName, warnUnknownOptions } from './chunk-MNM56B3X.js';
|
|
2
2
|
import * as PIXI from 'pixi.js';
|
|
3
3
|
import { Rectangle, Container, GraphicsPath, Graphics, Assets, Texture, Sprite, FillGradient, Text, Filter, GlProgram, defaultFilterVert, GpuProgram, UniformGroup, Color } from 'pixi.js';
|
|
4
4
|
import { gsap } from 'gsap';
|
|
@@ -396,6 +396,58 @@ function looksLikeColorString(s) {
|
|
|
396
396
|
if (s.charCodeAt(0) === 35) return true;
|
|
397
397
|
return /^(rgb|hsl|oklab|oklch|lab|lch)\b/i.test(s);
|
|
398
398
|
}
|
|
399
|
+
function cubicBezierEase(x1, y1, x2, y2) {
|
|
400
|
+
const cx = 3 * x1, bx = 3 * (x2 - x1) - cx, ax = 1 - cx - bx;
|
|
401
|
+
const cy = 3 * y1, by = 3 * (y2 - y1) - cy, ay = 1 - cy - by;
|
|
402
|
+
const X = (t) => ((ax * t + bx) * t + cx) * t;
|
|
403
|
+
const Y = (t) => ((ay * t + by) * t + cy) * t;
|
|
404
|
+
const dX = (t) => (3 * ax * t + 2 * bx) * t + cx;
|
|
405
|
+
return (p) => {
|
|
406
|
+
if (p <= 0) return 0;
|
|
407
|
+
if (p >= 1) return 1;
|
|
408
|
+
let t = p;
|
|
409
|
+
for (let i = 0; i < 8; i++) {
|
|
410
|
+
const err = X(t) - p;
|
|
411
|
+
if (Math.abs(err) < 1e-9) return Y(t);
|
|
412
|
+
const d = dX(t);
|
|
413
|
+
if (Math.abs(d) < 1e-6) break;
|
|
414
|
+
t -= err / d;
|
|
415
|
+
}
|
|
416
|
+
let lo = 0, hi = 1;
|
|
417
|
+
t = p;
|
|
418
|
+
for (let i = 0; i < 60; i++) {
|
|
419
|
+
const x = X(t);
|
|
420
|
+
if (Math.abs(x - p) < 1e-10) break;
|
|
421
|
+
if (x < p) lo = t;
|
|
422
|
+
else hi = t;
|
|
423
|
+
t = (lo + hi) / 2;
|
|
424
|
+
}
|
|
425
|
+
return Y(t);
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
var NUM = String.raw`\s*(-?(?:\d+\.?\d*|\.\d+)(?:e[-+]?\d+)?)\s*`;
|
|
429
|
+
var RE = new RegExp(`^\\s*cubic-bezier\\(${NUM},${NUM},${NUM},${NUM}\\)\\s*$`, "i");
|
|
430
|
+
function cubicBezierProblem(name) {
|
|
431
|
+
const m = RE.exec(name);
|
|
432
|
+
if (!m) return 'expected "cubic-bezier(x1, y1, x2, y2)" with four numbers, like CSS';
|
|
433
|
+
const x1 = Number(m[1]), x2 = Number(m[3]);
|
|
434
|
+
if (x1 < 0 || x1 > 1 || x2 < 0 || x2 > 1) return "x1 and x2 must be between 0 and 1 (y1 and y2 may overshoot)";
|
|
435
|
+
return null;
|
|
436
|
+
}
|
|
437
|
+
var registered2 = false;
|
|
438
|
+
function registerCubicBezierEase() {
|
|
439
|
+
if (registered2) return;
|
|
440
|
+
registered2 = true;
|
|
441
|
+
const base = ((p) => p);
|
|
442
|
+
base.config = (x1, y1, x2, y2) => {
|
|
443
|
+
const bad = [x1, y1, x2, y2].some((v) => typeof v !== "number" || !Number.isFinite(v)) || x1 < 0 || x1 > 1 || x2 < 0 || x2 > 1;
|
|
444
|
+
return bad ? (p) => p : cubicBezierEase(x1, y1, x2, y2);
|
|
445
|
+
};
|
|
446
|
+
gsap.registerEase("cubic-bezier", base);
|
|
447
|
+
}
|
|
448
|
+
registerCubicBezierEase();
|
|
449
|
+
|
|
450
|
+
// src/core/ease.ts
|
|
399
451
|
var FAMILIES = ["power1", "power2", "power3", "power4", "back", "elastic", "bounce", "circ", "expo", "sine"];
|
|
400
452
|
var EASE_NAMES = ["none", ...FAMILIES.flatMap((f) => [`${f}.in`, `${f}.out`, `${f}.inOut`])];
|
|
401
453
|
var warned = /* @__PURE__ */ new Set();
|
|
@@ -408,6 +460,13 @@ function checkEase(ease, where) {
|
|
|
408
460
|
console.warn(`pixi-effects: ${where}: unknown ease "${ease}" \u2014 ${problem}. GSAP would run it as its default ease, power1.out.`);
|
|
409
461
|
return;
|
|
410
462
|
}
|
|
463
|
+
if (/^\s*cubic-bezier/i.test(ease)) {
|
|
464
|
+
const problem = cubicBezierProblem(ease);
|
|
465
|
+
if (!problem || warned.has(ease)) return;
|
|
466
|
+
warned.add(ease);
|
|
467
|
+
console.warn(`pixi-effects: ${where}: unknown ease "${ease}" \u2014 ${problem}. It runs as 'none' (a straight line).`);
|
|
468
|
+
return;
|
|
469
|
+
}
|
|
411
470
|
const found = gsap.parseEase(ease);
|
|
412
471
|
if (typeof found === "function") return;
|
|
413
472
|
if (warned.has(ease)) return;
|
|
@@ -1082,7 +1141,7 @@ var GrainFilter = class extends Filter {
|
|
|
1082
1141
|
}
|
|
1083
1142
|
/** The movie calls this with the time (s) of the frame it is about to draw: the grain is new every 1/fps s. */
|
|
1084
1143
|
setTime(t) {
|
|
1085
|
-
this.u.uFrame = this._fps > 0 ? Math.floor(t * this._fps + 1e-
|
|
1144
|
+
this.u.uFrame = this._fps > 0 ? Math.floor(t * this._fps + 1e-3) : 0;
|
|
1086
1145
|
}
|
|
1087
1146
|
};
|
|
1088
1147
|
|
|
@@ -1297,13 +1356,21 @@ var Sequence = class {
|
|
|
1297
1356
|
pathRouters() {
|
|
1298
1357
|
return {};
|
|
1299
1358
|
}
|
|
1359
|
+
/**
|
|
1360
|
+
* The `initial` and `keyframes` that go onto the display object. A layer whose `time` runs a clock (video, composition) takes `time`
|
|
1361
|
+
* out of them: it is not a property of the display object.
|
|
1362
|
+
*/
|
|
1363
|
+
displayProps() {
|
|
1364
|
+
return { initial: this.spec.initial, keyframes: this.spec.keyframes };
|
|
1365
|
+
}
|
|
1300
1366
|
bindTimeline(timeline, offset = 0) {
|
|
1301
1367
|
if (!this.target) return;
|
|
1302
1368
|
const scope = this.scope();
|
|
1303
1369
|
const routers = this.pathRouters();
|
|
1304
1370
|
const startTime = offset + this.at;
|
|
1305
|
-
|
|
1306
|
-
|
|
1371
|
+
const { initial, keyframes } = this.displayProps();
|
|
1372
|
+
applyInitial(this.target, initial, scope, [], routers);
|
|
1373
|
+
applyKeyframes(timeline, this.target, keyframes, this.duration, scope, [], startTime, routers);
|
|
1307
1374
|
const endTime = startTime + this.duration;
|
|
1308
1375
|
this.absoluteStart = startTime;
|
|
1309
1376
|
if (this.keepHidden) return;
|
|
@@ -1356,11 +1423,11 @@ function collectPropKeys(spec) {
|
|
|
1356
1423
|
|
|
1357
1424
|
// src/core/layerKeys.ts
|
|
1358
1425
|
var COMMON = ["type", "name", "parent", "at", "duration", "initial", "keyframes", "filters", "filterArea", "mask", "maskInverted", "blendMode", "threeD", "hideBehindCamera"];
|
|
1359
|
-
var VIDEO = [...COMMON, "asset", "loop", "audio", "volume"];
|
|
1426
|
+
var VIDEO = [...COMMON, "asset", "loop", "audio", "volume", "speed"];
|
|
1360
1427
|
var IMAGE = [...COMMON, "asset", "colorSpace"];
|
|
1361
1428
|
var TEXT = [...COMMON, "text", "format", "style", "colorSpace", "fillGradient"];
|
|
1362
|
-
var AUDIO = [...COMMON, "volume", "asset", "loop", "sfx", "music"];
|
|
1363
|
-
var COMPOSITION = [...COMMON, "width", "height", "sequences", "transitions"];
|
|
1429
|
+
var AUDIO = [...COMMON, "volume", "asset", "loop", "sfx", "music", "speed"];
|
|
1430
|
+
var COMPOSITION = [...COMMON, "width", "height", "sequences", "transitions", "speed"];
|
|
1364
1431
|
var CAMERA = [...COMMON];
|
|
1365
1432
|
var NULL = [...COMMON];
|
|
1366
1433
|
var SHAPE = [...COMMON, "shape", "fillGradient", "colorSpace", "strokeCap", "strokeJoin"];
|
|
@@ -1450,6 +1517,7 @@ var PROP_KEYS = /* @__PURE__ */ new Set([
|
|
|
1450
1517
|
"visibleChars",
|
|
1451
1518
|
"text",
|
|
1452
1519
|
"volume",
|
|
1520
|
+
"time",
|
|
1453
1521
|
// camera
|
|
1454
1522
|
"lookAtX",
|
|
1455
1523
|
"lookAtY",
|
|
@@ -1526,12 +1594,54 @@ function lintText(spec, warn = defaultWarn) {
|
|
|
1526
1594
|
warn(`pixi-effects: ${describeLayer(spec)}: \`value\` is set or animated but the text has no {value} placeholder, so nothing shows it. Use text: '{value}' (or e.g. '{value} users').`);
|
|
1527
1595
|
}
|
|
1528
1596
|
}
|
|
1597
|
+
var REMAPPABLE = /* @__PURE__ */ new Set(["video", "audio", "composition"]);
|
|
1598
|
+
var REMAP_NAMES = /* @__PURE__ */ new Set(["time", "timeRemap", "reverse"]);
|
|
1599
|
+
var TIME_BAGS = ["set", "to", "from"];
|
|
1600
|
+
function lintRemap(spec, warn) {
|
|
1601
|
+
const s = spec;
|
|
1602
|
+
const who = describeLayer(spec);
|
|
1603
|
+
const kfs = s.keyframes ?? [];
|
|
1604
|
+
const bags = [s.initial, ...kfs.flatMap((kf) => TIME_BAGS.map((b) => kf[b]))];
|
|
1605
|
+
const timeInInitial = !!s.initial && s.initial.time !== void 0;
|
|
1606
|
+
const timeInKeyframes = kfs.some((kf) => TIME_BAGS.some((b) => kf[b] && kf[b].time !== void 0));
|
|
1607
|
+
const timed = timeInInitial || timeInKeyframes;
|
|
1608
|
+
if (bags.some((bag) => bag && bag.speed !== void 0)) {
|
|
1609
|
+
warn(`pixi-effects: ${who}: speed is a fixed setting, not an animatable property: write it on the layer (speed: 2); to change the speed over time, animate time (keyframes: [{ at: 0, from: { time: 0 }, to: { time: 4 }, duration: 2, ease: 'power2.in' }])`);
|
|
1610
|
+
}
|
|
1611
|
+
if (!REMAPPABLE.has(spec.type)) {
|
|
1612
|
+
if (timed) warn(`pixi-effects: ${who}: "time" only works on video, audio and composition layers; put this layer in a composition and remap that (it is ignored here)`);
|
|
1613
|
+
return;
|
|
1614
|
+
}
|
|
1615
|
+
if (s.reverse !== void 0) warn(`pixi-effects: ${who}: "reverse" is not a key: write speed: -1 to play backward`);
|
|
1616
|
+
if (s.timeRemap !== void 0) warn(`pixi-effects: ${who}: "timeRemap" is not a key: animate time in keyframes (from / to / set), or write speed`);
|
|
1617
|
+
if (s.time !== void 0) warn(`pixi-effects: ${who}: "time" belongs in initial or keyframes (initial: { time: 2 }), not on the layer`);
|
|
1618
|
+
if (spec.type === "audio" && (s.sfx !== void 0 || s.music !== void 0) && (s.speed !== void 0 || timed)) {
|
|
1619
|
+
warn(`pixi-effects: ${who}: speed and time do not apply to a synthesised sound (sfx, music); change an sfx's pitch with pitch (semitones), or put it in a composition and remap that`);
|
|
1620
|
+
return;
|
|
1621
|
+
}
|
|
1622
|
+
if (s.speed !== void 0 && (typeof s.speed !== "number" || !Number.isFinite(s.speed) || s.speed === 0)) {
|
|
1623
|
+
warn(`pixi-effects: ${who}: speed ${JSON.stringify(s.speed)} cannot be used: write a number other than 0 (negative plays backward); to hold a moment, key time to the same value twice`);
|
|
1624
|
+
}
|
|
1625
|
+
if (s.speed !== void 0 && timeInKeyframes) {
|
|
1626
|
+
warn(`pixi-effects: ${who}: speed and keyframed time are both set; time wins and speed is ignored. Use one of them`);
|
|
1627
|
+
}
|
|
1628
|
+
if (timeInInitial && typeof s.initial.time !== "number") {
|
|
1629
|
+
warn(`pixi-effects: ${who}: initial.time must be a number of seconds, got ${JSON.stringify(s.initial.time)}`);
|
|
1630
|
+
}
|
|
1631
|
+
kfs.forEach((kf, i) => {
|
|
1632
|
+
for (const b of TIME_BAGS) {
|
|
1633
|
+
const v = kf[b]?.time;
|
|
1634
|
+
if (v !== void 0 && typeof v !== "number" && typeof v !== "string") warn(`pixi-effects: ${who}: keyframes[${i}].${b}.time must be a number of seconds, got ${JSON.stringify(v)}`);
|
|
1635
|
+
}
|
|
1636
|
+
});
|
|
1637
|
+
}
|
|
1529
1638
|
function lintKeys(spec, warn = defaultWarn) {
|
|
1530
1639
|
const who = describeLayer(spec);
|
|
1531
1640
|
const valid = layerKeys(spec);
|
|
1532
1641
|
if (valid) {
|
|
1533
1642
|
for (const key of Object.keys(spec)) {
|
|
1534
1643
|
if (valid.includes(key) || spec[key] === void 0) continue;
|
|
1644
|
+
if (REMAPPABLE.has(spec.type) && REMAP_NAMES.has(key)) continue;
|
|
1535
1645
|
const guess = suggestName(key, valid.filter((k) => k !== "type"));
|
|
1536
1646
|
const owners = kindsWithKey(key);
|
|
1537
1647
|
const belongs = owners.length ? ` (it belongs to ${owners.slice(0, 3).join(", ")})` : "";
|
|
@@ -1539,12 +1649,13 @@ function lintKeys(spec, warn = defaultWarn) {
|
|
|
1539
1649
|
warn(`pixi-effects: ${who}: "${key}" is not a ${kindName(spec)} key${hint}. Valid keys: ${valid.join(", ")}`);
|
|
1540
1650
|
}
|
|
1541
1651
|
}
|
|
1652
|
+
lintRemap(spec, warn);
|
|
1542
1653
|
const said = /* @__PURE__ */ new Set();
|
|
1543
1654
|
const bags = [spec.initial, ...(spec.keyframes ?? []).flatMap((kf) => [kf.set, kf.to, kf.from])];
|
|
1544
1655
|
for (const bag of bags) {
|
|
1545
1656
|
for (const key of Object.keys(bag ?? {})) {
|
|
1546
1657
|
if (bag[key] === void 0) continue;
|
|
1547
|
-
if (PROP_KEYS.has(key) || key.includes(".") || /^gradient/i.test(key) || said.has(key)) continue;
|
|
1658
|
+
if (PROP_KEYS.has(key) || key.includes(".") || /^gradient/i.test(key) || said.has(key) || key === "speed") continue;
|
|
1548
1659
|
said.add(key);
|
|
1549
1660
|
const guess = suggestName(key, [...PROP_KEYS]);
|
|
1550
1661
|
warn(`pixi-effects: ${who}: "${key}" is not an animatable property${guess ? ` \u2014 did you mean "${guess}"?` : ""} (in initial, set, to or from). See the cheatsheet for the properties of this kind of layer`);
|
|
@@ -1558,6 +1669,116 @@ function lintKeys(spec, warn = defaultWarn) {
|
|
|
1558
1669
|
}
|
|
1559
1670
|
}
|
|
1560
1671
|
}
|
|
1672
|
+
var BAGS = ["set", "to", "from"];
|
|
1673
|
+
function timeRemapOf(spec, prop = "time") {
|
|
1674
|
+
const hasInitial = !!spec.initial && "time" in spec.initial;
|
|
1675
|
+
const hasKf = (spec.keyframes ?? []).some((kf) => BAGS.some((b) => kf[b] && "time" in kf[b]));
|
|
1676
|
+
const speed = typeof spec.speed === "number" && Number.isFinite(spec.speed) && spec.speed !== 0 ? spec.speed : void 0;
|
|
1677
|
+
if (!hasInitial && !hasKf && speed === void 0) return null;
|
|
1678
|
+
const timeKfs = [];
|
|
1679
|
+
const restKfs = [];
|
|
1680
|
+
for (const kf of spec.keyframes ?? []) {
|
|
1681
|
+
const t = { ...kf }, r = { ...kf };
|
|
1682
|
+
let touched = false, left = false;
|
|
1683
|
+
for (const b of BAGS) {
|
|
1684
|
+
const bag = kf[b];
|
|
1685
|
+
if (!bag) {
|
|
1686
|
+
delete t[b];
|
|
1687
|
+
delete r[b];
|
|
1688
|
+
continue;
|
|
1689
|
+
}
|
|
1690
|
+
const { time, ...others } = bag;
|
|
1691
|
+
if ("time" in bag) {
|
|
1692
|
+
touched = true;
|
|
1693
|
+
t[b] = { [prop]: time };
|
|
1694
|
+
} else delete t[b];
|
|
1695
|
+
if (Object.keys(others).length) {
|
|
1696
|
+
r[b] = others;
|
|
1697
|
+
left = true;
|
|
1698
|
+
} else delete r[b];
|
|
1699
|
+
}
|
|
1700
|
+
if (touched) timeKfs.push(t);
|
|
1701
|
+
if (!touched || left) restKfs.push(r);
|
|
1702
|
+
}
|
|
1703
|
+
let restInitial = spec.initial;
|
|
1704
|
+
let start;
|
|
1705
|
+
if (hasInitial) {
|
|
1706
|
+
const { time, ...others } = spec.initial;
|
|
1707
|
+
start = typeof time === "number" && Number.isFinite(time) ? time : void 0;
|
|
1708
|
+
restInitial = others;
|
|
1709
|
+
}
|
|
1710
|
+
return { timeKfs, restKfs: restKfs.length ? restKfs : void 0, restInitial, start, speed };
|
|
1711
|
+
}
|
|
1712
|
+
function resolveFromEnd(remap, length, prop) {
|
|
1713
|
+
const fix = (v) => typeof v === "number" && v < 0 ? Math.max(0, length + v) : v;
|
|
1714
|
+
const timeKfs = remap.timeKfs.map((kf) => {
|
|
1715
|
+
const out = { ...kf };
|
|
1716
|
+
for (const b of BAGS) {
|
|
1717
|
+
const bag = kf[b];
|
|
1718
|
+
if (bag && prop in bag) out[b] = { ...bag, [prop]: fix(bag[prop]) };
|
|
1719
|
+
}
|
|
1720
|
+
return out;
|
|
1721
|
+
});
|
|
1722
|
+
return { ...remap, timeKfs, start: remap.start === void 0 ? void 0 : fix(remap.start) };
|
|
1723
|
+
}
|
|
1724
|
+
function remapOf(spec, prop, length) {
|
|
1725
|
+
const r = timeRemapOf(spec, prop);
|
|
1726
|
+
return r && length !== null ? resolveFromEnd(r, length, prop) : r;
|
|
1727
|
+
}
|
|
1728
|
+
function contentLength(remap, duration) {
|
|
1729
|
+
let m = duration;
|
|
1730
|
+
if (remap.speed !== void 0) m = Math.max(m, Math.abs(remap.speed) * duration);
|
|
1731
|
+
if (remap.start !== void 0) m = Math.max(m, remap.start + (remap.speed ?? 1) * duration);
|
|
1732
|
+
for (const kf of remap.timeKfs) {
|
|
1733
|
+
for (const b of BAGS) {
|
|
1734
|
+
const bag = kf[b];
|
|
1735
|
+
const v = bag && Object.values(bag)[0];
|
|
1736
|
+
if (typeof v === "number") m = Math.max(m, v);
|
|
1737
|
+
}
|
|
1738
|
+
}
|
|
1739
|
+
return m;
|
|
1740
|
+
}
|
|
1741
|
+
function bindClock(timeline, clock, prop, remap, duration, at, scope) {
|
|
1742
|
+
if (remap.timeKfs.length) {
|
|
1743
|
+
if (remap.start !== void 0) timeline.set(clock, { [prop]: remap.start }, at);
|
|
1744
|
+
applyKeyframes(timeline, clock, remap.timeKfs, duration, scope, [], at);
|
|
1745
|
+
return;
|
|
1746
|
+
}
|
|
1747
|
+
const s = remap.speed ?? 1;
|
|
1748
|
+
const from = remap.start ?? (s < 0 ? -s * duration : 0);
|
|
1749
|
+
timeline.fromTo(clock, { [prop]: from }, { [prop]: from + s * duration, duration, ease: "none" }, at);
|
|
1750
|
+
}
|
|
1751
|
+
function clockTable(remap, prop, duration, at, scope, to) {
|
|
1752
|
+
const probe = gsap.timeline({ paused: true });
|
|
1753
|
+
const clock = { [prop]: remap.start ?? 0 };
|
|
1754
|
+
bindClock(probe, clock, prop, remap, duration, at, scope);
|
|
1755
|
+
probe.time(probe.duration());
|
|
1756
|
+
probe.time(0);
|
|
1757
|
+
const h = 1 / 1e3;
|
|
1758
|
+
const n = Math.max(2, Math.ceil(to / h) + 2);
|
|
1759
|
+
const tab = new Float64Array(n);
|
|
1760
|
+
let min = Infinity, max = -Infinity;
|
|
1761
|
+
for (let k = 0; k < n; k++) {
|
|
1762
|
+
probe.time(k * h);
|
|
1763
|
+
const v = clock[prop];
|
|
1764
|
+
tab[k] = v;
|
|
1765
|
+
const t = k * h;
|
|
1766
|
+
if (t >= at && t <= at + duration) {
|
|
1767
|
+
if (v < min) min = v;
|
|
1768
|
+
if (v > max) max = v;
|
|
1769
|
+
}
|
|
1770
|
+
}
|
|
1771
|
+
probe.kill();
|
|
1772
|
+
return {
|
|
1773
|
+
at(t) {
|
|
1774
|
+
const x = Math.min(Math.max(t / h, 0), n - 1.000001);
|
|
1775
|
+
const k = Math.floor(x), f = x - k;
|
|
1776
|
+
return tab[k] * (1 - f) + tab[k + 1] * f;
|
|
1777
|
+
},
|
|
1778
|
+
min: Number.isFinite(min) ? min : 0,
|
|
1779
|
+
max: Number.isFinite(max) ? max : 0
|
|
1780
|
+
};
|
|
1781
|
+
}
|
|
1561
1782
|
|
|
1562
1783
|
// src/space/math.ts
|
|
1563
1784
|
var DEG = Math.PI / 180;
|
|
@@ -2458,6 +2679,7 @@ var AudioSequence = class extends Sequence {
|
|
|
2458
2679
|
_audioBuffer = null;
|
|
2459
2680
|
_synth = null;
|
|
2460
2681
|
_source = "";
|
|
2682
|
+
_remap = null;
|
|
2461
2683
|
async build() {
|
|
2462
2684
|
this.target = null;
|
|
2463
2685
|
if (this.spec.music !== void 0) return this._buildMusic(this.spec);
|
|
@@ -2466,13 +2688,16 @@ var AudioSequence = class extends Sequence {
|
|
|
2466
2688
|
this._source = `asset "${spec.asset}"`;
|
|
2467
2689
|
const data = await Assets.get(spec.asset);
|
|
2468
2690
|
this._audioBuffer = data.audioBuffer;
|
|
2691
|
+
this._remap = remapOf(spec, "time", data.duration ?? null);
|
|
2692
|
+
const constant = this._remap && this._remap.timeKfs.length === 0 ? Math.abs(this._remap.speed ?? 1) : 1;
|
|
2469
2693
|
if (this.duration === void 0) {
|
|
2470
2694
|
const rest = Math.max(0, (this.parent?.duration ?? this.root.duration) - this.at);
|
|
2471
|
-
this.duration = spec.duration ?? (spec.loop ? rest : data.duration) ?? this.root.duration;
|
|
2695
|
+
this.duration = spec.duration ?? (spec.loop ? rest : data.duration !== void 0 ? data.duration / constant : void 0) ?? this.root.duration;
|
|
2472
2696
|
}
|
|
2473
|
-
|
|
2697
|
+
const playable = this._remap && this._remap.timeKfs.length > 0 ? Infinity : (data.duration ?? Infinity) / constant;
|
|
2698
|
+
if (!spec.loop && Number.isFinite(playable) && this.duration > playable + 0.05) {
|
|
2474
2699
|
console.warn(
|
|
2475
|
-
`pixi-effects: ${describeLayer(spec)}: audio asset "${spec.asset}"
|
|
2700
|
+
`pixi-effects: ${describeLayer(spec)}: audio asset "${spec.asset}" plays for ${playable.toFixed(1)}s (${data.duration.toFixed(1)}s at speed ${constant}) but the layer lasts ${this.duration.toFixed(1)}s, so it goes silent after ${playable.toFixed(1)}s. Add loop: true, or shorten the layer's duration.`
|
|
2476
2701
|
);
|
|
2477
2702
|
}
|
|
2478
2703
|
}
|
|
@@ -2481,7 +2706,7 @@ var AudioSequence = class extends Sequence {
|
|
|
2481
2706
|
const raw = spec;
|
|
2482
2707
|
if (raw.asset !== void 0) console.warn(`pixi-effects: ${who}: has both asset and sfx \u2014 the sfx plays; remove one`);
|
|
2483
2708
|
if (raw.loop) console.warn(`pixi-effects: ${who}: loop has no effect on an sfx \u2014 to repeat it, add one audio layer per hit (a JS loop)`);
|
|
2484
|
-
const { resolveSfx, renderSfx, sfxKey } = await import('./sfx-
|
|
2709
|
+
const { resolveSfx, renderSfx, sfxKey } = await import('./sfx-U3GM2MED.js');
|
|
2485
2710
|
const sfx = resolveSfx(spec.sfx, spec.duration, who);
|
|
2486
2711
|
if (!sfx) return;
|
|
2487
2712
|
this.duration = sfx.length;
|
|
@@ -2500,7 +2725,7 @@ var AudioSequence = class extends Sequence {
|
|
|
2500
2725
|
const raw = spec;
|
|
2501
2726
|
if (raw.asset !== void 0) console.warn(`pixi-effects: ${who}: has both asset and music \u2014 the music plays; remove one`);
|
|
2502
2727
|
if (raw.sfx !== void 0) console.warn(`pixi-effects: ${who}: has both sfx and music \u2014 the music plays; remove one`);
|
|
2503
|
-
const { resolveMusic, renderMusic, musicLength, musicKey } = await import('./music-
|
|
2728
|
+
const { resolveMusic, renderMusic, musicLength, musicKey } = await import('./music-CFEC7HKL.js');
|
|
2504
2729
|
const music = resolveMusic(spec.music, who);
|
|
2505
2730
|
if (!music) return;
|
|
2506
2731
|
const natural = musicLength(music);
|
|
@@ -2526,7 +2751,9 @@ var AudioSequence = class extends Sequence {
|
|
|
2526
2751
|
const initialVolume = this.spec.volume ?? this.spec.initial?.volume ?? 1;
|
|
2527
2752
|
const t0 = baseTime + this.at;
|
|
2528
2753
|
const dur = this.duration;
|
|
2754
|
+
const sourceMap = this._remap ? clockTable(this._remap, "time", dur, t0, this.scope(), t0 + dur).at : void 0;
|
|
2529
2755
|
out.push({
|
|
2756
|
+
...sourceMap ? { sourceMap } : {},
|
|
2530
2757
|
...this._audioBuffer ? { buffer: this._audioBuffer } : { synth: this._synth },
|
|
2531
2758
|
layer: describeLayer(this.spec),
|
|
2532
2759
|
source: this._source,
|
|
@@ -2585,7 +2812,7 @@ var FrameCache = class {
|
|
|
2585
2812
|
this.capacity = options.capacity ?? 30;
|
|
2586
2813
|
}
|
|
2587
2814
|
_key(time) {
|
|
2588
|
-
return Math.round(time *
|
|
2815
|
+
return Math.round(time * 1e6);
|
|
2589
2816
|
}
|
|
2590
2817
|
async getFrameAt(time) {
|
|
2591
2818
|
const key = this._key(time);
|
|
@@ -2650,6 +2877,15 @@ var FrameCache = class {
|
|
|
2650
2877
|
}
|
|
2651
2878
|
};
|
|
2652
2879
|
|
|
2880
|
+
// src/core/sourceTime.ts
|
|
2881
|
+
var FRAME_EPS = 5e-5;
|
|
2882
|
+
function sourceLookup(v, sourceDuration, loop) {
|
|
2883
|
+
if (!(sourceDuration > 0)) return Math.max(0, v);
|
|
2884
|
+
const w = v + FRAME_EPS;
|
|
2885
|
+
if (loop) return (w % sourceDuration + sourceDuration) % sourceDuration;
|
|
2886
|
+
return Math.min(Math.max(w, 0), sourceDuration);
|
|
2887
|
+
}
|
|
2888
|
+
|
|
2653
2889
|
// src/sequences/Video.ts
|
|
2654
2890
|
var VideoSequence = class extends Sequence {
|
|
2655
2891
|
_sourceDuration = 0;
|
|
@@ -2658,9 +2894,15 @@ var VideoSequence = class extends Sequence {
|
|
|
2658
2894
|
_canvas = null;
|
|
2659
2895
|
_ctx = null;
|
|
2660
2896
|
_drawSeq = 0;
|
|
2897
|
+
/** The playhead value (seconds in the file) the timeline last wrote: already remapped, and local inside a remapped composition. */
|
|
2898
|
+
_cur = 0;
|
|
2899
|
+
_remap = null;
|
|
2900
|
+
/** Movie asks this layer to draw the frame its own timeline is at, not the one for a time it computed. */
|
|
2901
|
+
selfTimed = true;
|
|
2661
2902
|
async build() {
|
|
2662
2903
|
const data = await Assets.get(this.spec.asset);
|
|
2663
2904
|
this._sourceDuration = data.duration;
|
|
2905
|
+
this._remap = remapOf(this.spec, "currentTime", this._sourceDuration);
|
|
2664
2906
|
this._audioBuffer = this.spec.audio !== false ? data.audioBuffer : null;
|
|
2665
2907
|
this._cache = new FrameCache(data.sink, { capacity: 30 });
|
|
2666
2908
|
const probeFrame = await this._cache.getFrameAt(0);
|
|
@@ -2679,7 +2921,8 @@ var VideoSequence = class extends Sequence {
|
|
|
2679
2921
|
this.intrinsicWidth = w;
|
|
2680
2922
|
this.intrinsicHeight = h;
|
|
2681
2923
|
if (this.duration === void 0) {
|
|
2682
|
-
this.
|
|
2924
|
+
const constant = this._remap && this._remap.timeKfs.length === 0 ? Math.abs(this._remap.speed ?? 1) : 1;
|
|
2925
|
+
this.duration = this.spec.duration ?? (data.duration ?? this.root.duration * constant) / constant;
|
|
2683
2926
|
}
|
|
2684
2927
|
let currentTime = 0;
|
|
2685
2928
|
const seq = this;
|
|
@@ -2689,8 +2932,9 @@ var VideoSequence = class extends Sequence {
|
|
|
2689
2932
|
},
|
|
2690
2933
|
set(v) {
|
|
2691
2934
|
currentTime = v;
|
|
2935
|
+
seq._cur = v;
|
|
2692
2936
|
const mySeq = ++seq._drawSeq;
|
|
2693
|
-
const lookup =
|
|
2937
|
+
const lookup = sourceLookup(v, seq._sourceDuration, !!seq.spec.loop);
|
|
2694
2938
|
seq._cache.getFrameAt(lookup).then((frame) => {
|
|
2695
2939
|
if (mySeq !== seq._drawSeq) return;
|
|
2696
2940
|
if (!frame || !seq._ctx) return;
|
|
@@ -2703,21 +2947,33 @@ var VideoSequence = class extends Sequence {
|
|
|
2703
2947
|
});
|
|
2704
2948
|
this.buildFilters();
|
|
2705
2949
|
}
|
|
2950
|
+
displayProps() {
|
|
2951
|
+
const r = this._remap;
|
|
2952
|
+
return r ? { initial: r.restInitial, keyframes: r.restKfs } : super.displayProps();
|
|
2953
|
+
}
|
|
2706
2954
|
bindTimeline(timeline, offset = 0) {
|
|
2707
2955
|
super.bindTimeline(timeline, offset);
|
|
2956
|
+
const at = offset + this.at;
|
|
2957
|
+
if (this._remap) {
|
|
2958
|
+
bindClock(timeline, this.target, "currentTime", this._remap, this.duration, at, this.scope());
|
|
2959
|
+
return;
|
|
2960
|
+
}
|
|
2708
2961
|
const playDuration = this.spec.loop ? this.duration : Math.min(this.duration, this._sourceDuration);
|
|
2709
2962
|
timeline.fromTo(
|
|
2710
2963
|
this.target,
|
|
2711
2964
|
{ currentTime: 0 },
|
|
2712
2965
|
{ currentTime: playDuration, duration: playDuration, ease: "none" },
|
|
2713
|
-
|
|
2966
|
+
at
|
|
2714
2967
|
// offset = start of the enclosing composition(s); dropping it misplaced videos inside nested compositions
|
|
2715
2968
|
);
|
|
2716
2969
|
}
|
|
2717
2970
|
collectAudio(out, baseTime) {
|
|
2718
2971
|
if (!this._audioBuffer) return;
|
|
2719
2972
|
const initialVolume = this.spec.volume ?? 1;
|
|
2973
|
+
const t0 = baseTime + this.at;
|
|
2974
|
+
const sourceMap = this._remap ? clockTable(this._remap, "currentTime", this.duration, t0, this.scope(), t0 + this.duration).at : void 0;
|
|
2720
2975
|
out.push({
|
|
2976
|
+
...sourceMap ? { sourceMap } : {},
|
|
2721
2977
|
buffer: this._audioBuffer,
|
|
2722
2978
|
layer: describeLayer(this.spec),
|
|
2723
2979
|
source: `video "${this.spec.asset}"`,
|
|
@@ -2728,9 +2984,12 @@ var VideoSequence = class extends Sequence {
|
|
|
2728
2984
|
volumeKeyframes: []
|
|
2729
2985
|
});
|
|
2730
2986
|
}
|
|
2731
|
-
|
|
2987
|
+
/** Draw the frame the playhead is at NOW (`_cur`). The argument (a time Movie worked out for layers that need it) is not used. */
|
|
2988
|
+
async awaitFrameAt(_time) {
|
|
2989
|
+
const time = this._cur;
|
|
2990
|
+
if (!this.keepHidden && !this.target?.renderable) return;
|
|
2732
2991
|
const mySeq = ++this._drawSeq;
|
|
2733
|
-
const lookup =
|
|
2992
|
+
const lookup = sourceLookup(time, this._sourceDuration, !!this.spec.loop);
|
|
2734
2993
|
let frame = null;
|
|
2735
2994
|
try {
|
|
2736
2995
|
frame = await this._cache.getFrameAt(lookup);
|
|
@@ -3460,7 +3719,7 @@ function numOrZero(v, scope) {
|
|
|
3460
3719
|
var _CompositionSequence = null;
|
|
3461
3720
|
async function getCompositionSequence() {
|
|
3462
3721
|
if (!_CompositionSequence) {
|
|
3463
|
-
_CompositionSequence = (await import('./Composition-
|
|
3722
|
+
_CompositionSequence = (await import('./Composition-6PA4C4TV.js')).CompositionSequence;
|
|
3464
3723
|
}
|
|
3465
3724
|
return _CompositionSequence;
|
|
3466
3725
|
}
|
|
@@ -3498,6 +3757,6 @@ async function buildSequenceTree(specs, parent, root) {
|
|
|
3498
3757
|
return out;
|
|
3499
3758
|
}
|
|
3500
3759
|
|
|
3501
|
-
export { CameraSequence, DEFAULT_FOV, DEG, NEAR, NullSequence, Sequence, buildScope, buildSequenceTree, cameraBasis, checkEase, collectPropKeys, describeLayer, ensureFilterLibrary, evaluateExpr, flattenSvgPath, homeCamera, homeDistance, lintKeys, lintText, lintTiming, noise, projectLayer, rand, random, registerSequenceType, resolveAt, summarizeWarnings };
|
|
3502
|
-
//# sourceMappingURL=chunk-
|
|
3503
|
-
//# sourceMappingURL=chunk-
|
|
3760
|
+
export { CameraSequence, DEFAULT_FOV, DEG, NEAR, NullSequence, Sequence, bindClock, buildScope, buildSequenceTree, cameraBasis, checkEase, clockTable, collectPropKeys, contentLength, describeLayer, ensureFilterLibrary, evaluateExpr, flattenSvgPath, homeCamera, homeDistance, lintKeys, lintText, lintTiming, noise, projectLayer, rand, random, registerSequenceType, remapOf, resolveAt, summarizeWarnings, timeRemapOf };
|
|
3761
|
+
//# sourceMappingURL=chunk-DQHXVNOI.js.map
|
|
3762
|
+
//# sourceMappingURL=chunk-DQHXVNOI.js.map
|