pixi-effects 0.5.0 → 0.7.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 +30 -0
- package/README.md +17 -10
- package/ai/SKILL.md +1 -1
- package/ai/reference/cheatsheet.md +8 -2
- package/ai/reference/pitfalls.md +1 -0
- package/ai/reference/recipes.md +36 -1
- package/ai/template.html +4 -3
- package/ai/tools/check.mjs +14 -5
- package/ai/tools/render.mjs +202 -0
- package/ai/tools/view.mjs +269 -0
- package/dist/{Base-DnRAxroQ.d.cts → Base-CSIulyIq.d.cts} +1 -1
- package/dist/{Base-CPSFBkPm.d.ts → Base-DVgwyIUj.d.ts} +1 -1
- package/dist/Composition-3KHQPRBA.cjs +14 -0
- package/dist/{Composition-63EXHNJJ.cjs.map → Composition-3KHQPRBA.cjs.map} +1 -1
- package/dist/Composition-DT657FO5.js +5 -0
- package/dist/{Composition-TUCRSMJU.js.map → Composition-DT657FO5.js.map} +1 -1
- package/dist/Controller.cjs +77 -2
- package/dist/Controller.cjs.map +1 -1
- package/dist/Controller.d.cts +16 -2
- package/dist/Controller.d.ts +16 -2
- package/dist/Controller.js +77 -2
- package/dist/Controller.js.map +1 -1
- package/dist/{Movie-CuU_aaCm.d.cts → Movie-B0OUKlZI.d.ts} +54 -2
- package/dist/{Movie-VyDiUYOj.d.ts → Movie-BK9daiTt.d.cts} +54 -2
- package/dist/{chunk-5Q5XZG7Z.js → chunk-36Z4RIRK.js} +3 -3
- package/dist/{chunk-5Q5XZG7Z.js.map → chunk-36Z4RIRK.js.map} +1 -1
- package/dist/{chunk-UBPZLGLU.js → chunk-4O2NYDJG.js} +365 -44
- package/dist/chunk-4O2NYDJG.js.map +1 -0
- package/dist/{chunk-23M5QTWW.cjs → chunk-4VSIJLU3.cjs} +21 -21
- package/dist/{chunk-23M5QTWW.cjs.map → chunk-4VSIJLU3.cjs.map} +1 -1
- package/dist/{chunk-2RR43OIN.cjs → chunk-6I55T4OH.cjs} +403 -62
- package/dist/chunk-6I55T4OH.cjs.map +1 -0
- package/dist/index.cjs +234 -24
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +226 -16
- package/dist/index.js.map +1 -1
- package/dist/three.cjs +6 -5
- package/dist/three.cjs.map +1 -1
- package/dist/three.d.cts +2 -2
- package/dist/three.d.ts +2 -2
- package/dist/three.js +2 -1
- package/dist/three.js.map +1 -1
- package/dist/{types-7VtTEKUW.d.ts → types-oJijbn-K.d.cts} +36 -7
- package/dist/{types-7VtTEKUW.d.cts → types-oJijbn-K.d.ts} +36 -7
- package/docs/api.md +7 -0
- package/docs/dsl.md +74 -8
- package/llms-full.txt +127 -12
- package/package.json +7 -4
- package/dist/Composition-63EXHNJJ.cjs +0 -13
- package/dist/Composition-TUCRSMJU.js +0 -4
- package/dist/chunk-2RR43OIN.cjs.map +0 -1
- package/dist/chunk-UBPZLGLU.js.map +0 -1
package/dist/Controller.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/Controller.ts"],"names":[],"mappings":"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","file":"Controller.cjs","sourcesContent":["import type { Movie } from './core/Movie';\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\nconst STYLE_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: -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 #007AFF;\n outline-offset: 2px;\n}\n.mc-progress::before {\n content: \"\"; position: absolute; left: 12px; right: 12px;\n height: 3px; background: rgba(255,255,255,0.25);\n transition: height 120ms ease;\n}\n.mc-progress:hover::before, .mc-progress.mc-scrubbing::before { height: 5px; }\n.mc-progress-fill {\n position: absolute; left: 12px; top: 50%;\n height: 3px;\n width: calc((100% - 24px) * var(--mc-fill, 0));\n background: #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: 5px; }\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: #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: linear-gradient(to top, rgba(0,0,0,0.75) 0%, rgba(0,0,0,0) 100%);\n color: #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: #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: #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 #007AFF; outline-offset: 2px; }\n.mc-vol-slider::before {\n content: \"\"; position: absolute; left: 4px; right: 4px;\n height: 3px; background: 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: #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: #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: #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, #007AFF, #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 = STYLE_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\nexport interface ControllerOptions {\n canvas: HTMLCanvasElement;\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 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 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.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 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\n return wrap;\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 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('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 this.refreshPlayIcon();\n this.kickIdleTimer();\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 private bindFullscreen(): void {\n if (!this.fullscreenBtn) return;\n this.fullscreenBtn.addEventListener('click', () => {\n void this.toggleFullscreen();\n });\n this.fullscreenChangeHandler = () => {\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.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 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":[],"mappings":"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","file":"Controller.cjs","sourcesContent":["import type { Movie } from './core/Movie';\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\nconst STYLE_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: -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 #007AFF;\n outline-offset: 2px;\n}\n.mc-progress::before {\n content: \"\"; position: absolute; left: 12px; right: 12px;\n height: 3px; background: rgba(255,255,255,0.25);\n transition: height 120ms ease;\n}\n.mc-progress:hover::before, .mc-progress.mc-scrubbing::before { height: 5px; }\n.mc-progress-fill {\n position: absolute; left: 12px; top: 50%;\n height: 3px;\n width: calc((100% - 24px) * var(--mc-fill, 0));\n background: #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: 5px; }\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: #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: linear-gradient(to top, rgba(0,0,0,0.75) 0%, rgba(0,0,0,0) 100%);\n color: #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: #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: #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 #007AFF; outline-offset: 2px; }\n.mc-vol-slider::before {\n content: \"\"; position: absolute; left: 4px; right: 4px;\n height: 3px; background: 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: #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: #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: #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, #007AFF, #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 = STYLE_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\nexport interface ControllerOptions {\n canvas: HTMLCanvasElement;\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.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 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 private bindFullscreen(): void {\n if (!this.fullscreenBtn) return;\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"]}
|
package/dist/Controller.d.cts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { M as Movie } from './Movie-
|
|
1
|
+
import { M as Movie } from './Movie-BK9daiTt.cjs';
|
|
2
2
|
import 'pixi.js';
|
|
3
3
|
import 'gsap';
|
|
4
|
-
import './types-
|
|
4
|
+
import './types-oJijbn-K.cjs';
|
|
5
5
|
|
|
6
6
|
declare function formatTime(seconds: number): string;
|
|
7
7
|
declare function frameToPercent(frame: number, totalFrames: number): number;
|
|
@@ -32,6 +32,11 @@ declare class Controller {
|
|
|
32
32
|
private root;
|
|
33
33
|
private wrapper;
|
|
34
34
|
private wrappedHere;
|
|
35
|
+
/** The canvas's own inline width / height, as the page wrote them (we override them while the wrapper is fitted). */
|
|
36
|
+
private canvasInlineWidth;
|
|
37
|
+
private canvasInlineHeight;
|
|
38
|
+
private fitWrapHandler;
|
|
39
|
+
private fitObserver;
|
|
35
40
|
private destroyed;
|
|
36
41
|
private progressEl;
|
|
37
42
|
private progressFillEl;
|
|
@@ -62,6 +67,7 @@ declare class Controller {
|
|
|
62
67
|
private settingsOutsideHandler;
|
|
63
68
|
private onReady;
|
|
64
69
|
private onFrame;
|
|
70
|
+
private onPlay;
|
|
65
71
|
private onPause;
|
|
66
72
|
private onProgress;
|
|
67
73
|
private onWrapPointerMove;
|
|
@@ -78,6 +84,14 @@ declare class Controller {
|
|
|
78
84
|
constructor(movie: Movie, options: ControllerOptions);
|
|
79
85
|
private buildBar;
|
|
80
86
|
private ensurePositioningContext;
|
|
87
|
+
/**
|
|
88
|
+
* Make the wrapper exactly as wide as the canvas. A shrink-to-fit wrapper around a canvas that is sized in percent (the usual
|
|
89
|
+
* `canvas { width: min(960px, 100%) }`) is as wide as the canvas's width ATTRIBUTE (1280), so the picture sat at its left edge
|
|
90
|
+
* with an empty strip beside it. We measure the canvas as the page styled it (the wrapper made transparent to layout), give
|
|
91
|
+
* the wrapper that width, and let the canvas fill the wrapper. Re-measured when the window or the page's box changes.
|
|
92
|
+
*/
|
|
93
|
+
private fitWrap;
|
|
94
|
+
private bindFitWrap;
|
|
81
95
|
private bindMovieEvents;
|
|
82
96
|
private bindPlayButton;
|
|
83
97
|
private refreshPlayIcon;
|
package/dist/Controller.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { M as Movie } from './Movie-
|
|
1
|
+
import { M as Movie } from './Movie-B0OUKlZI.js';
|
|
2
2
|
import 'pixi.js';
|
|
3
3
|
import 'gsap';
|
|
4
|
-
import './types-
|
|
4
|
+
import './types-oJijbn-K.js';
|
|
5
5
|
|
|
6
6
|
declare function formatTime(seconds: number): string;
|
|
7
7
|
declare function frameToPercent(frame: number, totalFrames: number): number;
|
|
@@ -32,6 +32,11 @@ declare class Controller {
|
|
|
32
32
|
private root;
|
|
33
33
|
private wrapper;
|
|
34
34
|
private wrappedHere;
|
|
35
|
+
/** The canvas's own inline width / height, as the page wrote them (we override them while the wrapper is fitted). */
|
|
36
|
+
private canvasInlineWidth;
|
|
37
|
+
private canvasInlineHeight;
|
|
38
|
+
private fitWrapHandler;
|
|
39
|
+
private fitObserver;
|
|
35
40
|
private destroyed;
|
|
36
41
|
private progressEl;
|
|
37
42
|
private progressFillEl;
|
|
@@ -62,6 +67,7 @@ declare class Controller {
|
|
|
62
67
|
private settingsOutsideHandler;
|
|
63
68
|
private onReady;
|
|
64
69
|
private onFrame;
|
|
70
|
+
private onPlay;
|
|
65
71
|
private onPause;
|
|
66
72
|
private onProgress;
|
|
67
73
|
private onWrapPointerMove;
|
|
@@ -78,6 +84,14 @@ declare class Controller {
|
|
|
78
84
|
constructor(movie: Movie, options: ControllerOptions);
|
|
79
85
|
private buildBar;
|
|
80
86
|
private ensurePositioningContext;
|
|
87
|
+
/**
|
|
88
|
+
* Make the wrapper exactly as wide as the canvas. A shrink-to-fit wrapper around a canvas that is sized in percent (the usual
|
|
89
|
+
* `canvas { width: min(960px, 100%) }`) is as wide as the canvas's width ATTRIBUTE (1280), so the picture sat at its left edge
|
|
90
|
+
* with an empty strip beside it. We measure the canvas as the page styled it (the wrapper made transparent to layout), give
|
|
91
|
+
* the wrapper that width, and let the canvas fill the wrapper. Re-measured when the window or the page's box changes.
|
|
92
|
+
*/
|
|
93
|
+
private fitWrap;
|
|
94
|
+
private bindFitWrap;
|
|
81
95
|
private bindMovieEvents;
|
|
82
96
|
private bindPlayButton;
|
|
83
97
|
private refreshPlayIcon;
|
package/dist/Controller.js
CHANGED
|
@@ -277,6 +277,11 @@ var Controller = class _Controller {
|
|
|
277
277
|
root;
|
|
278
278
|
wrapper;
|
|
279
279
|
wrappedHere = false;
|
|
280
|
+
/** The canvas's own inline width / height, as the page wrote them (we override them while the wrapper is fitted). */
|
|
281
|
+
canvasInlineWidth = "";
|
|
282
|
+
canvasInlineHeight = "";
|
|
283
|
+
fitWrapHandler = null;
|
|
284
|
+
fitObserver = null;
|
|
280
285
|
destroyed = false;
|
|
281
286
|
progressEl;
|
|
282
287
|
progressFillEl;
|
|
@@ -307,6 +312,7 @@ var Controller = class _Controller {
|
|
|
307
312
|
settingsOutsideHandler = null;
|
|
308
313
|
onReady = null;
|
|
309
314
|
onFrame = null;
|
|
315
|
+
onPlay = null;
|
|
310
316
|
onPause = null;
|
|
311
317
|
onProgress = null;
|
|
312
318
|
onWrapPointerMove = null;
|
|
@@ -337,6 +343,7 @@ var Controller = class _Controller {
|
|
|
337
343
|
this.root.className = this.options.className;
|
|
338
344
|
this.wrapper.appendChild(this.root);
|
|
339
345
|
this.buildBar();
|
|
346
|
+
this.bindFitWrap();
|
|
340
347
|
this.syncRootToCanvas();
|
|
341
348
|
if (typeof ResizeObserver !== "undefined") {
|
|
342
349
|
this.resizeObserver = new ResizeObserver(() => this.syncRootToCanvas());
|
|
@@ -434,8 +441,56 @@ var Controller = class _Controller {
|
|
|
434
441
|
parent.insertBefore(wrap, canvas);
|
|
435
442
|
wrap.appendChild(canvas);
|
|
436
443
|
this.wrappedHere = true;
|
|
444
|
+
this.canvasInlineWidth = canvas.style.width;
|
|
445
|
+
this.canvasInlineHeight = canvas.style.height;
|
|
437
446
|
return wrap;
|
|
438
447
|
}
|
|
448
|
+
/**
|
|
449
|
+
* Make the wrapper exactly as wide as the canvas. A shrink-to-fit wrapper around a canvas that is sized in percent (the usual
|
|
450
|
+
* `canvas { width: min(960px, 100%) }`) is as wide as the canvas's width ATTRIBUTE (1280), so the picture sat at its left edge
|
|
451
|
+
* with an empty strip beside it. We measure the canvas as the page styled it (the wrapper made transparent to layout), give
|
|
452
|
+
* the wrapper that width, and let the canvas fill the wrapper. Re-measured when the window or the page's box changes.
|
|
453
|
+
*/
|
|
454
|
+
fitWrap() {
|
|
455
|
+
if (!this.wrappedHere) return;
|
|
456
|
+
const wrap = this.wrapper, canvas = this.options.canvas;
|
|
457
|
+
if (document.fullscreenElement === wrap) {
|
|
458
|
+
wrap.style.width = "";
|
|
459
|
+
canvas.style.width = this.canvasInlineWidth;
|
|
460
|
+
canvas.style.height = this.canvasInlineHeight;
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
canvas.style.width = this.canvasInlineWidth;
|
|
464
|
+
canvas.style.height = this.canvasInlineHeight;
|
|
465
|
+
const display = wrap.style.display;
|
|
466
|
+
wrap.style.display = "contents";
|
|
467
|
+
wrap.style.width = "";
|
|
468
|
+
const w = canvas.getBoundingClientRect().width;
|
|
469
|
+
wrap.style.display = display;
|
|
470
|
+
if (!(w > 0)) return;
|
|
471
|
+
wrap.style.width = `${w}px`;
|
|
472
|
+
canvas.style.width = "100%";
|
|
473
|
+
canvas.style.height = "auto";
|
|
474
|
+
}
|
|
475
|
+
bindFitWrap() {
|
|
476
|
+
if (!this.wrappedHere) return;
|
|
477
|
+
this.fitWrap();
|
|
478
|
+
let queued = false;
|
|
479
|
+
this.fitWrapHandler = () => {
|
|
480
|
+
if (queued) return;
|
|
481
|
+
queued = true;
|
|
482
|
+
requestAnimationFrame(() => {
|
|
483
|
+
queued = false;
|
|
484
|
+
this.fitWrap();
|
|
485
|
+
});
|
|
486
|
+
};
|
|
487
|
+
window.addEventListener("resize", this.fitWrapHandler);
|
|
488
|
+
const parent = this.wrapper.parentElement;
|
|
489
|
+
if (parent && typeof ResizeObserver !== "undefined") {
|
|
490
|
+
this.fitObserver = new ResizeObserver(this.fitWrapHandler);
|
|
491
|
+
this.fitObserver.observe(parent);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
439
494
|
bindMovieEvents() {
|
|
440
495
|
this.onReady = () => {
|
|
441
496
|
this.progressEl.setAttribute("aria-valuemax", String(this.movie.totalFrames));
|
|
@@ -449,6 +504,10 @@ var Controller = class _Controller {
|
|
|
449
504
|
}
|
|
450
505
|
this.refreshTime(frame);
|
|
451
506
|
};
|
|
507
|
+
this.onPlay = () => {
|
|
508
|
+
this.refreshPlayIcon();
|
|
509
|
+
this.kickIdleTimer();
|
|
510
|
+
};
|
|
452
511
|
this.onPause = () => {
|
|
453
512
|
this.refreshPlayIcon();
|
|
454
513
|
this.kickIdleTimer();
|
|
@@ -460,6 +519,7 @@ var Controller = class _Controller {
|
|
|
460
519
|
};
|
|
461
520
|
this.movie.on("ready", this.onReady);
|
|
462
521
|
this.movie.on("frame", this.onFrame);
|
|
522
|
+
this.movie.on("play", this.onPlay);
|
|
463
523
|
this.movie.on("pause", this.onPause);
|
|
464
524
|
this.movie.on("progress", this.onProgress);
|
|
465
525
|
}
|
|
@@ -469,8 +529,6 @@ var Controller = class _Controller {
|
|
|
469
529
|
this.movie.pause();
|
|
470
530
|
} else {
|
|
471
531
|
this.movie.play();
|
|
472
|
-
this.refreshPlayIcon();
|
|
473
|
-
this.kickIdleTimer();
|
|
474
532
|
}
|
|
475
533
|
});
|
|
476
534
|
}
|
|
@@ -551,6 +609,7 @@ var Controller = class _Controller {
|
|
|
551
609
|
void this.toggleFullscreen();
|
|
552
610
|
});
|
|
553
611
|
this.fullscreenChangeHandler = () => {
|
|
612
|
+
this.fitWrap();
|
|
554
613
|
this.refreshFullscreenIcon();
|
|
555
614
|
this.syncRootToCanvas();
|
|
556
615
|
};
|
|
@@ -884,6 +943,10 @@ var Controller = class _Controller {
|
|
|
884
943
|
this.movie.off("frame", this.onFrame);
|
|
885
944
|
this.onFrame = null;
|
|
886
945
|
}
|
|
946
|
+
if (this.onPlay) {
|
|
947
|
+
this.movie.off("play", this.onPlay);
|
|
948
|
+
this.onPlay = null;
|
|
949
|
+
}
|
|
887
950
|
if (this.onPause) {
|
|
888
951
|
this.movie.off("pause", this.onPause);
|
|
889
952
|
this.onPause = null;
|
|
@@ -904,6 +967,18 @@ var Controller = class _Controller {
|
|
|
904
967
|
this.resizeObserver.disconnect();
|
|
905
968
|
this.resizeObserver = null;
|
|
906
969
|
}
|
|
970
|
+
if (this.fitObserver) {
|
|
971
|
+
this.fitObserver.disconnect();
|
|
972
|
+
this.fitObserver = null;
|
|
973
|
+
}
|
|
974
|
+
if (this.fitWrapHandler) {
|
|
975
|
+
window.removeEventListener("resize", this.fitWrapHandler);
|
|
976
|
+
this.fitWrapHandler = null;
|
|
977
|
+
}
|
|
978
|
+
if (this.wrappedHere) {
|
|
979
|
+
this.options.canvas.style.width = this.canvasInlineWidth;
|
|
980
|
+
this.options.canvas.style.height = this.canvasInlineHeight;
|
|
981
|
+
}
|
|
907
982
|
this.root.remove();
|
|
908
983
|
if (this.wrappedHere) {
|
|
909
984
|
const parent = this.wrapper.parentElement;
|