pixi-effects 0.11.0 → 0.13.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 +28 -0
- package/README.md +11 -8
- package/ai/SKILL.md +2 -1
- package/ai/reference/cheatsheet.md +12 -1
- package/ai/reference/pitfalls.md +4 -0
- package/ai/reference/recipes.md +57 -0
- package/ai/template.html +8 -4
- package/ai/tools/check.mjs +17 -1
- package/ai/tools/render.mjs +13 -9
- package/dist/{Base-CwUxTfja.d.cts → Base-C6ZnJ9pD.d.cts} +1 -1
- package/dist/{Base-CyvSLoCP.d.ts → Base-CQOlB2VH.d.ts} +1 -1
- package/dist/Controller.cjs +132 -15
- package/dist/Controller.cjs.map +1 -1
- package/dist/Controller.d.cts +25 -3
- package/dist/Controller.d.ts +25 -3
- package/dist/Controller.js +132 -15
- package/dist/Controller.js.map +1 -1
- package/dist/{Movie-DSSNOF3T.d.cts → Movie-DnR4H1OO.d.ts} +93 -2
- package/dist/{Movie-nzmWsxWX.d.ts → Movie-Tl5dRLJl.d.cts} +93 -2
- package/dist/Presenter.cjs +671 -0
- package/dist/Presenter.cjs.map +1 -0
- package/dist/Presenter.d.cts +123 -0
- package/dist/Presenter.d.ts +123 -0
- package/dist/Presenter.js +669 -0
- package/dist/Presenter.js.map +1 -0
- package/dist/index.cjs +665 -36
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +165 -5
- package/dist/index.d.ts +165 -5
- package/dist/index.js +659 -37
- package/dist/index.js.map +1 -1
- package/dist/loader.css +1 -1
- package/dist/three.d.cts +2 -2
- package/dist/three.d.ts +2 -2
- package/dist/{types-BXu28nJj.d.cts → types-CBSiUKau.d.cts} +56 -1
- package/dist/{types-BXu28nJj.d.ts → types-CBSiUKau.d.ts} +56 -1
- package/docs/api.md +80 -0
- package/docs/dsl.md +48 -0
- package/llms-full.txt +203 -2
- package/llms.txt +3 -3
- package/package.json +5 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/Presenter.ts"],"names":["warnUnknownOptions"],"mappings":"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","file":"Presenter.cjs","sourcesContent":["import type { Movie, StopEvent } from './core/Movie';\nimport type { Stop } from './core/stops';\nimport { warnUnknownOptions } from './core/options';\n\nexport interface PresenterOptions {\n canvas: HTMLCanvasElement;\n /** Keys on the page: arrows, Space, Enter, PageUp / PageDown, Home / End, page number + Enter, B / W, F, ?, Esc. Default true. */\n keyboard?: boolean;\n /** A click (or tap) on the picture is \"next\". Default true. */\n clickToAdvance?: boolean;\n /** A swipe to the left is \"next\", to the right \"back\" (touch screens). Default true. */\n swipe?: boolean;\n /** The page counter, the page name and a progress line (they fade out when nothing happens). Default true. */\n indicator?: boolean;\n /** Stops with `advance: seconds` move on by themselves. Default true. */\n autoAdvance?: boolean;\n /** Run off the end: go back to the start and play again (a kiosk, a looping demo). Default false. */\n loop?: boolean;\n /** The accent of the progress line (any CSS colour). */\n accent?: string;\n /** Called when the audience-facing session is over: Escape with nothing left to close, or fullscreen left. (`Controller`'s Present button uses it to bring its bar back.) */\n onExit?: () => void;\n}\n\nconst OPTION_KEYS = ['canvas', 'keyboard', 'clickToAdvance', 'swipe', 'indicator', 'autoAdvance', 'loop', 'accent', 'onExit'] as const;\nconst NEXT_KEYS = new Set(['ArrowRight', 'ArrowDown', ' ', 'Enter', 'PageDown']);\nconst PREV_KEYS = new Set(['ArrowLeft', 'ArrowUp', 'Backspace', 'PageUp']);\nconst clock = (ms: number): string => { const s = Math.floor(ms / 1000); return `${String(Math.floor(s / 60)).padStart(2, '0')}:${String(s % 60).padStart(2, '0')}`; };\nconst IDLE_MS = 2500;\nconst DIGITS_MS = 2000;\nconst SWIPE_PX = 50;\n\nconst CSS = `\n.movie-presenter { position: absolute; inset: 0; z-index: 3; pointer-events: none; font: 500 13px/1.3 system-ui, -apple-system, 'Helvetica Neue', Arial, sans-serif; color: #fff; }\n.movie-presenter .mp-info { position: absolute; left: 50%; bottom: 14px; transform: translateX(-50%); white-space: nowrap; display: flex; align-items: baseline; gap: 12px; padding: 6px 12px; border-radius: 999px; background: rgba(0, 0, 0, 0.45); transition: opacity 0.4s ease; }\n.movie-presenter .mp-title { opacity: 0.75; }\n.movie-presenter .mp-title:empty { display: none; }\n.movie-presenter .mp-counter { font-variant-numeric: tabular-nums; letter-spacing: 0.04em; }\n.movie-presenter .mp-progress { position: absolute; left: 0; right: 0; bottom: 0; height: 3px; background: rgba(255, 255, 255, 0.14); transition: opacity 0.4s ease; }\n.movie-presenter .mp-progress::after { content: ''; position: absolute; inset: 0; background: var(--mp-accent, #ffffff); transform-origin: 0 50%; transform: scaleX(var(--mp-fill, 0)); transition: transform 0.4s ease; }\n.movie-presenter[data-idle=\"true\"] .mp-info, .movie-presenter[data-idle=\"true\"] .mp-progress { opacity: 0; }\n.movie-presenter .mp-cover { position: absolute; inset: 0; z-index: 4; opacity: 0; pointer-events: none; background: #000; transition: opacity 0.25s ease; }\n.movie-presenter .mp-cover[data-mode=\"black\"] { opacity: 1; pointer-events: auto; background: #000; }\n.movie-presenter .mp-cover[data-mode=\"white\"] { opacity: 1; pointer-events: auto; background: #fff; }\n.movie-presenter .mp-jump { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); padding: 10px 22px; border-radius: 12px; background: rgba(0, 0, 0, 0.6); font-size: 34px; font-weight: 600; letter-spacing: 0.06em; opacity: 0; transition: opacity 0.15s ease; }\n.movie-presenter .mp-jump[data-active=\"true\"] { opacity: 1; }\n.movie-presenter .mp-help { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); z-index: 5; padding: 18px 26px; border-radius: 14px; background: rgba(12, 14, 24, 0.92); box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5); pointer-events: auto; }\n.movie-presenter .mp-help[data-open=\"false\"] { display: none; }\n.movie-presenter .mp-help h3 { margin: 0 0 10px; font-size: 13px; letter-spacing: 0.12em; opacity: 0.7; }\n.movie-presenter .mp-help dl { display: grid; grid-template-columns: auto auto; gap: 6px 22px; margin: 0; }\n.movie-presenter .mp-help dt { opacity: 0.95; font-weight: 600; white-space: nowrap; }\n.movie-presenter .mp-help dd { margin: 0; opacity: 0.75; }\n.movie-presenter .mp-wait { position: absolute; inset: 0; z-index: 7; display: grid; place-items: center; background: #000; font-size: 13px; letter-spacing: 0.4em; opacity: 0.9; padding-left: 0.4em; }\n.movie-presenter .mp-wait[data-open=\"false\"] { display: none; }\n.movie-presenter .mp-overview { position: absolute; inset: 0; z-index: 6; display: flex; flex-direction: column; gap: 14px; padding: 26px 30px 18px; overflow: auto; background: rgba(8, 10, 18, 0.985); pointer-events: auto; }\n.movie-presenter .mp-overview[data-open=\"false\"] { display: none; }\n.movie-presenter .mp-grid { display: grid; grid-template-columns: repeat(var(--mp-cols, 3), minmax(0, 1fr)); gap: 14px; }\n.movie-presenter .mp-cell { position: relative; aspect-ratio: var(--mp-ratio, 16 / 9); overflow: hidden; border-radius: 8px; background: #000; border: 2px solid transparent; cursor: pointer; }\n.movie-presenter .mp-cell img { display: block; width: 100%; height: 100%; object-fit: cover; }\n.movie-presenter .mp-cell[data-current=\"true\"] { border-color: rgba(255, 255, 255, 0.45); }\n.movie-presenter .mp-cell[data-selected=\"true\"] { border-color: var(--mp-accent, #ffffff); box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.18); }\n.movie-presenter .mp-cell-label { position: absolute; left: 0; right: 0; bottom: 0; display: flex; gap: 8px; align-items: baseline; padding: 18px 10px 7px; background: linear-gradient(to top, rgba(0, 0, 0, 0.7), transparent); font-size: 12px; }\n.movie-presenter .mp-cell-num { font-weight: 700; font-variant-numeric: tabular-nums; }\n.movie-presenter .mp-cell-name { opacity: 0.85; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n.movie-presenter .mp-overview-hint { margin-top: auto; opacity: 0.55; font-size: 12px; letter-spacing: 0.04em; }\n[data-pr-wrap] .movie-controller { display: none !important; }\n[data-pr-wrap]:fullscreen { width: 100vw; height: 100vh; display: flex; align-items: center; justify-content: center; background: #000; }\n[data-pr-wrap]:fullscreen > canvas { width: 100% !important; height: 100% !important; max-width: none !important; max-height: none !important; object-fit: contain; border-radius: 0; }\n@media (prefers-reduced-motion: reduce) { .movie-presenter * { transition: none !important; } }\n`;\nfunction installStyles(): void {\n if (typeof document === 'undefined' || document.head.querySelector('style[data-movie-presenter]')) return;\n const el = document.createElement('style');\n el.setAttribute('data-movie-presenter', '');\n el.textContent = CSS;\n document.head.appendChild(el);\n}\n\nconst HELP: Array<[string, string]> = [\n ['→ ↓ Space Enter PageDown click', 'next (plays to the next stop)'],\n ['← ↑ Backspace PageUp', 'back one stop'],\n ['Home / End', 'first page / last stop'],\n ['number, then Enter', 'jump to that page'],\n ['B or .', 'black screen'],\n ['W or ,', 'white screen'],\n ['G', 'overview of all pages (arrows + Enter, or click)'],\n ['P', 'presenter view: notes, next picture, timer (a second window)'],\n ['F', 'fullscreen'],\n ['Esc', 'close this / black screen / fullscreen'],\n ['swipe ← →', 'next / back (touch)'],\n];\n\nconst VIEW_CSS = `\nhtml, body { margin: 0; height: 100%; background: #0c0e16; color: #e8ecf8; font: 500 15px/1.4 system-ui, -apple-system, 'Helvetica Neue', Arial, sans-serif; }\n.pv { display: grid; grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr); gap: 18px; height: 100%; padding: 18px; box-sizing: border-box; }\n.pv-label { margin: 0 0 6px; font-size: 11px; font-weight: 700; letter-spacing: 0.18em; opacity: 0.55; }\n.pv-main { display: flex; flex-direction: column; min-height: 0; }\n.pv-now { width: 100%; height: auto; background: #000; border-radius: 8px; }\n.pv-side { display: flex; flex-direction: column; gap: 12px; min-height: 0; }\n.pv-top { display: flex; align-items: baseline; gap: 14px; }\n.pv-count { font-size: 30px; font-weight: 700; font-variant-numeric: tabular-nums; }\n.pv-title { flex: 1; opacity: 0.75; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n.pv-timer { font-size: 30px; font-weight: 600; font-variant-numeric: tabular-nums; letter-spacing: 0.04em; }\n.pv-nextbox { position: relative; aspect-ratio: var(--pv-ratio, 16 / 9); background: #000; border-radius: 8px; overflow: hidden; }\n.pv-next { display: block; width: 100%; height: 100%; object-fit: cover; }\n.pv-nextbox[data-end=\"true\"] .pv-next { display: none; }\n.pv-end { position: absolute; inset: 0; display: none; place-items: center; opacity: 0.6; letter-spacing: 0.2em; font-size: 12px; }\n.pv-nextbox[data-end=\"true\"] .pv-end { display: grid; }\n.pv-notes { flex: 1; min-height: 80px; overflow: auto; padding: 12px 14px; border-radius: 8px; background: #151927; font-size: 20px; line-height: 1.5; white-space: pre-wrap; }\n.pv-notes[data-empty=\"true\"] { opacity: 0.4; font-size: 14px; }\n.pv-notes[data-empty=\"true\"]::before { content: 'No notes for this page.'; }\n.pv-buttons { display: flex; gap: 10px; }\n.pv button { font: inherit; color: inherit; border: 0; border-radius: 8px; padding: 10px 16px; background: #232a40; cursor: pointer; }\n.pv button:hover { background: #2e3754; }\n.pv .pv-nextbtn { flex: 1; background: #3b5bdb; font-weight: 600; }\n.pv .pv-nextbtn:hover { background: #4c6ef5; }\n.pv .pv-reset { padding: 4px 10px; font-size: 12px; opacity: 0.7; }\n`;\n\n/**\n * A presentation player for a movie with `stops` (`composition.stops`): it stops where the stops are, and moves on with the keys,\n * a click, a tap or a swipe, like slides with animation. It draws only a small page counter, the page name and a progress line (they\n * fade out when idle), and a black / white screen, a list of keys (`?`) and fullscreen (`F`). Use it instead of `Controller` on the page.\n */\nexport class Presenter {\n readonly movie: Movie;\n readonly options: Required<Omit<PresenterOptions, 'accent' | 'onExit'>> & { accent?: string; onExit?: () => void };\n\n private box: HTMLElement;\n private wrappedHere = false;\n private root: HTMLDivElement;\n private counterEl: HTMLElement | null = null;\n private titleEl: HTMLElement | null = null;\n private progressEl: HTMLElement | null = null;\n private coverEl!: HTMLElement;\n private helpEl!: HTMLElement;\n private jumpEl!: HTMLElement;\n private idleTimer: ReturnType<typeof setTimeout> | null = null;\n private digitsTimer: ReturnType<typeof setTimeout> | null = null;\n private advanceTimer: ReturnType<typeof setTimeout> | null = null;\n private loopTimer: ReturnType<typeof setTimeout> | null = null;\n private overviewEl!: HTMLElement;\n private gridEl!: HTMLElement;\n private overviewSel = 0;\n /** A picture of every stop (by stop index), made once before the talk: for the overview and the presenter view's \"next\". */\n private thumbs = new Map<number, string>();\n private thumbsPromise: Promise<void> | null = null;\n private waitEl!: HTMLElement;\n private view: { win: Window; timer: ReturnType<typeof setInterval>; started: number; els: Record<string, HTMLElement>; onClose: () => void } | null = null;\n private digits = '';\n private downAt: { x: number; y: number } | null = null;\n private swiped = false;\n private canvasCursor = '';\n private destroyed = false;\n private wasWrapAttr = false;\n\n private onKey = (e: KeyboardEvent) => this.handleKey(e);\n private onStop = (e: StopEvent) => this.handleStop(e);\n private onSeeked = () => this.refresh();\n private onFrame = () => this.mirror();\n private onEnded = () => this.handleEnded();\n private onPointerDown = (e: PointerEvent) => { this.downAt = { x: e.clientX, y: e.clientY }; this.swiped = false; };\n private onPointerUp = (e: PointerEvent) => this.handlePointerUp(e);\n private onPointerMove = () => this.wake();\n private onClick = () => this.handleClick();\n private wasFullscreen = false;\n private onFullscreenChange = () => {\n const now = document.fullscreenElement === this.box;\n if (this.wasFullscreen && !now) this.options.onExit?.();\n this.wasFullscreen = now;\n };\n\n constructor(movie: Movie, options: PresenterOptions) {\n if (!options || !options.canvas) throw new Error('Presenter requires options.canvas (HTMLCanvasElement).');\n warnUnknownOptions('Presenter', options, OPTION_KEYS);\n this.movie = movie;\n this.options = {\n canvas: options.canvas, keyboard: options.keyboard ?? true, clickToAdvance: options.clickToAdvance ?? true, swipe: options.swipe ?? true,\n indicator: options.indicator ?? true, autoAdvance: options.autoAdvance ?? true, loop: options.loop ?? false, accent: options.accent, onExit: options.onExit,\n };\n if ((movie.stops?.length ?? 0) === 0) {\n console.warn('pixi-effects: Presenter: this movie has no stops, so there is nowhere to pause; add `stops: [2, 5, 9]` (seconds) to the composition. next() and back still work.');\n }\n installStyles();\n const canvas = this.options.canvas;\n this.box = this.positioningBox(canvas);\n this.wasWrapAttr = this.box.hasAttribute('data-pr-wrap');\n this.box.setAttribute('data-pr-wrap', '');\n this.root = document.createElement('div');\n this.root.className = 'movie-presenter';\n this.root.setAttribute('data-idle', 'false');\n if (this.options.accent) this.root.style.setProperty('--mp-accent', this.options.accent);\n this.root.innerHTML = `\n ${this.options.indicator ? '<div class=\"mp-progress\"></div><div class=\"mp-info\"><span class=\"mp-title\"></span><span class=\"mp-counter\"></span></div>' : ''}\n <div class=\"mp-wait\" data-open=\"false\">Preparing…</div>\n <div class=\"mp-jump\" data-active=\"false\"></div>\n <div class=\"mp-overview\" data-open=\"false\" role=\"dialog\" aria-label=\"Pages\"><div class=\"mp-grid\"></div><div class=\"mp-overview-hint\">← → ↑ ↓ choose · Enter or click: go · G or Esc: close</div></div>\n <div class=\"mp-cover\" data-mode=\"off\"></div>\n <div class=\"mp-help\" data-open=\"false\" role=\"dialog\" aria-label=\"Keys\"><h3>KEYS</h3><dl>${HELP.map(([k, d]) => `<dt>${k}</dt><dd>${d}</dd>`).join('')}</dl></div>`;\n this.box.appendChild(this.root);\n this.counterEl = this.root.querySelector('.mp-counter');\n this.titleEl = this.root.querySelector('.mp-title');\n this.progressEl = this.root.querySelector('.mp-progress');\n this.coverEl = this.root.querySelector('.mp-cover') as HTMLElement;\n this.helpEl = this.root.querySelector('.mp-help') as HTMLElement;\n this.jumpEl = this.root.querySelector('.mp-jump') as HTMLElement;\n this.waitEl = this.root.querySelector('.mp-wait') as HTMLElement;\n this.overviewEl = this.root.querySelector('.mp-overview') as HTMLElement;\n this.gridEl = this.root.querySelector('.mp-grid') as HTMLElement;\n this.coverEl.addEventListener('click', () => this.setCover('off'));\n\n this.canvasCursor = canvas.style.cursor;\n if (this.options.clickToAdvance) { canvas.style.cursor = 'pointer'; canvas.addEventListener('click', this.onClick); }\n if (this.options.swipe) { canvas.addEventListener('pointerdown', this.onPointerDown); canvas.addEventListener('pointerup', this.onPointerUp); }\n canvas.addEventListener('pointermove', this.onPointerMove);\n if (this.options.keyboard) document.addEventListener('keydown', this.onKey);\n document.addEventListener('fullscreenchange', this.onFullscreenChange);\n movie.on('stop', this.onStop);\n movie.on('seeked', this.onSeeked);\n movie.on('ended', this.onEnded);\n this.refresh();\n this.wake();\n }\n\n /** Enter presentation: ask for fullscreen (a browser needs a click or key press for that) and play to the first stop. */\n async start(): Promise<void> {\n this.waitEl.setAttribute('data-open', 'true'); // \"Preparing\": the pictures are made before the audience sees a thing\n try { await this.ensureThumbs(); } finally { this.waitEl.setAttribute('data-open', 'false'); }\n await this.enterFullscreen();\n await this.next();\n }\n\n /** Leave fullscreen. */\n async exit(): Promise<void> {\n if (document.fullscreenElement === this.box) await document.exitFullscreen?.().catch(() => {});\n }\n\n next(): Promise<void> { this.cancelAdvance(); return this.run(() => this.movie.next()); }\n prev(): Promise<void> { this.cancelAdvance(); return this.run(() => this.movie.prev()); }\n\n /** Black out (`'black'`), white out (`'white'`) or bring the picture back (`'off'`). */\n setCover(mode: 'black' | 'white' | 'off'): void {\n this.coverEl.setAttribute('data-mode', mode);\n if (mode !== 'off') this.cancelAdvance();\n }\n\n destroy(): void {\n if (this.destroyed) return;\n this.destroyed = true;\n const canvas = this.options.canvas;\n document.removeEventListener('keydown', this.onKey);\n document.removeEventListener('fullscreenchange', this.onFullscreenChange);\n canvas.removeEventListener('click', this.onClick);\n canvas.removeEventListener('pointerdown', this.onPointerDown);\n canvas.removeEventListener('pointerup', this.onPointerUp);\n canvas.removeEventListener('pointermove', this.onPointerMove);\n this.closePresenterView();\n this.movie.off('stop', this.onStop);\n this.movie.off('seeked', this.onSeeked);\n this.movie.off('ended', this.onEnded);\n for (const t of [this.idleTimer, this.digitsTimer, this.advanceTimer, this.loopTimer]) if (t) clearTimeout(t);\n canvas.style.cursor = this.canvasCursor;\n this.root.remove();\n if (!this.wasWrapAttr) this.box.removeAttribute('data-pr-wrap');\n if (this.wrappedHere) {\n const parent = this.box.parentElement;\n if (parent) { parent.insertBefore(canvas, this.box); this.box.remove(); }\n }\n }\n\n // ── internals ──\n\n private positioningBox(canvas: HTMLCanvasElement): HTMLElement {\n const parent = canvas.parentElement;\n if (!parent) throw new Error('Presenter: canvas must be attached to the DOM before constructing.');\n const pos = getComputedStyle(parent).position;\n if (pos === 'relative' || pos === 'absolute' || pos === 'fixed' || pos === 'sticky') return parent;\n const wrap = document.createElement('div');\n wrap.className = 'movie-presenter-wrap';\n wrap.style.cssText = 'position: relative; display: inline-block; line-height: 0;';\n parent.insertBefore(wrap, canvas);\n wrap.appendChild(canvas);\n this.wrappedHere = true;\n return wrap;\n }\n\n private run(fn: () => Promise<void>): Promise<void> {\n return fn().catch(err => { console.warn('pixi-effects: Presenter:', err); });\n }\n\n private async enterFullscreen(): Promise<void> {\n const box = this.box as HTMLElement & { requestFullscreen?: () => Promise<void> };\n try { await box.requestFullscreen?.(); } catch { /* the browser said no (no gesture, or iPhone Safari): present in the page */ }\n }\n\n private toggleFullscreen(): void {\n if (document.fullscreenElement === this.box) void this.exit();\n else void this.enterFullscreen();\n }\n\n private cancelAdvance(): void {\n if (this.advanceTimer) { clearTimeout(this.advanceTimer); this.advanceTimer = null; }\n if (this.loopTimer) { clearTimeout(this.loopTimer); this.loopTimer = null; }\n }\n\n private handleStop(e: StopEvent): void {\n this.refresh();\n this.cancelAdvance();\n if (this.options.autoAdvance && e.stop.advance !== undefined && this.coverEl.getAttribute('data-mode') === 'off') {\n this.advanceTimer = setTimeout(() => { this.advanceTimer = null; void this.next(); }, e.stop.advance * 1000);\n }\n }\n\n private handleEnded(): void {\n this.refresh();\n if (!this.options.loop) return;\n this.cancelAdvance();\n this.loopTimer = setTimeout(() => {\n this.loopTimer = null;\n void this.run(async () => { await this.movie.gotoFrame(0, true); await this.movie.next(); });\n }, 800);\n }\n\n private refresh(): void {\n const m = this.movie;\n const pages = m.pageCount ?? 0, stops = m.stops?.length ?? 0;\n if (this.counterEl) {\n this.counterEl.textContent = pages > 0 ? `${m.pageIndex >= 0 ? m.pageIndex + 1 : '–'} / ${pages}` : '';\n this.counterEl.style.display = pages > 0 ? '' : 'none';\n }\n if (this.titleEl) this.titleEl.textContent = m.currentStop?.page ?? '';\n if (this.progressEl) this.progressEl.style.setProperty('--mp-fill', String(stops > 0 ? (m.stopIndex + 1) / stops : 0));\n this.refreshView();\n }\n\n private wake(): void {\n this.root.setAttribute('data-idle', 'false');\n if (this.options.clickToAdvance) this.options.canvas.style.cursor = 'pointer';\n if (this.idleTimer) clearTimeout(this.idleTimer);\n this.idleTimer = setTimeout(() => {\n this.root.setAttribute('data-idle', 'true');\n this.options.canvas.style.cursor = 'none';\n }, IDLE_MS);\n }\n\n private showDigits(): void {\n this.jumpEl.textContent = this.digits ? `→ ${this.digits}` : '';\n this.jumpEl.setAttribute('data-active', this.digits ? 'true' : 'false');\n if (this.digitsTimer) clearTimeout(this.digitsTimer);\n this.digitsTimer = this.digits ? setTimeout(() => { this.digits = ''; this.showDigits(); }, DIGITS_MS) : null;\n }\n\n /** Something that moves the presentation: if the screen is blacked out (or the key list is open) the first press only brings it back. */\n private navigate(go: () => void): void {\n if (this.coverEl.getAttribute('data-mode') !== 'off') { this.setCover('off'); return; }\n if (this.helpEl.getAttribute('data-open') === 'true') { this.helpEl.setAttribute('data-open', 'false'); return; }\n go();\n }\n\n private handleKey(e: KeyboardEvent): void {\n if (this.destroyed || e.ctrlKey || e.metaKey || e.altKey) return;\n const t = e.target as HTMLElement | null;\n if (t && (t.tagName === 'INPUT' || t.tagName === 'TEXTAREA' || t.tagName === 'SELECT' || t.isContentEditable)) return;\n const k = e.key;\n let handled = true;\n this.wake();\n if (k === 'g' || k === 'G') { this.toggleOverview(); e.preventDefault(); return; }\n if (this.overviewOpen()) { if (this.handleOverviewKey(e)) e.preventDefault(); return; }\n if (k >= '0' && k <= '9' && k.length === 1) { this.digits = (this.digits + k).slice(0, 4); this.showDigits(); }\n else if (k === 'Enter' && this.digits) {\n const page = Number(this.digits) - 1; this.digits = ''; this.showDigits();\n this.navigate(() => { this.cancelAdvance(); void this.run(() => this.movie.goToPage(page)); });\n }\n else if (k === 'Backspace' && this.digits) { this.digits = this.digits.slice(0, -1); this.showDigits(); }\n else if (NEXT_KEYS.has(k)) this.navigate(() => void this.next());\n else if (PREV_KEYS.has(k)) this.navigate(() => void this.prev());\n else if (k === 'Home') this.navigate(() => { this.cancelAdvance(); void this.run(() => this.movie.goToPage(0)); });\n else if (k === 'End') this.navigate(() => { this.cancelAdvance(); void this.run(() => this.movie.goToStop(Math.max(0, (this.movie.stops?.length ?? 1) - 1))); });\n else if (k === 'b' || k === 'B' || k === '.') this.setCover(this.coverEl.getAttribute('data-mode') === 'black' ? 'off' : 'black');\n else if (k === 'w' || k === 'W' || k === ',') this.setCover(this.coverEl.getAttribute('data-mode') === 'white' ? 'off' : 'white');\n else if (k === 'p' || k === 'P') this.togglePresenterView();\n else if (k === 'f' || k === 'F') this.toggleFullscreen();\n else if (k === '?' || k === 'h' || k === 'H') this.helpEl.setAttribute('data-open', this.helpEl.getAttribute('data-open') === 'true' ? 'false' : 'true');\n else if (k === 'Escape') {\n if (this.helpEl.getAttribute('data-open') === 'true') this.helpEl.setAttribute('data-open', 'false');\n else if (this.coverEl.getAttribute('data-mode') !== 'off') this.setCover('off');\n else if (this.digits) { this.digits = ''; this.showDigits(); }\n else if (document.fullscreenElement === this.box) handled = false; // the browser's own Escape leaves fullscreen (and the change ends the session)\n else if (this.options.onExit) this.options.onExit();\n }\n else handled = false;\n if (handled) e.preventDefault();\n }\n\n // ── the presenter view: a second window for the speaker ──\n\n private togglePresenterView(): void {\n if (this.view && !this.view.win.closed) this.closePresenterView();\n else this.openPresenterView();\n }\n\n /** Open the speaker's window: what is on screen (live), the next picture, the notes of the page, a timer, and next / back. Returns it (null if the browser blocked the popup). */\n openPresenterView(): Window | null {\n if (this.view && !this.view.win.closed) { this.view.win.focus(); return this.view.win; }\n this.closePresenterView();\n const win = window.open('', 'pixi-effects-presenter-view', 'popup=yes,width=1180,height=720');\n if (!win) { console.warn('pixi-effects: Presenter: the browser blocked the presenter view popup; allow popups for this page and press P again.'); return null; }\n const doc = win.document;\n doc.title = 'Presenter view';\n const style = doc.createElement('style');\n style.textContent = VIEW_CSS;\n doc.head.appendChild(style);\n const { width, height } = this.options.canvas;\n doc.body.innerHTML = `<div class=\"pv\" style=\"--pv-ratio: ${width} / ${height}\">\n <div class=\"pv-main\"><div class=\"pv-label\">NOW</div><canvas class=\"pv-now\" width=\"${Math.min(width, 960)}\" height=\"${Math.round(height * Math.min(width, 960) / width)}\"></canvas></div>\n <div class=\"pv-side\">\n <div class=\"pv-top\"><span class=\"pv-count\"></span><span class=\"pv-title\"></span><span class=\"pv-timer\">00:00</span><button class=\"pv-reset\" type=\"button\">reset</button></div>\n <div><div class=\"pv-label\">NEXT</div><div class=\"pv-nextbox\" data-end=\"false\"><img class=\"pv-next\" alt=\"\"><div class=\"pv-end\">END OF THE TALK</div></div></div>\n <div class=\"pv-notes\" data-empty=\"true\"></div>\n <div class=\"pv-buttons\"><button class=\"pv-prev\" type=\"button\">◀ Back</button><button class=\"pv-nextbtn\" type=\"button\">Next ▶</button></div>\n </div></div>`;\n const els: Record<string, HTMLElement> = {};\n for (const c of ['count', 'title', 'timer', 'next', 'nextbox', 'notes', 'now']) els[c] = doc.querySelector(`.pv-${c}`) as HTMLElement;\n const started = Date.now();\n const onClose = () => { if (this.view && this.view.win === win) this.closePresenterView(); };\n const timer = setInterval(() => { els.timer!.textContent = clock(Date.now() - this.view!.started); }, 1000);\n this.view = { win, timer, started, els, onClose };\n (doc.querySelector('.pv-nextbtn') as HTMLElement).addEventListener('click', () => void this.next());\n (doc.querySelector('.pv-prev') as HTMLElement).addEventListener('click', () => void this.prev());\n (doc.querySelector('.pv-reset') as HTMLElement).addEventListener('click', () => { this.view!.started = Date.now(); els.timer!.textContent = '00:00'; });\n if (this.options.keyboard) doc.addEventListener('keydown', this.onKey);\n win.addEventListener?.('pagehide', onClose);\n this.movie.on('frame', this.onFrame);\n void this.ensureThumbs();\n this.refreshView();\n this.mirror();\n return win;\n }\n\n closePresenterView(): void {\n const v = this.view;\n if (!v) return;\n this.view = null;\n clearInterval(v.timer);\n this.movie.off('frame', this.onFrame);\n try { v.win.document.removeEventListener('keydown', this.onKey); v.win.removeEventListener?.('pagehide', v.onClose); } catch { /* the window is already gone */ }\n if (!v.win.closed) { try { v.win.close(); } catch { /* ignore */ } }\n }\n\n /** Copy what the movie has just drawn into the view (called from the `frame` event, right after the render, when the canvas can be read). */\n private mirror(): void {\n const v = this.view;\n if (!v || v.win.closed) return;\n const c = v.els.now as HTMLCanvasElement;\n c.getContext('2d')?.drawImage(this.options.canvas, 0, 0, c.width, c.height);\n }\n\n private refreshView(): void {\n const v = this.view;\n if (!v || v.win.closed) return;\n const m = this.movie;\n const stops = m.stops ?? [];\n const pages = m.pageCount ?? 0;\n const cur = m.stopIndex ?? -1;\n v.els.count!.textContent = pages > 0 ? `${m.pageIndex >= 0 ? m.pageIndex + 1 : '–'} / ${pages}` : '';\n v.els.title!.textContent = m.currentStop?.page ?? (cur < 0 ? stops[0]?.page ?? '' : '');\n // the notes of the page the talk is in (before the first stop: of the first page, \"coming up\"): the latest ones written on or before this stop\n const upTo = cur < 0 ? 0 : cur, pageIndex = stops[upTo]?.pageIndex;\n let notes = '';\n for (const s of stops) if (s.pageIndex === pageIndex && s.index <= upTo && s.notes) notes = s.notes;\n v.els.notes!.textContent = notes;\n v.els.notes!.setAttribute('data-empty', String(notes === ''));\n const next = stops[cur + 1];\n v.els.nextbox!.setAttribute('data-end', String(!next));\n const src = next ? this.thumbs.get(next.index) : undefined;\n if (src) v.els.next!.setAttribute('src', src); else v.els.next!.removeAttribute('src');\n }\n\n // ── the overview ──\n\n private pageStops(): Stop[] { return (this.movie.stops ?? []).filter(s => s.pageStart); }\n private overviewOpen(): boolean { return this.overviewEl.getAttribute('data-open') === 'true'; }\n\n private toggleOverview(): void {\n if (this.overviewOpen()) { this.overviewEl.setAttribute('data-open', 'false'); return; }\n if (this.pageStops().length === 0) return;\n this.cancelAdvance();\n if (this.movie.isPlaying) this.movie.pause();\n this.helpEl.setAttribute('data-open', 'false');\n this.buildOverview();\n this.overviewEl.setAttribute('data-open', 'true');\n void this.ensureThumbs();\n }\n\n /**\n * Make a picture of every stop, once. Taking them moves the playhead through the stops and back, which the audience would see:\n * `start()` does it before anything is shown (behind a \"Preparing\" cover), and an overview opened before that does it on the spot.\n */\n ensureThumbs(): Promise<void> {\n this.thumbsPromise ??= (async () => {\n try {\n await this.movie.stopImages({\n which: 'stops', as: 'dataURL', type: 'image/jpeg', quality: 0.72, scale: Math.min(1, 480 / Math.max(1, this.options.canvas.width)),\n onImage: img => { this.thumbs.set(img.stop.index, img.image as string); this.onThumb(img.stop.index); },\n });\n } catch (err) {\n console.warn('pixi-effects: Presenter: could not make the page pictures:', err);\n this.thumbsPromise = null;\n }\n })();\n return this.thumbsPromise;\n }\n\n /** A page's picture is its last stop's (the page fully built). */\n private pageThumb(page: number): string | undefined {\n const stops = (this.movie.stops ?? []).filter(s => s.pageIndex === page);\n return stops.length ? this.thumbs.get(stops[stops.length - 1]!.index) : undefined;\n }\n\n private onThumb(stopIndex: number): void {\n const stop = this.movie.stops?.[stopIndex];\n if (stop) this.fillThumb(stop.pageIndex);\n this.refreshView();\n }\n\n private buildOverview(): void {\n const pages = this.pageStops();\n const { width, height } = this.options.canvas;\n const cols = Math.min(5, Math.max(2, Math.ceil(Math.sqrt(pages.length))));\n this.gridEl.style.setProperty('--mp-cols', String(cols));\n this.gridEl.style.setProperty('--mp-ratio', `${width} / ${height}`);\n this.gridEl.innerHTML = '';\n const current = Math.max(0, this.movie.pageIndex ?? 0);\n pages.forEach((s, i) => {\n const cell = document.createElement('div');\n cell.className = 'mp-cell';\n cell.setAttribute('data-current', String(i === this.movie.pageIndex));\n cell.setAttribute('data-selected', String(i === current));\n cell.innerHTML = `<div class=\"mp-cell-label\"><span class=\"mp-cell-num\">${i + 1}</span><span class=\"mp-cell-name\"></span></div>`;\n (cell.querySelector('.mp-cell-name') as HTMLElement).textContent = s.page ?? '';\n cell.addEventListener('click', () => { this.overviewEl.setAttribute('data-open', 'false'); this.cancelAdvance(); void this.run(() => this.movie.goToPage(i)); });\n this.gridEl.appendChild(cell);\n this.fillThumb(i);\n });\n this.overviewSel = current;\n }\n\n private fillThumb(page: number): void {\n const cell = this.gridEl.children[page] as HTMLElement | undefined;\n const src = this.pageThumb(page);\n if (!cell || !src || cell.querySelector('img')) return;\n const img = document.createElement('img');\n img.alt = ''; img.src = src;\n cell.insertBefore(img, cell.firstChild);\n }\n\n private select(i: number): void {\n const cells = [...this.gridEl.children] as HTMLElement[];\n this.overviewSel = Math.min(cells.length - 1, Math.max(0, i));\n cells.forEach((c, k) => c.setAttribute('data-selected', String(k === this.overviewSel)));\n cells[this.overviewSel]?.scrollIntoView?.({ block: 'nearest' });\n }\n\n private handleOverviewKey(e: KeyboardEvent): boolean {\n const cols = Number(this.gridEl.style.getPropertyValue('--mp-cols')) || 3;\n switch (e.key) {\n case 'ArrowRight': this.select(this.overviewSel + 1); return true;\n case 'ArrowLeft': this.select(this.overviewSel - 1); return true;\n case 'ArrowDown': this.select(this.overviewSel + cols); return true;\n case 'ArrowUp': this.select(this.overviewSel - cols); return true;\n case 'Enter': { const page = this.overviewSel; this.overviewEl.setAttribute('data-open', 'false'); this.cancelAdvance(); void this.run(() => this.movie.goToPage(page)); return true; }\n case 'Escape': this.overviewEl.setAttribute('data-open', 'false'); return true;\n default: return NEXT_KEYS.has(e.key) || PREV_KEYS.has(e.key); // swallowed: the presentation does not move underneath\n }\n }\n\n private handleClick(): void {\n if (this.swiped) { this.swiped = false; return; }\n this.wake();\n this.navigate(() => void this.next());\n }\n\n private handlePointerUp(e: PointerEvent): void {\n const d = this.downAt; this.downAt = null;\n if (!d) return;\n const dx = e.clientX - d.x, dy = e.clientY - d.y;\n if (Math.abs(dx) < SWIPE_PX || Math.abs(dy) > Math.abs(dx)) return;\n this.swiped = true;\n this.wake();\n this.navigate(() => void (dx < 0 ? this.next() : this.prev()));\n }\n}\n"]}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { f as Movie } from './Movie-Tl5dRLJl.cjs';
|
|
2
|
+
import 'pixi.js';
|
|
3
|
+
import 'gsap';
|
|
4
|
+
import './types-CBSiUKau.cjs';
|
|
5
|
+
|
|
6
|
+
interface PresenterOptions {
|
|
7
|
+
canvas: HTMLCanvasElement;
|
|
8
|
+
/** Keys on the page: arrows, Space, Enter, PageUp / PageDown, Home / End, page number + Enter, B / W, F, ?, Esc. Default true. */
|
|
9
|
+
keyboard?: boolean;
|
|
10
|
+
/** A click (or tap) on the picture is "next". Default true. */
|
|
11
|
+
clickToAdvance?: boolean;
|
|
12
|
+
/** A swipe to the left is "next", to the right "back" (touch screens). Default true. */
|
|
13
|
+
swipe?: boolean;
|
|
14
|
+
/** The page counter, the page name and a progress line (they fade out when nothing happens). Default true. */
|
|
15
|
+
indicator?: boolean;
|
|
16
|
+
/** Stops with `advance: seconds` move on by themselves. Default true. */
|
|
17
|
+
autoAdvance?: boolean;
|
|
18
|
+
/** Run off the end: go back to the start and play again (a kiosk, a looping demo). Default false. */
|
|
19
|
+
loop?: boolean;
|
|
20
|
+
/** The accent of the progress line (any CSS colour). */
|
|
21
|
+
accent?: string;
|
|
22
|
+
/** Called when the audience-facing session is over: Escape with nothing left to close, or fullscreen left. (`Controller`'s Present button uses it to bring its bar back.) */
|
|
23
|
+
onExit?: () => void;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* A presentation player for a movie with `stops` (`composition.stops`): it stops where the stops are, and moves on with the keys,
|
|
27
|
+
* a click, a tap or a swipe, like slides with animation. It draws only a small page counter, the page name and a progress line (they
|
|
28
|
+
* fade out when idle), and a black / white screen, a list of keys (`?`) and fullscreen (`F`). Use it instead of `Controller` on the page.
|
|
29
|
+
*/
|
|
30
|
+
declare class Presenter {
|
|
31
|
+
readonly movie: Movie;
|
|
32
|
+
readonly options: Required<Omit<PresenterOptions, 'accent' | 'onExit'>> & {
|
|
33
|
+
accent?: string;
|
|
34
|
+
onExit?: () => void;
|
|
35
|
+
};
|
|
36
|
+
private box;
|
|
37
|
+
private wrappedHere;
|
|
38
|
+
private root;
|
|
39
|
+
private counterEl;
|
|
40
|
+
private titleEl;
|
|
41
|
+
private progressEl;
|
|
42
|
+
private coverEl;
|
|
43
|
+
private helpEl;
|
|
44
|
+
private jumpEl;
|
|
45
|
+
private idleTimer;
|
|
46
|
+
private digitsTimer;
|
|
47
|
+
private advanceTimer;
|
|
48
|
+
private loopTimer;
|
|
49
|
+
private overviewEl;
|
|
50
|
+
private gridEl;
|
|
51
|
+
private overviewSel;
|
|
52
|
+
/** A picture of every stop (by stop index), made once before the talk: for the overview and the presenter view's "next". */
|
|
53
|
+
private thumbs;
|
|
54
|
+
private thumbsPromise;
|
|
55
|
+
private waitEl;
|
|
56
|
+
private view;
|
|
57
|
+
private digits;
|
|
58
|
+
private downAt;
|
|
59
|
+
private swiped;
|
|
60
|
+
private canvasCursor;
|
|
61
|
+
private destroyed;
|
|
62
|
+
private wasWrapAttr;
|
|
63
|
+
private onKey;
|
|
64
|
+
private onStop;
|
|
65
|
+
private onSeeked;
|
|
66
|
+
private onFrame;
|
|
67
|
+
private onEnded;
|
|
68
|
+
private onPointerDown;
|
|
69
|
+
private onPointerUp;
|
|
70
|
+
private onPointerMove;
|
|
71
|
+
private onClick;
|
|
72
|
+
private wasFullscreen;
|
|
73
|
+
private onFullscreenChange;
|
|
74
|
+
constructor(movie: Movie, options: PresenterOptions);
|
|
75
|
+
/** Enter presentation: ask for fullscreen (a browser needs a click or key press for that) and play to the first stop. */
|
|
76
|
+
start(): Promise<void>;
|
|
77
|
+
/** Leave fullscreen. */
|
|
78
|
+
exit(): Promise<void>;
|
|
79
|
+
next(): Promise<void>;
|
|
80
|
+
prev(): Promise<void>;
|
|
81
|
+
/** Black out (`'black'`), white out (`'white'`) or bring the picture back (`'off'`). */
|
|
82
|
+
setCover(mode: 'black' | 'white' | 'off'): void;
|
|
83
|
+
destroy(): void;
|
|
84
|
+
private positioningBox;
|
|
85
|
+
private run;
|
|
86
|
+
private enterFullscreen;
|
|
87
|
+
private toggleFullscreen;
|
|
88
|
+
private cancelAdvance;
|
|
89
|
+
private handleStop;
|
|
90
|
+
private handleEnded;
|
|
91
|
+
private refresh;
|
|
92
|
+
private wake;
|
|
93
|
+
private showDigits;
|
|
94
|
+
/** Something that moves the presentation: if the screen is blacked out (or the key list is open) the first press only brings it back. */
|
|
95
|
+
private navigate;
|
|
96
|
+
private handleKey;
|
|
97
|
+
private togglePresenterView;
|
|
98
|
+
/** Open the speaker's window: what is on screen (live), the next picture, the notes of the page, a timer, and next / back. Returns it (null if the browser blocked the popup). */
|
|
99
|
+
openPresenterView(): Window | null;
|
|
100
|
+
closePresenterView(): void;
|
|
101
|
+
/** Copy what the movie has just drawn into the view (called from the `frame` event, right after the render, when the canvas can be read). */
|
|
102
|
+
private mirror;
|
|
103
|
+
private refreshView;
|
|
104
|
+
private pageStops;
|
|
105
|
+
private overviewOpen;
|
|
106
|
+
private toggleOverview;
|
|
107
|
+
/**
|
|
108
|
+
* Make a picture of every stop, once. Taking them moves the playhead through the stops and back, which the audience would see:
|
|
109
|
+
* `start()` does it before anything is shown (behind a "Preparing" cover), and an overview opened before that does it on the spot.
|
|
110
|
+
*/
|
|
111
|
+
ensureThumbs(): Promise<void>;
|
|
112
|
+
/** A page's picture is its last stop's (the page fully built). */
|
|
113
|
+
private pageThumb;
|
|
114
|
+
private onThumb;
|
|
115
|
+
private buildOverview;
|
|
116
|
+
private fillThumb;
|
|
117
|
+
private select;
|
|
118
|
+
private handleOverviewKey;
|
|
119
|
+
private handleClick;
|
|
120
|
+
private handlePointerUp;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export { Presenter, type PresenterOptions };
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { f as Movie } from './Movie-DnR4H1OO.js';
|
|
2
|
+
import 'pixi.js';
|
|
3
|
+
import 'gsap';
|
|
4
|
+
import './types-CBSiUKau.js';
|
|
5
|
+
|
|
6
|
+
interface PresenterOptions {
|
|
7
|
+
canvas: HTMLCanvasElement;
|
|
8
|
+
/** Keys on the page: arrows, Space, Enter, PageUp / PageDown, Home / End, page number + Enter, B / W, F, ?, Esc. Default true. */
|
|
9
|
+
keyboard?: boolean;
|
|
10
|
+
/** A click (or tap) on the picture is "next". Default true. */
|
|
11
|
+
clickToAdvance?: boolean;
|
|
12
|
+
/** A swipe to the left is "next", to the right "back" (touch screens). Default true. */
|
|
13
|
+
swipe?: boolean;
|
|
14
|
+
/** The page counter, the page name and a progress line (they fade out when nothing happens). Default true. */
|
|
15
|
+
indicator?: boolean;
|
|
16
|
+
/** Stops with `advance: seconds` move on by themselves. Default true. */
|
|
17
|
+
autoAdvance?: boolean;
|
|
18
|
+
/** Run off the end: go back to the start and play again (a kiosk, a looping demo). Default false. */
|
|
19
|
+
loop?: boolean;
|
|
20
|
+
/** The accent of the progress line (any CSS colour). */
|
|
21
|
+
accent?: string;
|
|
22
|
+
/** Called when the audience-facing session is over: Escape with nothing left to close, or fullscreen left. (`Controller`'s Present button uses it to bring its bar back.) */
|
|
23
|
+
onExit?: () => void;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* A presentation player for a movie with `stops` (`composition.stops`): it stops where the stops are, and moves on with the keys,
|
|
27
|
+
* a click, a tap or a swipe, like slides with animation. It draws only a small page counter, the page name and a progress line (they
|
|
28
|
+
* fade out when idle), and a black / white screen, a list of keys (`?`) and fullscreen (`F`). Use it instead of `Controller` on the page.
|
|
29
|
+
*/
|
|
30
|
+
declare class Presenter {
|
|
31
|
+
readonly movie: Movie;
|
|
32
|
+
readonly options: Required<Omit<PresenterOptions, 'accent' | 'onExit'>> & {
|
|
33
|
+
accent?: string;
|
|
34
|
+
onExit?: () => void;
|
|
35
|
+
};
|
|
36
|
+
private box;
|
|
37
|
+
private wrappedHere;
|
|
38
|
+
private root;
|
|
39
|
+
private counterEl;
|
|
40
|
+
private titleEl;
|
|
41
|
+
private progressEl;
|
|
42
|
+
private coverEl;
|
|
43
|
+
private helpEl;
|
|
44
|
+
private jumpEl;
|
|
45
|
+
private idleTimer;
|
|
46
|
+
private digitsTimer;
|
|
47
|
+
private advanceTimer;
|
|
48
|
+
private loopTimer;
|
|
49
|
+
private overviewEl;
|
|
50
|
+
private gridEl;
|
|
51
|
+
private overviewSel;
|
|
52
|
+
/** A picture of every stop (by stop index), made once before the talk: for the overview and the presenter view's "next". */
|
|
53
|
+
private thumbs;
|
|
54
|
+
private thumbsPromise;
|
|
55
|
+
private waitEl;
|
|
56
|
+
private view;
|
|
57
|
+
private digits;
|
|
58
|
+
private downAt;
|
|
59
|
+
private swiped;
|
|
60
|
+
private canvasCursor;
|
|
61
|
+
private destroyed;
|
|
62
|
+
private wasWrapAttr;
|
|
63
|
+
private onKey;
|
|
64
|
+
private onStop;
|
|
65
|
+
private onSeeked;
|
|
66
|
+
private onFrame;
|
|
67
|
+
private onEnded;
|
|
68
|
+
private onPointerDown;
|
|
69
|
+
private onPointerUp;
|
|
70
|
+
private onPointerMove;
|
|
71
|
+
private onClick;
|
|
72
|
+
private wasFullscreen;
|
|
73
|
+
private onFullscreenChange;
|
|
74
|
+
constructor(movie: Movie, options: PresenterOptions);
|
|
75
|
+
/** Enter presentation: ask for fullscreen (a browser needs a click or key press for that) and play to the first stop. */
|
|
76
|
+
start(): Promise<void>;
|
|
77
|
+
/** Leave fullscreen. */
|
|
78
|
+
exit(): Promise<void>;
|
|
79
|
+
next(): Promise<void>;
|
|
80
|
+
prev(): Promise<void>;
|
|
81
|
+
/** Black out (`'black'`), white out (`'white'`) or bring the picture back (`'off'`). */
|
|
82
|
+
setCover(mode: 'black' | 'white' | 'off'): void;
|
|
83
|
+
destroy(): void;
|
|
84
|
+
private positioningBox;
|
|
85
|
+
private run;
|
|
86
|
+
private enterFullscreen;
|
|
87
|
+
private toggleFullscreen;
|
|
88
|
+
private cancelAdvance;
|
|
89
|
+
private handleStop;
|
|
90
|
+
private handleEnded;
|
|
91
|
+
private refresh;
|
|
92
|
+
private wake;
|
|
93
|
+
private showDigits;
|
|
94
|
+
/** Something that moves the presentation: if the screen is blacked out (or the key list is open) the first press only brings it back. */
|
|
95
|
+
private navigate;
|
|
96
|
+
private handleKey;
|
|
97
|
+
private togglePresenterView;
|
|
98
|
+
/** Open the speaker's window: what is on screen (live), the next picture, the notes of the page, a timer, and next / back. Returns it (null if the browser blocked the popup). */
|
|
99
|
+
openPresenterView(): Window | null;
|
|
100
|
+
closePresenterView(): void;
|
|
101
|
+
/** Copy what the movie has just drawn into the view (called from the `frame` event, right after the render, when the canvas can be read). */
|
|
102
|
+
private mirror;
|
|
103
|
+
private refreshView;
|
|
104
|
+
private pageStops;
|
|
105
|
+
private overviewOpen;
|
|
106
|
+
private toggleOverview;
|
|
107
|
+
/**
|
|
108
|
+
* Make a picture of every stop, once. Taking them moves the playhead through the stops and back, which the audience would see:
|
|
109
|
+
* `start()` does it before anything is shown (behind a "Preparing" cover), and an overview opened before that does it on the spot.
|
|
110
|
+
*/
|
|
111
|
+
ensureThumbs(): Promise<void>;
|
|
112
|
+
/** A page's picture is its last stop's (the page fully built). */
|
|
113
|
+
private pageThumb;
|
|
114
|
+
private onThumb;
|
|
115
|
+
private buildOverview;
|
|
116
|
+
private fillThumb;
|
|
117
|
+
private select;
|
|
118
|
+
private handleOverviewKey;
|
|
119
|
+
private handleClick;
|
|
120
|
+
private handlePointerUp;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export { Presenter, type PresenterOptions };
|