pixi-effects 0.9.0 → 0.10.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 +15 -0
- package/README.md +6 -6
- package/ai/SKILL.md +2 -1
- package/ai/reference/cheatsheet.md +13 -5
- package/ai/reference/pitfalls.md +2 -2
- package/ai/reference/recipes.md +123 -2
- package/ai/template.html +3 -3
- package/dist/{Base-CSIulyIq.d.cts → Base-CwUxTfja.d.cts} +1 -1
- package/dist/{Base-DVgwyIUj.d.ts → Base-CyvSLoCP.d.ts} +1 -1
- package/dist/Composition-EKVTUYCI.cjs +14 -0
- package/dist/{Composition-CM62XJKT.cjs.map → Composition-EKVTUYCI.cjs.map} +1 -1
- package/dist/Composition-NJCOMGD7.js +5 -0
- package/dist/{Composition-RJDSQYTV.js.map → Composition-NJCOMGD7.js.map} +1 -1
- package/dist/Controller.cjs +34 -0
- package/dist/Controller.cjs.map +1 -1
- package/dist/Controller.d.cts +12 -2
- package/dist/Controller.d.ts +12 -2
- package/dist/Controller.js +34 -0
- package/dist/Controller.js.map +1 -1
- package/dist/{Movie-QMlFyHkf.d.ts → Movie-puD9oZPg.d.ts} +1 -1
- package/dist/{Movie-qGHp15c_.d.cts → Movie-w3GliuP3.d.cts} +1 -1
- package/dist/{chunk-PDBDDGG5.cjs → chunk-4WJUSDJJ.cjs} +103 -30
- package/dist/chunk-4WJUSDJJ.cjs.map +1 -0
- package/dist/{chunk-FNKSXBKB.js → chunk-JAMNDBXW.js} +193 -14
- package/dist/chunk-JAMNDBXW.js.map +1 -0
- package/dist/{chunk-AGMNSJJH.cjs → chunk-S3ZI4MKS.cjs} +196 -12
- package/dist/chunk-S3ZI4MKS.cjs.map +1 -0
- package/dist/{chunk-O4AJYUPK.js → chunk-WDGAVOMS.js} +85 -12
- package/dist/chunk-WDGAVOMS.js.map +1 -0
- package/dist/index.cjs +309 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +231 -5
- package/dist/index.d.ts +231 -5
- package/dist/index.js +282 -11
- package/dist/index.js.map +1 -1
- 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-oJijbn-K.d.ts → types-BXu28nJj.d.cts} +26 -2
- package/dist/{types-oJijbn-K.d.cts → types-BXu28nJj.d.ts} +26 -2
- package/docs/api.md +1 -0
- package/docs/dsl.md +108 -2
- package/llms-full.txt +249 -12
- package/package.json +1 -1
- package/dist/Composition-CM62XJKT.cjs +0 -14
- package/dist/Composition-RJDSQYTV.js +0 -5
- package/dist/chunk-AGMNSJJH.cjs.map +0 -1
- package/dist/chunk-FNKSXBKB.js.map +0 -1
- package/dist/chunk-O4AJYUPK.js.map +0 -1
- package/dist/chunk-PDBDDGG5.cjs.map +0 -1
package/dist/Controller.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/Controller.ts"],"names":["warnUnknownOptions"],"mappings":"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","file":"Controller.cjs","sourcesContent":["import type { Movie } from './core/Movie';\nimport { warnUnknownOptions } from './core/options';\n\nconst ICONS = {\n play: '<svg viewBox=\"0 0 16 16\" width=\"16\" height=\"16\" fill=\"currentColor\"><path d=\"M3 2 L13 8 L3 14 Z\"/></svg>',\n pause: '<svg viewBox=\"0 0 16 16\" width=\"16\" height=\"16\" fill=\"currentColor\"><rect x=\"3\" y=\"2\" width=\"3.5\" height=\"12\"/><rect x=\"9.5\" y=\"2\" width=\"3.5\" height=\"12\"/></svg>',\n volumeOn: '<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 Q13 8 11 11\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.2\"/><path d=\"M12.5 3.5 Q15.5 8 12.5 12.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.2\"/></svg>',\n 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>',\n 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>',\n 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>',\n 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>',\n} as const;\n\nconst STYLE_ATTR = 'data-movie-controller';\n\n/** 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. */\nexport 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`;\n\nlet styleRefCount = 0;\n\nfunction installStyles(): void {\n if (styleRefCount === 0) {\n const el = document.createElement('style');\n el.setAttribute(STYLE_ATTR, '');\n el.textContent = CONTROLLER_CSS;\n document.head.appendChild(el);\n }\n styleRefCount++;\n}\n\nfunction uninstallStyles(): void {\n styleRefCount = Math.max(0, styleRefCount - 1);\n if (styleRefCount === 0) {\n document.head.querySelectorAll(`style[${STYLE_ATTR}]`).forEach((n) => n.remove());\n }\n}\n\nexport function formatTime(seconds: number): string {\n const s = Math.max(0, Math.floor(seconds));\n const m = Math.floor(s / 60);\n const r = s % 60;\n return `${m}:${r.toString().padStart(2, '0')}`;\n}\n\nexport function frameToPercent(frame: number, totalFrames: number): number {\n if (totalFrames <= 0) return 0;\n const f = Math.min(Math.max(frame, 0), totalFrames);\n return (f / totalFrames) * 100;\n}\n\nexport function pxToFrame(clientX: number, rect: { left: number; width: number }, totalFrames: number): number {\n if (rect.width <= 0 || totalFrames <= 0) return 0;\n const ratio = (clientX - rect.left) / rect.width;\n const clamped = Math.min(Math.max(ratio, 0), 1);\n return Math.round(clamped * totalFrames);\n}\n\nexport function pxToFraction(clientX: number, rect: { left: number; width: number }, inset = 0): number {\n const innerLeft = rect.left + inset;\n const innerWidth = Math.max(0, rect.width - 2 * inset);\n if (innerWidth <= 0) return 0;\n const ratio = (clientX - innerLeft) / innerWidth;\n return Math.min(Math.max(ratio, 0), 1);\n}\n\nexport function extensionForMimeType(mime: string): string {\n const t = (mime || '').toLowerCase();\n if (t.includes('webm')) return 'webm';\n if (t.includes('quicktime') || t.includes('mov')) return 'mov';\n if (t.includes('matroska') || t.includes('mkv')) return 'mkv';\n return 'mp4';\n}\n\n/**\n * 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\n * canvas's parent or on `:root`). `null` puts a value back to the default.\n */\nexport interface ControllerTheme {\n /** The colour of the progress bar, its thumb and the focus rings. Default `#007AFF` (blue). */\n accent?: string | null;\n /** Icons, the time and the volume slider. Default `#fff`. */\n foreground?: string | null;\n /** The unfilled part of the progress and volume bars. Default `rgba(255,255,255,0.25)`. */\n track?: string | null;\n /** The background behind the buttons: any CSS background, e.g. a gradient. Default: black fading to transparent upward. */\n barBackground?: string | null;\n /** Thickness of the progress bar in px (a number) or any CSS length. Default 3. */\n trackHeight?: number | string | null;\n /** `font-family` of the bar. */\n font?: string | null;\n}\n\nconst THEME_PROPERTIES: Record<keyof ControllerTheme, string> = {\n accent: '--mc-accent', foreground: '--mc-fg', track: '--mc-track', barBackground: '--mc-bar-bg', trackHeight: '--mc-track-height', font: '--mc-font',\n};\n\nexport interface ControllerOptions {\n canvas: HTMLCanvasElement;\n /** Colours and sizes of the bar, see {@link ControllerTheme}. Can be changed later with `controller.setTheme()`. */\n theme?: ControllerTheme;\n showExportButton?: boolean;\n enableKeyboardShortcuts?: boolean;\n className?: string;\n}\n\ninterface ResolvedOptions {\n canvas: HTMLCanvasElement;\n showExportButton: boolean;\n enableKeyboardShortcuts: boolean;\n className: string;\n}\n\nexport class Controller {\n movie: Movie;\n options: ResolvedOptions;\n\n private root: HTMLDivElement;\n private wrapper: HTMLDivElement;\n private wrappedHere = false;\n /** The canvas's own inline width / height, as the page wrote them (we override them while the wrapper is fitted). */\n private canvasInlineWidth = '';\n private canvasInlineHeight = '';\n private fitWrapHandler: (() => void) | null = null;\n private fitObserver: ResizeObserver | null = null;\n private destroyed = false;\n\n private progressEl!: HTMLDivElement;\n private progressFillEl!: HTMLDivElement;\n private progressThumbEl!: HTMLDivElement;\n private playBtn!: HTMLButtonElement;\n private muteBtn!: HTMLButtonElement;\n private timeEl!: HTMLSpanElement;\n private exportBtn: HTMLButtonElement | null = null;\n private settingsPopoverEl: HTMLDivElement | null = null;\n private settingsFormatSelect: HTMLSelectElement | null = null;\n private settingsQualitySelect: HTMLSelectElement | null = null;\n private exportConfirmBtn: HTMLButtonElement | null = null;\n private exportFormat: 'mp4' | 'webm' | 'mov' = 'mp4';\n private exportQuality: 'low' | 'medium' | 'high' | 'very-high' = 'high';\n private settingsOpen = false;\n private hideTimer: ReturnType<typeof setTimeout> | null = null;\n private static readonly HIDE_DELAY_MS = 2500;\n private static readonly PROGRESS_INSET_PX = 12;\n private isScrubbing = false;\n private wasPlayingBeforeScrub = false;\n private activePointerId: number | null = null;\n private isExporting = false;\n private exportOverlay: HTMLDivElement | null = null;\n private exportFillEl: HTMLDivElement | null = null;\n private exportTextEl: HTMLDivElement | null = null;\n private keyHandler: ((e: KeyboardEvent) => void) | null = null;\n private settingsKeyHandler: ((e: KeyboardEvent) => void) | null = null;\n private settingsOutsideHandler: ((e: PointerEvent) => void) | null = null;\n private onReady: (() => void) | null = null;\n private onFrame: ((e: { frame: number; totalFrames: number }) => void) | null = null;\n private onPlay: (() => void) | null = null;\n private onPause: (() => void) | null = null;\n private onProgress: ((e: { progress: number; frame: number; totalFrames: number }) => void) | null = null;\n private onWrapPointerMove: (() => void) | null = null;\n private onWrapMouseLeave: (() => void) | null = null;\n private resizeObserver: ResizeObserver | null = null;\n private volumeSliderEl: HTMLDivElement | null = null;\n private volumeContainerEl: HTMLDivElement | null = null;\n private fullscreenBtn: HTMLButtonElement | null = null;\n private isVolumeScrubbing = false;\n private fullscreenChangeHandler: (() => void) | null = null;\n private wheelHandler: ((e: WheelEvent) => void) | null = null;\n /** Ends a drag the pointerup of which never arrives (see bindScrubbing). */\n private windowBlurHandler: (() => void) | null = null;\n\n constructor(movie: Movie, options: ControllerOptions) {\n if (!options || !options.canvas) {\n throw new Error('Controller requires options.canvas (HTMLCanvasElement).');\n }\n this.movie = movie;\n this.options = {\n canvas: options.canvas,\n showExportButton: options.showExportButton ?? true,\n enableKeyboardShortcuts: options.enableKeyboardShortcuts ?? true,\n className: options.className ?? 'movie-controller',\n };\n\n installStyles();\n this.wrapper = this.ensurePositioningContext(this.options.canvas);\n this.root = document.createElement('div');\n this.root.className = this.options.className;\n this.wrapper.appendChild(this.root);\n this.buildBar();\n this.setTheme(options.theme ?? {});\n this.bindFitWrap();\n this.syncRootToCanvas();\n if (typeof ResizeObserver !== 'undefined') {\n this.resizeObserver = new ResizeObserver(() => this.syncRootToCanvas());\n this.resizeObserver.observe(this.options.canvas);\n // Also observe the wrapper: when its size changes (browser resize, sibling\n // panels resizing) the canvas's position can shift without its own size\n // changing, which canvas-only observation would miss.\n this.resizeObserver.observe(this.wrapper);\n }\n this.root.setAttribute('data-state', 'visible');\n this.bindMovieEvents();\n this.bindPlayButton();\n this.bindScrubbing();\n this.bindMuteButton();\n this.bindVolumeSlider();\n this.bindExportPopover();\n this.bindFullscreen();\n this.bindVisibility();\n if (this.options.enableKeyboardShortcuts) this.bindKeyboard();\n }\n\n private buildBar(): void {\n const popoverHtml = this.options.showExportButton ? `\n <div class=\"mc-settings-popover\" role=\"dialog\" aria-label=\"Export settings\" data-open=\"false\">\n <label class=\"mc-settings-row\">\n <span>Format</span>\n <select class=\"mc-settings-format\">\n <option value=\"mp4\">MP4</option>\n <option value=\"webm\">WebM</option>\n <option value=\"mov\">MOV</option>\n </select>\n </label>\n <label class=\"mc-settings-row\">\n <span>Quality</span>\n <select class=\"mc-settings-quality\">\n <option value=\"low\">Low</option>\n <option value=\"medium\">Medium</option>\n <option value=\"high\" selected>High</option>\n <option value=\"very-high\">Very High</option>\n </select>\n </label>\n <button type=\"button\" class=\"mc-export-confirm\">Download</button>\n </div>\n ` : '';\n this.root.innerHTML = `\n <div class=\"mc-progress\" role=\"slider\" tabindex=\"0\" aria-label=\"Seek\" aria-valuemin=\"0\" aria-valuemax=\"${this.movie.totalFrames}\" aria-valuenow=\"0\">\n <div class=\"mc-progress-fill\"></div>\n <div class=\"mc-progress-thumb\"></div>\n </div>\n <div class=\"mc-bar\">\n ${popoverHtml}\n <button class=\"mc-btn mc-play\" aria-label=\"Play\">${ICONS.play}</button>\n <div class=\"mc-volume\">\n <button class=\"mc-btn mc-mute\" aria-label=\"Mute\">${ICONS.volumeOn}</button>\n <div class=\"mc-vol-slider\" role=\"slider\" tabindex=\"0\" aria-label=\"Volume\" aria-valuemin=\"0\" aria-valuemax=\"100\" aria-valuenow=\"100\">\n <div class=\"mc-vol-fill\"></div>\n <div class=\"mc-vol-thumb\"></div>\n </div>\n </div>\n <span class=\"mc-time\">0:00 / 0:00</span>\n <div class=\"mc-spacer\"></div>\n ${this.options.showExportButton ? `<button class=\"mc-btn mc-export\" aria-label=\"Export\" aria-expanded=\"false\">${ICONS.download}</button>` : ''}\n <button class=\"mc-btn mc-fullscreen\" aria-label=\"Enter fullscreen\">${ICONS.fullscreenEnter}</button>\n </div>\n `;\n this.progressEl = this.root.querySelector('.mc-progress') as HTMLDivElement;\n this.progressFillEl = this.root.querySelector('.mc-progress-fill') as HTMLDivElement;\n this.progressThumbEl = this.root.querySelector('.mc-progress-thumb') as HTMLDivElement;\n this.playBtn = this.root.querySelector('.mc-play') as HTMLButtonElement;\n this.muteBtn = this.root.querySelector('.mc-mute') as HTMLButtonElement;\n this.timeEl = this.root.querySelector('.mc-time') as HTMLSpanElement;\n this.exportBtn = this.root.querySelector('.mc-export') as HTMLButtonElement | null;\n this.settingsPopoverEl = this.root.querySelector('.mc-settings-popover') as HTMLDivElement | null;\n this.settingsFormatSelect = this.root.querySelector('.mc-settings-format') as HTMLSelectElement | null;\n this.settingsQualitySelect = this.root.querySelector('.mc-settings-quality') as HTMLSelectElement | null;\n this.exportConfirmBtn = this.root.querySelector('.mc-export-confirm') as HTMLButtonElement | null;\n this.volumeSliderEl = this.root.querySelector('.mc-vol-slider') as HTMLDivElement | null;\n this.volumeContainerEl = this.root.querySelector('.mc-volume') as HTMLDivElement | null;\n this.fullscreenBtn = this.root.querySelector('.mc-fullscreen') as HTMLButtonElement | null;\n if (this.settingsFormatSelect) this.settingsFormatSelect.value = this.exportFormat;\n if (this.settingsQualitySelect) this.settingsQualitySelect.value = this.exportQuality;\n }\n\n /** Change the look of the bar (see {@link ControllerTheme}): only the keys you give change, `null` restores the default. */\n setTheme(theme: ControllerTheme): void {\n warnUnknownOptions('Controller theme', theme as Record<string, unknown>, Object.keys(THEME_PROPERTIES));\n for (const key of Object.keys(THEME_PROPERTIES) as Array<keyof ControllerTheme>) {\n if (!(key in theme)) continue;\n const value = theme[key];\n const prop = THEME_PROPERTIES[key];\n if (value === null || value === undefined || value === '') this.root.style.removeProperty(prop);\n else this.root.style.setProperty(prop, typeof value === 'number' ? `${value}px` : String(value));\n }\n }\n\n private ensurePositioningContext(canvas: HTMLCanvasElement): HTMLDivElement {\n const parent = canvas.parentElement;\n if (!parent) {\n throw new Error('Controller: canvas must be attached to the DOM before constructing.');\n }\n const pos = getComputedStyle(parent).position;\n if (pos === 'relative' || pos === 'absolute' || pos === 'fixed' || pos === 'sticky') {\n // Tag the user's element so the [data-mc-wrap]:fullscreen style hooks apply\n // to it the same way they apply to our auto-wrap. Cleaned up on destroy.\n parent.setAttribute('data-mc-wrap', '');\n return parent as HTMLDivElement;\n }\n const wrap = document.createElement('div');\n wrap.className = 'movie-controller-wrap';\n wrap.setAttribute('data-mc-wrap', '');\n wrap.style.position = 'relative';\n wrap.style.display = 'inline-block';\n wrap.style.lineHeight = '0';\n parent.insertBefore(wrap, canvas);\n wrap.appendChild(canvas);\n this.wrappedHere = true;\n this.canvasInlineWidth = canvas.style.width;\n this.canvasInlineHeight = canvas.style.height;\n\n return wrap;\n }\n\n /**\n * Make the wrapper exactly as wide as the canvas. A shrink-to-fit wrapper around a canvas that is sized in percent (the usual\n * `canvas { width: min(960px, 100%) }`) is as wide as the canvas's width ATTRIBUTE (1280), so the picture sat at its left edge\n * with an empty strip beside it. We measure the canvas as the page styled it (the wrapper made transparent to layout), give\n * the wrapper that width, and let the canvas fill the wrapper. Re-measured when the window or the page's box changes.\n */\n private fitWrap(): void {\n if (!this.wrappedHere) return;\n const wrap = this.wrapper, canvas = this.options.canvas;\n if (document.fullscreenElement === wrap) { // the fullscreen CSS owns the size\n wrap.style.width = '';\n canvas.style.width = this.canvasInlineWidth; canvas.style.height = this.canvasInlineHeight;\n return;\n }\n canvas.style.width = this.canvasInlineWidth; canvas.style.height = this.canvasInlineHeight;\n const display = wrap.style.display;\n wrap.style.display = 'contents'; wrap.style.width = '';\n const w = canvas.getBoundingClientRect().width;\n wrap.style.display = display;\n if (!(w > 0)) return;\n wrap.style.width = `${w}px`;\n canvas.style.width = '100%'; canvas.style.height = 'auto';\n }\n\n private bindFitWrap(): void {\n if (!this.wrappedHere) return;\n this.fitWrap();\n let queued = false;\n this.fitWrapHandler = () => {\n if (queued) return;\n queued = true;\n requestAnimationFrame(() => { queued = false; this.fitWrap(); });\n };\n window.addEventListener('resize', this.fitWrapHandler);\n const parent = this.wrapper.parentElement;\n if (parent && typeof ResizeObserver !== 'undefined') {\n this.fitObserver = new ResizeObserver(this.fitWrapHandler);\n this.fitObserver.observe(parent);\n }\n }\n\n private bindMovieEvents(): void {\n this.onReady = () => {\n this.progressEl.setAttribute('aria-valuemax', String(this.movie.totalFrames));\n this.refreshTime(0);\n this.refreshProgress(0);\n this.refreshVolumeUI();\n };\n this.onFrame = ({ frame, totalFrames }) => {\n if (!this.isScrubbing) {\n this.refreshProgress(frame, totalFrames);\n }\n this.refreshTime(frame);\n };\n // `movie.play()` may be called by the host page, not only by this bar's button.\n this.onPlay = () => {\n this.refreshPlayIcon();\n this.kickIdleTimer();\n };\n this.onPause = () => {\n this.refreshPlayIcon();\n // YouTube-style: pause shows the bar momentarily, then auto-hides on idle.\n this.kickIdleTimer();\n };\n this.onProgress = ({ progress, frame, totalFrames }) => {\n if (!this.isExporting || !this.exportFillEl || !this.exportTextEl) return;\n this.exportFillEl.style.width = `${progress}%`;\n this.exportTextEl.textContent = `${progress}% (${frame} / ${totalFrames} frames)`;\n };\n this.movie.on('ready', this.onReady);\n this.movie.on('frame', this.onFrame);\n this.movie.on('play', this.onPlay);\n this.movie.on('pause', this.onPause);\n this.movie.on('progress', this.onProgress);\n }\n\n private bindPlayButton(): void {\n this.playBtn.addEventListener('click', () => {\n if (this.movie.isPlaying) {\n this.movie.pause();\n // movie.pause() emits 'pause' which the onPause handler turns into\n // refreshPlayIcon + kickIdleTimer, so no extra work here.\n } else {\n this.movie.play();\n // movie.play() emits 'play' (the onPlay handler refreshes the icon), same as 'pause' above.\n }\n });\n }\n\n private refreshPlayIcon(): void {\n this.playBtn.innerHTML = this.movie.isPlaying ? ICONS.pause : ICONS.play;\n this.playBtn.setAttribute('aria-label', this.movie.isPlaying ? 'Pause' : 'Play');\n }\n\n private bindMuteButton(): void {\n this.muteBtn.addEventListener('click', () => {\n this.movie.toggleMute();\n this.refreshVolumeUI();\n });\n }\n\n private refreshMuteIcon(): void {\n const silent = this.movie.muted || this.movie.volume <= 0;\n this.muteBtn.innerHTML = silent ? ICONS.volumeOff : ICONS.volumeOn;\n this.muteBtn.setAttribute('aria-label', silent ? 'Unmute' : 'Mute');\n }\n\n private refreshVolumeUI(): void {\n this.refreshMuteIcon();\n if (!this.volumeSliderEl) return;\n const effective = this.movie.muted ? 0 : this.movie.volume;\n this.volumeSliderEl.style.setProperty('--mc-volume', String(effective));\n this.volumeSliderEl.setAttribute('aria-valuenow', String(Math.round(effective * 100)));\n }\n\n private bindVolumeSlider(): void {\n if (!this.volumeSliderEl || !this.volumeContainerEl) return;\n const slider = this.volumeSliderEl;\n const container = this.volumeContainerEl;\n\n const setFromPointer = (clientX: number) => {\n const rect = slider.getBoundingClientRect();\n const v = pxToFraction(clientX, { left: rect.left, width: rect.width }, 4);\n this.movie.volume = v;\n if (this.movie.muted && v > 0) this.movie.muted = false;\n this.refreshVolumeUI();\n };\n\n const onDown = (e: PointerEvent) => {\n this.isVolumeScrubbing = true;\n slider.classList.add('mc-scrubbing');\n try { slider.setPointerCapture(e.pointerId); } catch { /* unsupported */ }\n setFromPointer(e.clientX);\n };\n const finish = (pointerId?: number) => {\n if (!this.isVolumeScrubbing) return;\n this.isVolumeScrubbing = false;\n slider.classList.remove('mc-scrubbing');\n try { if (pointerId !== undefined) slider.releasePointerCapture(pointerId); } catch { /* unsupported */ }\n };\n const onMove = (e: PointerEvent) => {\n if (!this.isVolumeScrubbing) return;\n if (e.buttons === 0) { finish(e.pointerId); return; } // released outside an iframe: see bindScrubbing\n setFromPointer(e.clientX);\n };\n const onUp = (e: PointerEvent) => finish(e.pointerId);\n slider.addEventListener('pointerdown', onDown);\n slider.addEventListener('pointermove', onMove);\n slider.addEventListener('pointerup', onUp);\n slider.addEventListener('pointercancel', onUp);\n slider.addEventListener('lostpointercapture', () => finish());\n\n this.wheelHandler = (e: WheelEvent) => {\n e.preventDefault();\n this.adjustVolume(e.deltaY < 0 ? 0.05 : -0.05);\n };\n container.addEventListener('wheel', this.wheelHandler, { passive: false });\n }\n\n /**\n * Does this browser have the Fullscreen API for an element? iPhone Safari does not (it can only put a <video> in fullscreen),\n * and a button that does nothing is worse than none.\n */\n private supportsFullscreen(): boolean {\n return typeof (this.wrapper as { requestFullscreen?: unknown }).requestFullscreen === 'function' && document.fullscreenEnabled !== false;\n }\n\n private bindFullscreen(): void {\n if (!this.fullscreenBtn) return;\n if (!this.supportsFullscreen()) {\n this.fullscreenBtn.remove();\n this.fullscreenBtn = null; // the F key checks this too\n return;\n }\n this.fullscreenBtn.addEventListener('click', () => {\n void this.toggleFullscreen();\n });\n this.fullscreenChangeHandler = () => {\n this.fitWrap();\n this.refreshFullscreenIcon();\n // Fullscreen reflow can shift the canvas without changing its size, which\n // ResizeObserver would miss; resync the overlay explicitly.\n this.syncRootToCanvas();\n };\n document.addEventListener('fullscreenchange', this.fullscreenChangeHandler);\n }\n\n private async toggleFullscreen(): Promise<void> {\n try {\n if (document.fullscreenElement === this.wrapper) {\n await document.exitFullscreen();\n } else {\n await this.wrapper.requestFullscreen();\n }\n } catch (err) {\n console.warn('pixi-effects: fullscreen denied:', err);\n }\n }\n\n private refreshFullscreenIcon(): void {\n if (!this.fullscreenBtn) return;\n const inFs = document.fullscreenElement === this.wrapper;\n this.fullscreenBtn.innerHTML = inFs ? ICONS.fullscreenExit : ICONS.fullscreenEnter;\n this.fullscreenBtn.setAttribute('aria-label', inFs ? 'Exit fullscreen' : 'Enter fullscreen');\n }\n\n private refreshProgress(frame: number, totalFrames?: number): void {\n const total = totalFrames ?? this.movie.totalFrames;\n const pct = frameToPercent(frame, total);\n this.progressEl.style.setProperty('--mc-fill', String(pct / 100));\n this.progressEl.setAttribute('aria-valuenow', String(frame));\n }\n\n private refreshTime(frame: number): void {\n const fr = this.movie.frameRate || 1;\n const cur = frame / fr;\n const total = this.movie.totalFrames / fr;\n this.timeEl.textContent = `${formatTime(cur)} / ${formatTime(total)}`;\n }\n\n private bindScrubbing(): void {\n const onDown = (e: PointerEvent) => {\n this.isScrubbing = true;\n this.activePointerId = e.pointerId;\n this.wasPlayingBeforeScrub = this.movie.isPlaying;\n if (this.movie.isPlaying) {\n this.movie.pause();\n this.refreshPlayIcon();\n }\n this.progressEl.classList.add('mc-scrubbing');\n try { this.progressEl.setPointerCapture(e.pointerId); } catch { /* unsupported */ }\n this.seekFromPointer(e.clientX);\n };\n // End the drag. `clientX` is given when the pointer was released over the bar (seek to where it was).\n // A page inside an iframe never receives the pointerup of a button released OUTSIDE the iframe, so the\n // drag also ends on lostpointercapture, on the window losing focus, and on the first pointermove that\n // has no button down — otherwise it stayed \"scrubbing\" (paused, seeking on every hover).\n const finish = (clientX?: number, pointerId?: number) => {\n if (!this.isScrubbing) return;\n if (clientX !== undefined) this.seekFromPointer(clientX);\n this.isScrubbing = false;\n this.activePointerId = null;\n this.progressEl.classList.remove('mc-scrubbing');\n try { if (pointerId !== undefined) this.progressEl.releasePointerCapture(pointerId); } catch { /* unsupported */ }\n if (this.wasPlayingBeforeScrub) {\n this.movie.play();\n this.refreshPlayIcon();\n }\n };\n const onMove = (e: PointerEvent) => {\n if (!this.isScrubbing) return;\n if (e.buttons === 0) { finish(undefined, e.pointerId); return; }\n this.seekFromPointer(e.clientX);\n };\n const onUp = (e: PointerEvent) => finish(e.clientX, e.pointerId);\n this.progressEl.addEventListener('pointerdown', onDown);\n this.progressEl.addEventListener('pointermove', onMove);\n this.progressEl.addEventListener('pointerup', onUp);\n this.progressEl.addEventListener('pointercancel', onUp);\n this.progressEl.addEventListener('lostpointercapture', () => finish());\n this.windowBlurHandler = () => { finish(); this.isVolumeScrubbing = false; this.volumeSliderEl?.classList.remove('mc-scrubbing'); };\n window.addEventListener('blur', this.windowBlurHandler);\n }\n\n private seekFromPointer(clientX: number): void {\n const rect = this.progressEl.getBoundingClientRect();\n const inset = Controller.PROGRESS_INSET_PX;\n const innerLeft = rect.left + inset;\n const innerWidth = Math.max(0, rect.width - 2 * inset);\n const frame = pxToFrame(clientX, { left: innerLeft, width: innerWidth }, this.movie.totalFrames);\n this.refreshProgress(frame);\n void this.movie.gotoFrame(frame);\n }\n\n private bindExportPopover(): void {\n if (!this.exportBtn || !this.settingsPopoverEl) return;\n\n // Download icon on the bar toggles the popover (it does NOT directly trigger export).\n this.exportBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n this.toggleSettings(!this.settingsOpen);\n });\n\n // Confirm button inside the popover triggers the actual export, then closes.\n if (this.exportConfirmBtn) {\n this.exportConfirmBtn.addEventListener('click', () => {\n this.toggleSettings(false);\n void this.handleExport();\n });\n }\n\n if (this.settingsFormatSelect) {\n this.settingsFormatSelect.addEventListener('change', (e) => {\n const v = (e.target as HTMLSelectElement).value;\n if (v === 'mp4' || v === 'webm' || v === 'mov') this.exportFormat = v;\n });\n }\n if (this.settingsQualitySelect) {\n this.settingsQualitySelect.addEventListener('change', (e) => {\n const v = (e.target as HTMLSelectElement).value;\n if (v === 'low' || v === 'medium' || v === 'high' || v === 'very-high') this.exportQuality = v;\n });\n }\n\n this.settingsKeyHandler = (e: KeyboardEvent) => {\n if (e.code === 'Escape' && this.settingsOpen) {\n e.preventDefault();\n this.toggleSettings(false);\n }\n };\n document.addEventListener('keydown', this.settingsKeyHandler);\n\n this.settingsOutsideHandler = (e: PointerEvent) => {\n if (!this.settingsOpen) return;\n const target = e.target as Node | null;\n if (!target) return;\n if (this.settingsPopoverEl?.contains(target)) return;\n if (this.exportBtn?.contains(target)) return;\n this.toggleSettings(false);\n };\n document.addEventListener('pointerdown', this.settingsOutsideHandler);\n }\n\n private toggleSettings(open: boolean): void {\n if (!this.exportBtn || !this.settingsPopoverEl) return;\n this.settingsOpen = open;\n this.settingsPopoverEl.setAttribute('data-open', open ? 'true' : 'false');\n this.exportBtn.setAttribute('aria-expanded', open ? 'true' : 'false');\n if (open) {\n // Keep the bar visible while the popover is open.\n if (this.hideTimer) { clearTimeout(this.hideTimer); this.hideTimer = null; }\n this.setVisible(true);\n } else {\n // Resume normal auto-hide cadence after closing.\n this.kickIdleTimer();\n }\n }\n\n private async handleExport(): Promise<void> {\n if (this.isExporting) return;\n this.isExporting = true;\n const wasPlaying = this.movie.isPlaying;\n if (wasPlaying) {\n this.movie.pause();\n this.refreshPlayIcon();\n }\n this.showExportOverlay();\n try {\n const blob = await this.movie.render({\n format: this.exportFormat,\n video: { bitrate: this.exportQuality },\n audio: { bitrate: this.exportQuality },\n });\n if (this.exportFillEl) this.exportFillEl.style.width = '100%';\n if (this.exportTextEl) this.exportTextEl.textContent = 'Preparing download...';\n this.triggerDownload(blob);\n await new Promise((r) => setTimeout(r, 300));\n } catch (err) {\n console.error('Export failed:', err);\n alert('Export failed.');\n } finally {\n this.hideExportOverlay();\n this.isExporting = false;\n if (wasPlaying) {\n this.movie.play();\n this.refreshPlayIcon();\n }\n }\n }\n\n private triggerDownload(blob: Blob): void {\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = this.makeFilename(blob);\n a.style.display = 'none';\n document.body.appendChild(a);\n a.click();\n a.remove();\n setTimeout(() => URL.revokeObjectURL(url), 100);\n }\n\n private makeFilename(blob: Blob): string {\n const ext = extensionForMimeType(blob.type);\n const d = new Date();\n const pad = (n: number) => n.toString().padStart(2, '0');\n const ts = `${d.getFullYear()}${pad(d.getMonth() + 1)}${pad(d.getDate())}-${pad(d.getHours())}${pad(d.getMinutes())}${pad(d.getSeconds())}`;\n return `movie-${ts}.${ext}`;\n }\n\n private showExportOverlay(): void {\n const overlay = document.createElement('div');\n overlay.className = 'mc-export-overlay';\n overlay.innerHTML = `\n <div class=\"mc-export-panel\">\n <div class=\"mc-export-title\">Exporting video...</div>\n <div class=\"mc-export-track\"><div class=\"mc-export-fill\"></div></div>\n <div class=\"mc-export-text\">0% (0 / 0 frames)</div>\n </div>\n `;\n this.root.appendChild(overlay);\n this.exportOverlay = overlay;\n this.exportFillEl = overlay.querySelector('.mc-export-fill') as HTMLDivElement;\n this.exportTextEl = overlay.querySelector('.mc-export-text') as HTMLDivElement;\n }\n\n private hideExportOverlay(): void {\n if (this.exportOverlay) {\n this.exportOverlay.remove();\n this.exportOverlay = null;\n this.exportFillEl = null;\n this.exportTextEl = null;\n }\n }\n\n private bindVisibility(): void {\n const wrap = this.wrapper;\n this.onWrapPointerMove = () => this.kickIdleTimer();\n this.onWrapMouseLeave = () => {\n if (!this.settingsOpen && !this.isScrubbing && !this.isVolumeScrubbing) this.setVisible(false);\n };\n wrap.addEventListener('pointermove', this.onWrapPointerMove);\n wrap.addEventListener('mouseleave', this.onWrapMouseLeave);\n this.root.addEventListener('pointerenter', () => {\n if (this.hideTimer) { clearTimeout(this.hideTimer); this.hideTimer = null; }\n this.setVisible(true);\n });\n }\n\n private kickIdleTimer(): void {\n this.setVisible(true);\n if (this.hideTimer) { clearTimeout(this.hideTimer); this.hideTimer = null; }\n if (this.settingsOpen) return;\n this.hideTimer = setTimeout(() => {\n if (!this.isScrubbing && !this.isVolumeScrubbing && !this.settingsOpen) this.setVisible(false);\n }, Controller.HIDE_DELAY_MS);\n }\n\n private setVisible(v: boolean): void {\n this.root.setAttribute('data-state', v ? 'visible' : 'hidden');\n }\n\n private syncRootToCanvas(): void {\n const c = this.options.canvas;\n const cr = c.getBoundingClientRect();\n const wr = this.wrapper.getBoundingClientRect();\n this.root.style.left = `${cr.left - wr.left}px`;\n this.root.style.top = `${cr.top - wr.top}px`;\n this.root.style.width = `${cr.width}px`;\n this.root.style.height = `${cr.height}px`;\n }\n\n private bindKeyboard(): void {\n this.keyHandler = (e: KeyboardEvent) => {\n const target = e.target as HTMLElement | null;\n if (target) {\n const tag = target.tagName;\n if (tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT') return;\n if (target.isContentEditable || target.getAttribute?.('contenteditable') === 'true') return;\n }\n if (this.isExporting) return;\n\n switch (e.code) {\n case 'Space':\n e.preventDefault();\n this.playBtn.click();\n break;\n case 'ArrowLeft':\n e.preventDefault();\n this.stepFrame(-1);\n break;\n case 'ArrowRight':\n e.preventDefault();\n this.stepFrame(1);\n break;\n case 'ArrowUp':\n e.preventDefault();\n this.adjustVolume(0.05);\n break;\n case 'ArrowDown':\n e.preventDefault();\n this.adjustVolume(-0.05);\n break;\n case 'KeyM':\n e.preventDefault();\n this.muteBtn.click();\n break;\n case 'KeyE':\n if (e.shiftKey && this.exportBtn) {\n e.preventDefault();\n // Power-user shortcut: skip the popover and export with current settings.\n void this.handleExport();\n }\n break;\n case 'KeyF':\n if (this.fullscreenBtn) {\n e.preventDefault();\n void this.toggleFullscreen();\n }\n break;\n }\n };\n document.addEventListener('keydown', this.keyHandler);\n }\n\n private stepFrame(delta: number): void {\n const next = Math.max(0, Math.min(this.movie.totalFrames, this.movie.currentFrame + delta));\n void this.movie.gotoFrame(next);\n }\n\n private adjustVolume(delta: number): void {\n const next = Math.max(0, Math.min(1, this.movie.volume + delta));\n this.movie.volume = next;\n if (this.movie.muted && next > 0) this.movie.muted = false;\n this.refreshVolumeUI();\n }\n\n destroy(): void {\n if (this.destroyed) return;\n this.destroyed = true;\n if (this.onReady) { this.movie.off('ready', this.onReady); this.onReady = null; }\n if (this.onFrame) { this.movie.off('frame', this.onFrame); this.onFrame = null; }\n if (this.onPlay) { this.movie.off('play', this.onPlay); this.onPlay = null; }\n if (this.onPause) { this.movie.off('pause', this.onPause); this.onPause = null; }\n if (this.onProgress) { this.movie.off('progress', this.onProgress); this.onProgress = null; }\n if (this.onWrapPointerMove) {\n this.wrapper.removeEventListener('pointermove', this.onWrapPointerMove);\n this.onWrapPointerMove = null;\n }\n if (this.onWrapMouseLeave) {\n this.wrapper.removeEventListener('mouseleave', this.onWrapMouseLeave);\n this.onWrapMouseLeave = null;\n }\n if (this.resizeObserver) {\n this.resizeObserver.disconnect();\n this.resizeObserver = null;\n }\n if (this.fitObserver) { this.fitObserver.disconnect(); this.fitObserver = null; }\n if (this.fitWrapHandler) { window.removeEventListener('resize', this.fitWrapHandler); this.fitWrapHandler = null; }\n if (this.wrappedHere) { // give the canvas its own sizing back\n this.options.canvas.style.width = this.canvasInlineWidth;\n this.options.canvas.style.height = this.canvasInlineHeight;\n }\n this.root.remove();\n if (this.wrappedHere) {\n const parent = this.wrapper.parentElement;\n const canvas = this.options.canvas;\n if (parent) {\n parent.insertBefore(canvas, this.wrapper);\n this.wrapper.remove();\n }\n } else {\n this.wrapper.removeAttribute('data-mc-wrap');\n }\n if (this.keyHandler) {\n document.removeEventListener('keydown', this.keyHandler);\n this.keyHandler = null;\n }\n if (this.settingsKeyHandler) {\n document.removeEventListener('keydown', this.settingsKeyHandler);\n this.settingsKeyHandler = null;\n }\n if (this.settingsOutsideHandler) {\n document.removeEventListener('pointerdown', this.settingsOutsideHandler);\n this.settingsOutsideHandler = null;\n }\n if (this.fullscreenChangeHandler) {\n document.removeEventListener('fullscreenchange', this.fullscreenChangeHandler);\n this.fullscreenChangeHandler = null;\n }\n if (this.windowBlurHandler) {\n window.removeEventListener('blur', this.windowBlurHandler);\n this.windowBlurHandler = null;\n }\n if (this.wheelHandler && this.volumeContainerEl) {\n this.volumeContainerEl.removeEventListener('wheel', this.wheelHandler);\n this.wheelHandler = null;\n }\n if (document.fullscreenElement === this.wrapper) {\n void document.exitFullscreen().catch(() => {});\n }\n if (this.hideTimer) { clearTimeout(this.hideTimer); this.hideTimer = null; }\n this.hideExportOverlay();\n uninstallStyles();\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/Controller.ts"],"names":["warnUnknownOptions"],"mappings":"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","file":"Controller.cjs","sourcesContent":["import type { Movie } from './core/Movie';\nimport { warnUnknownOptions } from './core/options';\n\nconst ICONS = {\n play: '<svg viewBox=\"0 0 16 16\" width=\"16\" height=\"16\" fill=\"currentColor\"><path d=\"M3 2 L13 8 L3 14 Z\"/></svg>',\n pause: '<svg viewBox=\"0 0 16 16\" width=\"16\" height=\"16\" fill=\"currentColor\"><rect x=\"3\" y=\"2\" width=\"3.5\" height=\"12\"/><rect x=\"9.5\" y=\"2\" width=\"3.5\" height=\"12\"/></svg>',\n volumeOn: '<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 Q13 8 11 11\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.2\"/><path d=\"M12.5 3.5 Q15.5 8 12.5 12.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.2\"/></svg>',\n 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>',\n 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>',\n 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>',\n 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>',\n} as const;\n\nconst STYLE_ATTR = 'data-movie-controller';\n\n/** 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. */\nexport 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`;\n\nlet styleRefCount = 0;\n\nfunction installStyles(): void {\n if (styleRefCount === 0) {\n const el = document.createElement('style');\n el.setAttribute(STYLE_ATTR, '');\n el.textContent = CONTROLLER_CSS;\n document.head.appendChild(el);\n }\n styleRefCount++;\n}\n\nfunction uninstallStyles(): void {\n styleRefCount = Math.max(0, styleRefCount - 1);\n if (styleRefCount === 0) {\n document.head.querySelectorAll(`style[${STYLE_ATTR}]`).forEach((n) => n.remove());\n }\n}\n\nexport function formatTime(seconds: number): string {\n const s = Math.max(0, Math.floor(seconds));\n const m = Math.floor(s / 60);\n const r = s % 60;\n return `${m}:${r.toString().padStart(2, '0')}`;\n}\n\nexport function frameToPercent(frame: number, totalFrames: number): number {\n if (totalFrames <= 0) return 0;\n const f = Math.min(Math.max(frame, 0), totalFrames);\n return (f / totalFrames) * 100;\n}\n\nexport function pxToFrame(clientX: number, rect: { left: number; width: number }, totalFrames: number): number {\n if (rect.width <= 0 || totalFrames <= 0) return 0;\n const ratio = (clientX - rect.left) / rect.width;\n const clamped = Math.min(Math.max(ratio, 0), 1);\n return Math.round(clamped * totalFrames);\n}\n\nexport function pxToFraction(clientX: number, rect: { left: number; width: number }, inset = 0): number {\n const innerLeft = rect.left + inset;\n const innerWidth = Math.max(0, rect.width - 2 * inset);\n if (innerWidth <= 0) return 0;\n const ratio = (clientX - innerLeft) / innerWidth;\n return Math.min(Math.max(ratio, 0), 1);\n}\n\nexport function extensionForMimeType(mime: string): string {\n const t = (mime || '').toLowerCase();\n if (t.includes('webm')) return 'webm';\n if (t.includes('quicktime') || t.includes('mov')) return 'mov';\n if (t.includes('matroska') || t.includes('mkv')) return 'mkv';\n return 'mp4';\n}\n\n/**\n * 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\n * canvas's parent or on `:root`). `null` puts a value back to the default.\n */\nexport interface ControllerTheme {\n /** The colour of the progress bar, its thumb and the focus rings. Default `#007AFF` (blue). */\n accent?: string | null;\n /** Icons, the time and the volume slider. Default `#fff`. */\n foreground?: string | null;\n /** The unfilled part of the progress and volume bars. Default `rgba(255,255,255,0.25)`. */\n track?: string | null;\n /** The background behind the buttons: any CSS background, e.g. a gradient. Default: black fading to transparent upward. */\n barBackground?: string | null;\n /** Thickness of the progress bar in px (a number) or any CSS length. Default 3. */\n trackHeight?: number | string | null;\n /** `font-family` of the bar. */\n font?: string | null;\n}\n\nconst THEME_PROPERTIES: Record<keyof ControllerTheme, string> = {\n accent: '--mc-accent', foreground: '--mc-fg', track: '--mc-track', barBackground: '--mc-bar-bg', trackHeight: '--mc-track-height', font: '--mc-font',\n};\n\nexport interface ControllerOptions {\n canvas: HTMLCanvasElement;\n /** Colours and sizes of the bar, see {@link ControllerTheme}. Can be changed later with `controller.setTheme()`. */\n theme?: ControllerTheme;\n showExportButton?: boolean;\n enableKeyboardShortcuts?: boolean;\n /** A click (or tap) on the picture plays / pauses, like a `<video>` element. Default true; `false` leaves the canvas alone. */\n clickToPlay?: boolean;\n className?: string;\n}\n\ninterface ResolvedOptions {\n canvas: HTMLCanvasElement;\n showExportButton: boolean;\n enableKeyboardShortcuts: boolean;\n clickToPlay: boolean;\n className: string;\n}\n\nexport class Controller {\n movie: Movie;\n options: ResolvedOptions;\n\n private root: HTMLDivElement;\n private wrapper: HTMLDivElement;\n private wrappedHere = false;\n /** The canvas's own inline width / height, as the page wrote them (we override them while the wrapper is fitted). */\n private canvasInlineWidth = '';\n private canvasInlineHeight = '';\n private fitWrapHandler: (() => void) | null = null;\n private fitObserver: ResizeObserver | null = null;\n private destroyed = false;\n\n private progressEl!: HTMLDivElement;\n private progressFillEl!: HTMLDivElement;\n private progressThumbEl!: HTMLDivElement;\n private playBtn!: HTMLButtonElement;\n private muteBtn!: HTMLButtonElement;\n private timeEl!: HTMLSpanElement;\n private exportBtn: HTMLButtonElement | null = null;\n private settingsPopoverEl: HTMLDivElement | null = null;\n private settingsFormatSelect: HTMLSelectElement | null = null;\n private settingsQualitySelect: HTMLSelectElement | null = null;\n private exportConfirmBtn: HTMLButtonElement | null = null;\n private exportFormat: 'mp4' | 'webm' | 'mov' = 'mp4';\n private exportQuality: 'low' | 'medium' | 'high' | 'very-high' = 'high';\n private settingsOpen = false;\n private hideTimer: ReturnType<typeof setTimeout> | null = null;\n private static readonly HIDE_DELAY_MS = 2500;\n private static readonly PROGRESS_INSET_PX = 12;\n private isScrubbing = false;\n private wasPlayingBeforeScrub = false;\n private activePointerId: number | null = null;\n private isExporting = false;\n private exportOverlay: HTMLDivElement | null = null;\n private exportFillEl: HTMLDivElement | null = null;\n private exportTextEl: HTMLDivElement | null = null;\n private keyHandler: ((e: KeyboardEvent) => void) | null = null;\n private settingsKeyHandler: ((e: KeyboardEvent) => void) | null = null;\n private settingsOutsideHandler: ((e: PointerEvent) => void) | null = null;\n private onReady: (() => void) | null = null;\n private onFrame: ((e: { frame: number; totalFrames: number }) => void) | null = null;\n private onPlay: (() => void) | null = null;\n private onPause: (() => void) | null = null;\n private onProgress: ((e: { progress: number; frame: number; totalFrames: number }) => void) | null = null;\n private onWrapPointerMove: (() => void) | null = null;\n private onWrapMouseLeave: (() => void) | null = null;\n private resizeObserver: ResizeObserver | null = null;\n private volumeSliderEl: HTMLDivElement | null = null;\n private volumeContainerEl: HTMLDivElement | null = null;\n private fullscreenBtn: HTMLButtonElement | null = null;\n private isVolumeScrubbing = false;\n private canvasClickHandler: (() => void) | null = null;\n private canvasPointerDownHandler: (() => void) | null = null;\n private canvasCursor = '';\n /** Set when a pointerdown on the canvas closed the export popover: the click that follows must not play / pause. */\n private swallowCanvasClick = false;\n private fullscreenChangeHandler: (() => void) | null = null;\n private wheelHandler: ((e: WheelEvent) => void) | null = null;\n /** Ends a drag the pointerup of which never arrives (see bindScrubbing). */\n private windowBlurHandler: (() => void) | null = null;\n\n constructor(movie: Movie, options: ControllerOptions) {\n if (!options || !options.canvas) {\n throw new Error('Controller requires options.canvas (HTMLCanvasElement).');\n }\n this.movie = movie;\n this.options = {\n canvas: options.canvas,\n showExportButton: options.showExportButton ?? true,\n enableKeyboardShortcuts: options.enableKeyboardShortcuts ?? true,\n clickToPlay: options.clickToPlay ?? true,\n className: options.className ?? 'movie-controller',\n };\n\n installStyles();\n this.wrapper = this.ensurePositioningContext(this.options.canvas);\n this.root = document.createElement('div');\n this.root.className = this.options.className;\n this.wrapper.appendChild(this.root);\n this.buildBar();\n this.setTheme(options.theme ?? {});\n this.bindFitWrap();\n this.syncRootToCanvas();\n if (typeof ResizeObserver !== 'undefined') {\n this.resizeObserver = new ResizeObserver(() => this.syncRootToCanvas());\n this.resizeObserver.observe(this.options.canvas);\n // Also observe the wrapper: when its size changes (browser resize, sibling\n // panels resizing) the canvas's position can shift without its own size\n // changing, which canvas-only observation would miss.\n this.resizeObserver.observe(this.wrapper);\n }\n this.root.setAttribute('data-state', 'visible');\n this.bindMovieEvents();\n this.bindPlayButton();\n if (this.options.clickToPlay) this.bindCanvasClick();\n this.bindScrubbing();\n this.bindMuteButton();\n this.bindVolumeSlider();\n this.bindExportPopover();\n this.bindFullscreen();\n this.bindVisibility();\n if (this.options.enableKeyboardShortcuts) this.bindKeyboard();\n }\n\n private buildBar(): void {\n const popoverHtml = this.options.showExportButton ? `\n <div class=\"mc-settings-popover\" role=\"dialog\" aria-label=\"Export settings\" data-open=\"false\">\n <label class=\"mc-settings-row\">\n <span>Format</span>\n <select class=\"mc-settings-format\">\n <option value=\"mp4\">MP4</option>\n <option value=\"webm\">WebM</option>\n <option value=\"mov\">MOV</option>\n </select>\n </label>\n <label class=\"mc-settings-row\">\n <span>Quality</span>\n <select class=\"mc-settings-quality\">\n <option value=\"low\">Low</option>\n <option value=\"medium\">Medium</option>\n <option value=\"high\" selected>High</option>\n <option value=\"very-high\">Very High</option>\n </select>\n </label>\n <button type=\"button\" class=\"mc-export-confirm\">Download</button>\n </div>\n ` : '';\n this.root.innerHTML = `\n <div class=\"mc-progress\" role=\"slider\" tabindex=\"0\" aria-label=\"Seek\" aria-valuemin=\"0\" aria-valuemax=\"${this.movie.totalFrames}\" aria-valuenow=\"0\">\n <div class=\"mc-progress-fill\"></div>\n <div class=\"mc-progress-thumb\"></div>\n </div>\n <div class=\"mc-bar\">\n ${popoverHtml}\n <button class=\"mc-btn mc-play\" aria-label=\"Play\">${ICONS.play}</button>\n <div class=\"mc-volume\">\n <button class=\"mc-btn mc-mute\" aria-label=\"Mute\">${ICONS.volumeOn}</button>\n <div class=\"mc-vol-slider\" role=\"slider\" tabindex=\"0\" aria-label=\"Volume\" aria-valuemin=\"0\" aria-valuemax=\"100\" aria-valuenow=\"100\">\n <div class=\"mc-vol-fill\"></div>\n <div class=\"mc-vol-thumb\"></div>\n </div>\n </div>\n <span class=\"mc-time\">0:00 / 0:00</span>\n <div class=\"mc-spacer\"></div>\n ${this.options.showExportButton ? `<button class=\"mc-btn mc-export\" aria-label=\"Export\" aria-expanded=\"false\">${ICONS.download}</button>` : ''}\n <button class=\"mc-btn mc-fullscreen\" aria-label=\"Enter fullscreen\">${ICONS.fullscreenEnter}</button>\n </div>\n `;\n this.progressEl = this.root.querySelector('.mc-progress') as HTMLDivElement;\n this.progressFillEl = this.root.querySelector('.mc-progress-fill') as HTMLDivElement;\n this.progressThumbEl = this.root.querySelector('.mc-progress-thumb') as HTMLDivElement;\n this.playBtn = this.root.querySelector('.mc-play') as HTMLButtonElement;\n this.muteBtn = this.root.querySelector('.mc-mute') as HTMLButtonElement;\n this.timeEl = this.root.querySelector('.mc-time') as HTMLSpanElement;\n this.exportBtn = this.root.querySelector('.mc-export') as HTMLButtonElement | null;\n this.settingsPopoverEl = this.root.querySelector('.mc-settings-popover') as HTMLDivElement | null;\n this.settingsFormatSelect = this.root.querySelector('.mc-settings-format') as HTMLSelectElement | null;\n this.settingsQualitySelect = this.root.querySelector('.mc-settings-quality') as HTMLSelectElement | null;\n this.exportConfirmBtn = this.root.querySelector('.mc-export-confirm') as HTMLButtonElement | null;\n this.volumeSliderEl = this.root.querySelector('.mc-vol-slider') as HTMLDivElement | null;\n this.volumeContainerEl = this.root.querySelector('.mc-volume') as HTMLDivElement | null;\n this.fullscreenBtn = this.root.querySelector('.mc-fullscreen') as HTMLButtonElement | null;\n if (this.settingsFormatSelect) this.settingsFormatSelect.value = this.exportFormat;\n if (this.settingsQualitySelect) this.settingsQualitySelect.value = this.exportQuality;\n }\n\n /** Change the look of the bar (see {@link ControllerTheme}): only the keys you give change, `null` restores the default. */\n setTheme(theme: ControllerTheme): void {\n warnUnknownOptions('Controller theme', theme as Record<string, unknown>, Object.keys(THEME_PROPERTIES));\n for (const key of Object.keys(THEME_PROPERTIES) as Array<keyof ControllerTheme>) {\n if (!(key in theme)) continue;\n const value = theme[key];\n const prop = THEME_PROPERTIES[key];\n if (value === null || value === undefined || value === '') this.root.style.removeProperty(prop);\n else this.root.style.setProperty(prop, typeof value === 'number' ? `${value}px` : String(value));\n }\n }\n\n private ensurePositioningContext(canvas: HTMLCanvasElement): HTMLDivElement {\n const parent = canvas.parentElement;\n if (!parent) {\n throw new Error('Controller: canvas must be attached to the DOM before constructing.');\n }\n const pos = getComputedStyle(parent).position;\n if (pos === 'relative' || pos === 'absolute' || pos === 'fixed' || pos === 'sticky') {\n // Tag the user's element so the [data-mc-wrap]:fullscreen style hooks apply\n // to it the same way they apply to our auto-wrap. Cleaned up on destroy.\n parent.setAttribute('data-mc-wrap', '');\n return parent as HTMLDivElement;\n }\n const wrap = document.createElement('div');\n wrap.className = 'movie-controller-wrap';\n wrap.setAttribute('data-mc-wrap', '');\n wrap.style.position = 'relative';\n wrap.style.display = 'inline-block';\n wrap.style.lineHeight = '0';\n parent.insertBefore(wrap, canvas);\n wrap.appendChild(canvas);\n this.wrappedHere = true;\n this.canvasInlineWidth = canvas.style.width;\n this.canvasInlineHeight = canvas.style.height;\n\n return wrap;\n }\n\n /**\n * Make the wrapper exactly as wide as the canvas. A shrink-to-fit wrapper around a canvas that is sized in percent (the usual\n * `canvas { width: min(960px, 100%) }`) is as wide as the canvas's width ATTRIBUTE (1280), so the picture sat at its left edge\n * with an empty strip beside it. We measure the canvas as the page styled it (the wrapper made transparent to layout), give\n * the wrapper that width, and let the canvas fill the wrapper. Re-measured when the window or the page's box changes.\n */\n private fitWrap(): void {\n if (!this.wrappedHere) return;\n const wrap = this.wrapper, canvas = this.options.canvas;\n if (document.fullscreenElement === wrap) { // the fullscreen CSS owns the size\n wrap.style.width = '';\n canvas.style.width = this.canvasInlineWidth; canvas.style.height = this.canvasInlineHeight;\n return;\n }\n canvas.style.width = this.canvasInlineWidth; canvas.style.height = this.canvasInlineHeight;\n const display = wrap.style.display;\n wrap.style.display = 'contents'; wrap.style.width = '';\n const w = canvas.getBoundingClientRect().width;\n wrap.style.display = display;\n if (!(w > 0)) return;\n wrap.style.width = `${w}px`;\n canvas.style.width = '100%'; canvas.style.height = 'auto';\n }\n\n private bindFitWrap(): void {\n if (!this.wrappedHere) return;\n this.fitWrap();\n let queued = false;\n this.fitWrapHandler = () => {\n if (queued) return;\n queued = true;\n requestAnimationFrame(() => { queued = false; this.fitWrap(); });\n };\n window.addEventListener('resize', this.fitWrapHandler);\n const parent = this.wrapper.parentElement;\n if (parent && typeof ResizeObserver !== 'undefined') {\n this.fitObserver = new ResizeObserver(this.fitWrapHandler);\n this.fitObserver.observe(parent);\n }\n }\n\n private bindMovieEvents(): void {\n this.onReady = () => {\n this.progressEl.setAttribute('aria-valuemax', String(this.movie.totalFrames));\n this.refreshTime(0);\n this.refreshProgress(0);\n this.refreshVolumeUI();\n };\n this.onFrame = ({ frame, totalFrames }) => {\n if (!this.isScrubbing) {\n this.refreshProgress(frame, totalFrames);\n }\n this.refreshTime(frame);\n };\n // `movie.play()` may be called by the host page, not only by this bar's button.\n this.onPlay = () => {\n this.refreshPlayIcon();\n this.kickIdleTimer();\n };\n this.onPause = () => {\n this.refreshPlayIcon();\n // YouTube-style: pause shows the bar momentarily, then auto-hides on idle.\n this.kickIdleTimer();\n };\n this.onProgress = ({ progress, frame, totalFrames }) => {\n if (!this.isExporting || !this.exportFillEl || !this.exportTextEl) return;\n this.exportFillEl.style.width = `${progress}%`;\n this.exportTextEl.textContent = `${progress}% (${frame} / ${totalFrames} frames)`;\n };\n this.movie.on('ready', this.onReady);\n this.movie.on('frame', this.onFrame);\n this.movie.on('play', this.onPlay);\n this.movie.on('pause', this.onPause);\n this.movie.on('progress', this.onProgress);\n }\n\n private bindPlayButton(): void {\n this.playBtn.addEventListener('click', () => {\n if (this.movie.isPlaying) {\n this.movie.pause();\n // movie.pause() emits 'pause' which the onPause handler turns into\n // refreshPlayIcon + kickIdleTimer, so no extra work here.\n } else {\n this.movie.play();\n // movie.play() emits 'play' (the onPlay handler refreshes the icon), same as 'pause' above.\n }\n });\n }\n\n /** Clicking the picture plays / pauses (a tap on a phone too). */\n private bindCanvasClick(): void {\n const canvas = this.options.canvas;\n this.canvasCursor = canvas.style.cursor;\n canvas.style.cursor = 'pointer';\n this.canvasPointerDownHandler = () => { this.swallowCanvasClick = false; };\n this.canvasClickHandler = () => {\n // the tap that closed the export popover (see bindExportPopover) is not also a play / pause\n if (this.swallowCanvasClick) { this.swallowCanvasClick = false; return; }\n if (this.movie.isPlaying) this.movie.pause(); else this.movie.play();\n };\n canvas.addEventListener('pointerdown', this.canvasPointerDownHandler);\n canvas.addEventListener('click', this.canvasClickHandler);\n }\n\n private refreshPlayIcon(): void {\n this.playBtn.innerHTML = this.movie.isPlaying ? ICONS.pause : ICONS.play;\n this.playBtn.setAttribute('aria-label', this.movie.isPlaying ? 'Pause' : 'Play');\n }\n\n private bindMuteButton(): void {\n this.muteBtn.addEventListener('click', () => {\n this.movie.toggleMute();\n this.refreshVolumeUI();\n });\n }\n\n private refreshMuteIcon(): void {\n const silent = this.movie.muted || this.movie.volume <= 0;\n this.muteBtn.innerHTML = silent ? ICONS.volumeOff : ICONS.volumeOn;\n this.muteBtn.setAttribute('aria-label', silent ? 'Unmute' : 'Mute');\n }\n\n private refreshVolumeUI(): void {\n this.refreshMuteIcon();\n if (!this.volumeSliderEl) return;\n const effective = this.movie.muted ? 0 : this.movie.volume;\n this.volumeSliderEl.style.setProperty('--mc-volume', String(effective));\n this.volumeSliderEl.setAttribute('aria-valuenow', String(Math.round(effective * 100)));\n }\n\n private bindVolumeSlider(): void {\n if (!this.volumeSliderEl || !this.volumeContainerEl) return;\n const slider = this.volumeSliderEl;\n const container = this.volumeContainerEl;\n\n const setFromPointer = (clientX: number) => {\n const rect = slider.getBoundingClientRect();\n const v = pxToFraction(clientX, { left: rect.left, width: rect.width }, 4);\n this.movie.volume = v;\n if (this.movie.muted && v > 0) this.movie.muted = false;\n this.refreshVolumeUI();\n };\n\n const onDown = (e: PointerEvent) => {\n this.isVolumeScrubbing = true;\n slider.classList.add('mc-scrubbing');\n try { slider.setPointerCapture(e.pointerId); } catch { /* unsupported */ }\n setFromPointer(e.clientX);\n };\n const finish = (pointerId?: number) => {\n if (!this.isVolumeScrubbing) return;\n this.isVolumeScrubbing = false;\n slider.classList.remove('mc-scrubbing');\n try { if (pointerId !== undefined) slider.releasePointerCapture(pointerId); } catch { /* unsupported */ }\n };\n const onMove = (e: PointerEvent) => {\n if (!this.isVolumeScrubbing) return;\n if (e.buttons === 0) { finish(e.pointerId); return; } // released outside an iframe: see bindScrubbing\n setFromPointer(e.clientX);\n };\n const onUp = (e: PointerEvent) => finish(e.pointerId);\n slider.addEventListener('pointerdown', onDown);\n slider.addEventListener('pointermove', onMove);\n slider.addEventListener('pointerup', onUp);\n slider.addEventListener('pointercancel', onUp);\n slider.addEventListener('lostpointercapture', () => finish());\n\n this.wheelHandler = (e: WheelEvent) => {\n e.preventDefault();\n this.adjustVolume(e.deltaY < 0 ? 0.05 : -0.05);\n };\n container.addEventListener('wheel', this.wheelHandler, { passive: false });\n }\n\n /**\n * Does this browser have the Fullscreen API for an element? iPhone Safari does not (it can only put a <video> in fullscreen),\n * and a button that does nothing is worse than none.\n */\n private supportsFullscreen(): boolean {\n return typeof (this.wrapper as { requestFullscreen?: unknown }).requestFullscreen === 'function' && document.fullscreenEnabled !== false;\n }\n\n private bindFullscreen(): void {\n if (!this.fullscreenBtn) return;\n if (!this.supportsFullscreen()) {\n this.fullscreenBtn.remove();\n this.fullscreenBtn = null; // the F key checks this too\n return;\n }\n this.fullscreenBtn.addEventListener('click', () => {\n void this.toggleFullscreen();\n });\n this.fullscreenChangeHandler = () => {\n this.fitWrap();\n this.refreshFullscreenIcon();\n // Fullscreen reflow can shift the canvas without changing its size, which\n // ResizeObserver would miss; resync the overlay explicitly.\n this.syncRootToCanvas();\n };\n document.addEventListener('fullscreenchange', this.fullscreenChangeHandler);\n }\n\n private async toggleFullscreen(): Promise<void> {\n try {\n if (document.fullscreenElement === this.wrapper) {\n await document.exitFullscreen();\n } else {\n await this.wrapper.requestFullscreen();\n }\n } catch (err) {\n console.warn('pixi-effects: fullscreen denied:', err);\n }\n }\n\n private refreshFullscreenIcon(): void {\n if (!this.fullscreenBtn) return;\n const inFs = document.fullscreenElement === this.wrapper;\n this.fullscreenBtn.innerHTML = inFs ? ICONS.fullscreenExit : ICONS.fullscreenEnter;\n this.fullscreenBtn.setAttribute('aria-label', inFs ? 'Exit fullscreen' : 'Enter fullscreen');\n }\n\n private refreshProgress(frame: number, totalFrames?: number): void {\n const total = totalFrames ?? this.movie.totalFrames;\n const pct = frameToPercent(frame, total);\n this.progressEl.style.setProperty('--mc-fill', String(pct / 100));\n this.progressEl.setAttribute('aria-valuenow', String(frame));\n }\n\n private refreshTime(frame: number): void {\n const fr = this.movie.frameRate || 1;\n const cur = frame / fr;\n const total = this.movie.totalFrames / fr;\n this.timeEl.textContent = `${formatTime(cur)} / ${formatTime(total)}`;\n }\n\n private bindScrubbing(): void {\n const onDown = (e: PointerEvent) => {\n this.isScrubbing = true;\n this.activePointerId = e.pointerId;\n this.wasPlayingBeforeScrub = this.movie.isPlaying;\n if (this.movie.isPlaying) {\n this.movie.pause();\n this.refreshPlayIcon();\n }\n this.progressEl.classList.add('mc-scrubbing');\n try { this.progressEl.setPointerCapture(e.pointerId); } catch { /* unsupported */ }\n this.seekFromPointer(e.clientX);\n };\n // End the drag. `clientX` is given when the pointer was released over the bar (seek to where it was).\n // A page inside an iframe never receives the pointerup of a button released OUTSIDE the iframe, so the\n // drag also ends on lostpointercapture, on the window losing focus, and on the first pointermove that\n // has no button down — otherwise it stayed \"scrubbing\" (paused, seeking on every hover).\n const finish = (clientX?: number, pointerId?: number) => {\n if (!this.isScrubbing) return;\n if (clientX !== undefined) this.seekFromPointer(clientX);\n this.isScrubbing = false;\n this.activePointerId = null;\n this.progressEl.classList.remove('mc-scrubbing');\n try { if (pointerId !== undefined) this.progressEl.releasePointerCapture(pointerId); } catch { /* unsupported */ }\n if (this.wasPlayingBeforeScrub) {\n this.movie.play();\n this.refreshPlayIcon();\n }\n };\n const onMove = (e: PointerEvent) => {\n if (!this.isScrubbing) return;\n if (e.buttons === 0) { finish(undefined, e.pointerId); return; }\n this.seekFromPointer(e.clientX);\n };\n const onUp = (e: PointerEvent) => finish(e.clientX, e.pointerId);\n this.progressEl.addEventListener('pointerdown', onDown);\n this.progressEl.addEventListener('pointermove', onMove);\n this.progressEl.addEventListener('pointerup', onUp);\n this.progressEl.addEventListener('pointercancel', onUp);\n this.progressEl.addEventListener('lostpointercapture', () => finish());\n this.windowBlurHandler = () => { finish(); this.isVolumeScrubbing = false; this.volumeSliderEl?.classList.remove('mc-scrubbing'); };\n window.addEventListener('blur', this.windowBlurHandler);\n }\n\n private seekFromPointer(clientX: number): void {\n const rect = this.progressEl.getBoundingClientRect();\n const inset = Controller.PROGRESS_INSET_PX;\n const innerLeft = rect.left + inset;\n const innerWidth = Math.max(0, rect.width - 2 * inset);\n const frame = pxToFrame(clientX, { left: innerLeft, width: innerWidth }, this.movie.totalFrames);\n this.refreshProgress(frame);\n void this.movie.gotoFrame(frame);\n }\n\n private bindExportPopover(): void {\n if (!this.exportBtn || !this.settingsPopoverEl) return;\n\n // Download icon on the bar toggles the popover (it does NOT directly trigger export).\n this.exportBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n this.toggleSettings(!this.settingsOpen);\n });\n\n // Confirm button inside the popover triggers the actual export, then closes.\n if (this.exportConfirmBtn) {\n this.exportConfirmBtn.addEventListener('click', () => {\n this.toggleSettings(false);\n void this.handleExport();\n });\n }\n\n if (this.settingsFormatSelect) {\n this.settingsFormatSelect.addEventListener('change', (e) => {\n const v = (e.target as HTMLSelectElement).value;\n if (v === 'mp4' || v === 'webm' || v === 'mov') this.exportFormat = v;\n });\n }\n if (this.settingsQualitySelect) {\n this.settingsQualitySelect.addEventListener('change', (e) => {\n const v = (e.target as HTMLSelectElement).value;\n if (v === 'low' || v === 'medium' || v === 'high' || v === 'very-high') this.exportQuality = v;\n });\n }\n\n this.settingsKeyHandler = (e: KeyboardEvent) => {\n if (e.code === 'Escape' && this.settingsOpen) {\n e.preventDefault();\n this.toggleSettings(false);\n }\n };\n document.addEventListener('keydown', this.settingsKeyHandler);\n\n this.settingsOutsideHandler = (e: PointerEvent) => {\n if (!this.settingsOpen) return;\n const target = e.target as Node | null;\n if (!target) return;\n if (this.settingsPopoverEl?.contains(target)) return;\n if (this.exportBtn?.contains(target)) return;\n if (this.options.canvas.contains(target)) this.swallowCanvasClick = true; // closing the popover is all this tap does\n this.toggleSettings(false);\n };\n document.addEventListener('pointerdown', this.settingsOutsideHandler);\n }\n\n private toggleSettings(open: boolean): void {\n if (!this.exportBtn || !this.settingsPopoverEl) return;\n this.settingsOpen = open;\n this.settingsPopoverEl.setAttribute('data-open', open ? 'true' : 'false');\n this.exportBtn.setAttribute('aria-expanded', open ? 'true' : 'false');\n if (open) {\n // Keep the bar visible while the popover is open.\n if (this.hideTimer) { clearTimeout(this.hideTimer); this.hideTimer = null; }\n this.setVisible(true);\n } else {\n // Resume normal auto-hide cadence after closing.\n this.kickIdleTimer();\n }\n }\n\n private async handleExport(): Promise<void> {\n if (this.isExporting) return;\n this.isExporting = true;\n const wasPlaying = this.movie.isPlaying;\n if (wasPlaying) {\n this.movie.pause();\n this.refreshPlayIcon();\n }\n this.showExportOverlay();\n try {\n const blob = await this.movie.render({\n format: this.exportFormat,\n video: { bitrate: this.exportQuality },\n audio: { bitrate: this.exportQuality },\n });\n if (this.exportFillEl) this.exportFillEl.style.width = '100%';\n if (this.exportTextEl) this.exportTextEl.textContent = 'Preparing download...';\n this.triggerDownload(blob);\n await new Promise((r) => setTimeout(r, 300));\n } catch (err) {\n console.error('Export failed:', err);\n alert('Export failed.');\n } finally {\n this.hideExportOverlay();\n this.isExporting = false;\n if (wasPlaying) {\n this.movie.play();\n this.refreshPlayIcon();\n }\n }\n }\n\n private triggerDownload(blob: Blob): void {\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = this.makeFilename(blob);\n a.style.display = 'none';\n document.body.appendChild(a);\n a.click();\n a.remove();\n setTimeout(() => URL.revokeObjectURL(url), 100);\n }\n\n private makeFilename(blob: Blob): string {\n const ext = extensionForMimeType(blob.type);\n const d = new Date();\n const pad = (n: number) => n.toString().padStart(2, '0');\n const ts = `${d.getFullYear()}${pad(d.getMonth() + 1)}${pad(d.getDate())}-${pad(d.getHours())}${pad(d.getMinutes())}${pad(d.getSeconds())}`;\n return `movie-${ts}.${ext}`;\n }\n\n private showExportOverlay(): void {\n const overlay = document.createElement('div');\n overlay.className = 'mc-export-overlay';\n overlay.innerHTML = `\n <div class=\"mc-export-panel\">\n <div class=\"mc-export-title\">Exporting video...</div>\n <div class=\"mc-export-track\"><div class=\"mc-export-fill\"></div></div>\n <div class=\"mc-export-text\">0% (0 / 0 frames)</div>\n </div>\n `;\n this.root.appendChild(overlay);\n this.exportOverlay = overlay;\n this.exportFillEl = overlay.querySelector('.mc-export-fill') as HTMLDivElement;\n this.exportTextEl = overlay.querySelector('.mc-export-text') as HTMLDivElement;\n }\n\n private hideExportOverlay(): void {\n if (this.exportOverlay) {\n this.exportOverlay.remove();\n this.exportOverlay = null;\n this.exportFillEl = null;\n this.exportTextEl = null;\n }\n }\n\n private bindVisibility(): void {\n const wrap = this.wrapper;\n this.onWrapPointerMove = () => this.kickIdleTimer();\n this.onWrapMouseLeave = () => {\n if (!this.settingsOpen && !this.isScrubbing && !this.isVolumeScrubbing) this.setVisible(false);\n };\n wrap.addEventListener('pointermove', this.onWrapPointerMove);\n wrap.addEventListener('mouseleave', this.onWrapMouseLeave);\n this.root.addEventListener('pointerenter', () => {\n if (this.hideTimer) { clearTimeout(this.hideTimer); this.hideTimer = null; }\n this.setVisible(true);\n });\n }\n\n private kickIdleTimer(): void {\n this.setVisible(true);\n if (this.hideTimer) { clearTimeout(this.hideTimer); this.hideTimer = null; }\n if (this.settingsOpen) return;\n this.hideTimer = setTimeout(() => {\n if (!this.isScrubbing && !this.isVolumeScrubbing && !this.settingsOpen) this.setVisible(false);\n }, Controller.HIDE_DELAY_MS);\n }\n\n private setVisible(v: boolean): void {\n this.root.setAttribute('data-state', v ? 'visible' : 'hidden');\n }\n\n private syncRootToCanvas(): void {\n const c = this.options.canvas;\n const cr = c.getBoundingClientRect();\n const wr = this.wrapper.getBoundingClientRect();\n this.root.style.left = `${cr.left - wr.left}px`;\n this.root.style.top = `${cr.top - wr.top}px`;\n this.root.style.width = `${cr.width}px`;\n this.root.style.height = `${cr.height}px`;\n }\n\n private bindKeyboard(): void {\n this.keyHandler = (e: KeyboardEvent) => {\n const target = e.target as HTMLElement | null;\n if (target) {\n const tag = target.tagName;\n if (tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT') return;\n if (target.isContentEditable || target.getAttribute?.('contenteditable') === 'true') return;\n }\n if (this.isExporting) return;\n\n switch (e.code) {\n case 'Space':\n e.preventDefault();\n this.playBtn.click();\n break;\n case 'ArrowLeft':\n e.preventDefault();\n this.stepFrame(-1);\n break;\n case 'ArrowRight':\n e.preventDefault();\n this.stepFrame(1);\n break;\n case 'ArrowUp':\n e.preventDefault();\n this.adjustVolume(0.05);\n break;\n case 'ArrowDown':\n e.preventDefault();\n this.adjustVolume(-0.05);\n break;\n case 'KeyM':\n e.preventDefault();\n this.muteBtn.click();\n break;\n case 'KeyE':\n if (e.shiftKey && this.exportBtn) {\n e.preventDefault();\n // Power-user shortcut: skip the popover and export with current settings.\n void this.handleExport();\n }\n break;\n case 'KeyF':\n if (this.fullscreenBtn) {\n e.preventDefault();\n void this.toggleFullscreen();\n }\n break;\n }\n };\n document.addEventListener('keydown', this.keyHandler);\n }\n\n private stepFrame(delta: number): void {\n const next = Math.max(0, Math.min(this.movie.totalFrames, this.movie.currentFrame + delta));\n void this.movie.gotoFrame(next);\n }\n\n private adjustVolume(delta: number): void {\n const next = Math.max(0, Math.min(1, this.movie.volume + delta));\n this.movie.volume = next;\n if (this.movie.muted && next > 0) this.movie.muted = false;\n this.refreshVolumeUI();\n }\n\n destroy(): void {\n if (this.destroyed) return;\n this.destroyed = true;\n if (this.onReady) { this.movie.off('ready', this.onReady); this.onReady = null; }\n if (this.onFrame) { this.movie.off('frame', this.onFrame); this.onFrame = null; }\n if (this.onPlay) { this.movie.off('play', this.onPlay); this.onPlay = null; }\n if (this.onPause) { this.movie.off('pause', this.onPause); this.onPause = null; }\n if (this.onProgress) { this.movie.off('progress', this.onProgress); this.onProgress = null; }\n if (this.onWrapPointerMove) {\n this.wrapper.removeEventListener('pointermove', this.onWrapPointerMove);\n this.onWrapPointerMove = null;\n }\n if (this.onWrapMouseLeave) {\n this.wrapper.removeEventListener('mouseleave', this.onWrapMouseLeave);\n this.onWrapMouseLeave = null;\n }\n if (this.resizeObserver) {\n this.resizeObserver.disconnect();\n this.resizeObserver = null;\n }\n if (this.canvasClickHandler) {\n this.options.canvas.removeEventListener('click', this.canvasClickHandler);\n this.options.canvas.removeEventListener('pointerdown', this.canvasPointerDownHandler!);\n this.options.canvas.style.cursor = this.canvasCursor;\n this.canvasClickHandler = null; this.canvasPointerDownHandler = null;\n }\n if (this.fitObserver) { this.fitObserver.disconnect(); this.fitObserver = null; }\n if (this.fitWrapHandler) { window.removeEventListener('resize', this.fitWrapHandler); this.fitWrapHandler = null; }\n if (this.wrappedHere) { // give the canvas its own sizing back\n this.options.canvas.style.width = this.canvasInlineWidth;\n this.options.canvas.style.height = this.canvasInlineHeight;\n }\n this.root.remove();\n if (this.wrappedHere) {\n const parent = this.wrapper.parentElement;\n const canvas = this.options.canvas;\n if (parent) {\n parent.insertBefore(canvas, this.wrapper);\n this.wrapper.remove();\n }\n } else {\n this.wrapper.removeAttribute('data-mc-wrap');\n }\n if (this.keyHandler) {\n document.removeEventListener('keydown', this.keyHandler);\n this.keyHandler = null;\n }\n if (this.settingsKeyHandler) {\n document.removeEventListener('keydown', this.settingsKeyHandler);\n this.settingsKeyHandler = null;\n }\n if (this.settingsOutsideHandler) {\n document.removeEventListener('pointerdown', this.settingsOutsideHandler);\n this.settingsOutsideHandler = null;\n }\n if (this.fullscreenChangeHandler) {\n document.removeEventListener('fullscreenchange', this.fullscreenChangeHandler);\n this.fullscreenChangeHandler = null;\n }\n if (this.windowBlurHandler) {\n window.removeEventListener('blur', this.windowBlurHandler);\n this.windowBlurHandler = null;\n }\n if (this.wheelHandler && this.volumeContainerEl) {\n this.volumeContainerEl.removeEventListener('wheel', this.wheelHandler);\n this.wheelHandler = null;\n }\n if (document.fullscreenElement === this.wrapper) {\n void document.exitFullscreen().catch(() => {});\n }\n if (this.hideTimer) { clearTimeout(this.hideTimer); this.hideTimer = null; }\n this.hideExportOverlay();\n uninstallStyles();\n }\n}\n"]}
|
package/dist/Controller.d.cts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { M as Movie } from './Movie-
|
|
1
|
+
import { M as Movie } from './Movie-w3GliuP3.cjs';
|
|
2
2
|
import 'pixi.js';
|
|
3
3
|
import 'gsap';
|
|
4
|
-
import './types-
|
|
4
|
+
import './types-BXu28nJj.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
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";
|
|
@@ -40,12 +40,15 @@ interface ControllerOptions {
|
|
|
40
40
|
theme?: ControllerTheme;
|
|
41
41
|
showExportButton?: boolean;
|
|
42
42
|
enableKeyboardShortcuts?: boolean;
|
|
43
|
+
/** A click (or tap) on the picture plays / pauses, like a `<video>` element. Default true; `false` leaves the canvas alone. */
|
|
44
|
+
clickToPlay?: boolean;
|
|
43
45
|
className?: string;
|
|
44
46
|
}
|
|
45
47
|
interface ResolvedOptions {
|
|
46
48
|
canvas: HTMLCanvasElement;
|
|
47
49
|
showExportButton: boolean;
|
|
48
50
|
enableKeyboardShortcuts: boolean;
|
|
51
|
+
clickToPlay: boolean;
|
|
49
52
|
className: string;
|
|
50
53
|
}
|
|
51
54
|
declare class Controller {
|
|
@@ -99,6 +102,11 @@ declare class Controller {
|
|
|
99
102
|
private volumeContainerEl;
|
|
100
103
|
private fullscreenBtn;
|
|
101
104
|
private isVolumeScrubbing;
|
|
105
|
+
private canvasClickHandler;
|
|
106
|
+
private canvasPointerDownHandler;
|
|
107
|
+
private canvasCursor;
|
|
108
|
+
/** Set when a pointerdown on the canvas closed the export popover: the click that follows must not play / pause. */
|
|
109
|
+
private swallowCanvasClick;
|
|
102
110
|
private fullscreenChangeHandler;
|
|
103
111
|
private wheelHandler;
|
|
104
112
|
/** Ends a drag the pointerup of which never arrives (see bindScrubbing). */
|
|
@@ -118,6 +126,8 @@ declare class Controller {
|
|
|
118
126
|
private bindFitWrap;
|
|
119
127
|
private bindMovieEvents;
|
|
120
128
|
private bindPlayButton;
|
|
129
|
+
/** Clicking the picture plays / pauses (a tap on a phone too). */
|
|
130
|
+
private bindCanvasClick;
|
|
121
131
|
private refreshPlayIcon;
|
|
122
132
|
private bindMuteButton;
|
|
123
133
|
private refreshMuteIcon;
|
package/dist/Controller.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { M as Movie } from './Movie-
|
|
1
|
+
import { M as Movie } from './Movie-puD9oZPg.js';
|
|
2
2
|
import 'pixi.js';
|
|
3
3
|
import 'gsap';
|
|
4
|
-
import './types-
|
|
4
|
+
import './types-BXu28nJj.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
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";
|
|
@@ -40,12 +40,15 @@ interface ControllerOptions {
|
|
|
40
40
|
theme?: ControllerTheme;
|
|
41
41
|
showExportButton?: boolean;
|
|
42
42
|
enableKeyboardShortcuts?: boolean;
|
|
43
|
+
/** A click (or tap) on the picture plays / pauses, like a `<video>` element. Default true; `false` leaves the canvas alone. */
|
|
44
|
+
clickToPlay?: boolean;
|
|
43
45
|
className?: string;
|
|
44
46
|
}
|
|
45
47
|
interface ResolvedOptions {
|
|
46
48
|
canvas: HTMLCanvasElement;
|
|
47
49
|
showExportButton: boolean;
|
|
48
50
|
enableKeyboardShortcuts: boolean;
|
|
51
|
+
clickToPlay: boolean;
|
|
49
52
|
className: string;
|
|
50
53
|
}
|
|
51
54
|
declare class Controller {
|
|
@@ -99,6 +102,11 @@ declare class Controller {
|
|
|
99
102
|
private volumeContainerEl;
|
|
100
103
|
private fullscreenBtn;
|
|
101
104
|
private isVolumeScrubbing;
|
|
105
|
+
private canvasClickHandler;
|
|
106
|
+
private canvasPointerDownHandler;
|
|
107
|
+
private canvasCursor;
|
|
108
|
+
/** Set when a pointerdown on the canvas closed the export popover: the click that follows must not play / pause. */
|
|
109
|
+
private swallowCanvasClick;
|
|
102
110
|
private fullscreenChangeHandler;
|
|
103
111
|
private wheelHandler;
|
|
104
112
|
/** Ends a drag the pointerup of which never arrives (see bindScrubbing). */
|
|
@@ -118,6 +126,8 @@ declare class Controller {
|
|
|
118
126
|
private bindFitWrap;
|
|
119
127
|
private bindMovieEvents;
|
|
120
128
|
private bindPlayButton;
|
|
129
|
+
/** Clicking the picture plays / pauses (a tap on a phone too). */
|
|
130
|
+
private bindCanvasClick;
|
|
121
131
|
private refreshPlayIcon;
|
|
122
132
|
private bindMuteButton;
|
|
123
133
|
private refreshMuteIcon;
|
package/dist/Controller.js
CHANGED
|
@@ -332,6 +332,11 @@ var Controller = class _Controller {
|
|
|
332
332
|
volumeContainerEl = null;
|
|
333
333
|
fullscreenBtn = null;
|
|
334
334
|
isVolumeScrubbing = false;
|
|
335
|
+
canvasClickHandler = null;
|
|
336
|
+
canvasPointerDownHandler = null;
|
|
337
|
+
canvasCursor = "";
|
|
338
|
+
/** Set when a pointerdown on the canvas closed the export popover: the click that follows must not play / pause. */
|
|
339
|
+
swallowCanvasClick = false;
|
|
335
340
|
fullscreenChangeHandler = null;
|
|
336
341
|
wheelHandler = null;
|
|
337
342
|
/** Ends a drag the pointerup of which never arrives (see bindScrubbing). */
|
|
@@ -345,6 +350,7 @@ var Controller = class _Controller {
|
|
|
345
350
|
canvas: options.canvas,
|
|
346
351
|
showExportButton: options.showExportButton ?? true,
|
|
347
352
|
enableKeyboardShortcuts: options.enableKeyboardShortcuts ?? true,
|
|
353
|
+
clickToPlay: options.clickToPlay ?? true,
|
|
348
354
|
className: options.className ?? "movie-controller"
|
|
349
355
|
};
|
|
350
356
|
installStyles();
|
|
@@ -364,6 +370,7 @@ var Controller = class _Controller {
|
|
|
364
370
|
this.root.setAttribute("data-state", "visible");
|
|
365
371
|
this.bindMovieEvents();
|
|
366
372
|
this.bindPlayButton();
|
|
373
|
+
if (this.options.clickToPlay) this.bindCanvasClick();
|
|
367
374
|
this.bindScrubbing();
|
|
368
375
|
this.bindMuteButton();
|
|
369
376
|
this.bindVolumeSlider();
|
|
@@ -554,6 +561,25 @@ var Controller = class _Controller {
|
|
|
554
561
|
}
|
|
555
562
|
});
|
|
556
563
|
}
|
|
564
|
+
/** Clicking the picture plays / pauses (a tap on a phone too). */
|
|
565
|
+
bindCanvasClick() {
|
|
566
|
+
const canvas = this.options.canvas;
|
|
567
|
+
this.canvasCursor = canvas.style.cursor;
|
|
568
|
+
canvas.style.cursor = "pointer";
|
|
569
|
+
this.canvasPointerDownHandler = () => {
|
|
570
|
+
this.swallowCanvasClick = false;
|
|
571
|
+
};
|
|
572
|
+
this.canvasClickHandler = () => {
|
|
573
|
+
if (this.swallowCanvasClick) {
|
|
574
|
+
this.swallowCanvasClick = false;
|
|
575
|
+
return;
|
|
576
|
+
}
|
|
577
|
+
if (this.movie.isPlaying) this.movie.pause();
|
|
578
|
+
else this.movie.play();
|
|
579
|
+
};
|
|
580
|
+
canvas.addEventListener("pointerdown", this.canvasPointerDownHandler);
|
|
581
|
+
canvas.addEventListener("click", this.canvasClickHandler);
|
|
582
|
+
}
|
|
557
583
|
refreshPlayIcon() {
|
|
558
584
|
this.playBtn.innerHTML = this.movie.isPlaying ? ICONS.pause : ICONS.play;
|
|
559
585
|
this.playBtn.setAttribute("aria-label", this.movie.isPlaying ? "Pause" : "Play");
|
|
@@ -776,6 +802,7 @@ var Controller = class _Controller {
|
|
|
776
802
|
if (!target) return;
|
|
777
803
|
if (this.settingsPopoverEl?.contains(target)) return;
|
|
778
804
|
if (this.exportBtn?.contains(target)) return;
|
|
805
|
+
if (this.options.canvas.contains(target)) this.swallowCanvasClick = true;
|
|
779
806
|
this.toggleSettings(false);
|
|
780
807
|
};
|
|
781
808
|
document.addEventListener("pointerdown", this.settingsOutsideHandler);
|
|
@@ -1001,6 +1028,13 @@ var Controller = class _Controller {
|
|
|
1001
1028
|
this.resizeObserver.disconnect();
|
|
1002
1029
|
this.resizeObserver = null;
|
|
1003
1030
|
}
|
|
1031
|
+
if (this.canvasClickHandler) {
|
|
1032
|
+
this.options.canvas.removeEventListener("click", this.canvasClickHandler);
|
|
1033
|
+
this.options.canvas.removeEventListener("pointerdown", this.canvasPointerDownHandler);
|
|
1034
|
+
this.options.canvas.style.cursor = this.canvasCursor;
|
|
1035
|
+
this.canvasClickHandler = null;
|
|
1036
|
+
this.canvasPointerDownHandler = null;
|
|
1037
|
+
}
|
|
1004
1038
|
if (this.fitObserver) {
|
|
1005
1039
|
this.fitObserver.disconnect();
|
|
1006
1040
|
this.fitObserver = null;
|