pixi-effects 0.10.0 → 0.12.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 +37 -0
- package/README.md +11 -8
- package/ai/SKILL.md +4 -3
- package/ai/reference/cheatsheet.md +16 -2
- package/ai/reference/pitfalls.md +6 -2
- package/ai/reference/recipes.md +76 -10
- package/ai/template.html +15 -8
- package/ai/tools/check.mjs +17 -1
- package/ai/tools/render.mjs +23 -10
- package/dist/{Base-CyvSLoCP.d.ts → Base-CYH9vPCH.d.ts} +1 -1
- package/dist/{Base-CwUxTfja.d.cts → Base-W3sQzGPO.d.cts} +1 -1
- package/dist/Composition-7TEKHZNQ.cjs +14 -0
- package/dist/{Composition-EKVTUYCI.cjs.map → Composition-7TEKHZNQ.cjs.map} +1 -1
- package/dist/Composition-HIISJAX2.js +5 -0
- package/dist/{Composition-NJCOMGD7.js.map → Composition-HIISJAX2.js.map} +1 -1
- package/dist/Controller.cjs +58 -0
- package/dist/Controller.cjs.map +1 -1
- package/dist/Controller.d.cts +13 -3
- package/dist/Controller.d.ts +13 -3
- package/dist/Controller.js +58 -0
- package/dist/Controller.js.map +1 -1
- package/dist/{Movie-w3GliuP3.d.cts → Movie-CY2QPVVM.d.cts} +149 -2
- package/dist/{Movie-puD9oZPg.d.ts → Movie-EBF6_RfX.d.ts} +149 -2
- package/dist/Presenter.cjs +671 -0
- package/dist/Presenter.cjs.map +1 -0
- package/dist/Presenter.d.cts +123 -0
- package/dist/Presenter.d.ts +123 -0
- package/dist/Presenter.js +669 -0
- package/dist/Presenter.js.map +1 -0
- package/dist/{chunk-WDGAVOMS.js → chunk-3IPDNC3E.js} +8 -5
- package/dist/chunk-3IPDNC3E.js.map +1 -0
- package/dist/{chunk-S3ZI4MKS.cjs → chunk-6NWJLVCA.cjs} +3 -3
- package/dist/{chunk-S3ZI4MKS.cjs.map → chunk-6NWJLVCA.cjs.map} +1 -1
- package/dist/{chunk-JAMNDBXW.js → chunk-C6QHKYC5.js} +3 -3
- package/dist/{chunk-JAMNDBXW.js.map → chunk-C6QHKYC5.js.map} +1 -1
- package/dist/{chunk-4WJUSDJJ.cjs → chunk-F7NCHS6Q.cjs} +31 -28
- package/dist/chunk-F7NCHS6Q.cjs.map +1 -0
- package/dist/index.cjs +884 -58
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +234 -5
- package/dist/index.d.ts +234 -5
- package/dist/index.js +856 -40
- package/dist/index.js.map +1 -1
- package/dist/loader.css +110 -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-BXu28nJj.d.cts → types-mpqQO8MJ.d.cts} +39 -1
- package/dist/{types-BXu28nJj.d.ts → types-mpqQO8MJ.d.ts} +39 -1
- package/docs/api.md +94 -1
- package/docs/dsl.md +77 -0
- package/llms-full.txt +273 -18
- package/llms.txt +3 -3
- package/package.json +9 -2
- package/dist/Composition-EKVTUYCI.cjs +0 -14
- package/dist/Composition-NJCOMGD7.js +0 -5
- package/dist/chunk-4WJUSDJJ.cjs.map +0 -1
- package/dist/chunk-WDGAVOMS.js.map +0 -1
package/dist/Controller.d.cts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { f as Movie } from './Movie-CY2QPVVM.cjs';
|
|
2
2
|
import 'pixi.js';
|
|
3
3
|
import 'gsap';
|
|
4
|
-
import './types-
|
|
4
|
+
import './types-mpqQO8MJ.cjs';
|
|
5
5
|
|
|
6
6
|
/** The bar's default stylesheet. Its colours and sizes are CSS custom properties (`--mc-accent`, `--mc-fg`, `--mc-track`, `--mc-bar-bg`, `--mc-track-height`, `--mc-font`): set them in your page CSS, or with the `theme` option. */
|
|
7
|
-
declare const CONTROLLER_CSS = "\n.movie-controller-wrap { position: relative; display: inline-block; line-height: 0; }\n.movie-controller {\n position: absolute;\n pointer-events: none;\n font-family: var(--mc-font, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif);\n display: flex;\n flex-direction: column;\n justify-content: flex-end;\n opacity: 1;\n transition: opacity 200ms ease;\n}\n.movie-controller[data-state=\"hidden\"] { opacity: 0; }\n.movie-controller > * { pointer-events: auto; }\n\n.mc-progress {\n position: relative;\n width: 100%;\n height: 16px;\n cursor: pointer;\n display: flex;\n align-items: center;\n outline: none;\n}\n.mc-progress:focus-visible {\n outline: 2px solid var(--mc-accent, #007AFF);\n outline-offset: 2px;\n}\n.mc-progress::before {\n content: \"\"; position: absolute; left: 12px; right: 12px;\n height: var(--mc-track-height, 3px); background: var(--mc-track, rgba(255,255,255,0.25));\n transition: height 120ms ease;\n}\n.mc-progress:hover::before, .mc-progress.mc-scrubbing::before { height: calc(var(--mc-track-height, 3px) + 2px); }\n.mc-progress-fill {\n position: absolute; left: 12px; top: 50%;\n height: var(--mc-track-height, 3px);\n width: calc((100% - 24px) * var(--mc-fill, 0));\n background: var(--mc-accent, #007AFF);\n transform: translateY(-50%);\n transition: height 120ms ease;\n pointer-events: none;\n}\n.mc-progress:hover .mc-progress-fill,\n.mc-progress.mc-scrubbing .mc-progress-fill { height: calc(var(--mc-track-height, 3px) + 2px); }\n.mc-progress-thumb {\n position: absolute; top: 50%;\n left: calc(12px + (100% - 24px) * var(--mc-fill, 0));\n width: 12px; height: 12px; border-radius: 50%;\n background: var(--mc-accent, #007AFF);\n transform: translate(-50%, -50%) scale(0);\n transition: transform 120ms ease;\n pointer-events: none;\n}\n.mc-progress:hover .mc-progress-thumb,\n.mc-progress.mc-scrubbing .mc-progress-thumb { transform: translate(-50%, -50%) scale(1); }\n\n.mc-bar {\n position: relative;\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 6px 12px 8px 12px;\n background: var(--mc-bar-bg, linear-gradient(to top, rgba(0,0,0,0.75) 0%, rgba(0,0,0,0) 100%));\n color: var(--mc-fg, #fff);\n line-height: 1;\n}\n.mc-btn {\n background: none; border: 0; padding: 0; margin: 0;\n width: 28px; height: 28px;\n display: inline-flex; align-items: center; justify-content: center;\n color: var(--mc-fg, #fff); opacity: 0.85; cursor: pointer;\n transition: opacity 120ms ease;\n}\n.mc-btn:hover { opacity: 1; }\n.mc-btn:disabled { opacity: 0.4; cursor: not-allowed; }\n.mc-time {\n font-size: 12px; font-family: Menlo, Monaco, monospace;\n color: var(--mc-fg, #fff); opacity: 0.85;\n min-width: 90px;\n}\n.mc-spacer { flex: 1; }\n\n.mc-volume { display: flex; align-items: center; }\n.mc-vol-slider {\n position: relative;\n width: 0;\n height: 28px;\n display: flex;\n align-items: center;\n cursor: pointer;\n margin-left: 0;\n outline: none;\n transition: width 200ms ease, margin-left 200ms ease;\n overflow: hidden;\n}\n.mc-volume:hover .mc-vol-slider,\n.mc-volume:focus-within .mc-vol-slider,\n.mc-vol-slider.mc-scrubbing {\n width: 70px;\n margin-left: 6px;\n}\n.mc-vol-slider:focus-visible { outline: 2px solid var(--mc-accent, #007AFF); outline-offset: 2px; }\n.mc-vol-slider::before {\n content: \"\"; position: absolute; left: 4px; right: 4px;\n height: 3px; background: var(--mc-track, rgba(255,255,255,0.25)); border-radius: 2px;\n}\n.mc-vol-fill {\n position: absolute; left: 4px; top: 50%;\n height: 3px;\n width: calc((100% - 8px) * var(--mc-volume, 1));\n background: var(--mc-fg, #fff);\n transform: translateY(-50%);\n border-radius: 2px;\n pointer-events: none;\n}\n.mc-vol-thumb {\n position: absolute; top: 50%;\n left: calc(4px + (100% - 8px) * var(--mc-volume, 1));\n width: 10px; height: 10px; border-radius: 50%;\n background: var(--mc-fg, #fff);\n transform: translate(-50%, -50%);\n pointer-events: none;\n}\n\n[data-mc-wrap]:fullscreen {\n width: 100vw; height: 100vh;\n display: flex; align-items: center; justify-content: center;\n background: #000;\n}\n[data-mc-wrap]:fullscreen > canvas {\n width: 100% !important;\n height: 100% !important;\n max-width: none !important;\n max-height: none !important;\n object-fit: contain;\n border-radius: 0;\n}\n\n.mc-settings-popover {\n position: absolute;\n bottom: calc(100% + 8px);\n right: 12px;\n background: rgba(20, 20, 20, 0.96);\n border-radius: 8px;\n padding: 10px 12px;\n min-width: 180px;\n color: #fff;\n font-size: 12px;\n box-shadow: 0 4px 16px rgba(0,0,0,0.4);\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n.mc-settings-popover[data-open=\"false\"] { display: none; }\n.mc-settings-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n}\n.mc-settings-row > span { color: rgba(255,255,255,0.85); }\n.mc-settings-row > select {\n font: inherit;\n background: rgba(255,255,255,0.1);\n color: #fff;\n border: 1px solid rgba(255,255,255,0.18);\n border-radius: 4px;\n padding: 2px 6px;\n cursor: pointer;\n}\n.mc-export-confirm {\n margin-top: 4px;\n width: 100%;\n background: var(--mc-accent, #007AFF);\n color: #fff;\n border: 0;\n border-radius: 4px;\n padding: 6px 10px;\n font: inherit;\n font-weight: 600;\n cursor: pointer;\n transition: background 120ms ease;\n}\n.mc-export-confirm:hover { background: #0066d6; }\n.mc-export-confirm:disabled { background: rgba(255,255,255,0.18); cursor: not-allowed; }\n\n.mc-export-overlay {\n position: absolute; inset: 0;\n background: rgba(0,0,0,0.7);\n display: flex; justify-content: center; align-items: center;\n z-index: 2;\n}\n.mc-export-panel {\n background: rgba(20,20,20,0.96); color: #fff;\n border-radius: 8px; padding: 16px 20px;\n text-align: center; min-width: 200px; max-width: 80%;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n}\n.mc-export-title { font-size: 13px; margin-bottom: 10px; opacity: 0.9; }\n.mc-export-track {\n width: 100%; height: 6px;\n background: rgba(255,255,255,0.15); border-radius: 3px;\n margin-bottom: 8px; overflow: hidden;\n}\n.mc-export-fill {\n height: 100%; width: 0%;\n background: linear-gradient(90deg, var(--mc-accent, #007AFF), var(--mc-accent, #0056CC));\n transition: width 0.3s ease; border-radius: 3px;\n}\n.mc-export-text {\n color: rgba(255,255,255,0.7); font-size: 11px;\n font-family: Menlo, Monaco, monospace;\n}\n";
|
|
7
|
+
declare const CONTROLLER_CSS = "\n.movie-controller-wrap { position: relative; display: inline-block; line-height: 0; }\n.movie-controller {\n position: absolute;\n pointer-events: none;\n font-family: var(--mc-font, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif);\n display: flex;\n flex-direction: column;\n justify-content: flex-end;\n opacity: 1;\n transition: opacity 200ms ease;\n}\n.movie-controller[data-state=\"hidden\"] { opacity: 0; }\n.movie-controller > * { pointer-events: auto; }\n\n.mc-progress {\n position: relative;\n width: 100%;\n height: 16px;\n cursor: pointer;\n display: flex;\n align-items: center;\n outline: none;\n}\n.mc-progress:focus-visible {\n outline: 2px solid var(--mc-accent, #007AFF);\n outline-offset: 2px;\n}\n.mc-progress::before {\n content: \"\"; position: absolute; left: 12px; right: 12px;\n height: var(--mc-track-height, 3px); background: var(--mc-track, rgba(255,255,255,0.25));\n transition: height 120ms ease;\n}\n.mc-progress:hover::before, .mc-progress.mc-scrubbing::before { height: calc(var(--mc-track-height, 3px) + 2px); }\n.mc-stops { position: absolute; left: 12px; right: 12px; top: 0; bottom: 0; pointer-events: none; }\n.mc-stop-tick { position: absolute; top: 50%; width: 2px; height: calc(var(--mc-track-height, 3px) + 6px); transform: translate(-50%, -50%); background: var(--mc-fg, #fff); opacity: 0.6; border-radius: 1px; }\n.mc-progress-fill {\n position: absolute; left: 12px; top: 50%;\n height: var(--mc-track-height, 3px);\n width: calc((100% - 24px) * var(--mc-fill, 0));\n background: var(--mc-accent, #007AFF);\n transform: translateY(-50%);\n transition: height 120ms ease;\n pointer-events: none;\n}\n.mc-progress:hover .mc-progress-fill,\n.mc-progress.mc-scrubbing .mc-progress-fill { height: calc(var(--mc-track-height, 3px) + 2px); }\n.mc-progress-thumb {\n position: absolute; top: 50%;\n left: calc(12px + (100% - 24px) * var(--mc-fill, 0));\n width: 12px; height: 12px; border-radius: 50%;\n background: var(--mc-accent, #007AFF);\n transform: translate(-50%, -50%) scale(0);\n transition: transform 120ms ease;\n pointer-events: none;\n}\n.mc-progress:hover .mc-progress-thumb,\n.mc-progress.mc-scrubbing .mc-progress-thumb { transform: translate(-50%, -50%) scale(1); }\n\n.mc-bar {\n position: relative;\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 6px 12px 8px 12px;\n background: var(--mc-bar-bg, linear-gradient(to top, rgba(0,0,0,0.75) 0%, rgba(0,0,0,0) 100%));\n color: var(--mc-fg, #fff);\n line-height: 1;\n}\n.mc-btn {\n background: none; border: 0; padding: 0; margin: 0;\n width: 28px; height: 28px;\n display: inline-flex; align-items: center; justify-content: center;\n color: var(--mc-fg, #fff); opacity: 0.85; cursor: pointer;\n transition: opacity 120ms ease;\n}\n.mc-btn:hover { opacity: 1; }\n.mc-btn:disabled { opacity: 0.4; cursor: not-allowed; }\n.mc-time {\n font-size: 12px; font-family: Menlo, Monaco, monospace;\n color: var(--mc-fg, #fff); opacity: 0.85;\n min-width: 90px;\n}\n.mc-spacer { flex: 1; }\n\n.mc-volume { display: flex; align-items: center; }\n.mc-vol-slider {\n position: relative;\n width: 0;\n height: 28px;\n display: flex;\n align-items: center;\n cursor: pointer;\n margin-left: 0;\n outline: none;\n transition: width 200ms ease, margin-left 200ms ease;\n overflow: hidden;\n}\n.mc-volume:hover .mc-vol-slider,\n.mc-volume:focus-within .mc-vol-slider,\n.mc-vol-slider.mc-scrubbing {\n width: 70px;\n margin-left: 6px;\n}\n.mc-vol-slider:focus-visible { outline: 2px solid var(--mc-accent, #007AFF); outline-offset: 2px; }\n.mc-vol-slider::before {\n content: \"\"; position: absolute; left: 4px; right: 4px;\n height: 3px; background: var(--mc-track, rgba(255,255,255,0.25)); border-radius: 2px;\n}\n.mc-vol-fill {\n position: absolute; left: 4px; top: 50%;\n height: 3px;\n width: calc((100% - 8px) * var(--mc-volume, 1));\n background: var(--mc-fg, #fff);\n transform: translateY(-50%);\n border-radius: 2px;\n pointer-events: none;\n}\n.mc-vol-thumb {\n position: absolute; top: 50%;\n left: calc(4px + (100% - 8px) * var(--mc-volume, 1));\n width: 10px; height: 10px; border-radius: 50%;\n background: var(--mc-fg, #fff);\n transform: translate(-50%, -50%);\n pointer-events: none;\n}\n\n[data-mc-wrap]:fullscreen {\n width: 100vw; height: 100vh;\n display: flex; align-items: center; justify-content: center;\n background: #000;\n}\n[data-mc-wrap]:fullscreen > canvas {\n width: 100% !important;\n height: 100% !important;\n max-width: none !important;\n max-height: none !important;\n object-fit: contain;\n border-radius: 0;\n}\n\n.mc-settings-popover {\n position: absolute;\n bottom: calc(100% + 8px);\n right: 12px;\n background: rgba(20, 20, 20, 0.96);\n border-radius: 8px;\n padding: 10px 12px;\n min-width: 180px;\n color: #fff;\n font-size: 12px;\n box-shadow: 0 4px 16px rgba(0,0,0,0.4);\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n.mc-settings-popover[data-open=\"false\"] { display: none; }\n.mc-settings-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n}\n.mc-settings-row > span { color: rgba(255,255,255,0.85); }\n.mc-settings-row > select {\n font: inherit;\n background: rgba(255,255,255,0.1);\n color: #fff;\n border: 1px solid rgba(255,255,255,0.18);\n border-radius: 4px;\n padding: 2px 6px;\n cursor: pointer;\n}\n.mc-export-confirm {\n margin-top: 4px;\n width: 100%;\n background: var(--mc-accent, #007AFF);\n color: #fff;\n border: 0;\n border-radius: 4px;\n padding: 6px 10px;\n font: inherit;\n font-weight: 600;\n cursor: pointer;\n transition: background 120ms ease;\n}\n.mc-export-confirm:hover { background: #0066d6; }\n.mc-export-confirm:disabled { background: rgba(255,255,255,0.18); cursor: not-allowed; }\n\n.mc-export-overlay {\n position: absolute; inset: 0;\n background: rgba(0,0,0,0.7);\n display: flex; justify-content: center; align-items: center;\n z-index: 2;\n}\n.mc-export-panel {\n background: rgba(20,20,20,0.96); color: #fff;\n border-radius: 8px; padding: 16px 20px;\n text-align: center; min-width: 200px; max-width: 80%;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n}\n.mc-export-title { font-size: 13px; margin-bottom: 10px; opacity: 0.9; }\n.mc-export-track {\n width: 100%; height: 6px;\n background: rgba(255,255,255,0.15); border-radius: 3px;\n margin-bottom: 8px; overflow: hidden;\n}\n.mc-export-fill {\n height: 100%; width: 0%;\n background: linear-gradient(90deg, var(--mc-accent, #007AFF), var(--mc-accent, #0056CC));\n transition: width 0.3s ease; border-radius: 3px;\n}\n.mc-export-text {\n color: rgba(255,255,255,0.7); font-size: 11px;\n font-family: Menlo, Monaco, monospace;\n}\n";
|
|
8
8
|
declare function formatTime(seconds: number): string;
|
|
9
9
|
declare function frameToPercent(frame: number, totalFrames: number): number;
|
|
10
10
|
declare function pxToFrame(clientX: number, rect: {
|
|
@@ -42,6 +42,8 @@ interface ControllerOptions {
|
|
|
42
42
|
enableKeyboardShortcuts?: boolean;
|
|
43
43
|
/** A click (or tap) on the picture plays / pauses, like a `<video>` element. Default true; `false` leaves the canvas alone. */
|
|
44
44
|
clickToPlay?: boolean;
|
|
45
|
+
/** A movie with `stops` gets a Present button that starts a {@link Presenter} (keys, click and swipe move through the stops). Default true; `false` keeps only the marks on the seek bar. */
|
|
46
|
+
present?: boolean;
|
|
45
47
|
className?: string;
|
|
46
48
|
}
|
|
47
49
|
interface ResolvedOptions {
|
|
@@ -49,6 +51,7 @@ interface ResolvedOptions {
|
|
|
49
51
|
showExportButton: boolean;
|
|
50
52
|
enableKeyboardShortcuts: boolean;
|
|
51
53
|
clickToPlay: boolean;
|
|
54
|
+
present: boolean;
|
|
52
55
|
className: string;
|
|
53
56
|
}
|
|
54
57
|
declare class Controller {
|
|
@@ -91,6 +94,8 @@ declare class Controller {
|
|
|
91
94
|
private settingsKeyHandler;
|
|
92
95
|
private settingsOutsideHandler;
|
|
93
96
|
private onReady;
|
|
97
|
+
private presenter;
|
|
98
|
+
private presentBtn;
|
|
94
99
|
private onFrame;
|
|
95
100
|
private onPlay;
|
|
96
101
|
private onPause;
|
|
@@ -125,6 +130,11 @@ declare class Controller {
|
|
|
125
130
|
private fitWrap;
|
|
126
131
|
private bindFitWrap;
|
|
127
132
|
private bindMovieEvents;
|
|
133
|
+
/** The stops of a presentation as marks on the seek bar, and the Present button. */
|
|
134
|
+
private refreshStops;
|
|
135
|
+
/** Hand the page over to a Presenter (fullscreen, keys, click and swipe move through the stops); Escape gives it back. */
|
|
136
|
+
private startPresenting;
|
|
137
|
+
private stopPresenting;
|
|
128
138
|
private bindPlayButton;
|
|
129
139
|
/** Clicking the picture plays / pauses (a tap on a phone too). */
|
|
130
140
|
private bindCanvasClick;
|
package/dist/Controller.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { f as Movie } from './Movie-EBF6_RfX.js';
|
|
2
2
|
import 'pixi.js';
|
|
3
3
|
import 'gsap';
|
|
4
|
-
import './types-
|
|
4
|
+
import './types-mpqQO8MJ.js';
|
|
5
5
|
|
|
6
6
|
/** The bar's default stylesheet. Its colours and sizes are CSS custom properties (`--mc-accent`, `--mc-fg`, `--mc-track`, `--mc-bar-bg`, `--mc-track-height`, `--mc-font`): set them in your page CSS, or with the `theme` option. */
|
|
7
|
-
declare const CONTROLLER_CSS = "\n.movie-controller-wrap { position: relative; display: inline-block; line-height: 0; }\n.movie-controller {\n position: absolute;\n pointer-events: none;\n font-family: var(--mc-font, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif);\n display: flex;\n flex-direction: column;\n justify-content: flex-end;\n opacity: 1;\n transition: opacity 200ms ease;\n}\n.movie-controller[data-state=\"hidden\"] { opacity: 0; }\n.movie-controller > * { pointer-events: auto; }\n\n.mc-progress {\n position: relative;\n width: 100%;\n height: 16px;\n cursor: pointer;\n display: flex;\n align-items: center;\n outline: none;\n}\n.mc-progress:focus-visible {\n outline: 2px solid var(--mc-accent, #007AFF);\n outline-offset: 2px;\n}\n.mc-progress::before {\n content: \"\"; position: absolute; left: 12px; right: 12px;\n height: var(--mc-track-height, 3px); background: var(--mc-track, rgba(255,255,255,0.25));\n transition: height 120ms ease;\n}\n.mc-progress:hover::before, .mc-progress.mc-scrubbing::before { height: calc(var(--mc-track-height, 3px) + 2px); }\n.mc-progress-fill {\n position: absolute; left: 12px; top: 50%;\n height: var(--mc-track-height, 3px);\n width: calc((100% - 24px) * var(--mc-fill, 0));\n background: var(--mc-accent, #007AFF);\n transform: translateY(-50%);\n transition: height 120ms ease;\n pointer-events: none;\n}\n.mc-progress:hover .mc-progress-fill,\n.mc-progress.mc-scrubbing .mc-progress-fill { height: calc(var(--mc-track-height, 3px) + 2px); }\n.mc-progress-thumb {\n position: absolute; top: 50%;\n left: calc(12px + (100% - 24px) * var(--mc-fill, 0));\n width: 12px; height: 12px; border-radius: 50%;\n background: var(--mc-accent, #007AFF);\n transform: translate(-50%, -50%) scale(0);\n transition: transform 120ms ease;\n pointer-events: none;\n}\n.mc-progress:hover .mc-progress-thumb,\n.mc-progress.mc-scrubbing .mc-progress-thumb { transform: translate(-50%, -50%) scale(1); }\n\n.mc-bar {\n position: relative;\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 6px 12px 8px 12px;\n background: var(--mc-bar-bg, linear-gradient(to top, rgba(0,0,0,0.75) 0%, rgba(0,0,0,0) 100%));\n color: var(--mc-fg, #fff);\n line-height: 1;\n}\n.mc-btn {\n background: none; border: 0; padding: 0; margin: 0;\n width: 28px; height: 28px;\n display: inline-flex; align-items: center; justify-content: center;\n color: var(--mc-fg, #fff); opacity: 0.85; cursor: pointer;\n transition: opacity 120ms ease;\n}\n.mc-btn:hover { opacity: 1; }\n.mc-btn:disabled { opacity: 0.4; cursor: not-allowed; }\n.mc-time {\n font-size: 12px; font-family: Menlo, Monaco, monospace;\n color: var(--mc-fg, #fff); opacity: 0.85;\n min-width: 90px;\n}\n.mc-spacer { flex: 1; }\n\n.mc-volume { display: flex; align-items: center; }\n.mc-vol-slider {\n position: relative;\n width: 0;\n height: 28px;\n display: flex;\n align-items: center;\n cursor: pointer;\n margin-left: 0;\n outline: none;\n transition: width 200ms ease, margin-left 200ms ease;\n overflow: hidden;\n}\n.mc-volume:hover .mc-vol-slider,\n.mc-volume:focus-within .mc-vol-slider,\n.mc-vol-slider.mc-scrubbing {\n width: 70px;\n margin-left: 6px;\n}\n.mc-vol-slider:focus-visible { outline: 2px solid var(--mc-accent, #007AFF); outline-offset: 2px; }\n.mc-vol-slider::before {\n content: \"\"; position: absolute; left: 4px; right: 4px;\n height: 3px; background: var(--mc-track, rgba(255,255,255,0.25)); border-radius: 2px;\n}\n.mc-vol-fill {\n position: absolute; left: 4px; top: 50%;\n height: 3px;\n width: calc((100% - 8px) * var(--mc-volume, 1));\n background: var(--mc-fg, #fff);\n transform: translateY(-50%);\n border-radius: 2px;\n pointer-events: none;\n}\n.mc-vol-thumb {\n position: absolute; top: 50%;\n left: calc(4px + (100% - 8px) * var(--mc-volume, 1));\n width: 10px; height: 10px; border-radius: 50%;\n background: var(--mc-fg, #fff);\n transform: translate(-50%, -50%);\n pointer-events: none;\n}\n\n[data-mc-wrap]:fullscreen {\n width: 100vw; height: 100vh;\n display: flex; align-items: center; justify-content: center;\n background: #000;\n}\n[data-mc-wrap]:fullscreen > canvas {\n width: 100% !important;\n height: 100% !important;\n max-width: none !important;\n max-height: none !important;\n object-fit: contain;\n border-radius: 0;\n}\n\n.mc-settings-popover {\n position: absolute;\n bottom: calc(100% + 8px);\n right: 12px;\n background: rgba(20, 20, 20, 0.96);\n border-radius: 8px;\n padding: 10px 12px;\n min-width: 180px;\n color: #fff;\n font-size: 12px;\n box-shadow: 0 4px 16px rgba(0,0,0,0.4);\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n.mc-settings-popover[data-open=\"false\"] { display: none; }\n.mc-settings-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n}\n.mc-settings-row > span { color: rgba(255,255,255,0.85); }\n.mc-settings-row > select {\n font: inherit;\n background: rgba(255,255,255,0.1);\n color: #fff;\n border: 1px solid rgba(255,255,255,0.18);\n border-radius: 4px;\n padding: 2px 6px;\n cursor: pointer;\n}\n.mc-export-confirm {\n margin-top: 4px;\n width: 100%;\n background: var(--mc-accent, #007AFF);\n color: #fff;\n border: 0;\n border-radius: 4px;\n padding: 6px 10px;\n font: inherit;\n font-weight: 600;\n cursor: pointer;\n transition: background 120ms ease;\n}\n.mc-export-confirm:hover { background: #0066d6; }\n.mc-export-confirm:disabled { background: rgba(255,255,255,0.18); cursor: not-allowed; }\n\n.mc-export-overlay {\n position: absolute; inset: 0;\n background: rgba(0,0,0,0.7);\n display: flex; justify-content: center; align-items: center;\n z-index: 2;\n}\n.mc-export-panel {\n background: rgba(20,20,20,0.96); color: #fff;\n border-radius: 8px; padding: 16px 20px;\n text-align: center; min-width: 200px; max-width: 80%;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n}\n.mc-export-title { font-size: 13px; margin-bottom: 10px; opacity: 0.9; }\n.mc-export-track {\n width: 100%; height: 6px;\n background: rgba(255,255,255,0.15); border-radius: 3px;\n margin-bottom: 8px; overflow: hidden;\n}\n.mc-export-fill {\n height: 100%; width: 0%;\n background: linear-gradient(90deg, var(--mc-accent, #007AFF), var(--mc-accent, #0056CC));\n transition: width 0.3s ease; border-radius: 3px;\n}\n.mc-export-text {\n color: rgba(255,255,255,0.7); font-size: 11px;\n font-family: Menlo, Monaco, monospace;\n}\n";
|
|
7
|
+
declare const CONTROLLER_CSS = "\n.movie-controller-wrap { position: relative; display: inline-block; line-height: 0; }\n.movie-controller {\n position: absolute;\n pointer-events: none;\n font-family: var(--mc-font, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif);\n display: flex;\n flex-direction: column;\n justify-content: flex-end;\n opacity: 1;\n transition: opacity 200ms ease;\n}\n.movie-controller[data-state=\"hidden\"] { opacity: 0; }\n.movie-controller > * { pointer-events: auto; }\n\n.mc-progress {\n position: relative;\n width: 100%;\n height: 16px;\n cursor: pointer;\n display: flex;\n align-items: center;\n outline: none;\n}\n.mc-progress:focus-visible {\n outline: 2px solid var(--mc-accent, #007AFF);\n outline-offset: 2px;\n}\n.mc-progress::before {\n content: \"\"; position: absolute; left: 12px; right: 12px;\n height: var(--mc-track-height, 3px); background: var(--mc-track, rgba(255,255,255,0.25));\n transition: height 120ms ease;\n}\n.mc-progress:hover::before, .mc-progress.mc-scrubbing::before { height: calc(var(--mc-track-height, 3px) + 2px); }\n.mc-stops { position: absolute; left: 12px; right: 12px; top: 0; bottom: 0; pointer-events: none; }\n.mc-stop-tick { position: absolute; top: 50%; width: 2px; height: calc(var(--mc-track-height, 3px) + 6px); transform: translate(-50%, -50%); background: var(--mc-fg, #fff); opacity: 0.6; border-radius: 1px; }\n.mc-progress-fill {\n position: absolute; left: 12px; top: 50%;\n height: var(--mc-track-height, 3px);\n width: calc((100% - 24px) * var(--mc-fill, 0));\n background: var(--mc-accent, #007AFF);\n transform: translateY(-50%);\n transition: height 120ms ease;\n pointer-events: none;\n}\n.mc-progress:hover .mc-progress-fill,\n.mc-progress.mc-scrubbing .mc-progress-fill { height: calc(var(--mc-track-height, 3px) + 2px); }\n.mc-progress-thumb {\n position: absolute; top: 50%;\n left: calc(12px + (100% - 24px) * var(--mc-fill, 0));\n width: 12px; height: 12px; border-radius: 50%;\n background: var(--mc-accent, #007AFF);\n transform: translate(-50%, -50%) scale(0);\n transition: transform 120ms ease;\n pointer-events: none;\n}\n.mc-progress:hover .mc-progress-thumb,\n.mc-progress.mc-scrubbing .mc-progress-thumb { transform: translate(-50%, -50%) scale(1); }\n\n.mc-bar {\n position: relative;\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 6px 12px 8px 12px;\n background: var(--mc-bar-bg, linear-gradient(to top, rgba(0,0,0,0.75) 0%, rgba(0,0,0,0) 100%));\n color: var(--mc-fg, #fff);\n line-height: 1;\n}\n.mc-btn {\n background: none; border: 0; padding: 0; margin: 0;\n width: 28px; height: 28px;\n display: inline-flex; align-items: center; justify-content: center;\n color: var(--mc-fg, #fff); opacity: 0.85; cursor: pointer;\n transition: opacity 120ms ease;\n}\n.mc-btn:hover { opacity: 1; }\n.mc-btn:disabled { opacity: 0.4; cursor: not-allowed; }\n.mc-time {\n font-size: 12px; font-family: Menlo, Monaco, monospace;\n color: var(--mc-fg, #fff); opacity: 0.85;\n min-width: 90px;\n}\n.mc-spacer { flex: 1; }\n\n.mc-volume { display: flex; align-items: center; }\n.mc-vol-slider {\n position: relative;\n width: 0;\n height: 28px;\n display: flex;\n align-items: center;\n cursor: pointer;\n margin-left: 0;\n outline: none;\n transition: width 200ms ease, margin-left 200ms ease;\n overflow: hidden;\n}\n.mc-volume:hover .mc-vol-slider,\n.mc-volume:focus-within .mc-vol-slider,\n.mc-vol-slider.mc-scrubbing {\n width: 70px;\n margin-left: 6px;\n}\n.mc-vol-slider:focus-visible { outline: 2px solid var(--mc-accent, #007AFF); outline-offset: 2px; }\n.mc-vol-slider::before {\n content: \"\"; position: absolute; left: 4px; right: 4px;\n height: 3px; background: var(--mc-track, rgba(255,255,255,0.25)); border-radius: 2px;\n}\n.mc-vol-fill {\n position: absolute; left: 4px; top: 50%;\n height: 3px;\n width: calc((100% - 8px) * var(--mc-volume, 1));\n background: var(--mc-fg, #fff);\n transform: translateY(-50%);\n border-radius: 2px;\n pointer-events: none;\n}\n.mc-vol-thumb {\n position: absolute; top: 50%;\n left: calc(4px + (100% - 8px) * var(--mc-volume, 1));\n width: 10px; height: 10px; border-radius: 50%;\n background: var(--mc-fg, #fff);\n transform: translate(-50%, -50%);\n pointer-events: none;\n}\n\n[data-mc-wrap]:fullscreen {\n width: 100vw; height: 100vh;\n display: flex; align-items: center; justify-content: center;\n background: #000;\n}\n[data-mc-wrap]:fullscreen > canvas {\n width: 100% !important;\n height: 100% !important;\n max-width: none !important;\n max-height: none !important;\n object-fit: contain;\n border-radius: 0;\n}\n\n.mc-settings-popover {\n position: absolute;\n bottom: calc(100% + 8px);\n right: 12px;\n background: rgba(20, 20, 20, 0.96);\n border-radius: 8px;\n padding: 10px 12px;\n min-width: 180px;\n color: #fff;\n font-size: 12px;\n box-shadow: 0 4px 16px rgba(0,0,0,0.4);\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n.mc-settings-popover[data-open=\"false\"] { display: none; }\n.mc-settings-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n}\n.mc-settings-row > span { color: rgba(255,255,255,0.85); }\n.mc-settings-row > select {\n font: inherit;\n background: rgba(255,255,255,0.1);\n color: #fff;\n border: 1px solid rgba(255,255,255,0.18);\n border-radius: 4px;\n padding: 2px 6px;\n cursor: pointer;\n}\n.mc-export-confirm {\n margin-top: 4px;\n width: 100%;\n background: var(--mc-accent, #007AFF);\n color: #fff;\n border: 0;\n border-radius: 4px;\n padding: 6px 10px;\n font: inherit;\n font-weight: 600;\n cursor: pointer;\n transition: background 120ms ease;\n}\n.mc-export-confirm:hover { background: #0066d6; }\n.mc-export-confirm:disabled { background: rgba(255,255,255,0.18); cursor: not-allowed; }\n\n.mc-export-overlay {\n position: absolute; inset: 0;\n background: rgba(0,0,0,0.7);\n display: flex; justify-content: center; align-items: center;\n z-index: 2;\n}\n.mc-export-panel {\n background: rgba(20,20,20,0.96); color: #fff;\n border-radius: 8px; padding: 16px 20px;\n text-align: center; min-width: 200px; max-width: 80%;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n}\n.mc-export-title { font-size: 13px; margin-bottom: 10px; opacity: 0.9; }\n.mc-export-track {\n width: 100%; height: 6px;\n background: rgba(255,255,255,0.15); border-radius: 3px;\n margin-bottom: 8px; overflow: hidden;\n}\n.mc-export-fill {\n height: 100%; width: 0%;\n background: linear-gradient(90deg, var(--mc-accent, #007AFF), var(--mc-accent, #0056CC));\n transition: width 0.3s ease; border-radius: 3px;\n}\n.mc-export-text {\n color: rgba(255,255,255,0.7); font-size: 11px;\n font-family: Menlo, Monaco, monospace;\n}\n";
|
|
8
8
|
declare function formatTime(seconds: number): string;
|
|
9
9
|
declare function frameToPercent(frame: number, totalFrames: number): number;
|
|
10
10
|
declare function pxToFrame(clientX: number, rect: {
|
|
@@ -42,6 +42,8 @@ interface ControllerOptions {
|
|
|
42
42
|
enableKeyboardShortcuts?: boolean;
|
|
43
43
|
/** A click (or tap) on the picture plays / pauses, like a `<video>` element. Default true; `false` leaves the canvas alone. */
|
|
44
44
|
clickToPlay?: boolean;
|
|
45
|
+
/** A movie with `stops` gets a Present button that starts a {@link Presenter} (keys, click and swipe move through the stops). Default true; `false` keeps only the marks on the seek bar. */
|
|
46
|
+
present?: boolean;
|
|
45
47
|
className?: string;
|
|
46
48
|
}
|
|
47
49
|
interface ResolvedOptions {
|
|
@@ -49,6 +51,7 @@ interface ResolvedOptions {
|
|
|
49
51
|
showExportButton: boolean;
|
|
50
52
|
enableKeyboardShortcuts: boolean;
|
|
51
53
|
clickToPlay: boolean;
|
|
54
|
+
present: boolean;
|
|
52
55
|
className: string;
|
|
53
56
|
}
|
|
54
57
|
declare class Controller {
|
|
@@ -91,6 +94,8 @@ declare class Controller {
|
|
|
91
94
|
private settingsKeyHandler;
|
|
92
95
|
private settingsOutsideHandler;
|
|
93
96
|
private onReady;
|
|
97
|
+
private presenter;
|
|
98
|
+
private presentBtn;
|
|
94
99
|
private onFrame;
|
|
95
100
|
private onPlay;
|
|
96
101
|
private onPause;
|
|
@@ -125,6 +130,11 @@ declare class Controller {
|
|
|
125
130
|
private fitWrap;
|
|
126
131
|
private bindFitWrap;
|
|
127
132
|
private bindMovieEvents;
|
|
133
|
+
/** The stops of a presentation as marks on the seek bar, and the Present button. */
|
|
134
|
+
private refreshStops;
|
|
135
|
+
/** Hand the page over to a Presenter (fullscreen, keys, click and swipe move through the stops); Escape gives it back. */
|
|
136
|
+
private startPresenting;
|
|
137
|
+
private stopPresenting;
|
|
128
138
|
private bindPlayButton;
|
|
129
139
|
/** Clicking the picture plays / pauses (a tap on a phone too). */
|
|
130
140
|
private bindCanvasClick;
|
package/dist/Controller.js
CHANGED
|
@@ -8,6 +8,7 @@ var ICONS = {
|
|
|
8
8
|
volumeOff: '<svg viewBox="0 0 16 16" width="16" height="16" fill="currentColor"><path d="M2 6 H5 L9 2 V14 L5 10 H2 Z"/><path d="M11 5 L15 11 M15 5 L11 11" fill="none" stroke="currentColor" stroke-width="1.4"/></svg>',
|
|
9
9
|
download: '<svg viewBox="0 0 16 16" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"><path d="M8 2 V11 M4 7 L8 11 L12 7 M3 13 H13"/></svg>',
|
|
10
10
|
fullscreenEnter: '<svg viewBox="0 0 16 16" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"><path d="M2 6 V2 H6 M14 6 V2 H10 M2 10 V14 H6 M14 10 V14 H10"/></svg>',
|
|
11
|
+
present: '<svg viewBox="0 0 16 16" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"><path d="M2 2.5 H14 V10.5 H2 Z M8 10.5 V13.5 M5 13.5 H11"/></svg>',
|
|
11
12
|
fullscreenExit: '<svg viewBox="0 0 16 16" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"><path d="M6 2 V6 H2 M10 2 V6 H14 M6 14 V10 H2 M10 14 V10 H14"/></svg>'
|
|
12
13
|
};
|
|
13
14
|
var STYLE_ATTR = "data-movie-controller";
|
|
@@ -45,6 +46,8 @@ var CONTROLLER_CSS = `
|
|
|
45
46
|
transition: height 120ms ease;
|
|
46
47
|
}
|
|
47
48
|
.mc-progress:hover::before, .mc-progress.mc-scrubbing::before { height: calc(var(--mc-track-height, 3px) + 2px); }
|
|
49
|
+
.mc-stops { position: absolute; left: 12px; right: 12px; top: 0; bottom: 0; pointer-events: none; }
|
|
50
|
+
.mc-stop-tick { position: absolute; top: 50%; width: 2px; height: calc(var(--mc-track-height, 3px) + 6px); transform: translate(-50%, -50%); background: var(--mc-fg, #fff); opacity: 0.6; border-radius: 1px; }
|
|
48
51
|
.mc-progress-fill {
|
|
49
52
|
position: absolute; left: 12px; top: 50%;
|
|
50
53
|
height: var(--mc-track-height, 3px);
|
|
@@ -321,6 +324,8 @@ var Controller = class _Controller {
|
|
|
321
324
|
settingsKeyHandler = null;
|
|
322
325
|
settingsOutsideHandler = null;
|
|
323
326
|
onReady = null;
|
|
327
|
+
presenter = null;
|
|
328
|
+
presentBtn = null;
|
|
324
329
|
onFrame = null;
|
|
325
330
|
onPlay = null;
|
|
326
331
|
onPause = null;
|
|
@@ -351,6 +356,7 @@ var Controller = class _Controller {
|
|
|
351
356
|
showExportButton: options.showExportButton ?? true,
|
|
352
357
|
enableKeyboardShortcuts: options.enableKeyboardShortcuts ?? true,
|
|
353
358
|
clickToPlay: options.clickToPlay ?? true,
|
|
359
|
+
present: options.present ?? true,
|
|
354
360
|
className: options.className ?? "movie-controller"
|
|
355
361
|
};
|
|
356
362
|
installStyles();
|
|
@@ -369,6 +375,7 @@ var Controller = class _Controller {
|
|
|
369
375
|
}
|
|
370
376
|
this.root.setAttribute("data-state", "visible");
|
|
371
377
|
this.bindMovieEvents();
|
|
378
|
+
this.refreshStops();
|
|
372
379
|
this.bindPlayButton();
|
|
373
380
|
if (this.options.clickToPlay) this.bindCanvasClick();
|
|
374
381
|
this.bindScrubbing();
|
|
@@ -526,6 +533,7 @@ var Controller = class _Controller {
|
|
|
526
533
|
this.refreshTime(0);
|
|
527
534
|
this.refreshProgress(0);
|
|
528
535
|
this.refreshVolumeUI();
|
|
536
|
+
this.refreshStops();
|
|
529
537
|
};
|
|
530
538
|
this.onFrame = ({ frame, totalFrames }) => {
|
|
531
539
|
if (!this.isScrubbing) {
|
|
@@ -552,6 +560,53 @@ var Controller = class _Controller {
|
|
|
552
560
|
this.movie.on("pause", this.onPause);
|
|
553
561
|
this.movie.on("progress", this.onProgress);
|
|
554
562
|
}
|
|
563
|
+
/** The stops of a presentation as marks on the seek bar, and the Present button. */
|
|
564
|
+
refreshStops() {
|
|
565
|
+
this.progressEl.querySelector(".mc-stops")?.remove();
|
|
566
|
+
const stops = this.movie.stops ?? [];
|
|
567
|
+
if (stops.length === 0) {
|
|
568
|
+
this.presentBtn?.remove();
|
|
569
|
+
this.presentBtn = null;
|
|
570
|
+
return;
|
|
571
|
+
}
|
|
572
|
+
const total = this.movie.totalFrames || 1;
|
|
573
|
+
const holder = document.createElement("div");
|
|
574
|
+
holder.className = "mc-stops";
|
|
575
|
+
for (const s of stops) {
|
|
576
|
+
const tick = document.createElement("div");
|
|
577
|
+
tick.className = "mc-stop-tick";
|
|
578
|
+
tick.style.left = `${s.frame / total * 100}%`;
|
|
579
|
+
if (s.page) tick.title = s.page;
|
|
580
|
+
holder.appendChild(tick);
|
|
581
|
+
}
|
|
582
|
+
this.progressEl.appendChild(holder);
|
|
583
|
+
if (this.options.present && !this.presentBtn && this.fullscreenBtn) {
|
|
584
|
+
const btn = document.createElement("button");
|
|
585
|
+
btn.className = "mc-btn mc-present";
|
|
586
|
+
btn.setAttribute("aria-label", "Present");
|
|
587
|
+
btn.title = "Present";
|
|
588
|
+
btn.innerHTML = ICONS.present;
|
|
589
|
+
btn.addEventListener("click", () => {
|
|
590
|
+
void this.startPresenting();
|
|
591
|
+
});
|
|
592
|
+
this.fullscreenBtn.parentElement?.insertBefore(btn, this.fullscreenBtn);
|
|
593
|
+
this.presentBtn = btn;
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
/** Hand the page over to a Presenter (fullscreen, keys, click and swipe move through the stops); Escape gives it back. */
|
|
597
|
+
async startPresenting() {
|
|
598
|
+
if (this.presenter || this.destroyed) return;
|
|
599
|
+
const { Presenter } = await import('./Presenter.js');
|
|
600
|
+
if (this.presenter || this.destroyed) return;
|
|
601
|
+
const p = new Presenter(this.movie, { canvas: this.options.canvas, onExit: () => this.stopPresenting() });
|
|
602
|
+
this.presenter = p;
|
|
603
|
+
await p.start();
|
|
604
|
+
}
|
|
605
|
+
stopPresenting() {
|
|
606
|
+
const p = this.presenter;
|
|
607
|
+
this.presenter = null;
|
|
608
|
+
p?.destroy();
|
|
609
|
+
}
|
|
555
610
|
bindPlayButton() {
|
|
556
611
|
this.playBtn.addEventListener("click", () => {
|
|
557
612
|
if (this.movie.isPlaying) {
|
|
@@ -570,6 +625,7 @@ var Controller = class _Controller {
|
|
|
570
625
|
this.swallowCanvasClick = false;
|
|
571
626
|
};
|
|
572
627
|
this.canvasClickHandler = () => {
|
|
628
|
+
if (this.presenter) return;
|
|
573
629
|
if (this.swallowCanvasClick) {
|
|
574
630
|
this.swallowCanvasClick = false;
|
|
575
631
|
return;
|
|
@@ -935,6 +991,7 @@ var Controller = class _Controller {
|
|
|
935
991
|
}
|
|
936
992
|
bindKeyboard() {
|
|
937
993
|
this.keyHandler = (e) => {
|
|
994
|
+
if (this.presenter) return;
|
|
938
995
|
const target = e.target;
|
|
939
996
|
if (target) {
|
|
940
997
|
const tag = target.tagName;
|
|
@@ -996,6 +1053,7 @@ var Controller = class _Controller {
|
|
|
996
1053
|
destroy() {
|
|
997
1054
|
if (this.destroyed) return;
|
|
998
1055
|
this.destroyed = true;
|
|
1056
|
+
this.stopPresenting();
|
|
999
1057
|
if (this.onReady) {
|
|
1000
1058
|
this.movie.off("ready", this.onReady);
|
|
1001
1059
|
this.onReady = null;
|