pixi-effects 0.26.0 → 0.26.2
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 +20 -0
- package/README.md +6 -6
- package/ai/chat-template.html +3 -3
- package/ai/tools/check.mjs +12 -0
- package/dist/{Base-BgnRXbtJ.d.ts → Base-CpdDs4HT.d.ts} +1 -1
- package/dist/{Base-DHVKqA46.d.cts → Base-TbBhHPrG.d.cts} +1 -1
- package/dist/Composition-H4QA24MV.js +7 -0
- package/dist/{Composition-C4FSWJZF.js.map → Composition-H4QA24MV.js.map} +1 -1
- package/dist/Composition-HM4YT5L7.cjs +16 -0
- package/dist/{Composition-2GJSCHPP.cjs.map → Composition-HM4YT5L7.cjs.map} +1 -1
- package/dist/Controller.d.cts +2 -2
- package/dist/Controller.d.ts +2 -2
- package/dist/{Movie-DP5p1r4E.d.ts → Movie-DVeDTdnc.d.ts} +23 -2
- package/dist/{Movie-DXReF4-W.d.cts → Movie-i05Oh9mJ.d.cts} +23 -2
- package/dist/Presenter.d.cts +2 -2
- package/dist/Presenter.d.ts +2 -2
- package/dist/{chunk-SY27HZC5.cjs → chunk-555URQHQ.cjs} +59 -59
- package/dist/{chunk-SY27HZC5.cjs.map → chunk-555URQHQ.cjs.map} +1 -1
- package/dist/{chunk-XS6GSJCN.js → chunk-GBUM7X2S.js} +3 -3
- package/dist/{chunk-XS6GSJCN.js.map → chunk-GBUM7X2S.js.map} +1 -1
- package/dist/{chunk-DP37TTMO.cjs → chunk-WPXDRSGN.cjs} +164 -9
- package/dist/chunk-WPXDRSGN.cjs.map +1 -0
- package/dist/{chunk-PRZ4U6JN.js → chunk-X3HB4DSR.js} +164 -9
- package/dist/chunk-X3HB4DSR.js.map +1 -0
- package/dist/index.cjs +188 -34
- 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 +164 -10
- package/dist/index.js.map +1 -1
- package/dist/loader.css +35 -2
- package/dist/{music-AF4VTFAF.js → music-3O5MDQXY.js} +52 -6
- package/dist/music-3O5MDQXY.js.map +1 -0
- package/dist/{music-KB7YZLHP.cjs → music-4O367SPR.cjs} +52 -6
- package/dist/music-4O367SPR.cjs.map +1 -0
- package/dist/three.cjs +5 -5
- package/dist/three.d.cts +2 -2
- package/dist/three.d.ts +2 -2
- package/dist/three.js +1 -1
- package/dist/{types-CoT0ypcx.d.ts → types-DSGwN5w1.d.cts} +2 -0
- package/dist/{types-CoT0ypcx.d.cts → types-DSGwN5w1.d.ts} +2 -0
- package/docs/api.md +3 -2
- package/docs/dsl.md +2 -2
- package/llms-full.txt +8 -6
- package/package.json +1 -1
- package/skills/pixi-effects/SKILL.md +2 -2
- package/skills/pixi-effects/reference/cheatsheet.md +1 -1
- package/skills/pixi-effects/reference/pitfalls.md +1 -0
- package/skills/pixi-effects/template.html +6 -5
- package/dist/Composition-2GJSCHPP.cjs +0 -16
- package/dist/Composition-C4FSWJZF.js +0 -7
- package/dist/chunk-DP37TTMO.cjs.map +0 -1
- package/dist/chunk-PRZ4U6JN.js.map +0 -1
- package/dist/music-AF4VTFAF.js.map +0 -1
- package/dist/music-KB7YZLHP.cjs.map +0 -1
|
@@ -2965,7 +2965,7 @@ var AudioSequence = class extends Sequence {
|
|
|
2965
2965
|
const raw = spec;
|
|
2966
2966
|
if (raw.asset !== void 0) console.warn(`pixi-effects: ${who}: has both asset and music \u2014 the music plays; remove one`);
|
|
2967
2967
|
if (raw.sfx !== void 0) console.warn(`pixi-effects: ${who}: has both sfx and music \u2014 the music plays; remove one`);
|
|
2968
|
-
const { resolveMusic, renderMusic, musicLength, musicKey } = await import('./music-
|
|
2968
|
+
const { resolveMusic, renderMusic, musicLength, musicKey } = await import('./music-3O5MDQXY.js');
|
|
2969
2969
|
const music = resolveMusic(spec.music, who);
|
|
2970
2970
|
if (!music) return;
|
|
2971
2971
|
const natural = musicLength(music);
|
|
@@ -3042,19 +3042,41 @@ var AudioSequence = class extends Sequence {
|
|
|
3042
3042
|
};
|
|
3043
3043
|
|
|
3044
3044
|
// src/core/FrameCache.ts
|
|
3045
|
+
var BUDGET_BYTES = 96 * 1024 * 1024;
|
|
3046
|
+
var MIN_HELD = 3;
|
|
3047
|
+
var JUMP_SECONDS = 1;
|
|
3048
|
+
var EPS = 1e-6;
|
|
3049
|
+
function reportDecodeError(err, time) {
|
|
3050
|
+
const isTransient = err instanceof DOMException && (err.name === "EncodingError" || err.name === "NotSupportedError");
|
|
3051
|
+
if (isTransient) console.debug("pixi-effects: transient video decode failure at", time, "s \u2014", err.name);
|
|
3052
|
+
else console.warn("pixi-effects: video frame decode failed at", time, "s \u2014", err);
|
|
3053
|
+
}
|
|
3045
3054
|
var FrameCache = class {
|
|
3046
3055
|
sink;
|
|
3047
3056
|
capacity;
|
|
3048
3057
|
cache = /* @__PURE__ */ new Map();
|
|
3049
3058
|
_pending = /* @__PURE__ */ new Map();
|
|
3059
|
+
// Sequential mode (the sink has `samples()`): one decoder pass that runs forward as the movie asks for frame after frame.
|
|
3060
|
+
_frames = [];
|
|
3061
|
+
_cur = null;
|
|
3062
|
+
_iter = null;
|
|
3063
|
+
_next = null;
|
|
3064
|
+
_held = 0;
|
|
3065
|
+
_lock = Promise.resolve();
|
|
3066
|
+
_lastTime = null;
|
|
3050
3067
|
constructor(sink, options = {}) {
|
|
3051
3068
|
this.sink = sink;
|
|
3052
3069
|
this.capacity = options.capacity ?? 30;
|
|
3053
3070
|
}
|
|
3071
|
+
/** How many decoded frames are held right now (the sequential reader's own list, plus the exact-time cache of the old path). */
|
|
3072
|
+
get heldFrames() {
|
|
3073
|
+
return this._frames.length + this.cache.size;
|
|
3074
|
+
}
|
|
3054
3075
|
_key(time) {
|
|
3055
3076
|
return Math.round(time * 1e6);
|
|
3056
3077
|
}
|
|
3057
3078
|
async getFrameAt(time) {
|
|
3079
|
+
if (this.sink.samples) return this._enqueue(() => this._sequentialAt(time));
|
|
3058
3080
|
const key = this._key(time);
|
|
3059
3081
|
if (this.cache.has(key)) {
|
|
3060
3082
|
const v = this.cache.get(key);
|
|
@@ -3092,15 +3114,138 @@ var FrameCache = class {
|
|
|
3092
3114
|
sample.close?.();
|
|
3093
3115
|
return frame;
|
|
3094
3116
|
} catch (err) {
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3117
|
+
reportDecodeError(err, time);
|
|
3118
|
+
return null;
|
|
3119
|
+
}
|
|
3120
|
+
}
|
|
3121
|
+
// ── sequential mode ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────
|
|
3122
|
+
/** Requests are answered one at a time, in the order they arrive: one pass cannot serve two places at once. */
|
|
3123
|
+
_enqueue(fn) {
|
|
3124
|
+
const run = this._lock.then(fn, fn);
|
|
3125
|
+
this._lock = run.then(() => void 0, () => void 0);
|
|
3126
|
+
return run;
|
|
3127
|
+
}
|
|
3128
|
+
_covering(time) {
|
|
3129
|
+
for (const e of this._frames) {
|
|
3130
|
+
if (e.end === null ? e.req !== void 0 && Math.abs(e.req - time) < EPS : e.ts <= time + EPS && time < e.end - EPS) {
|
|
3131
|
+
this._frames.splice(this._frames.indexOf(e), 1);
|
|
3132
|
+
this._frames.push(e);
|
|
3133
|
+
return e;
|
|
3100
3134
|
}
|
|
3135
|
+
}
|
|
3136
|
+
return null;
|
|
3137
|
+
}
|
|
3138
|
+
async _sequentialAt(time) {
|
|
3139
|
+
try {
|
|
3140
|
+
const last = this._lastTime;
|
|
3141
|
+
this._lastTime = time;
|
|
3142
|
+
const hit = this._covering(time);
|
|
3143
|
+
if (hit) return hit.frame;
|
|
3144
|
+
if (last === null || Math.abs(time - last) > JUMP_SECONDS) return await this._single(time);
|
|
3145
|
+
const cur = this._cur;
|
|
3146
|
+
if (this._iter && cur && time >= cur.ts && time - cur.ts <= JUMP_SECONDS) return await this._advance(time);
|
|
3147
|
+
const backwards = !!cur && time < cur.ts;
|
|
3148
|
+
return await this._restart(time, backwards ? Math.max(0, time - this._held / 30) : time);
|
|
3149
|
+
} catch (err) {
|
|
3150
|
+
reportDecodeError(err, time);
|
|
3151
|
+
await this._closeIter();
|
|
3101
3152
|
return null;
|
|
3102
3153
|
}
|
|
3103
3154
|
}
|
|
3155
|
+
/** One frame by itself (a seek): getSample, kept so that asking again for the same time costs nothing. The running pass, if any, is closed: it no longer follows the playhead. */
|
|
3156
|
+
async _single(time) {
|
|
3157
|
+
await this._closeIter();
|
|
3158
|
+
this._cur = null;
|
|
3159
|
+
const sample = await this.sink.getSample(time);
|
|
3160
|
+
if (!sample) return null;
|
|
3161
|
+
const frame = sample.toVideoFrame();
|
|
3162
|
+
sample.close?.();
|
|
3163
|
+
this._keep({ ts: sample.timestamp, end: null, frame, req: time }, frame);
|
|
3164
|
+
return frame;
|
|
3165
|
+
}
|
|
3166
|
+
/** Start a pass at `time` (a seek and the frames of one group of pictures), keeping what is still held for a step back. */
|
|
3167
|
+
async _restart(time, from = time) {
|
|
3168
|
+
await this._closeIter();
|
|
3169
|
+
this._cur = null;
|
|
3170
|
+
const iter = this.sink.samples(from);
|
|
3171
|
+
this._iter = iter;
|
|
3172
|
+
const first = await iter.next();
|
|
3173
|
+
if (first.done) {
|
|
3174
|
+
await this._closeIter();
|
|
3175
|
+
return null;
|
|
3176
|
+
}
|
|
3177
|
+
if (first.value.timestamp > time + EPS) {
|
|
3178
|
+
first.value.close?.();
|
|
3179
|
+
await this._closeIter();
|
|
3180
|
+
return null;
|
|
3181
|
+
}
|
|
3182
|
+
this._take(first.value);
|
|
3183
|
+
return this._advance(time);
|
|
3184
|
+
}
|
|
3185
|
+
/** Run the pass forward until the frame that covers `time` is the current one; the next frame is read ahead (its start is where this one ends). */
|
|
3186
|
+
async _advance(time) {
|
|
3187
|
+
const cur = () => this._cur;
|
|
3188
|
+
for (; ; ) {
|
|
3189
|
+
if (!this._next) {
|
|
3190
|
+
let r;
|
|
3191
|
+
try {
|
|
3192
|
+
r = await this._iter.next();
|
|
3193
|
+
} catch (err) {
|
|
3194
|
+
reportDecodeError(err, time);
|
|
3195
|
+
await this._closeIter();
|
|
3196
|
+
const prev = this._frames.length > 1 ? this._frames[this._frames.length - 2] : null;
|
|
3197
|
+
const spacing = prev ? cur().ts - prev.ts : 1 / 24;
|
|
3198
|
+
return time < cur().ts + spacing - EPS ? cur().frame : null;
|
|
3199
|
+
}
|
|
3200
|
+
if (r.done) {
|
|
3201
|
+
cur().end = Infinity;
|
|
3202
|
+
this._iter = null;
|
|
3203
|
+
break;
|
|
3204
|
+
}
|
|
3205
|
+
this._next = r.value;
|
|
3206
|
+
}
|
|
3207
|
+
cur().end = this._next.timestamp;
|
|
3208
|
+
if (this._next.timestamp <= time + EPS) {
|
|
3209
|
+
const s = this._next;
|
|
3210
|
+
this._next = null;
|
|
3211
|
+
this._take(s);
|
|
3212
|
+
} else break;
|
|
3213
|
+
}
|
|
3214
|
+
return cur().frame;
|
|
3215
|
+
}
|
|
3216
|
+
_take(sample) {
|
|
3217
|
+
const frame = sample.toVideoFrame();
|
|
3218
|
+
sample.close?.();
|
|
3219
|
+
const entry = { ts: sample.timestamp, end: null, frame };
|
|
3220
|
+
this._keep(entry, frame);
|
|
3221
|
+
this._cur = entry;
|
|
3222
|
+
}
|
|
3223
|
+
/** Hold a frame (the first one sets how many fit: a byte budget, not a count) and close the oldest beyond that; the frame the pass stands on is never closed. */
|
|
3224
|
+
_keep(entry, frame) {
|
|
3225
|
+
if (this._held === 0) {
|
|
3226
|
+
const bytes = frame.allocationSize?.() ?? frame.displayWidth * frame.displayHeight * 1.5;
|
|
3227
|
+
this._held = Math.max(MIN_HELD, Math.min(this.capacity, Math.floor(BUDGET_BYTES / Math.max(1, bytes))));
|
|
3228
|
+
}
|
|
3229
|
+
this._frames.push(entry);
|
|
3230
|
+
while (this._frames.length > this._held) {
|
|
3231
|
+
const oldest = this._frames.find((e) => e !== this._cur && e !== entry);
|
|
3232
|
+
if (!oldest) break;
|
|
3233
|
+
this._frames.splice(this._frames.indexOf(oldest), 1);
|
|
3234
|
+
oldest.frame.close?.();
|
|
3235
|
+
}
|
|
3236
|
+
}
|
|
3237
|
+
async _closeIter() {
|
|
3238
|
+
const iter = this._iter;
|
|
3239
|
+
this._iter = null;
|
|
3240
|
+
this._next?.close?.();
|
|
3241
|
+
this._next = null;
|
|
3242
|
+
if (iter) {
|
|
3243
|
+
try {
|
|
3244
|
+
await iter.return?.(void 0);
|
|
3245
|
+
} catch {
|
|
3246
|
+
}
|
|
3247
|
+
}
|
|
3248
|
+
}
|
|
3104
3249
|
_evictIfNeeded() {
|
|
3105
3250
|
while (this.cache.size > this.capacity) {
|
|
3106
3251
|
const oldestKey = this.cache.keys().next().value;
|
|
@@ -3114,6 +3259,14 @@ var FrameCache = class {
|
|
|
3114
3259
|
for (const f of this.cache.values()) f?.close?.();
|
|
3115
3260
|
this.cache.clear();
|
|
3116
3261
|
this._pending.clear();
|
|
3262
|
+
for (const e of this._frames) e.frame.close?.();
|
|
3263
|
+
this._frames = [];
|
|
3264
|
+
this._cur = null;
|
|
3265
|
+
this._next?.close?.();
|
|
3266
|
+
this._next = null;
|
|
3267
|
+
const iter = this._iter;
|
|
3268
|
+
this._iter = null;
|
|
3269
|
+
void iter?.return?.(void 0);
|
|
3117
3270
|
}
|
|
3118
3271
|
};
|
|
3119
3272
|
|
|
@@ -4344,7 +4497,7 @@ function resolveDim(v, scope) {
|
|
|
4344
4497
|
var _CompositionSequence = null;
|
|
4345
4498
|
async function getCompositionSequence() {
|
|
4346
4499
|
if (!_CompositionSequence) {
|
|
4347
|
-
_CompositionSequence = (await import('./Composition-
|
|
4500
|
+
_CompositionSequence = (await import('./Composition-H4QA24MV.js')).CompositionSequence;
|
|
4348
4501
|
}
|
|
4349
4502
|
return _CompositionSequence;
|
|
4350
4503
|
}
|
|
@@ -4372,10 +4525,12 @@ async function buildSequenceTree(specs, parent, root) {
|
|
|
4372
4525
|
}
|
|
4373
4526
|
if (!Cls) {
|
|
4374
4527
|
console.warn(`pixi-effects: unknown sequence type "${spec.type}"`);
|
|
4528
|
+
await root.onLayerBuilt?.();
|
|
4375
4529
|
continue;
|
|
4376
4530
|
}
|
|
4377
4531
|
const seq = new Cls(spec, parent, root);
|
|
4378
4532
|
await seq.build();
|
|
4533
|
+
await root.onLayerBuilt?.();
|
|
4379
4534
|
if (seq.duration === void 0) {
|
|
4380
4535
|
seq.duration = parent?.duration ?? root.duration;
|
|
4381
4536
|
}
|
|
@@ -4385,5 +4540,5 @@ async function buildSequenceTree(specs, parent, root) {
|
|
|
4385
4540
|
}
|
|
4386
4541
|
|
|
4387
4542
|
export { CameraSequence, DEFAULT_FOV, DEG2 as DEG, FALLOFFS, LIGHT_KINDS, LIGHT_PROPS, LightSequence, MANY_BLURRED, MAX_BLUR, MAX_CASTERS, MAX_LIGHTS, MIN_BLUR, NEAR, NullSequence, SHADOW_TAPS, Sequence, bindClock, blurRadius, buildScope, buildSequenceTree, cameraBasis, checkEase, clockTable, contentLength, ensureFilterLibrary, evaluateExpr, flattenSvgPath, focusProblems, homeCamera, homeDistance, layerInitialZ, layerToWorld, lightLevel, noise, packLights, projectLayer, projectPoint, rand, random, registerSequenceType, remapOf, resolveAt, timeRemapOf };
|
|
4388
|
-
//# sourceMappingURL=chunk-
|
|
4389
|
-
//# sourceMappingURL=chunk-
|
|
4543
|
+
//# sourceMappingURL=chunk-X3HB4DSR.js.map
|
|
4544
|
+
//# sourceMappingURL=chunk-X3HB4DSR.js.map
|