pixi-effects 0.34.0 → 0.36.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 +27 -0
- package/README.md +5 -5
- package/ai/chat-template.html +3 -3
- package/ai/tools/check.mjs +26 -7
- package/ai/tools/lookup.mjs +14 -2
- package/dist/{Base-CXsMdmJB.d.ts → Base-CdF7AJop.d.ts} +1 -1
- package/dist/{Base-pNq6sVGl.d.cts → Base-CmiFiwQM.d.cts} +1 -1
- package/dist/Composition-BMRCE5FH.js +7 -0
- package/dist/{Composition-NDXKQHB4.js.map → Composition-BMRCE5FH.js.map} +1 -1
- package/dist/Composition-XRLYR6GL.cjs +16 -0
- package/dist/{Composition-OLH7RC5Z.cjs.map → Composition-XRLYR6GL.cjs.map} +1 -1
- package/dist/Controller.cjs +130 -1
- package/dist/Controller.cjs.map +1 -1
- package/dist/Controller.d.cts +24 -2
- package/dist/Controller.d.ts +24 -2
- package/dist/Controller.js +130 -1
- package/dist/Controller.js.map +1 -1
- package/dist/{Movie-f0tQG9y5.d.ts → Movie-Bh1HPdKw.d.cts} +30 -2
- package/dist/{Movie-CL6SsAWe.d.cts → Movie-D5WFfZdZ.d.ts} +30 -2
- package/dist/{Spans-QRMN2EZO.cjs → Spans-4IRBSOLI.cjs} +11 -11
- package/dist/{Spans-QRMN2EZO.cjs.map → Spans-4IRBSOLI.cjs.map} +1 -1
- package/dist/{Spans-QHHWC2PB.js → Spans-MWP2FX3T.js} +6 -6
- package/dist/{Spans-QHHWC2PB.js.map → Spans-MWP2FX3T.js.map} +1 -1
- package/dist/{blendModes-WIUCYIMC.cjs → blendModes-KU7XLV7U.cjs} +5 -5
- package/dist/{blendModes-WIUCYIMC.cjs.map → blendModes-KU7XLV7U.cjs.map} +1 -1
- package/dist/{blendModes-PP5NPBXY.js → blendModes-OOI3T6BE.js} +4 -4
- package/dist/{blendModes-PP5NPBXY.js.map → blendModes-OOI3T6BE.js.map} +1 -1
- package/dist/{chunk-ITDYFBB6.js → chunk-2JFFKHXO.js} +5 -5
- package/dist/chunk-2JFFKHXO.js.map +1 -0
- package/dist/{chunk-GL2AQFLQ.cjs → chunk-42ML5AKN.cjs} +5 -5
- package/dist/chunk-42ML5AKN.cjs.map +1 -0
- package/dist/{chunk-XV4L72FW.js → chunk-AZ6AINSW.js} +5 -5
- package/dist/{chunk-XV4L72FW.js.map → chunk-AZ6AINSW.js.map} +1 -1
- package/dist/{chunk-FVZEBYLW.cjs → chunk-CC7SUR7Q.cjs} +237 -54
- package/dist/chunk-CC7SUR7Q.cjs.map +1 -0
- package/dist/{chunk-Y253JQOH.js → chunk-G3DX65HO.js} +110 -10
- package/dist/chunk-G3DX65HO.js.map +1 -0
- package/dist/{chunk-LEECUCTG.cjs → chunk-KJSEQVBV.cjs} +129 -29
- package/dist/chunk-KJSEQVBV.cjs.map +1 -0
- package/dist/{chunk-IMQJVRMT.cjs → chunk-NEUPEENI.cjs} +5 -5
- package/dist/{chunk-IMQJVRMT.cjs.map → chunk-NEUPEENI.cjs.map} +1 -1
- package/dist/{chunk-67LG7MN5.js → chunk-VF56PRAA.js} +205 -22
- package/dist/chunk-VF56PRAA.js.map +1 -0
- package/dist/{chunk-RTJD3ZSW.js → chunk-WIIU42FH.js} +4 -4
- package/dist/{chunk-RTJD3ZSW.js.map → chunk-WIIU42FH.js.map} +1 -1
- package/dist/{chunk-5IJENZOG.cjs → chunk-Y5UWFH6Y.cjs} +91 -91
- package/dist/{chunk-5IJENZOG.cjs.map → chunk-Y5UWFH6Y.cjs.map} +1 -1
- package/dist/index.cjs +33 -33
- package/dist/index.d.cts +20 -6
- package/dist/index.d.ts +20 -6
- 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.ts → types-B6zDTU2V.d.cts} +14 -1
- package/dist/{types-CavnUvd5.d.cts → types-B6zDTU2V.d.ts} +14 -1
- package/docs/api.md +15 -4
- package/docs/dsl.md +7 -5
- package/llms-full.txt +95 -18
- package/package.json +1 -1
- package/skills/pixi-effects/SKILL.md +3 -3
- package/skills/pixi-effects/reference/cheatsheet.md +7 -6
- package/skills/pixi-effects/reference/pitfalls.md +3 -0
- package/skills/pixi-effects/reference/recipes.md +60 -0
- 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-67LG7MN5.js.map +0 -1
- package/dist/chunk-FVZEBYLW.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-Y253JQOH.js.map +0 -1
package/dist/Controller.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { l as Movie } from './Movie-
|
|
1
|
+
import { l as Movie } from './Movie-D5WFfZdZ.js';
|
|
2
2
|
import 'pixi.js';
|
|
3
|
-
import './types-
|
|
3
|
+
import './types-B6zDTU2V.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* The look of the bar. Each key sets a CSS custom property on the bar (so you can also set `--mc-accent` … in your own CSS, on the
|
|
@@ -36,6 +36,12 @@ interface ControllerOptions {
|
|
|
36
36
|
pauseAtStops?: boolean;
|
|
37
37
|
/** The loop button (and the L key) next to the volume: it flips `movie.loop`, so playing goes back to the start at the end. Default true; `false` leaves the loop to the page. */
|
|
38
38
|
loopButton?: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* A small picture of the frame under the pointer, above the seek bar, with its time (like a video site). Default false. It is made with `movie.thumbnail()` without
|
|
41
|
+
* moving the playhead or changing the picture, also while the movie plays. It switches itself off for a movie with video footage or variables (`movie.thumbnailsOff`
|
|
42
|
+
* says why), where a frame cannot be drawn on the side.
|
|
43
|
+
*/
|
|
44
|
+
thumbnails?: boolean;
|
|
39
45
|
className?: string;
|
|
40
46
|
}
|
|
41
47
|
interface ResolvedOptions {
|
|
@@ -46,6 +52,7 @@ interface ResolvedOptions {
|
|
|
46
52
|
presentButton: boolean;
|
|
47
53
|
pauseAtStops: boolean;
|
|
48
54
|
loopButton: boolean;
|
|
55
|
+
thumbnails: boolean;
|
|
49
56
|
className: string;
|
|
50
57
|
}
|
|
51
58
|
declare class Controller {
|
|
@@ -93,6 +100,17 @@ declare class Controller {
|
|
|
93
100
|
private onReady;
|
|
94
101
|
/** A rebuild (setVars, resize, rebuild) may have moved the stops: draw their marks again. */
|
|
95
102
|
private onRebuilt;
|
|
103
|
+
private previewEl;
|
|
104
|
+
private previewCanvas;
|
|
105
|
+
private previewTimeEl;
|
|
106
|
+
/** Pictures already made, by frame bucket (a frame is a pure function of time; cleared on a rebuild). */
|
|
107
|
+
private previewCache;
|
|
108
|
+
private previewWanted;
|
|
109
|
+
private previewRunning;
|
|
110
|
+
private previewRetry;
|
|
111
|
+
private previewRetries;
|
|
112
|
+
private previewCleanup;
|
|
113
|
+
private static readonly PREVIEW_WIDTH_PX;
|
|
96
114
|
private presenter;
|
|
97
115
|
/** `pixi-effects/present`, loaded as soon as the movie has stops (a press of play must not wait for it). */
|
|
98
116
|
private present;
|
|
@@ -165,6 +183,10 @@ declare class Controller {
|
|
|
165
183
|
private refreshProgress;
|
|
166
184
|
private refreshTime;
|
|
167
185
|
private bindScrubbing;
|
|
186
|
+
/** The hover preview above the seek bar (`thumbnails: true`). */
|
|
187
|
+
private bindPreview;
|
|
188
|
+
/** Draws the picture of the wanted frame into the preview; one at a time, and the last wish wins. */
|
|
189
|
+
private runPreview;
|
|
168
190
|
private seekFromPointer;
|
|
169
191
|
private bindExportPopover;
|
|
170
192
|
private toggleSettings;
|
package/dist/Controller.js
CHANGED
|
@@ -61,6 +61,19 @@ var CONTROLLER_CSS = `
|
|
|
61
61
|
.mc-progress:hover .mc-progress-thumb,
|
|
62
62
|
.mc-progress.mc-scrubbing .mc-progress-thumb { transform: translate(-50%, -50%) scale(1); }
|
|
63
63
|
|
|
64
|
+
.movie-controller > .mc-preview {
|
|
65
|
+
position: absolute; bottom: 74px; left: 0;
|
|
66
|
+
transform: translateX(-50%);
|
|
67
|
+
display: flex; flex-direction: column; align-items: center; gap: 4px;
|
|
68
|
+
padding: 3px; border-radius: 4px;
|
|
69
|
+
background: rgba(0,0,0,0.75);
|
|
70
|
+
pointer-events: none;
|
|
71
|
+
opacity: 0; transition: opacity 100ms ease;
|
|
72
|
+
}
|
|
73
|
+
.mc-preview[data-show="1"] { opacity: 1; }
|
|
74
|
+
.mc-preview canvas { display: block; width: 160px; height: auto; border-radius: 2px; }
|
|
75
|
+
.mc-preview-time { font-size: 12px; line-height: 1; color: var(--mc-fg, #fff); font-variant-numeric: tabular-nums; }
|
|
76
|
+
|
|
64
77
|
.mc-bar {
|
|
65
78
|
position: relative;
|
|
66
79
|
display: flex;
|
|
@@ -293,7 +306,7 @@ var THEME_PROPERTIES = {
|
|
|
293
306
|
trackHeight: "--mc-track-height",
|
|
294
307
|
font: "--mc-font"
|
|
295
308
|
};
|
|
296
|
-
var CONTROLLER_OPTION_KEYS = ["canvas", "theme", "exportButton", "keyboard", "clickToPlay", "presentButton", "pauseAtStops", "loopButton", "className"];
|
|
309
|
+
var CONTROLLER_OPTION_KEYS = ["canvas", "theme", "exportButton", "keyboard", "clickToPlay", "presentButton", "pauseAtStops", "loopButton", "thumbnails", "className"];
|
|
297
310
|
var Controller = class _Controller {
|
|
298
311
|
movie;
|
|
299
312
|
options;
|
|
@@ -339,6 +352,17 @@ var Controller = class _Controller {
|
|
|
339
352
|
onReady = null;
|
|
340
353
|
/** A rebuild (setVars, resize, rebuild) may have moved the stops: draw their marks again. */
|
|
341
354
|
onRebuilt = null;
|
|
355
|
+
previewEl = null;
|
|
356
|
+
previewCanvas = null;
|
|
357
|
+
previewTimeEl = null;
|
|
358
|
+
/** Pictures already made, by frame bucket (a frame is a pure function of time; cleared on a rebuild). */
|
|
359
|
+
previewCache = /* @__PURE__ */ new Map();
|
|
360
|
+
previewWanted = null;
|
|
361
|
+
previewRunning = false;
|
|
362
|
+
previewRetry = null;
|
|
363
|
+
previewRetries = 0;
|
|
364
|
+
previewCleanup = null;
|
|
365
|
+
static PREVIEW_WIDTH_PX = 160;
|
|
342
366
|
presenter = null;
|
|
343
367
|
/** `pixi-effects/present`, loaded as soon as the movie has stops (a press of play must not wait for it). */
|
|
344
368
|
present = null;
|
|
@@ -385,6 +409,7 @@ var Controller = class _Controller {
|
|
|
385
409
|
presentButton: options.presentButton ?? true,
|
|
386
410
|
pauseAtStops: options.pauseAtStops ?? true,
|
|
387
411
|
loopButton: options.loopButton ?? true,
|
|
412
|
+
thumbnails: options.thumbnails ?? false,
|
|
388
413
|
className: options.className ?? "movie-controller"
|
|
389
414
|
};
|
|
390
415
|
installStyles();
|
|
@@ -407,6 +432,7 @@ var Controller = class _Controller {
|
|
|
407
432
|
this.bindPlayButton();
|
|
408
433
|
if (this.options.clickToPlay) this.bindCanvasClick();
|
|
409
434
|
this.bindScrubbing();
|
|
435
|
+
if (this.options.thumbnails) this.bindPreview();
|
|
410
436
|
this.bindMuteButton();
|
|
411
437
|
this.bindLoopButton();
|
|
412
438
|
this.bindVolumeSlider();
|
|
@@ -586,6 +612,7 @@ var Controller = class _Controller {
|
|
|
586
612
|
};
|
|
587
613
|
this.onRebuilt = () => {
|
|
588
614
|
this.refreshStops();
|
|
615
|
+
this.previewCache.clear();
|
|
589
616
|
};
|
|
590
617
|
this.movie.on("ready", this.onReady);
|
|
591
618
|
this.movie.on("rebuilt", this.onRebuilt);
|
|
@@ -909,6 +936,104 @@ var Controller = class _Controller {
|
|
|
909
936
|
};
|
|
910
937
|
window.addEventListener("blur", this.windowBlurHandler);
|
|
911
938
|
}
|
|
939
|
+
/** The hover preview above the seek bar (`thumbnails: true`). */
|
|
940
|
+
bindPreview() {
|
|
941
|
+
const el = document.createElement("div");
|
|
942
|
+
el.className = "mc-preview";
|
|
943
|
+
el.setAttribute("aria-hidden", "true");
|
|
944
|
+
const canvas = document.createElement("canvas");
|
|
945
|
+
const time = document.createElement("span");
|
|
946
|
+
time.className = "mc-preview-time";
|
|
947
|
+
el.append(canvas, time);
|
|
948
|
+
this.root.appendChild(el);
|
|
949
|
+
this.previewEl = el;
|
|
950
|
+
this.previewCanvas = canvas;
|
|
951
|
+
this.previewTimeEl = time;
|
|
952
|
+
const hide = () => {
|
|
953
|
+
this.previewWanted = null;
|
|
954
|
+
el.removeAttribute("data-show");
|
|
955
|
+
};
|
|
956
|
+
const onMove = (e) => {
|
|
957
|
+
if (this.isScrubbing || this.movie.thumbnailsOff || e.pointerType === "touch") {
|
|
958
|
+
hide();
|
|
959
|
+
return;
|
|
960
|
+
}
|
|
961
|
+
const rect = this.progressEl.getBoundingClientRect();
|
|
962
|
+
const inset = _Controller.PROGRESS_INSET_PX;
|
|
963
|
+
const frame = pxToFrame(e.clientX, { left: rect.left + inset, width: Math.max(0, rect.width - 2 * inset) }, this.movie.totalFrames);
|
|
964
|
+
const rootRect = this.root.getBoundingClientRect();
|
|
965
|
+
const half = el.getBoundingClientRect().width / 2 + 2;
|
|
966
|
+
const x = Math.min(Math.max(e.clientX - rootRect.left, half), Math.max(half, rootRect.width - half));
|
|
967
|
+
el.style.left = `${rootRect.width > 0 ? x / rootRect.width * 100 : 50}%`;
|
|
968
|
+
this.previewRetries = 0;
|
|
969
|
+
time.textContent = formatTime(frame / (this.movie.frameRate || 1));
|
|
970
|
+
this.previewWanted = frame;
|
|
971
|
+
void this.runPreview();
|
|
972
|
+
};
|
|
973
|
+
this.progressEl.addEventListener("pointermove", onMove);
|
|
974
|
+
this.progressEl.addEventListener("pointerleave", hide);
|
|
975
|
+
this.progressEl.addEventListener("pointerdown", hide);
|
|
976
|
+
this.previewCleanup = () => {
|
|
977
|
+
this.progressEl.removeEventListener("pointermove", onMove);
|
|
978
|
+
this.progressEl.removeEventListener("pointerleave", hide);
|
|
979
|
+
this.progressEl.removeEventListener("pointerdown", hide);
|
|
980
|
+
if (this.previewRetry) {
|
|
981
|
+
clearTimeout(this.previewRetry);
|
|
982
|
+
this.previewRetry = null;
|
|
983
|
+
}
|
|
984
|
+
el.remove();
|
|
985
|
+
};
|
|
986
|
+
}
|
|
987
|
+
/** Draws the picture of the wanted frame into the preview; one at a time, and the last wish wins. */
|
|
988
|
+
async runPreview() {
|
|
989
|
+
if (this.previewRunning) return;
|
|
990
|
+
this.previewRunning = true;
|
|
991
|
+
try {
|
|
992
|
+
while (this.previewWanted !== null && !this.destroyed) {
|
|
993
|
+
const wanted = this.previewWanted;
|
|
994
|
+
const fps = this.movie.frameRate || 30;
|
|
995
|
+
const step = Math.max(1, Math.round(fps / 10));
|
|
996
|
+
const key = Math.min(this.movie.totalFrames, Math.round(wanted / step) * step);
|
|
997
|
+
let pic = this.previewCache.get(key) ?? null;
|
|
998
|
+
if (!pic) {
|
|
999
|
+
try {
|
|
1000
|
+
pic = await this.movie.thumbnail(key, { width: _Controller.PREVIEW_WIDTH_PX });
|
|
1001
|
+
} catch {
|
|
1002
|
+
this.previewWanted = null;
|
|
1003
|
+
this.previewEl?.removeAttribute("data-show");
|
|
1004
|
+
break;
|
|
1005
|
+
}
|
|
1006
|
+
if (pic) {
|
|
1007
|
+
if (this.previewCache.size >= 120) this.previewCache.delete(this.previewCache.keys().next().value);
|
|
1008
|
+
this.previewCache.set(key, pic);
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
if (this.previewWanted === null || this.destroyed) break;
|
|
1012
|
+
if (pic) {
|
|
1013
|
+
const c = this.previewCanvas;
|
|
1014
|
+
if (c.width !== pic.width || c.height !== pic.height) {
|
|
1015
|
+
c.width = pic.width;
|
|
1016
|
+
c.height = pic.height;
|
|
1017
|
+
}
|
|
1018
|
+
c.getContext("2d").drawImage(pic, 0, 0);
|
|
1019
|
+
this.previewEl.setAttribute("data-show", "1");
|
|
1020
|
+
if (this.previewWanted === wanted) this.previewWanted = null;
|
|
1021
|
+
} else if (this.previewWanted !== wanted) {
|
|
1022
|
+
} else if (!this.movie.thumbnailsOff && this.previewRetries++ < 10) {
|
|
1023
|
+
this.previewRetry = setTimeout(() => {
|
|
1024
|
+
this.previewRetry = null;
|
|
1025
|
+
void this.runPreview();
|
|
1026
|
+
}, 120);
|
|
1027
|
+
break;
|
|
1028
|
+
} else {
|
|
1029
|
+
this.previewWanted = null;
|
|
1030
|
+
this.previewEl?.removeAttribute("data-show");
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
} finally {
|
|
1034
|
+
this.previewRunning = false;
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
912
1037
|
seekFromPointer(clientX) {
|
|
913
1038
|
const rect = this.progressEl.getBoundingClientRect();
|
|
914
1039
|
const inset = _Controller.PROGRESS_INSET_PX;
|
|
@@ -1185,6 +1310,10 @@ var Controller = class _Controller {
|
|
|
1185
1310
|
if (this.destroyed) return;
|
|
1186
1311
|
this.destroyed = true;
|
|
1187
1312
|
this.stopPresenting();
|
|
1313
|
+
if (this.previewCleanup) {
|
|
1314
|
+
this.previewCleanup();
|
|
1315
|
+
this.previewCleanup = null;
|
|
1316
|
+
}
|
|
1188
1317
|
if (this.onReady) {
|
|
1189
1318
|
this.movie.off("ready", this.onReady);
|
|
1190
1319
|
this.onReady = null;
|