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
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import { suggestName } from './chunk-DKGG7WD4.js';
|
|
2
|
+
import * as PIXI from 'pixi.js';
|
|
1
3
|
import { Rectangle, Container, Graphics, Assets, Texture, Sprite, Text, Filter, GlProgram, defaultFilterVert, GpuProgram, UniformGroup, FillGradient, Color, GraphicsPath } from 'pixi.js';
|
|
2
4
|
import { gsap } from 'gsap';
|
|
3
5
|
|
|
4
|
-
// src/sequences/Base.ts
|
|
5
|
-
|
|
6
6
|
// src/expr/Parser.ts
|
|
7
7
|
var FUNCS = {
|
|
8
8
|
min: Math.min,
|
|
@@ -696,6 +696,124 @@ var ChromaKeyFilter = class extends Filter {
|
|
|
696
696
|
u[2] = rgb[2];
|
|
697
697
|
}
|
|
698
698
|
};
|
|
699
|
+
var CORE = { blur: "BlurFilter", noise: "NoiseFilter", alpha: "AlphaFilter" };
|
|
700
|
+
var CORE_TYPES = [...Object.keys(CORE), "colorMatrix"];
|
|
701
|
+
var LIBRARY_TYPES = [
|
|
702
|
+
"adjustment",
|
|
703
|
+
"advancedBloom",
|
|
704
|
+
"ascii",
|
|
705
|
+
"backdropBlur",
|
|
706
|
+
"bevel",
|
|
707
|
+
"bloom",
|
|
708
|
+
"bulgePinch",
|
|
709
|
+
"colorGradient",
|
|
710
|
+
"colorMap",
|
|
711
|
+
"colorOverlay",
|
|
712
|
+
"colorReplace",
|
|
713
|
+
"convolution",
|
|
714
|
+
"crossHatch",
|
|
715
|
+
"crt",
|
|
716
|
+
"dot",
|
|
717
|
+
"dropShadow",
|
|
718
|
+
"emboss",
|
|
719
|
+
"glitch",
|
|
720
|
+
"glow",
|
|
721
|
+
"godray",
|
|
722
|
+
"grayscale",
|
|
723
|
+
"hslAdjustment",
|
|
724
|
+
"kawaseBlur",
|
|
725
|
+
"motionBlur",
|
|
726
|
+
"multiColorReplace",
|
|
727
|
+
"oldFilm",
|
|
728
|
+
"outline",
|
|
729
|
+
"pixelate",
|
|
730
|
+
"radialBlur",
|
|
731
|
+
"reflection",
|
|
732
|
+
"rgbSplit",
|
|
733
|
+
"shockwave",
|
|
734
|
+
"simpleLightmap",
|
|
735
|
+
"simplexNoise",
|
|
736
|
+
"tiltShift",
|
|
737
|
+
"tiltShiftAxis",
|
|
738
|
+
"twist",
|
|
739
|
+
"zoomBlur"
|
|
740
|
+
];
|
|
741
|
+
var FILTER_TYPES = [...CORE_TYPES, ...LIBRARY_TYPES];
|
|
742
|
+
var NOT_NAMED = /* @__PURE__ */ new Set(["custom", "chromaKey"]);
|
|
743
|
+
var lower = (s) => s.toLowerCase();
|
|
744
|
+
var isLibraryType = (t) => LIBRARY_TYPES.some((n) => lower(n) === lower(t));
|
|
745
|
+
var isCoreType = (t) => CORE_TYPES.some((n) => lower(n) === lower(t));
|
|
746
|
+
function isNamedFilterType(t) {
|
|
747
|
+
return !NOT_NAMED.has(t);
|
|
748
|
+
}
|
|
749
|
+
function unknownType(t) {
|
|
750
|
+
const guess = suggestName(t, FILTER_TYPES);
|
|
751
|
+
return new Error(`pixi-effects: unknown filter type "${t}"${guess ? ` \u2014 did you mean "${guess}"?` : ""} (valid: ${[...FILTER_TYPES, "chromaKey", "custom"].join(", ")})`);
|
|
752
|
+
}
|
|
753
|
+
var library = null;
|
|
754
|
+
function registerFilterLibrary(mod) {
|
|
755
|
+
library = /* @__PURE__ */ new Map();
|
|
756
|
+
for (const [key, value] of Object.entries(mod)) {
|
|
757
|
+
if (key.endsWith("Filter") && typeof value === "function") library.set(lower(key.slice(0, -"Filter".length)), value);
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
var MISSING = (type, why) => new Error(
|
|
761
|
+
`pixi-effects: the filter "${type}" comes from the pixi-filters package${why ? ` (${why})` : ""}. Add it to your import map ("pixi-filters": "https://esm.sh/pixi-filters@6.1.5?external=pixi.js") or run \`npm i pixi-filters\`.`
|
|
762
|
+
);
|
|
763
|
+
function needsFilterLibrary(spec) {
|
|
764
|
+
let needs = false;
|
|
765
|
+
const visit = (node) => {
|
|
766
|
+
if (!node || typeof node !== "object") return;
|
|
767
|
+
if (Array.isArray(node)) {
|
|
768
|
+
node.forEach(visit);
|
|
769
|
+
return;
|
|
770
|
+
}
|
|
771
|
+
const o = node;
|
|
772
|
+
if (Array.isArray(o.filters)) {
|
|
773
|
+
for (const f of o.filters) {
|
|
774
|
+
if (typeof f?.type !== "string" || !isNamedFilterType(f.type)) continue;
|
|
775
|
+
if (isLibraryType(f.type)) needs = true;
|
|
776
|
+
else if (!isCoreType(f.type)) throw unknownType(f.type);
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
for (const key of ["sequences", "mask"]) visit(o[key]);
|
|
780
|
+
};
|
|
781
|
+
visit(spec);
|
|
782
|
+
return needs;
|
|
783
|
+
}
|
|
784
|
+
async function ensureFilterLibrary(spec, load = () => import('pixi-filters')) {
|
|
785
|
+
if (!needsFilterLibrary(spec) || library) return;
|
|
786
|
+
try {
|
|
787
|
+
registerFilterLibrary(await load());
|
|
788
|
+
} catch (e) {
|
|
789
|
+
throw MISSING("(see the type in your filters)", e.message);
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
var SINGLE_VALUE = { pixelate: "size", emboss: "strength" };
|
|
793
|
+
var MATRIX_PRESETS = ["sepia", "grayscale", "negative", "polaroid", "technicolor", "vintage", "kodachrome", "browni"];
|
|
794
|
+
function colorMatrix(params) {
|
|
795
|
+
const f = new PIXI.ColorMatrixFilter();
|
|
796
|
+
const preset = params.preset;
|
|
797
|
+
if (preset !== void 0) {
|
|
798
|
+
if (!MATRIX_PRESETS.includes(preset)) {
|
|
799
|
+
const guess = suggestName(preset, MATRIX_PRESETS);
|
|
800
|
+
throw new Error(`pixi-effects: colorMatrix preset "${preset}" is not one of ${MATRIX_PRESETS.join(", ")}${guess ? ` \u2014 did you mean "${guess}"?` : ""}`);
|
|
801
|
+
}
|
|
802
|
+
f[preset === "grayscale" ? "desaturate" : preset].call(f);
|
|
803
|
+
}
|
|
804
|
+
if (Array.isArray(params.matrix)) f.matrix = params.matrix;
|
|
805
|
+
return f;
|
|
806
|
+
}
|
|
807
|
+
function createNamedFilter(type, params) {
|
|
808
|
+
if (lower(type) === "colormatrix") return colorMatrix(params);
|
|
809
|
+
const core = Object.entries(CORE).find(([k]) => lower(k) === lower(type));
|
|
810
|
+
if (core) return new PIXI[core[1]](params);
|
|
811
|
+
if (!isLibraryType(type)) throw unknownType(type);
|
|
812
|
+
const Ctor = library?.get(lower(type));
|
|
813
|
+
if (!Ctor) throw MISSING(type, library ? "not found in the loaded package" : "not loaded yet");
|
|
814
|
+
const single = SINGLE_VALUE[Object.keys(SINGLE_VALUE).find((k) => lower(k) === lower(type)) ?? ""];
|
|
815
|
+
return single ? new Ctor(params[single]) : new Ctor(params);
|
|
816
|
+
}
|
|
699
817
|
|
|
700
818
|
// src/filters/index.ts
|
|
701
819
|
var registry = {
|
|
@@ -714,10 +832,9 @@ function createFilter(spec) {
|
|
|
714
832
|
named._name = spec.name;
|
|
715
833
|
return named;
|
|
716
834
|
}
|
|
717
|
-
const
|
|
718
|
-
|
|
719
|
-
const
|
|
720
|
-
const inst = new Cls(params);
|
|
835
|
+
const { type, name, ...params } = spec;
|
|
836
|
+
const Cls = registry[type];
|
|
837
|
+
const inst = Cls ? new Cls(params) : createNamedFilter(type, params);
|
|
721
838
|
inst._name = name;
|
|
722
839
|
return inst;
|
|
723
840
|
}
|
|
@@ -859,10 +976,12 @@ function summarizeWarnings(messages, shown = 3) {
|
|
|
859
976
|
}
|
|
860
977
|
function lintText(spec, warn = defaultWarn) {
|
|
861
978
|
if (spec.type !== "text") return;
|
|
862
|
-
|
|
979
|
+
const strings = [spec.text ?? "", ...(spec.keyframes ?? []).map((kf) => String(kf.set?.text ?? ""))];
|
|
980
|
+
const hasPlaceholder = strings.some((t) => t.includes("{value}"));
|
|
981
|
+
if (hasPlaceholder && !collectPropKeys(spec).has("value")) {
|
|
863
982
|
warn(`pixi-effects: ${describeLayer(spec)}: the text has a {value} placeholder but nothing sets or animates \`value\`, so it prints 0. Set initial: { value: \u2026 } or animate it; {value} is reserved for counters (there is no way to print a literal "{value}").`);
|
|
864
983
|
}
|
|
865
|
-
if (collectPropKeys(spec).has("value") && !
|
|
984
|
+
if (collectPropKeys(spec).has("value") && !hasPlaceholder) {
|
|
866
985
|
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').`);
|
|
867
986
|
}
|
|
868
987
|
}
|
|
@@ -1331,14 +1450,21 @@ function formatValue(v, f) {
|
|
|
1331
1450
|
return sign + int + (frac !== void 0 ? "." + frac : "");
|
|
1332
1451
|
}
|
|
1333
1452
|
var TextSequence = class extends Sequence {
|
|
1334
|
-
/**
|
|
1335
|
-
|
|
1453
|
+
/** `value`: the number for the `{value}` placeholder; `visibleChars`: how many characters show (typewriter). Both tweened by keyframes. */
|
|
1454
|
+
_counters = { value: 0, visibleChars: 0 };
|
|
1455
|
+
/** The string now on the layer (before `{value}` / `visibleChars`): `text`, or the last `set: { text }`. */
|
|
1456
|
+
_template = "";
|
|
1457
|
+
/** `visibleChars` is in play (initial or animated): otherwise the whole text shows. */
|
|
1458
|
+
_typed = false;
|
|
1336
1459
|
_lastText = "";
|
|
1337
|
-
/**
|
|
1460
|
+
/** A typewriter that has typed nothing yet: the layer is empty on purpose (inspect must not call that "no size"). */
|
|
1461
|
+
get showsNothingYet() {
|
|
1462
|
+
return this._typed && this._lastText === "" && this._template !== "";
|
|
1463
|
+
}
|
|
1464
|
+
/** Rewrite the displayed string from the template, the current `value` and `visibleChars`. */
|
|
1338
1465
|
_refreshText() {
|
|
1339
|
-
|
|
1340
|
-
if (
|
|
1341
|
-
const next = template.split("{value}").join(formatValue(this._value.value, this.spec.format));
|
|
1466
|
+
let next = this._template.includes("{value}") ? this._template.split("{value}").join(formatValue(this._counters.value, this.spec.format)) : this._template;
|
|
1467
|
+
if (this._typed) next = Array.from(next).slice(0, Math.max(0, Math.floor(this._counters.visibleChars))).join("");
|
|
1342
1468
|
if (next === this._lastText) return;
|
|
1343
1469
|
this._lastText = next;
|
|
1344
1470
|
this.target.text = next;
|
|
@@ -1350,8 +1476,10 @@ var TextSequence = class extends Sequence {
|
|
|
1350
1476
|
fill: "#ffffff",
|
|
1351
1477
|
align: "center"
|
|
1352
1478
|
};
|
|
1479
|
+
const initialProps = this.spec.initial ?? {};
|
|
1480
|
+
this._template = String(initialProps.text ?? this.spec.text ?? "");
|
|
1353
1481
|
const text = new Text({
|
|
1354
|
-
text: this.
|
|
1482
|
+
text: this._template,
|
|
1355
1483
|
style: baseStyle,
|
|
1356
1484
|
label: this.spec.name
|
|
1357
1485
|
});
|
|
@@ -1363,10 +1491,10 @@ var TextSequence = class extends Sequence {
|
|
|
1363
1491
|
this.duration = this.parent?.duration ?? this.root.duration;
|
|
1364
1492
|
}
|
|
1365
1493
|
if (this.spec.style) {
|
|
1366
|
-
const
|
|
1494
|
+
const scope2 = this.scope();
|
|
1367
1495
|
const resolved = normalizeProps(
|
|
1368
1496
|
this.spec.style,
|
|
1369
|
-
|
|
1497
|
+
scope2,
|
|
1370
1498
|
{ skipKeys: STYLE_OPAQUE_KEYS }
|
|
1371
1499
|
);
|
|
1372
1500
|
for (const k of Object.keys(resolved)) {
|
|
@@ -1375,22 +1503,36 @@ var TextSequence = class extends Sequence {
|
|
|
1375
1503
|
this.intrinsicWidth = text.width;
|
|
1376
1504
|
this.intrinsicHeight = text.height;
|
|
1377
1505
|
}
|
|
1378
|
-
const
|
|
1379
|
-
if (
|
|
1506
|
+
const scope = this.scope();
|
|
1507
|
+
if (initialProps.value !== void 0) this._counters.value = resolveNumber(initialProps.value, scope);
|
|
1508
|
+
this._typed = initialProps.visibleChars !== void 0 || animates(this.spec.keyframes, "visibleChars");
|
|
1509
|
+
if (initialProps.visibleChars !== void 0) this._counters.visibleChars = resolveNumber(initialProps.visibleChars, scope);
|
|
1510
|
+
const typed = this._typed;
|
|
1511
|
+
this._typed = false;
|
|
1380
1512
|
this._refreshText();
|
|
1381
1513
|
if (this._lastText !== "") {
|
|
1382
1514
|
this.intrinsicWidth = text.width;
|
|
1383
1515
|
this.intrinsicHeight = text.height;
|
|
1384
1516
|
}
|
|
1517
|
+
this._typed = typed;
|
|
1518
|
+
this._refreshText();
|
|
1385
1519
|
this.buildFilters();
|
|
1386
1520
|
}
|
|
1387
1521
|
bindTimeline(timeline, offset = 0) {
|
|
1388
1522
|
if (!this.target) return;
|
|
1389
1523
|
const colorSpace = this.spec.colorSpace ?? "rgb";
|
|
1390
|
-
const stripped = stripKeys2(this.spec, ["fill", "value"]);
|
|
1524
|
+
const stripped = stripKeys2(this.spec, ["fill", "value", "text", "visibleChars"]);
|
|
1391
1525
|
runSuperWithStrippedSpec(this, stripped, timeline, offset);
|
|
1392
|
-
|
|
1393
|
-
|
|
1526
|
+
const keyframes = this.spec.keyframes ?? [];
|
|
1527
|
+
const origin = offset + this.at;
|
|
1528
|
+
bindFillKeyframes(timeline, this.target, keyframes, this.duration, origin, colorSpace);
|
|
1529
|
+
const refresh = () => this._refreshText();
|
|
1530
|
+
bindCounterKeyframes(timeline, this._counters, "value", refresh, keyframes, this.duration, origin, this.scope());
|
|
1531
|
+
bindCounterKeyframes(timeline, this._counters, "visibleChars", refresh, keyframes, this.duration, origin, this.scope());
|
|
1532
|
+
bindTextKeyframes(timeline, keyframes, this.duration, origin, () => this._template, (t) => {
|
|
1533
|
+
this._template = t;
|
|
1534
|
+
refresh();
|
|
1535
|
+
}, describeLayer(this.spec));
|
|
1394
1536
|
}
|
|
1395
1537
|
};
|
|
1396
1538
|
function runSuperWithStrippedSpec(inst, strippedSpec, timeline, offset) {
|
|
@@ -1426,11 +1568,11 @@ function resolveNumber(v, scope) {
|
|
|
1426
1568
|
const out = normalizeProps({ v }, scope).v;
|
|
1427
1569
|
return typeof out === "number" ? out : Number(out) || 0;
|
|
1428
1570
|
}
|
|
1429
|
-
function
|
|
1571
|
+
function bindCounterKeyframes(timeline, state, key, refresh, keyframes, parentDuration, origin, scope) {
|
|
1430
1572
|
for (const kf of keyframes) {
|
|
1431
|
-
const setV = kf.set?.
|
|
1432
|
-
const fromV = kf.from?.
|
|
1433
|
-
const toV = kf.to?.
|
|
1573
|
+
const setV = kf.set?.[key];
|
|
1574
|
+
const fromV = kf.from?.[key];
|
|
1575
|
+
const toV = kf.to?.[key];
|
|
1434
1576
|
if (setV === void 0 && fromV === void 0 && toV === void 0) continue;
|
|
1435
1577
|
const at = origin + resolveAt(kf.at, parentDuration);
|
|
1436
1578
|
const duration = kf.duration ?? 0;
|
|
@@ -1438,25 +1580,40 @@ function bindValueKeyframes(timeline, state, refresh, keyframes, parentDuration,
|
|
|
1438
1580
|
const loop = loopVars(kf);
|
|
1439
1581
|
if (setV !== void 0) {
|
|
1440
1582
|
const v = resolveNumber(setV, scope);
|
|
1441
|
-
revertibleSet(timeline, at, () => state
|
|
1442
|
-
state
|
|
1583
|
+
revertibleSet(timeline, at, () => state[key], (n) => {
|
|
1584
|
+
state[key] = n;
|
|
1443
1585
|
refresh();
|
|
1444
1586
|
}, v);
|
|
1445
1587
|
}
|
|
1446
1588
|
if (toV !== void 0 && fromV !== void 0) {
|
|
1447
1589
|
timeline.fromTo(
|
|
1448
1590
|
state,
|
|
1449
|
-
{
|
|
1450
|
-
{
|
|
1591
|
+
{ [key]: resolveNumber(fromV, scope) },
|
|
1592
|
+
{ [key]: resolveNumber(toV, scope), duration, ease, ...loop, onUpdate: refresh },
|
|
1451
1593
|
at
|
|
1452
1594
|
);
|
|
1453
1595
|
} else if (toV !== void 0) {
|
|
1454
|
-
timeline.to(state, {
|
|
1596
|
+
timeline.to(state, { [key]: resolveNumber(toV, scope), duration, ease, ...loop, onUpdate: refresh }, at);
|
|
1455
1597
|
} else if (fromV !== void 0) {
|
|
1456
|
-
timeline.from(state, {
|
|
1598
|
+
timeline.from(state, { [key]: resolveNumber(fromV, scope), duration, ease, ...loop, onUpdate: refresh }, at);
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
}
|
|
1602
|
+
function bindTextKeyframes(timeline, keyframes, parentDuration, origin, read, write, who) {
|
|
1603
|
+
for (const kf of keyframes) {
|
|
1604
|
+
for (const [what, props] of [["to", kf.to], ["from", kf.from]]) {
|
|
1605
|
+
if (props && props.text !== void 0) {
|
|
1606
|
+
console.warn(`pixi-effects: ${who}: a keyframe's ${what}: { text } cannot tween a string: use set: { text: '\u2026' } at the time it should change`);
|
|
1607
|
+
}
|
|
1457
1608
|
}
|
|
1609
|
+
const t = kf.set?.text;
|
|
1610
|
+
if (t === void 0) continue;
|
|
1611
|
+
revertibleSet(timeline, origin + resolveAt(kf.at, parentDuration), read, write, String(t));
|
|
1458
1612
|
}
|
|
1459
1613
|
}
|
|
1614
|
+
function animates(keyframes, key) {
|
|
1615
|
+
return (keyframes ?? []).some((kf) => [kf.set, kf.to, kf.from].some((p) => p && p[key] !== void 0));
|
|
1616
|
+
}
|
|
1460
1617
|
function bindFillKeyframes(timeline, text, keyframes, parentDuration, offset, colorSpace) {
|
|
1461
1618
|
const state = { fill: text.style.fill };
|
|
1462
1619
|
const writeFill = () => {
|
|
@@ -1820,18 +1977,105 @@ function makeGradientFill(g) {
|
|
|
1820
1977
|
}
|
|
1821
1978
|
return new FillGradient(gradientOptions(g));
|
|
1822
1979
|
}
|
|
1980
|
+
var CURVE_STEPS = 24;
|
|
1981
|
+
var ELLIPSE_STEPS = 128;
|
|
1982
|
+
function flattenSvgPath(d) {
|
|
1983
|
+
const prims = new GraphicsPath(d).shapePath.shapePrimitives;
|
|
1984
|
+
const out = [];
|
|
1985
|
+
for (const { shape } of prims) {
|
|
1986
|
+
const poly = shape;
|
|
1987
|
+
if (poly.points && poly.points.length >= 4) out.push({ pts: poly.points.slice(), closed: poly.closePath === true });
|
|
1988
|
+
}
|
|
1989
|
+
return out;
|
|
1990
|
+
}
|
|
1991
|
+
function rectOutline(x, y, w, h, radius) {
|
|
1992
|
+
const r = Math.max(0, Math.min(radius, Math.abs(w) / 2, Math.abs(h) / 2));
|
|
1993
|
+
if (r === 0) return { pts: [x, y, x + w, y, x + w, y + h, x, y + h], closed: true };
|
|
1994
|
+
const pts = [];
|
|
1995
|
+
const corner = (cx, cy, from) => {
|
|
1996
|
+
for (let i = 0; i <= CURVE_STEPS; i++) {
|
|
1997
|
+
const a = from + i / CURVE_STEPS * (Math.PI / 2);
|
|
1998
|
+
pts.push(cx + r * Math.cos(a), cy + r * Math.sin(a));
|
|
1999
|
+
}
|
|
2000
|
+
};
|
|
2001
|
+
corner(x + w - r, y + r, -Math.PI / 2);
|
|
2002
|
+
corner(x + w - r, y + h - r, 0);
|
|
2003
|
+
corner(x + r, y + h - r, Math.PI / 2);
|
|
2004
|
+
corner(x + r, y + r, Math.PI);
|
|
2005
|
+
const startAt = pts.length - 2;
|
|
2006
|
+
const rotated = pts.slice(startAt).concat(pts.slice(0, startAt));
|
|
2007
|
+
return { pts: rotated, closed: true };
|
|
2008
|
+
}
|
|
2009
|
+
function ellipseOutline(cx, cy, rx, ry) {
|
|
2010
|
+
const pts = [];
|
|
2011
|
+
for (let i = 0; i < ELLIPSE_STEPS; i++) {
|
|
2012
|
+
const a = -Math.PI / 2 + i / ELLIPSE_STEPS * Math.PI * 2;
|
|
2013
|
+
pts.push(cx + rx * Math.cos(a), cy + ry * Math.sin(a));
|
|
2014
|
+
}
|
|
2015
|
+
return { pts, closed: true };
|
|
2016
|
+
}
|
|
2017
|
+
function trimPolylines(lines, start, end) {
|
|
2018
|
+
const s = Math.max(0, Math.min(1, start)), e = Math.max(0, Math.min(1, end));
|
|
2019
|
+
if (!(e > s)) return [];
|
|
2020
|
+
const lengths = lines.map(polylineLength);
|
|
2021
|
+
const total = lengths.reduce((a, b) => a + b, 0);
|
|
2022
|
+
if (!(total > 0)) return [];
|
|
2023
|
+
const from = s * total, to = e * total;
|
|
2024
|
+
const out = [];
|
|
2025
|
+
let offset = 0;
|
|
2026
|
+
lines.forEach((line, i) => {
|
|
2027
|
+
const len = lengths[i];
|
|
2028
|
+
const a = Math.max(from - offset, 0), b = Math.min(to - offset, len);
|
|
2029
|
+
offset += len;
|
|
2030
|
+
if (!(b > a) || len === 0) return;
|
|
2031
|
+
if (line.closed && a <= 0 && b >= len) {
|
|
2032
|
+
out.push({ pts: line.pts.slice(), closed: true });
|
|
2033
|
+
return;
|
|
2034
|
+
}
|
|
2035
|
+
out.push({ pts: slice(line, a, b), closed: false });
|
|
2036
|
+
});
|
|
2037
|
+
return out;
|
|
2038
|
+
}
|
|
2039
|
+
function points(line) {
|
|
2040
|
+
return line.closed ? [...line.pts, line.pts[0], line.pts[1]] : line.pts;
|
|
2041
|
+
}
|
|
2042
|
+
function polylineLength(line) {
|
|
2043
|
+
const p = points(line);
|
|
2044
|
+
let len = 0;
|
|
2045
|
+
for (let i = 2; i < p.length; i += 2) len += Math.hypot(p[i] - p[i - 2], p[i + 1] - p[i - 1]);
|
|
2046
|
+
return len;
|
|
2047
|
+
}
|
|
2048
|
+
function slice(line, a, b) {
|
|
2049
|
+
const p = points(line);
|
|
2050
|
+
const out = [];
|
|
2051
|
+
let at = 0;
|
|
2052
|
+
for (let i = 2; i < p.length; i += 2) {
|
|
2053
|
+
const x0 = p[i - 2], y0 = p[i - 1], x1 = p[i], y1 = p[i + 1];
|
|
2054
|
+
const seg = Math.hypot(x1 - x0, y1 - y0);
|
|
2055
|
+
const segEnd = at + seg;
|
|
2056
|
+
if (segEnd > a && at < b && seg > 0) {
|
|
2057
|
+
const t0 = Math.max(a - at, 0) / seg, t1 = Math.min(b - at, seg) / seg;
|
|
2058
|
+
if (out.length === 0) out.push(x0 + (x1 - x0) * t0, y0 + (y1 - y0) * t0);
|
|
2059
|
+
out.push(x0 + (x1 - x0) * t1, y0 + (y1 - y0) * t1);
|
|
2060
|
+
}
|
|
2061
|
+
at = segEnd;
|
|
2062
|
+
if (at >= b) break;
|
|
2063
|
+
}
|
|
2064
|
+
return out;
|
|
2065
|
+
}
|
|
1823
2066
|
|
|
1824
2067
|
// src/sequences/Shape.ts
|
|
1825
2068
|
var STYLE_KEYS = ["fillColor", "fillAlpha", "strokeColor", "strokeAlpha", "strokeWidth"];
|
|
1826
2069
|
var COLOR_KEYS = /* @__PURE__ */ new Set(["fillColor", "strokeColor"]);
|
|
2070
|
+
var TRIM_KEYS = ["trimStart", "trimEnd"];
|
|
1827
2071
|
var GEOMETRY_KEYS_BY_SHAPE = {
|
|
1828
|
-
rect: ["width", "height", "cornerRadius", "anchorX", "anchorY"],
|
|
1829
|
-
circle: ["radius", "anchorX", "anchorY"],
|
|
1830
|
-
ellipse: ["radiusX", "radiusY", "anchorX", "anchorY"],
|
|
2072
|
+
rect: ["width", "height", "cornerRadius", "anchorX", "anchorY", ...TRIM_KEYS],
|
|
2073
|
+
circle: ["radius", "anchorX", "anchorY", ...TRIM_KEYS],
|
|
2074
|
+
ellipse: ["radiusX", "radiusY", "anchorX", "anchorY", ...TRIM_KEYS],
|
|
1831
2075
|
arc: ["radius", "innerRadius", "startAngle", "endAngle"],
|
|
1832
|
-
line: [],
|
|
1833
|
-
polygon: [],
|
|
1834
|
-
path: []
|
|
2076
|
+
line: [...TRIM_KEYS],
|
|
2077
|
+
polygon: [...TRIM_KEYS],
|
|
2078
|
+
path: [...TRIM_KEYS]
|
|
1835
2079
|
};
|
|
1836
2080
|
var ANCHORED_SHAPES = /* @__PURE__ */ new Set(["rect", "circle", "ellipse", "arc"]);
|
|
1837
2081
|
var ShapeSequence = class extends Sequence {
|
|
@@ -1864,13 +2108,26 @@ var ShapeSequence = class extends Sequence {
|
|
|
1864
2108
|
if (this.spec.shape === "arc") {
|
|
1865
2109
|
this._state.startAngle ??= 0;
|
|
1866
2110
|
this._state.endAngle ??= 360;
|
|
2111
|
+
const top = this.spec, ini = this.spec.initial ?? {};
|
|
2112
|
+
if ("trimStart" in top || "trimEnd" in top || "trimStart" in ini || "trimEnd" in ini) {
|
|
2113
|
+
console.warn(`pixi-effects: ${describeLayer(this.spec)}: trimStart / trimEnd do not apply to an arc: animate its endAngle (and startAngle) instead`);
|
|
2114
|
+
}
|
|
2115
|
+
} else {
|
|
2116
|
+
this._state.trimStart ??= 0;
|
|
2117
|
+
this._state.trimEnd ??= 1;
|
|
1867
2118
|
}
|
|
1868
2119
|
const gradientSpec = this.spec.fillGradient ?? this.spec.initial?.fillGradient;
|
|
1869
2120
|
if (gradientSpec) this._state.fillStyle = makeGradientFill(gradientSpec);
|
|
1870
2121
|
this._drawGeometry = makeDrawGeometry(this.spec, scope, this._state);
|
|
2122
|
+
this._outline = makeOutline(this.spec, scope, this._state);
|
|
2123
|
+
const { trimStart, trimEnd } = this._state;
|
|
2124
|
+
this._state.trimStart = 0;
|
|
2125
|
+
this._state.trimEnd = 1;
|
|
1871
2126
|
this._drawGeometry(graphics);
|
|
1872
2127
|
applyState(graphics, this._state);
|
|
1873
2128
|
const bounds = graphics.getLocalBounds();
|
|
2129
|
+
this._state.trimStart = trimStart;
|
|
2130
|
+
this._state.trimEnd = trimEnd;
|
|
1874
2131
|
this.intrinsicWidth = bounds.width;
|
|
1875
2132
|
this.intrinsicHeight = bounds.height;
|
|
1876
2133
|
if (!ANCHORED_SHAPES.has(this.spec.shape)) {
|
|
@@ -1888,14 +2145,37 @@ var ShapeSequence = class extends Sequence {
|
|
|
1888
2145
|
}
|
|
1889
2146
|
this._redraw();
|
|
1890
2147
|
};
|
|
2148
|
+
this._redraw();
|
|
1891
2149
|
this.buildFilters();
|
|
1892
2150
|
}
|
|
1893
2151
|
_fresh = false;
|
|
2152
|
+
_outline = null;
|
|
1894
2153
|
_redraw() {
|
|
1895
2154
|
const graphics = this.target;
|
|
2155
|
+
const s = this._state;
|
|
1896
2156
|
graphics.clear();
|
|
1897
|
-
|
|
1898
|
-
|
|
2157
|
+
const trimmed = (s.trimStart ?? 0) > 0 || (s.trimEnd ?? 1) < 1;
|
|
2158
|
+
if (!trimmed || !this._outline || !(s.strokeColor !== void 0 && s.strokeWidth > 0)) {
|
|
2159
|
+
this._drawGeometry(graphics);
|
|
2160
|
+
applyState(graphics, s);
|
|
2161
|
+
return;
|
|
2162
|
+
}
|
|
2163
|
+
if (s.fillStyle || s.fillColor !== void 0) {
|
|
2164
|
+
this._drawGeometry(graphics);
|
|
2165
|
+
applyFill(graphics, s);
|
|
2166
|
+
graphics.beginPath();
|
|
2167
|
+
}
|
|
2168
|
+
const parts = trimPolylines(this._outline(), s.trimStart ?? 0, s.trimEnd ?? 1);
|
|
2169
|
+
if (parts.length === 0) return;
|
|
2170
|
+
for (const part of parts) {
|
|
2171
|
+
if (part.closed) {
|
|
2172
|
+
graphics.poly(part.pts, true);
|
|
2173
|
+
continue;
|
|
2174
|
+
}
|
|
2175
|
+
graphics.moveTo(part.pts[0], part.pts[1]);
|
|
2176
|
+
for (let i = 2; i < part.pts.length; i += 2) graphics.lineTo(part.pts[i], part.pts[i + 1]);
|
|
2177
|
+
}
|
|
2178
|
+
applyStroke(graphics, s);
|
|
1899
2179
|
}
|
|
1900
2180
|
/**
|
|
1901
2181
|
* Draw from the tweened `_state` before the culler runs. The culler measures the geometry as last
|
|
@@ -1998,11 +2278,17 @@ function resolveLiveValue(key, value, scope) {
|
|
|
1998
2278
|
return numOrZero(value, scope);
|
|
1999
2279
|
}
|
|
2000
2280
|
function applyState(g, s) {
|
|
2281
|
+
applyFill(g, s);
|
|
2282
|
+
applyStroke(g, s);
|
|
2283
|
+
}
|
|
2284
|
+
function applyFill(g, s) {
|
|
2001
2285
|
if (s.fillStyle) {
|
|
2002
2286
|
g.fill(s.fillStyle);
|
|
2003
2287
|
} else if (s.fillColor !== void 0) {
|
|
2004
2288
|
g.fill({ color: s.fillColor, alpha: s.fillAlpha });
|
|
2005
2289
|
}
|
|
2290
|
+
}
|
|
2291
|
+
function applyStroke(g, s) {
|
|
2006
2292
|
if (s.strokeColor !== void 0 && s.strokeWidth > 0) {
|
|
2007
2293
|
g.stroke({
|
|
2008
2294
|
color: s.strokeColor,
|
|
@@ -2110,6 +2396,41 @@ function makeDrawGeometry(spec, scope, state) {
|
|
|
2110
2396
|
return () => {
|
|
2111
2397
|
};
|
|
2112
2398
|
}
|
|
2399
|
+
function makeOutline(spec, scope, s) {
|
|
2400
|
+
switch (spec.shape) {
|
|
2401
|
+
case "rect":
|
|
2402
|
+
return () => {
|
|
2403
|
+
const w = s.width ?? 0, h = s.height ?? 0;
|
|
2404
|
+
return [rectOutline(0 - (s.anchorX ?? 0.5) * w, 0 - (s.anchorY ?? 0.5) * h, w, h, s.cornerRadius ?? 0)];
|
|
2405
|
+
};
|
|
2406
|
+
case "circle":
|
|
2407
|
+
return () => {
|
|
2408
|
+
const r = s.radius ?? 0;
|
|
2409
|
+
return [ellipseOutline((0.5 - (s.anchorX ?? 0.5)) * 2 * r, (0.5 - (s.anchorY ?? 0.5)) * 2 * r, r, r)];
|
|
2410
|
+
};
|
|
2411
|
+
case "ellipse":
|
|
2412
|
+
return () => {
|
|
2413
|
+
const rx = s.radiusX ?? 0, ry = s.radiusY ?? 0;
|
|
2414
|
+
return [ellipseOutline((0.5 - (s.anchorX ?? 0.5)) * 2 * rx, (0.5 - (s.anchorY ?? 0.5)) * 2 * ry, rx, ry)];
|
|
2415
|
+
};
|
|
2416
|
+
case "line": {
|
|
2417
|
+
const lines = [{ pts: [num(spec.from[0], scope), num(spec.from[1], scope), num(spec.to[0], scope), num(spec.to[1], scope)], closed: false }];
|
|
2418
|
+
return () => lines;
|
|
2419
|
+
}
|
|
2420
|
+
case "polygon": {
|
|
2421
|
+
const pts = [];
|
|
2422
|
+
for (const [x, y] of spec.points) pts.push(num(x, scope), num(y, scope));
|
|
2423
|
+
const lines = pts.length >= 4 ? [{ pts, closed: !spec.open }] : [];
|
|
2424
|
+
return () => lines;
|
|
2425
|
+
}
|
|
2426
|
+
case "path": {
|
|
2427
|
+
let lines = null;
|
|
2428
|
+
return () => lines ??= flattenSvgPath(spec.d);
|
|
2429
|
+
}
|
|
2430
|
+
default:
|
|
2431
|
+
return null;
|
|
2432
|
+
}
|
|
2433
|
+
}
|
|
2113
2434
|
function bindLiveKeyframes(timeline, state, liveKeys, keyframes, parentDuration, scope, offset, colorSpace) {
|
|
2114
2435
|
for (const kf of keyframes) {
|
|
2115
2436
|
const at = offset + resolveAt(kf.at, parentDuration);
|
|
@@ -2183,7 +2504,7 @@ function numOrZero(v, scope) {
|
|
|
2183
2504
|
var _CompositionSequence = null;
|
|
2184
2505
|
async function getCompositionSequence() {
|
|
2185
2506
|
if (!_CompositionSequence) {
|
|
2186
|
-
_CompositionSequence = (await import('./Composition-
|
|
2507
|
+
_CompositionSequence = (await import('./Composition-DT657FO5.js')).CompositionSequence;
|
|
2187
2508
|
}
|
|
2188
2509
|
return _CompositionSequence;
|
|
2189
2510
|
}
|
|
@@ -2220,6 +2541,6 @@ async function buildSequenceTree(specs, parent, root) {
|
|
|
2220
2541
|
return out;
|
|
2221
2542
|
}
|
|
2222
2543
|
|
|
2223
|
-
export { CameraSequence, DEFAULT_FOV, DEG, NEAR, Sequence, buildScope, buildSequenceTree, cameraBasis, collectPropKeys, describeLayer, evaluateExpr, homeCamera, homeDistance, lintText, lintTiming, projectLayer, registerSequenceType, resolveAt, summarizeWarnings };
|
|
2224
|
-
//# sourceMappingURL=chunk-
|
|
2225
|
-
//# sourceMappingURL=chunk-
|
|
2544
|
+
export { CameraSequence, DEFAULT_FOV, DEG, NEAR, Sequence, buildScope, buildSequenceTree, cameraBasis, collectPropKeys, describeLayer, ensureFilterLibrary, evaluateExpr, homeCamera, homeDistance, lintText, lintTiming, projectLayer, registerSequenceType, resolveAt, summarizeWarnings };
|
|
2545
|
+
//# sourceMappingURL=chunk-4O2NYDJG.js.map
|
|
2546
|
+
//# sourceMappingURL=chunk-4O2NYDJG.js.map
|