pixi-effects 0.35.0 → 0.37.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 +35 -0
- package/README.md +5 -5
- package/ai/chat-template.html +3 -3
- package/ai/tools/check.mjs +38 -9
- package/ai/tools/lookup.mjs +15 -2
- package/dist/{Base-pNq6sVGl.d.cts → Base-BlA6SeqJ.d.cts} +1 -1
- package/dist/{Base-CXsMdmJB.d.ts → Base-YqM0Ljvp.d.ts} +1 -1
- package/dist/Composition-5KZETM4J.js +7 -0
- package/dist/{Composition-NDXKQHB4.js.map → Composition-5KZETM4J.js.map} +1 -1
- package/dist/Composition-MHDI7UNZ.cjs +16 -0
- package/dist/{Composition-OLH7RC5Z.cjs.map → Composition-MHDI7UNZ.cjs.map} +1 -1
- package/dist/Controller.d.cts +2 -2
- package/dist/Controller.d.ts +2 -2
- package/dist/{Movie-VYtUN4TS.d.ts → Movie-CJN_gvLB.d.cts} +26 -2
- package/dist/{Movie-Db4QnMIH.d.cts → Movie-CfHaGmUP.d.ts} +26 -2
- package/dist/{Spans-QHHWC2PB.js → Spans-FSSO2HGX.js} +6 -6
- package/dist/{Spans-QHHWC2PB.js.map → Spans-FSSO2HGX.js.map} +1 -1
- package/dist/{Spans-QRMN2EZO.cjs → Spans-WVJH77BW.cjs} +11 -11
- package/dist/{Spans-QRMN2EZO.cjs.map → Spans-WVJH77BW.cjs.map} +1 -1
- package/dist/{blendModes-WIUCYIMC.cjs → blendModes-FD3THLNC.cjs} +5 -5
- package/dist/{blendModes-WIUCYIMC.cjs.map → blendModes-FD3THLNC.cjs.map} +1 -1
- package/dist/{blendModes-PP5NPBXY.js → blendModes-FMYO6SQN.js} +4 -4
- package/dist/{blendModes-PP5NPBXY.js.map → blendModes-FMYO6SQN.js.map} +1 -1
- package/dist/{chunk-ITDYFBB6.js → chunk-32MMNDDN.js} +7 -6
- package/dist/chunk-32MMNDDN.js.map +1 -0
- package/dist/{chunk-GL2AQFLQ.cjs → chunk-3SAS3ZE5.cjs} +7 -6
- package/dist/chunk-3SAS3ZE5.cjs.map +1 -0
- package/dist/{chunk-7TTCPHAV.cjs → chunk-E26M4NTL.cjs} +235 -49
- package/dist/chunk-E26M4NTL.cjs.map +1 -0
- package/dist/{chunk-XV4L72FW.js → chunk-IPQNT65V.js} +6 -6
- package/dist/chunk-IPQNT65V.js.map +1 -0
- package/dist/{chunk-IMQJVRMT.cjs → chunk-JN7JHNZR.cjs} +5 -5
- package/dist/{chunk-IMQJVRMT.cjs.map → chunk-JN7JHNZR.cjs.map} +1 -1
- package/dist/{chunk-2GNK6DPV.js → chunk-KNDEKWQO.js} +203 -18
- package/dist/chunk-KNDEKWQO.js.map +1 -0
- package/dist/{chunk-5IJENZOG.cjs → chunk-MJMOPWMK.cjs} +92 -92
- package/dist/chunk-MJMOPWMK.cjs.map +1 -0
- package/dist/{chunk-LEECUCTG.cjs → chunk-QHIOOK5S.cjs} +436 -29
- package/dist/chunk-QHIOOK5S.cjs.map +1 -0
- package/dist/{chunk-Y253JQOH.js → chunk-SBR75G73.js} +416 -11
- package/dist/chunk-SBR75G73.js.map +1 -0
- package/dist/{chunk-RTJD3ZSW.js → chunk-VNP7QCJE.js} +4 -4
- package/dist/{chunk-RTJD3ZSW.js.map → chunk-VNP7QCJE.js.map} +1 -1
- package/dist/index.cjs +41 -33
- package/dist/index.d.cts +47 -7
- package/dist/index.d.ts +47 -7
- package/dist/index.js +5 -5
- package/dist/loader.css +1 -1
- package/dist/present.cjs +5 -5
- package/dist/present.d.cts +2 -2
- package/dist/present.d.ts +2 -2
- package/dist/present.js +5 -5
- 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-CavnUvd5.d.cts → types-DvnXXm33.d.cts} +67 -3
- package/dist/{types-CavnUvd5.d.ts → types-DvnXXm33.d.ts} +67 -3
- package/docs/api.md +5 -4
- package/docs/dsl.md +42 -5
- package/llms-full.txt +305 -22
- package/package.json +1 -1
- package/skills/pixi-effects/SKILL.md +5 -4
- package/skills/pixi-effects/reference/cheatsheet.md +9 -6
- package/skills/pixi-effects/reference/pitfalls.md +7 -0
- package/skills/pixi-effects/reference/recipes.md +237 -3
- package/skills/pixi-effects/template.html +6 -6
- package/dist/Composition-NDXKQHB4.js +0 -7
- package/dist/Composition-OLH7RC5Z.cjs +0 -16
- package/dist/chunk-2GNK6DPV.js.map +0 -1
- package/dist/chunk-5IJENZOG.cjs.map +0 -1
- package/dist/chunk-7TTCPHAV.cjs.map +0 -1
- package/dist/chunk-GL2AQFLQ.cjs.map +0 -1
- package/dist/chunk-ITDYFBB6.js.map +0 -1
- package/dist/chunk-LEECUCTG.cjs.map +0 -1
- package/dist/chunk-XV4L72FW.js.map +0 -1
- package/dist/chunk-Y253JQOH.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunk3SAS3ZE5_cjs = require('./chunk-3SAS3ZE5.cjs');
|
|
4
4
|
var chunkTWZNOUM7_cjs = require('./chunk-TWZNOUM7.cjs');
|
|
5
5
|
var PIXI = require('pixi.js');
|
|
6
6
|
|
|
@@ -992,6 +992,17 @@ function noise(x, seed = 0) {
|
|
|
992
992
|
const u = f * f * f * (f * (f * 6 - 15) + 10);
|
|
993
993
|
return a + (b - a) * u;
|
|
994
994
|
}
|
|
995
|
+
function noise2(x, y, seed = 0) {
|
|
996
|
+
if (!Number.isFinite(x) || !Number.isFinite(y)) return 0;
|
|
997
|
+
const i = Math.floor(x), j = Math.floor(y);
|
|
998
|
+
const fx = x - i, fy = y - j;
|
|
999
|
+
const s = fold(seed) * 668265261;
|
|
1000
|
+
const corner = (a, b) => mix2(Math.imul((a | 0) + s, 2654435761) ^ Math.imul((b | 0) + 2135587861, 2246822507)) / 2147483648 - 1;
|
|
1001
|
+
const ux = fx * fx * fx * (fx * (fx * 6 - 15) + 10), uy = fy * fy * fy * (fy * (fy * 6 - 15) + 10);
|
|
1002
|
+
const top = corner(i, j) + (corner(i + 1, j) - corner(i, j)) * ux;
|
|
1003
|
+
const bottom = corner(i, j + 1) + (corner(i + 1, j + 1) - corner(i, j + 1)) * ux;
|
|
1004
|
+
return top + (bottom - top) * uy;
|
|
1005
|
+
}
|
|
995
1006
|
|
|
996
1007
|
// src/expr/Parser.ts
|
|
997
1008
|
var FUNCS = {
|
|
@@ -2347,6 +2358,11 @@ function createFilter(spec) {
|
|
|
2347
2358
|
return named;
|
|
2348
2359
|
}
|
|
2349
2360
|
const { type, name, ...given } = spec;
|
|
2361
|
+
const unset = Object.keys(given).filter((k) => given[k] === void 0);
|
|
2362
|
+
if (unset.length > 0) {
|
|
2363
|
+
console.warn(`pixi-effects: the "${type}" filter has ${unset.map((k) => `"${k}"`).join(", ")} set to undefined (a misspelt variable or a missing field?): the filter's default is used instead.`);
|
|
2364
|
+
for (const k of unset) delete given[k];
|
|
2365
|
+
}
|
|
2350
2366
|
const params = copyPlain(given);
|
|
2351
2367
|
const Cls = registry[type];
|
|
2352
2368
|
const inst = Cls ? new Cls(params) : createNamedFilter(type, params);
|
|
@@ -2862,7 +2878,37 @@ var TEXT_STYLE_DEFAULTS = {
|
|
|
2862
2878
|
};
|
|
2863
2879
|
|
|
2864
2880
|
// src/sequences/Text.ts
|
|
2865
|
-
|
|
2881
|
+
var TIME_PATTERNS = ["hh:mm:ss", "h:mm:ss", "hh:mm", "mm:ss", "m:ss"];
|
|
2882
|
+
function formatTime(v, pattern, warned2) {
|
|
2883
|
+
if (!TIME_PATTERNS.includes(pattern)) {
|
|
2884
|
+
if (!warned2.has(pattern)) {
|
|
2885
|
+
warned2.add(pattern);
|
|
2886
|
+
console.warn(`pixi-effects: format.time "${pattern}" is not one of ${TIME_PATTERNS.map((p) => `"${p}"`).join(", ")}: the value is printed as a number`);
|
|
2887
|
+
}
|
|
2888
|
+
return null;
|
|
2889
|
+
}
|
|
2890
|
+
const total = Math.floor(Math.abs(v));
|
|
2891
|
+
const h = Math.floor(total / 3600), m = Math.floor(total % 3600 / 60), sec = total % 60;
|
|
2892
|
+
const two = (n) => String(n).padStart(2, "0");
|
|
2893
|
+
const sign = v < 0 && total > 0 ? "-" : "";
|
|
2894
|
+
switch (pattern) {
|
|
2895
|
+
case "hh:mm:ss":
|
|
2896
|
+
return `${sign}${two(h)}:${two(m)}:${two(sec)}`;
|
|
2897
|
+
case "h:mm:ss":
|
|
2898
|
+
return `${sign}${h}:${two(m)}:${two(sec)}`;
|
|
2899
|
+
case "hh:mm":
|
|
2900
|
+
return `${sign}${two(h)}:${two(m)}`;
|
|
2901
|
+
case "mm:ss":
|
|
2902
|
+
return `${sign}${two(Math.floor(total / 60))}:${two(sec)}`;
|
|
2903
|
+
default:
|
|
2904
|
+
return `${sign}${Math.floor(total / 60)}:${two(sec)}`;
|
|
2905
|
+
}
|
|
2906
|
+
}
|
|
2907
|
+
function formatValue(v, f, warned2 = /* @__PURE__ */ new Set()) {
|
|
2908
|
+
if (f?.time !== void 0) {
|
|
2909
|
+
const t = formatTime(v, String(f.time), warned2);
|
|
2910
|
+
if (t !== null) return t;
|
|
2911
|
+
}
|
|
2866
2912
|
const fixed = v.toFixed(Math.max(0, Math.floor(f?.decimals ?? 0)));
|
|
2867
2913
|
const pad = Math.max(0, Math.floor(f?.pad ?? 0));
|
|
2868
2914
|
if (!f?.grouping && !pad) return fixed;
|
|
@@ -2881,6 +2927,8 @@ var TextSequence = class extends Sequence {
|
|
|
2881
2927
|
/** `visibleChars` is in play (initial or animated): otherwise the whole text shows. */
|
|
2882
2928
|
_typed = false;
|
|
2883
2929
|
_lastText = "";
|
|
2930
|
+
/** The `format.time` patterns already said to be wrong on this layer. */
|
|
2931
|
+
_timeWarned = /* @__PURE__ */ new Set();
|
|
2884
2932
|
/** A gradient fill for the text (`fillGradient`, static or animated): rebuilt as a FillGradient on each change (the text is re-rasterised). */
|
|
2885
2933
|
_grad = null;
|
|
2886
2934
|
_fillGradient = null;
|
|
@@ -2907,7 +2955,7 @@ var TextSequence = class extends Sequence {
|
|
|
2907
2955
|
}
|
|
2908
2956
|
/** Rewrite the displayed string from the template, the current `value` and `visibleChars`. */
|
|
2909
2957
|
_refreshText() {
|
|
2910
|
-
let next = this._template.includes("{value}") ? this._template.split("{value}").join(formatValue(this._counters.value, this.spec.format)) : this._template;
|
|
2958
|
+
let next = this._template.includes("{value}") ? this._template.split("{value}").join(formatValue(this._counters.value, this.spec.format, this._timeWarned)) : this._template;
|
|
2911
2959
|
if (this._typed) next = Array.from(next).slice(0, Math.max(0, Math.floor(this._counters.visibleChars))).join("");
|
|
2912
2960
|
if (next === this._lastText) return;
|
|
2913
2961
|
this._lastText = next;
|
|
@@ -2923,6 +2971,11 @@ var TextSequence = class extends Sequence {
|
|
|
2923
2971
|
label: this.spec.name
|
|
2924
2972
|
});
|
|
2925
2973
|
text.cullable = true;
|
|
2974
|
+
if (this.spec.resolution !== void 0) {
|
|
2975
|
+
const r = this.spec.resolution;
|
|
2976
|
+
if (typeof r === "number" && r >= 1 && r <= 8) text.resolution = r;
|
|
2977
|
+
else console.warn(`pixi-effects: ${chunk3SAS3ZE5_cjs.describeLayer(this.spec)}: resolution must be a number from 1 to 8 (the text is drawn at that many times the pixels), got ${JSON.stringify(r)}: ignored`);
|
|
2978
|
+
}
|
|
2926
2979
|
this.target = text;
|
|
2927
2980
|
this.intrinsicWidth = text.width;
|
|
2928
2981
|
this.intrinsicHeight = text.height;
|
|
@@ -2937,7 +2990,7 @@ var TextSequence = class extends Sequence {
|
|
|
2937
2990
|
{ skipKeys: STYLE_OPAQUE_KEYS }
|
|
2938
2991
|
);
|
|
2939
2992
|
const unset = Object.keys(resolved).filter((k) => resolved[k] === void 0);
|
|
2940
|
-
if (unset.length) console.warn(`pixi-effects: ${
|
|
2993
|
+
if (unset.length) console.warn(`pixi-effects: ${chunk3SAS3ZE5_cjs.describeLayer(this.spec)}: ${unset.map((k) => `style.${k}`).join(", ")} ${unset.length > 1 ? "are" : "is"} undefined (a variable that was never set?), so ${unset.length > 1 ? "they are" : "it is"} ignored and the default is used: omit the key instead`);
|
|
2941
2994
|
const outline = resolved.stroke;
|
|
2942
2995
|
if (outline && typeof outline === "object" && !("join" in outline) && !("lineJoin" in outline)) resolved.stroke = { ...outline, join: "round" };
|
|
2943
2996
|
for (const k of Object.keys(resolved)) {
|
|
@@ -2947,7 +3000,9 @@ var TextSequence = class extends Sequence {
|
|
|
2947
3000
|
this.intrinsicWidth = text.width;
|
|
2948
3001
|
this.intrinsicHeight = text.height;
|
|
2949
3002
|
}
|
|
2950
|
-
|
|
3003
|
+
const startFill = initialProps.fill;
|
|
3004
|
+
if (typeof startFill === "string" || typeof startFill === "number") text.style.fill = startFill;
|
|
3005
|
+
validateGradientKeyframes(this.spec, chunk3SAS3ZE5_cjs.describeLayer(this.spec), void 0, "text");
|
|
2951
3006
|
const gradientSpec = this.spec.fillGradient ?? initialProps.fillGradient;
|
|
2952
3007
|
if (gradientSpec) {
|
|
2953
3008
|
this._grad = { grad: gradStateFrom(gradientSpec) };
|
|
@@ -2983,7 +3038,7 @@ var TextSequence = class extends Sequence {
|
|
|
2983
3038
|
bindTextKeyframes(timeline, keyframes, this.duration, origin, () => this._template, (t) => {
|
|
2984
3039
|
this._template = t;
|
|
2985
3040
|
refresh();
|
|
2986
|
-
},
|
|
3041
|
+
}, chunk3SAS3ZE5_cjs.describeLayer(this.spec));
|
|
2987
3042
|
}
|
|
2988
3043
|
};
|
|
2989
3044
|
function runSuperWithStrippedSpec(inst, strippedSpec, timeline, offset) {
|
|
@@ -3433,7 +3488,7 @@ var CameraSequence = class extends Sequence {
|
|
|
3433
3488
|
carrier.fogColor = "#000000";
|
|
3434
3489
|
carrier.fogAmount = 1;
|
|
3435
3490
|
this.target = carrier;
|
|
3436
|
-
const keys =
|
|
3491
|
+
const keys = chunk3SAS3ZE5_cjs.collectPropKeys(this.spec);
|
|
3437
3492
|
this.autoZ = !keys.has("z");
|
|
3438
3493
|
this.dof = keys.has("focus") || keys.has("aperture");
|
|
3439
3494
|
this.fog = keys.has("fogNear") || keys.has("fogFar") || keys.has("fogColor") || keys.has("fogAmount");
|
|
@@ -3751,10 +3806,10 @@ function resolveSpansStyle(style, scope, who, warn = defaultWarn) {
|
|
|
3751
3806
|
}
|
|
3752
3807
|
return out;
|
|
3753
3808
|
}
|
|
3754
|
-
var TEXT_ONLY = ["type", "spans", "text", "style", "format", "colorSpace", "fillGradient", "initial", "keyframes"];
|
|
3809
|
+
var TEXT_ONLY = ["type", "spans", "text", "style", "format", "colorSpace", "fillGradient", "initial", "keyframes", "resolution"];
|
|
3755
3810
|
var NOT_FOR_A_GROUP = ["fill", "text", "value", "fillGradient"];
|
|
3756
3811
|
function expandSpans(spec, warn = defaultWarn, scope) {
|
|
3757
|
-
const who =
|
|
3812
|
+
const who = chunk3SAS3ZE5_cjs.describeLayer(spec);
|
|
3758
3813
|
const s = spec;
|
|
3759
3814
|
if (s.text !== void 0) warn(`pixi-effects: ${who}: "text" is ignored when the layer has spans: write the text as spans`);
|
|
3760
3815
|
const style = resolveSpansStyle(s.style ?? {}, scope, who, warn);
|
|
@@ -3796,7 +3851,9 @@ function expandSpans(spec, warn = defaultWarn, scope) {
|
|
|
3796
3851
|
name: `${baseName}.${i}`,
|
|
3797
3852
|
text: p.text,
|
|
3798
3853
|
style: { ...style, ...p.style },
|
|
3799
|
-
initial: { x: p.x, y: p.y, ...typed ? { visibleChars: p.length } : {} }
|
|
3854
|
+
initial: { x: p.x, y: p.y, ...typed ? { visibleChars: p.length } : {} },
|
|
3855
|
+
...s.resolution !== void 0 ? { resolution: s.resolution } : {}
|
|
3856
|
+
// the pieces are what is drawn
|
|
3800
3857
|
}));
|
|
3801
3858
|
const rest = {};
|
|
3802
3859
|
for (const [k, v] of Object.entries(s)) if (!TEXT_ONLY.includes(k)) rest[k] = v;
|
|
@@ -3804,9 +3861,15 @@ function expandSpans(spec, warn = defaultWarn, scope) {
|
|
|
3804
3861
|
spansMeta.set(group, { typed, pieces: drawn.map((p) => ({ start: p.start, length: p.length })), preview: layout.pieces.map((p, i) => (i > 0 && p.line !== layout.pieces[i - 1].line ? " " : "") + p.text).join("") });
|
|
3805
3862
|
return group;
|
|
3806
3863
|
}
|
|
3864
|
+
var ORIGINAL_SCALE_MODE = /* @__PURE__ */ new WeakMap();
|
|
3807
3865
|
var ImageSequence = class extends Sequence {
|
|
3808
3866
|
async build() {
|
|
3809
3867
|
const texture = await PIXI.Assets.get(this.spec.asset);
|
|
3868
|
+
const source = texture.source;
|
|
3869
|
+
if (source && !ORIGINAL_SCALE_MODE.has(source)) ORIGINAL_SCALE_MODE.set(source, source.scaleMode);
|
|
3870
|
+
const mode = this.spec.scaleMode;
|
|
3871
|
+
if (mode !== void 0 && mode !== "nearest" && mode !== "linear") console.warn(`pixi-effects: ${chunk3SAS3ZE5_cjs.describeLayer(this.spec)}: scaleMode "${String(mode)}" is not "nearest" or "linear": ignored`);
|
|
3872
|
+
if (source) source.scaleMode = mode === "nearest" || mode === "linear" ? mode : ORIGINAL_SCALE_MODE.get(source);
|
|
3810
3873
|
const sprite = new PIXI.Sprite({ texture, label: this.spec.name });
|
|
3811
3874
|
sprite.cullable = true;
|
|
3812
3875
|
this.target = sprite;
|
|
@@ -3914,12 +3977,12 @@ var AudioSequence = class extends Sequence {
|
|
|
3914
3977
|
const playable = this._remap && this._remap.timeKfs.length > 0 ? Infinity : (data.duration ?? Infinity) / constant;
|
|
3915
3978
|
if (!spec.loop && Number.isFinite(playable) && this.duration > playable + 0.05) {
|
|
3916
3979
|
console.warn(
|
|
3917
|
-
`pixi-effects: ${
|
|
3980
|
+
`pixi-effects: ${chunk3SAS3ZE5_cjs.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.`
|
|
3918
3981
|
);
|
|
3919
3982
|
}
|
|
3920
3983
|
}
|
|
3921
3984
|
async _buildSfx(spec) {
|
|
3922
|
-
const who =
|
|
3985
|
+
const who = chunk3SAS3ZE5_cjs.describeLayer(spec);
|
|
3923
3986
|
const raw = spec;
|
|
3924
3987
|
if (raw.asset !== void 0) console.warn(`pixi-effects: ${who}: has both asset and sfx \u2014 the sfx plays; remove one`);
|
|
3925
3988
|
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)`);
|
|
@@ -3938,7 +4001,7 @@ var AudioSequence = class extends Sequence {
|
|
|
3938
4001
|
});
|
|
3939
4002
|
}
|
|
3940
4003
|
async _buildMusic(spec) {
|
|
3941
|
-
const who =
|
|
4004
|
+
const who = chunk3SAS3ZE5_cjs.describeLayer(spec);
|
|
3942
4005
|
const raw = spec;
|
|
3943
4006
|
if (raw.asset !== void 0) console.warn(`pixi-effects: ${who}: has both asset and music \u2014 the music plays; remove one`);
|
|
3944
4007
|
if (raw.sfx !== void 0) console.warn(`pixi-effects: ${who}: has both sfx and music \u2014 the music plays; remove one`);
|
|
@@ -3973,7 +4036,7 @@ var AudioSequence = class extends Sequence {
|
|
|
3973
4036
|
out.push({
|
|
3974
4037
|
...sourceMap ? { sourceMap } : {},
|
|
3975
4038
|
...this._audioBuffer ? { buffer: this._audioBuffer } : { synth: this._synth },
|
|
3976
|
-
layer:
|
|
4039
|
+
layer: chunk3SAS3ZE5_cjs.describeLayer(this.spec),
|
|
3977
4040
|
source: this._source,
|
|
3978
4041
|
...this._music ? { music: this._music } : {},
|
|
3979
4042
|
loop: !this._synth && !!this.spec.loop,
|
|
@@ -4515,7 +4578,7 @@ var VideoSequence = class extends Sequence {
|
|
|
4515
4578
|
out.push({
|
|
4516
4579
|
...sourceMap ? { sourceMap } : {},
|
|
4517
4580
|
buffer: this._audioBuffer,
|
|
4518
|
-
layer:
|
|
4581
|
+
layer: chunk3SAS3ZE5_cjs.describeLayer(this.spec),
|
|
4519
4582
|
source: `video "${this.spec.asset}"`,
|
|
4520
4583
|
loop: !!this.spec.loop,
|
|
4521
4584
|
start: baseTime + this.at,
|
|
@@ -4663,6 +4726,21 @@ function slice(line, a, b) {
|
|
|
4663
4726
|
}
|
|
4664
4727
|
return out;
|
|
4665
4728
|
}
|
|
4729
|
+
function splitEvenOdd(d) {
|
|
4730
|
+
const parts = d.split(/(?=[Mm])/).map((x) => x.trim()).filter(Boolean);
|
|
4731
|
+
if (parts.length < 2) return { main: d.trim(), holes: [] };
|
|
4732
|
+
const area = (sub2) => flattenSvgPath(sub2).reduce((sum, line) => {
|
|
4733
|
+
let a = 0;
|
|
4734
|
+
for (let i = 0; i < line.pts.length; i += 2) {
|
|
4735
|
+
const j = (i + 2) % line.pts.length;
|
|
4736
|
+
a += line.pts[i] * line.pts[j + 1] - line.pts[j] * line.pts[i + 1];
|
|
4737
|
+
}
|
|
4738
|
+
return sum + Math.abs(a) / 2;
|
|
4739
|
+
}, 0);
|
|
4740
|
+
const areas = parts.map(area);
|
|
4741
|
+
const big = areas.indexOf(Math.max(...areas));
|
|
4742
|
+
return { main: parts[big], holes: parts.filter((_, i) => i !== big) };
|
|
4743
|
+
}
|
|
4666
4744
|
|
|
4667
4745
|
// src/sequences/morphPath.ts
|
|
4668
4746
|
function resample(line, n) {
|
|
@@ -4725,6 +4803,11 @@ function buildMorph(from, to, n = 128) {
|
|
|
4725
4803
|
for (let i = 0; i < count; i++) {
|
|
4726
4804
|
const fa = from[i], fb = to[i];
|
|
4727
4805
|
const closed = (fa?.closed ?? fb.closed) && (fb?.closed ?? fa.closed);
|
|
4806
|
+
if (fa && fb && fa.closed === fb.closed && fa.pts.length === fb.pts.length && fa.pts.length >= 6) {
|
|
4807
|
+
const a2 = [...fa.pts];
|
|
4808
|
+
pairs.push({ a: a2, b: closed ? align(a2, [...fb.pts]) : [...fb.pts], closed });
|
|
4809
|
+
continue;
|
|
4810
|
+
}
|
|
4728
4811
|
const a = fa ? resample({ pts: fa.pts, closed }, n) : collapsed(resample({ pts: fb.pts, closed }, n));
|
|
4729
4812
|
let b = fb ? resample({ pts: fb.pts, closed }, n) : collapsed(a);
|
|
4730
4813
|
if (closed && fa && fb) b = align(a, b);
|
|
@@ -4783,20 +4866,20 @@ var ShapeSequence = class extends Sequence {
|
|
|
4783
4866
|
for (const k of geomKeys) this._liveKeys.add(k);
|
|
4784
4867
|
seedGeometry(this._state, this.spec, scope);
|
|
4785
4868
|
seedStyle(this._state, this.spec.initial ?? {}, scope);
|
|
4786
|
-
seedStrokeStyle(this._state, this.spec, this.spec.initial ?? {},
|
|
4869
|
+
seedStrokeStyle(this._state, this.spec, this.spec.initial ?? {}, chunk3SAS3ZE5_cjs.describeLayer(this.spec));
|
|
4787
4870
|
if (this.spec.shape === "arc") {
|
|
4788
4871
|
this._state.startAngle ??= 0;
|
|
4789
4872
|
this._state.endAngle ??= 360;
|
|
4790
4873
|
const top = this.spec, ini = this.spec.initial ?? {};
|
|
4791
4874
|
if ("trimStart" in top || "trimEnd" in top || "trimStart" in ini || "trimEnd" in ini) {
|
|
4792
|
-
console.warn(`pixi-effects: ${
|
|
4875
|
+
console.warn(`pixi-effects: ${chunk3SAS3ZE5_cjs.describeLayer(this.spec)}: trimStart / trimEnd do not apply to an arc: animate its endAngle (and startAngle) instead`);
|
|
4793
4876
|
}
|
|
4794
4877
|
} else {
|
|
4795
4878
|
this._state.trimStart ??= 0;
|
|
4796
4879
|
this._state.trimEnd ??= 1;
|
|
4797
4880
|
}
|
|
4798
4881
|
const gradientSpec = this.spec.fillGradient ?? this.spec.initial?.fillGradient;
|
|
4799
|
-
validateGradientKeyframes(this.spec,
|
|
4882
|
+
validateGradientKeyframes(this.spec, chunk3SAS3ZE5_cjs.describeLayer(this.spec));
|
|
4800
4883
|
if (gradientSpec) {
|
|
4801
4884
|
if (hasGradientKeys(this.spec.keyframes)) {
|
|
4802
4885
|
this._grad = { grad: gradStateFrom(gradientSpec) };
|
|
@@ -4808,6 +4891,8 @@ var ShapeSequence = class extends Sequence {
|
|
|
4808
4891
|
const morph = this._setupMorph();
|
|
4809
4892
|
this._drawGeometry = makeDrawGeometry(this.spec, scope, this._state, morph);
|
|
4810
4893
|
this._outline = makeOutline(this.spec, scope, this._state, morph);
|
|
4894
|
+
const eo = this.spec.shape === "path" && this.spec.fillRule === "evenodd" && !morph ? splitEvenOdd(this.spec.d) : null;
|
|
4895
|
+
this._evenOdd = eo && eo.holes.length > 0 ? eo : null;
|
|
4811
4896
|
const { trimStart, trimEnd } = this._state;
|
|
4812
4897
|
this._state.trimStart = 0;
|
|
4813
4898
|
this._state.trimEnd = 1;
|
|
@@ -4838,9 +4923,9 @@ var ShapeSequence = class extends Sequence {
|
|
|
4838
4923
|
}
|
|
4839
4924
|
/** The prepared morph between `d` and `morphTo`, or null (and a warning when the spec asked for one that cannot work). */
|
|
4840
4925
|
_setupMorph() {
|
|
4841
|
-
const who =
|
|
4926
|
+
const who = chunk3SAS3ZE5_cjs.describeLayer(this.spec);
|
|
4842
4927
|
const top = this.spec;
|
|
4843
|
-
const wanted = this.spec.shape === "path" && (this._state.morph !== void 0 ||
|
|
4928
|
+
const wanted = this.spec.shape === "path" && (this._state.morph !== void 0 || chunk3SAS3ZE5_cjs.collectPropKeys(this.spec).has("morph"));
|
|
4844
4929
|
if (this.spec.shape !== "path") {
|
|
4845
4930
|
if ("morphTo" in top) console.warn(`pixi-effects: ${who}: morphTo only works on a path shape (shape: 'path'); ignored`);
|
|
4846
4931
|
return null;
|
|
@@ -4873,6 +4958,27 @@ var ShapeSequence = class extends Sequence {
|
|
|
4873
4958
|
_painter = null;
|
|
4874
4959
|
_gradDirty = false;
|
|
4875
4960
|
_outline = null;
|
|
4961
|
+
/** fillRule 'evenodd' on a path: the shape and the sub-paths cut out of it after it is filled (null: not used). */
|
|
4962
|
+
_evenOdd = null;
|
|
4963
|
+
/**
|
|
4964
|
+
* fillRule 'evenodd': the shape is filled, each hole is cut out of that fill, and the stroke goes round the shape and every hole. (PIXI's `cut()` only reaches the
|
|
4965
|
+
* LAST instruction, so it has to come between the fill and the stroke.)
|
|
4966
|
+
*/
|
|
4967
|
+
_fillWithHoles(g) {
|
|
4968
|
+
const s = this._state, { main, holes } = this._evenOdd;
|
|
4969
|
+
applyFill(g, s);
|
|
4970
|
+
for (const hole of holes) {
|
|
4971
|
+
g.beginPath();
|
|
4972
|
+
g.path(new PIXI.GraphicsPath(hole));
|
|
4973
|
+
g.cut();
|
|
4974
|
+
}
|
|
4975
|
+
if (s.strokeColor !== void 0 && s.strokeWidth > 0) {
|
|
4976
|
+
g.beginPath();
|
|
4977
|
+
g.path(new PIXI.GraphicsPath(main));
|
|
4978
|
+
for (const hole of holes) g.path(new PIXI.GraphicsPath(hole));
|
|
4979
|
+
applyStroke(g, s);
|
|
4980
|
+
}
|
|
4981
|
+
}
|
|
4876
4982
|
_redraw() {
|
|
4877
4983
|
const graphics = this.target;
|
|
4878
4984
|
const s = this._state;
|
|
@@ -4884,6 +4990,10 @@ var ShapeSequence = class extends Sequence {
|
|
|
4884
4990
|
const trimmed = (s.trimStart ?? 0) > 0 || (s.trimEnd ?? 1) < 1;
|
|
4885
4991
|
if (!trimmed || !this._outline || !(s.strokeColor !== void 0 && s.strokeWidth > 0)) {
|
|
4886
4992
|
this._drawGeometry(graphics);
|
|
4993
|
+
if (this._evenOdd) {
|
|
4994
|
+
this._fillWithHoles(graphics);
|
|
4995
|
+
return;
|
|
4996
|
+
}
|
|
4887
4997
|
applyState(graphics, s);
|
|
4888
4998
|
return;
|
|
4889
4999
|
}
|
|
@@ -5107,8 +5217,9 @@ function makePolygonDraw(spec, scope) {
|
|
|
5107
5217
|
};
|
|
5108
5218
|
}
|
|
5109
5219
|
function makePathDraw(spec) {
|
|
5220
|
+
const d = spec.fillRule === "evenodd" ? splitEvenOdd(spec.d).main : spec.d;
|
|
5110
5221
|
return (g) => {
|
|
5111
|
-
g.path(new PIXI.GraphicsPath(
|
|
5222
|
+
g.path(new PIXI.GraphicsPath(d));
|
|
5112
5223
|
};
|
|
5113
5224
|
}
|
|
5114
5225
|
var STATE_DRAWERS = {
|
|
@@ -5450,7 +5561,7 @@ var ShaderSequence = class extends Sequence {
|
|
|
5450
5561
|
}
|
|
5451
5562
|
async build() {
|
|
5452
5563
|
const spec = this.shaderSpec;
|
|
5453
|
-
const who =
|
|
5564
|
+
const who = chunk3SAS3ZE5_cjs.describeLayer(spec);
|
|
5454
5565
|
for (const m of shaderProblems(spec)) console.warn(`pixi-effects: ${who}: ${m}`);
|
|
5455
5566
|
if (this.duration === void 0) this.duration = this.parent?.duration ?? this.root.duration;
|
|
5456
5567
|
const scope = buildScope(this, this.parent, this.root);
|
|
@@ -5494,7 +5605,7 @@ var ShaderSequence = class extends Sequence {
|
|
|
5494
5605
|
const warn = (why) => {
|
|
5495
5606
|
if (this.warnedPaths.has(path)) return;
|
|
5496
5607
|
this.warnedPaths.add(path);
|
|
5497
|
-
console.warn(`pixi-effects: ${
|
|
5608
|
+
console.warn(`pixi-effects: ${chunk3SAS3ZE5_cjs.describeLayer(this.spec)}: keyframe path uniforms.${path} ${why}; skipped`);
|
|
5498
5609
|
};
|
|
5499
5610
|
if (slot === void 0) {
|
|
5500
5611
|
const guess = chunkTWZNOUM7_cjs.suggestName(name, Object.keys(this.carrier));
|
|
@@ -5529,7 +5640,7 @@ var ShaderSequence = class extends Sequence {
|
|
|
5529
5640
|
this.failed = true;
|
|
5530
5641
|
if (!this.warnedNoGl) {
|
|
5531
5642
|
this.warnedNoGl = true;
|
|
5532
|
-
console.warn(`pixi-effects: ${
|
|
5643
|
+
console.warn(`pixi-effects: ${chunk3SAS3ZE5_cjs.describeLayer(this.spec)}: this browser has no WebGL2, so the shader cannot run; the layer is drawn as a checkerboard`);
|
|
5533
5644
|
}
|
|
5534
5645
|
}
|
|
5535
5646
|
compile() {
|
|
@@ -5560,7 +5671,7 @@ var ShaderSequence = class extends Sequence {
|
|
|
5560
5671
|
gl.deleteProgram(p);
|
|
5561
5672
|
this.failed = true;
|
|
5562
5673
|
this.prog = null;
|
|
5563
|
-
console.warn(`pixi-effects: ${
|
|
5674
|
+
console.warn(`pixi-effects: ${chunk3SAS3ZE5_cjs.describeLayer(this.spec)}: the fragment shader did not compile (the line numbers are the lines of your code):
|
|
5564
5675
|
${glslErrors(log).join("\n")}
|
|
5565
5676
|
The layer is drawn as a checkerboard until it is fixed.`);
|
|
5566
5677
|
return;
|
|
@@ -5639,18 +5750,311 @@ function resolveDim(v, scope) {
|
|
|
5639
5750
|
if (typeof v === "number") return v;
|
|
5640
5751
|
return evaluateExpr(v, scope);
|
|
5641
5752
|
}
|
|
5753
|
+
var MAX_SIZE = 8192;
|
|
5754
|
+
var MIN_RESOLUTION = 0.25;
|
|
5755
|
+
var MAX_RESOLUTION = 4;
|
|
5756
|
+
var NOT_PURE = /\bMath\s*\.\s*random\s*\(|\bDate\s*\.\s*now\s*\(|\bperformance\s*\.\s*now\s*\(|\bnew\s+Date\s*\(/;
|
|
5757
|
+
function seeded(seed) {
|
|
5758
|
+
let a = seed >>> 0;
|
|
5759
|
+
return () => {
|
|
5760
|
+
a = a + 1831565813 >>> 0;
|
|
5761
|
+
let t = a;
|
|
5762
|
+
t = Math.imul(t ^ t >>> 15, t | 1);
|
|
5763
|
+
t ^= t + Math.imul(t ^ t >>> 7, t | 61);
|
|
5764
|
+
return ((t ^ t >>> 14) >>> 0) / 4294967296;
|
|
5765
|
+
};
|
|
5766
|
+
}
|
|
5767
|
+
function offscreen(width, height) {
|
|
5768
|
+
const c = document.createElement("canvas");
|
|
5769
|
+
c.width = Math.max(1, Math.round(width));
|
|
5770
|
+
c.height = Math.max(1, Math.round(height));
|
|
5771
|
+
c.getContext("2d", { willReadFrequently: true });
|
|
5772
|
+
return c;
|
|
5773
|
+
}
|
|
5774
|
+
var CanvasSequence = class extends Sequence {
|
|
5775
|
+
canvas = null;
|
|
5776
|
+
w = 1;
|
|
5777
|
+
h = 1;
|
|
5778
|
+
res = 1;
|
|
5779
|
+
fps = 30;
|
|
5780
|
+
layerW = 1;
|
|
5781
|
+
layerH = 1;
|
|
5782
|
+
seed = 0;
|
|
5783
|
+
smoothing = true;
|
|
5784
|
+
drawFn = null;
|
|
5785
|
+
state;
|
|
5786
|
+
/** The current value of every param: what keyframes move (`params.amount`). */
|
|
5787
|
+
carrier = {};
|
|
5788
|
+
failed = false;
|
|
5789
|
+
warnedDraw = false;
|
|
5790
|
+
warnedPaths = /* @__PURE__ */ new Set();
|
|
5791
|
+
lastKey = "";
|
|
5792
|
+
lastLocal = 0;
|
|
5793
|
+
get canvasSpec() {
|
|
5794
|
+
return this.spec;
|
|
5795
|
+
}
|
|
5796
|
+
pathRouters() {
|
|
5797
|
+
return { params: (path) => this.resolveParam(path) };
|
|
5798
|
+
}
|
|
5799
|
+
async build() {
|
|
5800
|
+
const spec = this.canvasSpec;
|
|
5801
|
+
const who = chunk3SAS3ZE5_cjs.describeLayer(spec);
|
|
5802
|
+
if (this.duration === void 0) this.duration = this.parent?.duration ?? this.root.duration;
|
|
5803
|
+
const scope = buildScope(this, this.parent, this.root);
|
|
5804
|
+
this.layerW = this.size("width", spec.width, scope, this.parent?.width ?? this.root.width, who);
|
|
5805
|
+
this.layerH = this.size("height", spec.height, scope, this.parent?.height ?? this.root.height, who);
|
|
5806
|
+
const r = spec.resolution;
|
|
5807
|
+
if (r === void 0) this.res = 1;
|
|
5808
|
+
else if (typeof r === "number" && Number.isFinite(r) && r >= MIN_RESOLUTION && r <= MAX_RESOLUTION) this.res = r;
|
|
5809
|
+
else {
|
|
5810
|
+
this.res = typeof r === "number" && Number.isFinite(r) ? Math.min(MAX_RESOLUTION, Math.max(MIN_RESOLUTION, r)) : 1;
|
|
5811
|
+
console.warn(`pixi-effects: ${who}: resolution must be a number from ${MIN_RESOLUTION} to ${MAX_RESOLUTION} (canvas pixels per layer pixel), got ${JSON.stringify(r)}: ${this.res} is used`);
|
|
5812
|
+
}
|
|
5813
|
+
const longest = Math.max(this.layerW, this.layerH);
|
|
5814
|
+
if (longest * this.res > MAX_SIZE) {
|
|
5815
|
+
const fitted = MAX_SIZE / longest;
|
|
5816
|
+
console.warn(`pixi-effects: ${who}: ${this.layerW}\xD7${this.layerH} at resolution ${this.res} would be a canvas of ${Math.round(longest * this.res)} pixels, more than ${MAX_SIZE}: resolution ${Math.round(fitted * 1e3) / 1e3} is used (lower the size or the resolution)`);
|
|
5817
|
+
this.res = fitted;
|
|
5818
|
+
}
|
|
5819
|
+
this.w = Math.max(1, Math.round(this.layerW * this.res));
|
|
5820
|
+
this.h = Math.max(1, Math.round(this.layerH * this.res));
|
|
5821
|
+
this.fps = this.root.frameRate ?? 30;
|
|
5822
|
+
this.seed = typeof spec.seed === "number" && Number.isFinite(spec.seed) ? Math.floor(spec.seed) : 0;
|
|
5823
|
+
this.smoothing = spec.smoothing !== false;
|
|
5824
|
+
const params = spec.params;
|
|
5825
|
+
if (params !== void 0) {
|
|
5826
|
+
if (params === null || typeof params !== "object" || Array.isArray(params)) {
|
|
5827
|
+
console.warn(`pixi-effects: ${who}: params must be an object of numbers, got ${JSON.stringify(params)}: ignored`);
|
|
5828
|
+
} else {
|
|
5829
|
+
const bad = [];
|
|
5830
|
+
for (const [k, v] of Object.entries(params)) {
|
|
5831
|
+
if (typeof v === "number" && Number.isFinite(v)) this.carrier[k] = v;
|
|
5832
|
+
else bad.push(`"${k}"`);
|
|
5833
|
+
}
|
|
5834
|
+
if (bad.length) console.warn(`pixi-effects: ${who}: params ${bad.join(", ")} ${bad.length > 1 ? "are" : "is"} not a number, so ${bad.length > 1 ? "they are" : "it is"} ignored (params holds numbers that keyframes can animate as 'params.<name>')`);
|
|
5835
|
+
}
|
|
5836
|
+
}
|
|
5837
|
+
if (typeof spec.draw === "function") {
|
|
5838
|
+
this.drawFn = spec.draw;
|
|
5839
|
+
if (NOT_PURE.test(spec.draw.toString())) {
|
|
5840
|
+
console.warn(`pixi-effects: ${who}: draw calls Math.random, Date.now, performance.now or new Date, so it is not deterministic: the same frame would draw differently in playback, in a seek and in an export. Use info.random() (seeded), or derive the value from t`);
|
|
5841
|
+
}
|
|
5842
|
+
} else {
|
|
5843
|
+
this.failed = true;
|
|
5844
|
+
console.warn(`pixi-effects: ${who}: a canvas layer needs draw: (ctx, t, info) => { \u2026 } (a function that draws the picture at time t); the layer is drawn as a checkerboard`);
|
|
5845
|
+
}
|
|
5846
|
+
this.canvas = document.createElement("canvas");
|
|
5847
|
+
this.canvas.width = this.w;
|
|
5848
|
+
this.canvas.height = this.h;
|
|
5849
|
+
const sprite = new PIXI.Sprite({ texture: PIXI.Texture.from(this.canvas), label: spec.name });
|
|
5850
|
+
if (!this.smoothing) sprite.texture.source.scaleMode = "nearest";
|
|
5851
|
+
sprite.width = this.layerW;
|
|
5852
|
+
sprite.height = this.layerH;
|
|
5853
|
+
this.target = sprite;
|
|
5854
|
+
this.intrinsicWidth = this.layerW;
|
|
5855
|
+
this.intrinsicHeight = this.layerH;
|
|
5856
|
+
this.buildFilters();
|
|
5857
|
+
if (typeof spec.setup === "function" && !this.failed) {
|
|
5858
|
+
try {
|
|
5859
|
+
this.state = await spec.setup(this.info(0));
|
|
5860
|
+
} catch (e) {
|
|
5861
|
+
this.failed = true;
|
|
5862
|
+
this.say(`setup failed: ${e instanceof Error ? e.message : String(e)}; the layer is drawn as a checkerboard`);
|
|
5863
|
+
}
|
|
5864
|
+
}
|
|
5865
|
+
this.drawAt(0);
|
|
5866
|
+
}
|
|
5867
|
+
async awaitFrameAt(local) {
|
|
5868
|
+
this.drawAt(Math.max(0, Math.min(local, this.duration ?? local)));
|
|
5869
|
+
}
|
|
5870
|
+
size(name, v, scope, fallback, who) {
|
|
5871
|
+
if (v === void 0) return fallback;
|
|
5872
|
+
const n = typeof v === "number" ? v : evaluateExpr(v, scope);
|
|
5873
|
+
if (!Number.isFinite(n) || n < 1) {
|
|
5874
|
+
console.warn(`pixi-effects: ${who}: ${name} must be a number of pixels of at least 1 (or an expression), got ${JSON.stringify(v)}: ${fallback} is used`);
|
|
5875
|
+
return fallback;
|
|
5876
|
+
}
|
|
5877
|
+
if (n > MAX_SIZE) {
|
|
5878
|
+
console.warn(`pixi-effects: ${who}: ${name} ${n} is more than ${MAX_SIZE}: ${MAX_SIZE} is used`);
|
|
5879
|
+
return MAX_SIZE;
|
|
5880
|
+
}
|
|
5881
|
+
return n;
|
|
5882
|
+
}
|
|
5883
|
+
say(why) {
|
|
5884
|
+
if (this.warnedDraw) return;
|
|
5885
|
+
this.warnedDraw = true;
|
|
5886
|
+
console.warn(`pixi-effects: ${chunk3SAS3ZE5_cjs.describeLayer(this.spec)}: ${why}`);
|
|
5887
|
+
}
|
|
5888
|
+
info(local) {
|
|
5889
|
+
const duration = this.duration ?? 0;
|
|
5890
|
+
const start = this.absoluteStart ?? this.at;
|
|
5891
|
+
return {
|
|
5892
|
+
frame: Math.round(local * this.fps),
|
|
5893
|
+
duration,
|
|
5894
|
+
progress: duration > 0 ? local / duration : 0,
|
|
5895
|
+
width: this.layerW,
|
|
5896
|
+
height: this.layerH,
|
|
5897
|
+
resolution: this.res,
|
|
5898
|
+
frameRate: this.fps,
|
|
5899
|
+
params: { ...this.carrier },
|
|
5900
|
+
state: this.state,
|
|
5901
|
+
random: seeded(this.seed),
|
|
5902
|
+
start,
|
|
5903
|
+
time: start + local,
|
|
5904
|
+
canvas: offscreen
|
|
5905
|
+
};
|
|
5906
|
+
}
|
|
5907
|
+
/** Resolve `params.amount` for the keyframe pipeline; a name nobody declared is said once and dropped. */
|
|
5908
|
+
resolveParam(path) {
|
|
5909
|
+
if (path in this.carrier && !path.includes(".")) return { target: this.carrier, prop: path };
|
|
5910
|
+
if (!this.warnedPaths.has(path)) {
|
|
5911
|
+
this.warnedPaths.add(path);
|
|
5912
|
+
const guess = chunkTWZNOUM7_cjs.suggestName(path.split(".")[0], Object.keys(this.carrier));
|
|
5913
|
+
console.warn(`pixi-effects: ${chunk3SAS3ZE5_cjs.describeLayer(this.spec)}: keyframe path params.${path} names no param "${path}"${guess ? `; did you mean "${guess}"?` : ""} (declare it in params with a starting value); skipped`);
|
|
5914
|
+
}
|
|
5915
|
+
return null;
|
|
5916
|
+
}
|
|
5917
|
+
drawAt(local) {
|
|
5918
|
+
const c = this.canvas;
|
|
5919
|
+
if (!c) return;
|
|
5920
|
+
const ctx = c.getContext("2d");
|
|
5921
|
+
if (!ctx) {
|
|
5922
|
+
this.say("this browser gave no 2D context for the layer's canvas, so nothing can be drawn");
|
|
5923
|
+
return;
|
|
5924
|
+
}
|
|
5925
|
+
const key = `${local}|${this.absoluteStart ?? this.at}|${JSON.stringify(this.carrier)}`;
|
|
5926
|
+
if (key === this.lastKey) return;
|
|
5927
|
+
this.lastKey = key;
|
|
5928
|
+
this.lastLocal = local;
|
|
5929
|
+
if (!this.paint(ctx, c, local)) this.lastKey = "";
|
|
5930
|
+
this.target?.texture.source.update();
|
|
5931
|
+
}
|
|
5932
|
+
/** Draws one frame of the layer into `ctx` (the layer's own canvas, or the scratch one of the determinism check). false: `draw` threw. */
|
|
5933
|
+
paint(ctx, c, local) {
|
|
5934
|
+
const hasReset = "reset" in ctx && typeof ctx.reset === "function";
|
|
5935
|
+
const fresh = () => {
|
|
5936
|
+
if (hasReset) ctx.reset();
|
|
5937
|
+
else {
|
|
5938
|
+
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
5939
|
+
ctx.clearRect(0, 0, c.width, c.height);
|
|
5940
|
+
}
|
|
5941
|
+
};
|
|
5942
|
+
fresh();
|
|
5943
|
+
if (this.failed || !this.drawFn) {
|
|
5944
|
+
this.checkerboard(ctx, c);
|
|
5945
|
+
return true;
|
|
5946
|
+
}
|
|
5947
|
+
if (!hasReset) ctx.save();
|
|
5948
|
+
let ok = true;
|
|
5949
|
+
try {
|
|
5950
|
+
ctx.scale(this.res, this.res);
|
|
5951
|
+
ctx.imageSmoothingEnabled = this.smoothing;
|
|
5952
|
+
this.drawFn(ctx, local, this.info(local));
|
|
5953
|
+
} catch (e) {
|
|
5954
|
+
if (!hasReset) {
|
|
5955
|
+
ctx.restore();
|
|
5956
|
+
ctx.save();
|
|
5957
|
+
}
|
|
5958
|
+
fresh();
|
|
5959
|
+
this.say(`draw threw at ${local.toFixed(2)} s: ${e instanceof Error ? e.message : String(e)}; that frame is drawn as a checkerboard (the other frames are tried again)`);
|
|
5960
|
+
this.checkerboard(ctx, c);
|
|
5961
|
+
ok = false;
|
|
5962
|
+
}
|
|
5963
|
+
if (!hasReset) ctx.restore();
|
|
5964
|
+
return ok;
|
|
5965
|
+
}
|
|
5966
|
+
/**
|
|
5967
|
+
* Draws each of `times` in two orders and returns the moments where the pictures differ (a draw that uses Math.random, the clock or state that outlives the call), with how much
|
|
5968
|
+
* (channel values that differ, the largest difference out of 255), and how long a draw took. One draw of every moment comes first and is thrown away: a browser can draw a canvas
|
|
5969
|
+
* made in `setup` differently the first time it is used as a source, and a cache a draw fills on its first call is fine. The layer's own canvas is not touched (everything is drawn in a scratch canvas).
|
|
5970
|
+
* A layer that failed, or a draw that throws, is reported in `threw`.
|
|
5971
|
+
*/
|
|
5972
|
+
checkDeterminism(times) {
|
|
5973
|
+
const none = { differs: [], drawMs: 0, threw: [] };
|
|
5974
|
+
if (!this.canvas) return none;
|
|
5975
|
+
if (this.failed || !this.drawFn) return { ...none, threw: [...times] };
|
|
5976
|
+
const scratch = document.createElement("canvas");
|
|
5977
|
+
scratch.width = this.w;
|
|
5978
|
+
scratch.height = this.h;
|
|
5979
|
+
const ctx = scratch.getContext("2d", { willReadFrequently: true });
|
|
5980
|
+
if (!ctx) return none;
|
|
5981
|
+
const keep = this.w * this.h * 4 * times.length <= 96e6;
|
|
5982
|
+
const read2 = () => ctx.getImageData(0, 0, scratch.width, scratch.height).data;
|
|
5983
|
+
const hash = (d) => {
|
|
5984
|
+
let h = 2166136261;
|
|
5985
|
+
for (let i = 0; i < d.length; i++) {
|
|
5986
|
+
h ^= d[i];
|
|
5987
|
+
h = Math.imul(h, 16777619);
|
|
5988
|
+
}
|
|
5989
|
+
return h >>> 0;
|
|
5990
|
+
};
|
|
5991
|
+
const ms = [];
|
|
5992
|
+
const threw = /* @__PURE__ */ new Set();
|
|
5993
|
+
const once = (t, timed) => {
|
|
5994
|
+
const from = performance.now();
|
|
5995
|
+
if (!this.paint(ctx, scratch, t)) threw.add(t);
|
|
5996
|
+
if (timed) {
|
|
5997
|
+
ctx.getImageData(0, 0, 1, 1);
|
|
5998
|
+
ms.push(performance.now() - from);
|
|
5999
|
+
}
|
|
6000
|
+
return read2();
|
|
6001
|
+
};
|
|
6002
|
+
for (const t of times) once(t, false);
|
|
6003
|
+
const first = times.map((t) => {
|
|
6004
|
+
const d = once(t, true);
|
|
6005
|
+
return keep ? d.slice() : hash(d);
|
|
6006
|
+
});
|
|
6007
|
+
const second = [...times].reverse().map((t) => once(t, false)).reverse();
|
|
6008
|
+
scratch.width = scratch.height = 1;
|
|
6009
|
+
const differs = [];
|
|
6010
|
+
times.forEach((t, i) => {
|
|
6011
|
+
const a = first[i], b = second[i];
|
|
6012
|
+
if (typeof a === "number") {
|
|
6013
|
+
if (a !== hash(b)) differs.push({ t, pixels: -1, maxDiff: -1 });
|
|
6014
|
+
return;
|
|
6015
|
+
}
|
|
6016
|
+
let pixels = 0, maxDiff = 0;
|
|
6017
|
+
for (let k = 0; k < a.length; k++) {
|
|
6018
|
+
const d = Math.abs(a[k] - b[k]);
|
|
6019
|
+
if (d) {
|
|
6020
|
+
pixels++;
|
|
6021
|
+
if (d > maxDiff) maxDiff = d;
|
|
6022
|
+
}
|
|
6023
|
+
}
|
|
6024
|
+
if (pixels) differs.push({ t, pixels, maxDiff });
|
|
6025
|
+
});
|
|
6026
|
+
ms.sort((x, y) => x - y);
|
|
6027
|
+
return { differs: differs.filter((d) => !threw.has(d.t)), drawMs: ms.length ? ms[Math.floor(ms.length / 2)] : 0, threw: times.filter((t) => threw.has(t)) };
|
|
6028
|
+
}
|
|
6029
|
+
checkerboard(ctx, c) {
|
|
6030
|
+
const s = 32;
|
|
6031
|
+
for (let y = 0; y < c.height; y += s) for (let x = 0; x < c.width; x += s) {
|
|
6032
|
+
ctx.fillStyle = x / s + y / s & 1 ? "#ff00ff" : "#220022";
|
|
6033
|
+
ctx.fillRect(x, y, s, s);
|
|
6034
|
+
}
|
|
6035
|
+
}
|
|
6036
|
+
destroy() {
|
|
6037
|
+
const texture = this.target?.texture;
|
|
6038
|
+
if (this.canvas) {
|
|
6039
|
+
this.canvas.width = this.canvas.height = 1;
|
|
6040
|
+
this.canvas = null;
|
|
6041
|
+
}
|
|
6042
|
+
super.destroy();
|
|
6043
|
+
texture?.destroy(true);
|
|
6044
|
+
}
|
|
6045
|
+
};
|
|
5642
6046
|
|
|
5643
6047
|
// src/core/Composition.ts
|
|
5644
6048
|
var _CompositionSequence = null;
|
|
5645
6049
|
async function getCompositionSequence() {
|
|
5646
6050
|
if (!_CompositionSequence) {
|
|
5647
|
-
_CompositionSequence = (await import('./Composition-
|
|
6051
|
+
_CompositionSequence = (await import('./Composition-MHDI7UNZ.cjs')).CompositionSequence;
|
|
5648
6052
|
}
|
|
5649
6053
|
return _CompositionSequence;
|
|
5650
6054
|
}
|
|
5651
6055
|
var _SpansSequence = null;
|
|
5652
6056
|
async function getSpansSequence() {
|
|
5653
|
-
if (!_SpansSequence) _SpansSequence = (await import('./Spans-
|
|
6057
|
+
if (!_SpansSequence) _SpansSequence = (await import('./Spans-WVJH77BW.cjs')).SpansSequence;
|
|
5654
6058
|
return _SpansSequence;
|
|
5655
6059
|
}
|
|
5656
6060
|
var staticTypes = {
|
|
@@ -5662,6 +6066,7 @@ var staticTypes = {
|
|
|
5662
6066
|
camera: CameraSequence,
|
|
5663
6067
|
light: LightSequence,
|
|
5664
6068
|
shader: ShaderSequence,
|
|
6069
|
+
canvas: CanvasSequence,
|
|
5665
6070
|
null: NullSequence
|
|
5666
6071
|
};
|
|
5667
6072
|
var registry2 = {};
|
|
@@ -5734,6 +6139,7 @@ exports.layerToWorld = layerToWorld;
|
|
|
5734
6139
|
exports.lengthen = lengthen;
|
|
5735
6140
|
exports.lightLevel = lightLevel;
|
|
5736
6141
|
exports.noise = noise;
|
|
6142
|
+
exports.noise2 = noise2;
|
|
5737
6143
|
exports.packLights = packLights;
|
|
5738
6144
|
exports.parseEase = parseEase;
|
|
5739
6145
|
exports.parseSpring = parseSpring;
|
|
@@ -5748,5 +6154,6 @@ exports.resolveNumber = resolveNumber;
|
|
|
5748
6154
|
exports.spansMeta = spansMeta;
|
|
5749
6155
|
exports.springDuration = springDuration;
|
|
5750
6156
|
exports.timeRemapOf = timeRemapOf;
|
|
5751
|
-
|
|
5752
|
-
//# sourceMappingURL=chunk-
|
|
6157
|
+
exports.trimPolylines = trimPolylines;
|
|
6158
|
+
//# sourceMappingURL=chunk-QHIOOK5S.cjs.map
|
|
6159
|
+
//# sourceMappingURL=chunk-QHIOOK5S.cjs.map
|