@idle-screens/core 0.4.1 → 0.4.3
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/dist/index.d.ts +18 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -131,6 +131,8 @@ interface SaverInstance {
|
|
|
131
131
|
interface SaverManifest {
|
|
132
132
|
id: string;
|
|
133
133
|
label: string;
|
|
134
|
+
/** One-line summary for catalogs / agent tooling (e.g. MCP `listSavers`). */
|
|
135
|
+
description?: string;
|
|
134
136
|
passthrough?: boolean;
|
|
135
137
|
minBackend?: 'css' | 'canvas2d' | 'webgl2' | 'webgpu';
|
|
136
138
|
costTier?: 'idle' | 'low' | 'medium' | 'high';
|
|
@@ -162,6 +164,22 @@ interface SaverManifest {
|
|
|
162
164
|
/** Saver renders on a provided surface (canvas/OffscreenCanvas) and avoids DOM
|
|
163
165
|
* APIs, enabling Worker execution when the browser supports OffscreenCanvas. */
|
|
164
166
|
workerReady?: boolean;
|
|
167
|
+
/**
|
|
168
|
+
* How the saver relates to time — a semantic claim about the program, not
|
|
169
|
+
* an API flag (renderFrame's presence is the API).
|
|
170
|
+
*
|
|
171
|
+
* - 'closed-form': every frame is a pure function of (t, seed, params) —
|
|
172
|
+
* compiled plans, phase integrals, triangle waves, CSS keyframes. With
|
|
173
|
+
* `renderFrame` this means scrubbing, seek-back determinism, and
|
|
174
|
+
* reproducible perception readings; without it (DOM/CSS savers) the
|
|
175
|
+
* motion is still periodic and pure, just not pixel-addressable by us.
|
|
176
|
+
* - 'simulated': state genuinely evolves by integration (fluid dynamics,
|
|
177
|
+
* reaction-diffusion) — frames depend on history, sampling is the only
|
|
178
|
+
* honest observation, and motion metrics between runs are meaningless.
|
|
179
|
+
*
|
|
180
|
+
* Tooling should prefer this over hardcoded per-saver capability lists.
|
|
181
|
+
*/
|
|
182
|
+
timeModel?: 'closed-form' | 'simulated';
|
|
165
183
|
}
|
|
166
184
|
/** A registered saver: manifest + a (possibly lazy/async) mount factory. */
|
|
167
185
|
interface SaverPlugin {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts","../src/rng.ts","../src/reactive.ts","../src/control-track.ts","../src/idle-detector.ts","../src/engine.ts","../src/idle-screen.element.ts","../src/worker-protocol.ts"],"sourcesContent":["import type { Rng } from './rng';\n\n/** How a parameter interpolates between control-track deltas. */\nexport type Ease = 'step' | 'linear' | 'smooth';\n\nexport type ParamType = 'number' | 'color' | 'bool' | 'enum';\nexport type ParamValue = number | string | boolean;\n\n/** One typed, ranged, interpolatable knob: an agent's steering surface. */\nexport interface ParamDef {\n type: ParamType;\n default: ParamValue;\n min?: number;\n max?: number;\n options?: string[];\n /** Default interpolation when a delta targets this knob. */\n ease?: Ease;\n}\n\nexport type ParamSpace = Record<string, ParamDef>;\n\n/** A sparse, timestamped, interpolatable parameter change. Agents stream THESE\n * (over AG-UI state-patches / MCP resource updates), never frames. */\nexport interface ParamDelta {\n /** ms from track start. */\n t: number;\n /** key in the saver's paramSpace. */\n path: string;\n value: ParamValue;\n ease?: Ease;\n /** ramp duration ms from the previous value (0 = instant). */\n dur?: number;\n}\n\n/** A recorded or live steering performance for a seeded program. */\nexport interface ControlTrack {\n program: string;\n seed: number;\n duration?: number;\n loop?: boolean;\n deltas: ParamDelta[];\n}\n\n/** Page-context seam: passthrough savers read/eat the live page through this,\n * rather than querying `document` directly. */\nexport interface PageContext {\n /** Sample dominant colors of the page (for palette-reactive savers). */\n palette(): string[];\n /** Visible page blocks a passthrough saver may transform (\"victims\"). */\n victims(selector: string): HTMLElement[];\n}\n\n/** What the host hands a saver when it mounts. */\nexport interface SaverContext {\n /** A full-viewport container the saver renders into. Canvas savers create a\n * canvas inside it; DOM savers (toasters, DVD, messages) append elements. The\n * host is cleared by the runtime on dispose. */\n host: HTMLElement;\n /** Pre-created rendering surface. When present, canvas savers should use this\n * instead of creating their own canvas. In a Worker this is an OffscreenCanvas. */\n surface?: HTMLCanvasElement | OffscreenCanvas;\n /** Device pixel ratio — use instead of reading window.devicePixelRatio. */\n dpr: number;\n width: number;\n height: number;\n /** Seeded PRNG. Use this, never Math.random(), for determinism. */\n rng: Rng;\n seed: number;\n reducedMotion: boolean;\n /** Present for passthrough savers (over the live page). */\n page?: PageContext;\n}\n\n/**\n * One deck of a mounted saver's practical composition stack, bottom-up.\n *\n * This is deliberately NOT the schema's layer concept (declared sprite\n * layers): it describes what a running instance is actually composed of, so\n * hosts and tooling can present and inspect the stack uniformly. A\n * passthrough saver is at minimum `page` + `surface`; a classic canvas saver\n * is just its `surface`; savers may further describe the logical draw passes\n * inside a surface. The model is intentionally small and open — future work\n * (multi-surface savers, per-pass toggles, cross-saver scenes) extends it\n * rather than replacing it.\n */\nexport interface SaverLayer {\n id: string;\n label: string;\n /** 'page' = the live document a passthrough saver performs on;\n * 'surface' = a rendering surface the instance owns (usually a canvas);\n * 'pass' = a logical draw pass inside the surface above it. */\n kind: 'page' | 'surface' | 'pass';\n /** The element that IS this layer, when one exists. Hosts may toggle its\n * visibility for inspection. A `page` layer has no element — the HOST\n * owns the document and binds it (the saver only borrows it). */\n el?: HTMLElement;\n description?: string;\n}\n\nexport interface SaverInstance {\n /** Freeze/unfreeze the render loop (paused, reduced-motion, or screensaver end). */\n setPaused(paused: boolean): void;\n resize(width: number, height: number, dpr?: number): void;\n /** Deterministic, frame-addressable render: draw the state at logical time `t`\n * (ms) for `seed`. Pure w.r.t. (program, seed, applied track, t). Optional. */\n renderFrame?(t: number, seed: number): void;\n /** Steer parameters over time. Optional. */\n applyTrack?(track: ControlTrack): void;\n /** Seek logical animation time (ms) for workbench preview. Optional. */\n previewAt?(t: number): void;\n /** Describe the practical composition stack, bottom-up. Optional.\n * (Named `composition`, not `layers`: schema-compiled instances already\n * carry their declared sprite `layers` as data.) */\n composition?(): SaverLayer[];\n /** Tear down; MUST restore any live-page mutations. */\n dispose(): void;\n}\n\n/** Self-describing metadata, readable WITHOUT executing the saver. */\nexport interface SaverManifest {\n id: string;\n label: string;\n passthrough?: boolean;\n minBackend?: 'css' | 'canvas2d' | 'webgl2' | 'webgpu';\n costTier?: 'idle' | 'low' | 'medium' | 'high';\n motionIntensity?: 'calm' | 'moderate' | 'energetic';\n reducedMotionFallback?: 'static' | 'slow' | 'hide';\n palette?: string[];\n paramSpace?: ParamSpace;\n a11y?: { flashSafe?: boolean; notes?: string };\n provenance?: { prompt?: string; seed?: number; model?: string };\n /** Attribution for savers derived from licensed or third-party work — the\n * concept, reference implementation, or embedded assets. Hosts SHOULD show\n * this wherever the saver is showcased; the full ledger is CREDITS.md. */\n attribution?: {\n /** What this saver descends from, e.g. 'After Dark \"Messages\" — concept by Berkeley Systems'. */\n source: string;\n /** The licensing situation, ours and upstream, e.g. 'MIT port; reference CSS MIT (Bryan Braun)'. */\n license: string;\n /** Reference implementation or rights context. */\n url?: string;\n };\n thumbnail?: string;\n /** Saver renders on a provided surface (canvas/OffscreenCanvas) and avoids DOM\n * APIs, enabling Worker execution when the browser supports OffscreenCanvas. */\n workerReady?: boolean;\n}\n\n/** A registered saver: manifest + a (possibly lazy/async) mount factory. */\nexport interface SaverPlugin {\n manifest: SaverManifest;\n mount(ctx: SaverContext): SaverInstance | Promise<SaverInstance>;\n /** Original schema spec (JSON-serializable). When present, the element sends\n * a `mount-spec` message to the Worker instead of `mount`, so the Worker can\n * compile and run the spec without pre-registration in its registry. */\n spec?: unknown;\n}\n\n/** Engine configuration. */\nexport interface IdleScreensConfig {\n /** Idle time before sleeping, in ms. */\n timeoutMs: number;\n /** Also sleep when the window loses focus. */\n sleepOnBlur: boolean;\n /** Do not run on localhost (debug hooks bypass this). */\n disableOnLocalhost: boolean;\n /** Which registered saver to show. */\n defaultPluginId: string;\n /** How to pick across sleeps. */\n selection: 'fixed' | 'random' | 'rotate';\n /** Show the clock chrome (non-passthrough savers only). */\n showClock: boolean;\n /** Exact document title while asleep. */\n sleepTitle?: string;\n /** Master seed for plugin selection + the default saver seed. */\n seed: number;\n /** Return true for a URL where the saver must never sleep. */\n suppress?: (url: string) => boolean;\n /** Pluggable persistence (defaults to localStorage when available). */\n storage?: { get(key: string): string | null; set(key: string, value: string): void };\n /** URL of the idle-worker script. When set, savers with `workerReady: true`\n * render in a Web Worker via OffscreenCanvas. Omit to disable Worker rendering. */\n workerUrl?: string;\n /** Built-in, keyboard-opened config menu (saver picker). `true`/omitted =\n * enabled with ⌘K / Ctrl+K; `false` = no hotkey and no built-in menu (the\n * `configMenuOpen` signal + open/close API still work, so a host may render\n * its own). Pass an object to reconfigure. */\n configMenu?: boolean | ConfigMenuConfig;\n}\n\n/** Options for the built-in, keyboard-opened config menu. */\nexport interface ConfigMenuConfig {\n /** Master switch. Default true. */\n enabled?: boolean;\n /** Decides whether a keydown opens/toggles the menu. Default: ⌘K / Ctrl+K. */\n hotkey?: (e: KeyboardEvent) => boolean;\n /** Show the saver picker control. Default true. */\n showPicker?: boolean;\n /** Preview the picked saver immediately (sleep to show it). Default true. */\n previewOnPick?: boolean;\n /** Heading text. Default 'Screen Saver'. */\n title?: string;\n}\n\n/** Default menu hotkey: ⌘K (mac) / Ctrl+K, no other modifiers. */\nexport const DEFAULT_MENU_HOTKEY = (e: KeyboardEvent): boolean =>\n (e.metaKey || e.ctrlKey) && !e.altKey && !e.shiftKey && e.key.toLowerCase() === 'k';\n\n/** Normalize `configMenu` to a filled config, or null when disabled. */\nexport function resolveConfigMenu(\n c: boolean | ConfigMenuConfig | undefined,\n): Required<ConfigMenuConfig> | null {\n if (c === false) return null;\n const o: ConfigMenuConfig = c === true || c === undefined ? {} : c;\n if (o.enabled === false) return null;\n return {\n enabled: true,\n hotkey: o.hotkey ?? DEFAULT_MENU_HOTKEY,\n showPicker: o.showPicker ?? true,\n previewOnPick: o.previewOnPick ?? true,\n title: o.title ?? 'Screen Saver',\n };\n}\n\nexport const DEFAULT_CONFIG: IdleScreensConfig = {\n timeoutMs: 60_000,\n sleepOnBlur: true,\n disableOnLocalhost: false,\n defaultPluginId: '',\n selection: 'fixed',\n showClock: true,\n seed: 1,\n configMenu: true,\n};\n","/**\n * A tiny, fast, seedable PRNG (splitmix32). Deterministic: the same seed always\n * yields the same sequence, on any machine. This is what makes \"same program +\n * seed + control-track = identical frames\" hold. Savers take an `Rng` from their\n * `SaverContext` instead of calling `Math.random()`.\n */\nexport interface Rng {\n /** Next float in [0, 1). */\n next(): number;\n /** Float in [min, max). */\n range(min: number, max: number): number;\n /** Integer in [min, max] inclusive. */\n int(min: number, max: number): number;\n /** Random element of a non-empty array. */\n pick<T>(arr: readonly T[]): T;\n /** A fresh independent stream (e.g. per subsystem), derived from this seed. */\n fork(salt: number): Rng;\n}\n\nexport function createRng(seed: number): Rng {\n let a = seed >>> 0;\n const next = (): number => {\n a |= 0;\n a = (a + 0x9e3779b9) | 0;\n let t = a ^ (a >>> 16);\n t = Math.imul(t, 0x21f0aaad);\n t = t ^ (t >>> 15);\n t = Math.imul(t, 0x735a2d97);\n return ((t = t ^ (t >>> 15)) >>> 0) / 4294967296;\n };\n const rng: Rng = {\n next,\n range: (min, max) => min + (max - min) * next(),\n int: (min, max) => min + Math.floor(next() * (max - min + 1)),\n pick: (arr) => arr[Math.floor(next() * arr.length)] as (typeof arr)[number],\n fork: (salt) => createRng((seed ^ Math.imul(salt + 1, 0x9e3779b9)) >>> 0),\n };\n return rng;\n}\n","/**\n * Framework-agnostic reactivity. We re-export `@preact/signals-core` so the rest\n * of the engine uses the same `signal` / `computed` / `effect` primitives it did\n * as Angular signals, with near-identical semantics.\n */\nexport {\n signal,\n computed,\n effect,\n batch,\n untracked,\n type Signal,\n type ReadonlySignal,\n} from '@preact/signals-core';\n","import type { ControlTrack, Ease, ParamDelta, ParamSpace, ParamValue } from './types';\n\nfunction easeFn(e: Ease, p: number): number {\n const x = p <= 0 ? 0 : p >= 1 ? 1 : p;\n switch (e) {\n case 'step':\n return x >= 1 ? 1 : 0;\n case 'smooth':\n return x * x * (3 - 2 * x);\n case 'linear':\n default:\n return x;\n }\n}\n\nfunction lerp(a: number, b: number, p: number): number {\n return a + (b - a) * p;\n}\n\nfunction parseHex(c: string): [number, number, number] | null {\n const m = /^#?([0-9a-f]{6})$/i.exec(c.trim());\n if (!m) return null;\n const n = parseInt(m[1]!, 16);\n return [(n >> 16) & 255, (n >> 8) & 255, n & 255];\n}\n\nfunction toHex(rgb: [number, number, number]): string {\n const h = (v: number): string =>\n Math.round(Math.max(0, Math.min(255, v)))\n .toString(16)\n .padStart(2, '0');\n return `#${h(rgb[0])}${h(rgb[1])}${h(rgb[2])}`;\n}\n\nfunction lerpValue(type: string, a: ParamValue, b: ParamValue, p: number): ParamValue {\n if (type === 'number' && typeof a === 'number' && typeof b === 'number') return lerp(a, b, p);\n if (type === 'color' && typeof a === 'string' && typeof b === 'string') {\n const ca = parseHex(a);\n const cb = parseHex(b);\n if (ca && cb) return toHex([lerp(ca[0], cb[0], p), lerp(ca[1], cb[1], p), lerp(ca[2], cb[2], p)]);\n }\n return p >= 1 ? b : a; // bool / enum / step\n}\n\nfunction evalPath(\n dflt: ParamValue,\n type: string,\n defaultEase: Ease,\n deltas: ParamDelta[],\n t: number,\n): ParamValue {\n if (deltas.length === 0) return dflt;\n let prevVal = dflt;\n let prevT = -Infinity;\n for (const k of deltas) {\n if (t < k.t) {\n const rampStart = k.dur != null ? k.t - k.dur : prevT === -Infinity ? k.t : prevT;\n if (t <= rampStart) return prevVal;\n const p = easeFn(k.ease ?? defaultEase, (t - rampStart) / (k.t - rampStart || 1));\n return lerpValue(type, prevVal, k.value, p);\n }\n prevVal = k.value;\n prevT = k.t;\n }\n return prevVal; // after the last keyframe\n}\n\n/**\n * Sample a control track: given the saver's param space (defaults + types) and a\n * track, return the interpolated parameter values at logical time `t` (ms). Pure\n * and deterministic: identical `(space, track, t)` yields identical output.\n */\nexport function sampleTrack(\n space: ParamSpace,\n track: ControlTrack,\n t: number,\n): Record<string, ParamValue> {\n const byPath = new Map<string, ParamDelta[]>();\n for (const d of track.deltas) {\n const arr = byPath.get(d.path) ?? [];\n arr.push(d);\n byPath.set(d.path, arr);\n }\n const wrapped =\n track.loop && track.duration && track.duration > 0 ? t % track.duration : t;\n\n const out: Record<string, ParamValue> = {};\n for (const [path, def] of Object.entries(space)) {\n const deltas = (byPath.get(path) ?? []).slice().sort((a, b) => a.t - b.t);\n out[path] = evalPath(def.default, def.type, def.ease ?? 'linear', deltas, wrapped);\n }\n return out;\n}\n\n/** Default param values (the \"resting\" program before any track is applied). */\nexport function defaultParams(space: ParamSpace): Record<string, ParamValue> {\n const out: Record<string, ParamValue> = {};\n for (const [path, def] of Object.entries(space)) out[path] = def.default;\n return out;\n}\n","import { signal, type ReadonlySignal } from './reactive';\n\n/**\n * Detects user inactivity. `idle` flips true once no activity for `timeoutMs`.\n * Framework-agnostic port of the Angular IdleService: 6 activity events + a\n * single `setTimeout` (not a poll) whose reschedule is throttled to >=500ms so\n * frequent pointermove events do not thrash timers.\n */\nexport class IdleDetector {\n private readonly _idle = signal(false);\n readonly idle: ReadonlySignal<boolean> = this._idle;\n\n private timer: ReturnType<typeof setTimeout> | null = null;\n private lastReset = 0;\n private running = false;\n\n private static readonly EVENTS = [\n 'pointerdown',\n 'pointermove',\n 'keydown',\n 'wheel',\n 'touchstart',\n 'scroll',\n ] as const;\n\n constructor(private readonly timeoutMs: number) {}\n\n private readonly onActivity = (): void => this.markActive();\n\n start(): void {\n if (this.running || typeof window === 'undefined') return;\n this.running = true;\n for (const e of IdleDetector.EVENTS) {\n window.addEventListener(e, this.onActivity, { passive: true });\n }\n this.schedule();\n }\n\n stop(): void {\n if (!this.running) return;\n this.running = false;\n for (const e of IdleDetector.EVENTS) {\n window.removeEventListener(e, this.onActivity);\n }\n this.clear();\n }\n\n /** Force an activity pulse (resets the countdown, wakes from idle). */\n markActive(): void {\n if (this._idle.value) this._idle.value = false;\n const now = typeof performance !== 'undefined' ? performance.now() : Date.now();\n if (now - this.lastReset < 500) return; // throttle reschedules\n this.lastReset = now;\n this.schedule();\n }\n\n private schedule(): void {\n this.clear();\n this.timer = setTimeout(() => {\n this._idle.value = true;\n }, this.timeoutMs);\n }\n\n private clear(): void {\n if (this.timer !== null) {\n clearTimeout(this.timer);\n this.timer = null;\n }\n }\n}\n","import { computed, effect, signal, untracked, type ReadonlySignal } from './reactive';\nimport { IdleDetector } from './idle-detector';\nimport { createRng, type Rng } from './rng';\nimport {\n DEFAULT_CONFIG,\n resolveConfigMenu,\n type ConfigMenuConfig,\n type IdleScreensConfig,\n type SaverPlugin,\n} from './types';\n\nexport type EngineState = 'awake' | 'sleeping';\n\nconst hasWindow = typeof window !== 'undefined';\nconst hasDoc = typeof document !== 'undefined';\n\nfunction defaultStorage(): IdleScreensConfig['storage'] {\n return {\n get: (k) => {\n try {\n return hasWindow ? window.localStorage.getItem(k) : null;\n } catch {\n return null;\n }\n },\n set: (k, v) => {\n try {\n if (hasWindow) window.localStorage.setItem(k, v);\n } catch {\n /* private mode / disabled storage */\n }\n },\n };\n}\n\n/**\n * The framework-agnostic idle-screens state machine (port of the Angular\n * ScreensaverService). Owns: awake/sleeping state, plugin selection, the sleep\n * clock, reduced-motion + visibility, idle/blur triggers, and the\n * `window.__idleScreens` debug hook. It does NOT render; the `<idle-screen>`\n * element observes its signals.\n */\nexport class IdleScreensEngine {\n readonly config: IdleScreensConfig;\n private readonly plugins: SaverPlugin[];\n private readonly storage: NonNullable<IdleScreensConfig['storage']>;\n private readonly idle: IdleDetector;\n private readonly selectionRng: Rng;\n\n private readonly _state = signal<EngineState>('awake');\n readonly state: ReadonlySignal<EngineState> = this._state;\n readonly isSleeping = computed(() => this._state.value === 'sleeping');\n\n private readonly _activeId = signal('');\n readonly activePlugin = computed(\n () =>\n this.plugins.find((p) => p.manifest.id === this._activeId.value) ??\n this.plugins[0] ??\n null,\n );\n readonly activeIsPassthrough = computed(\n () => this.activePlugin.value?.manifest.passthrough ?? false,\n );\n\n private readonly _now = signal(new Date(0));\n readonly now: ReadonlySignal<Date> = this._now;\n private readonly _hidden = signal(false);\n readonly hidden: ReadonlySignal<boolean> = this._hidden;\n private readonly _reducedMotion = signal(false);\n readonly reducedMotion: ReadonlySignal<boolean> = this._reducedMotion;\n\n /** Resolved built-in config-menu options, or null when disabled. */\n readonly configMenu: Required<ConfigMenuConfig> | null;\n private readonly _configMenuOpen = signal(false);\n /** Whether the config menu is open. Drives the built-in `<idle-screen>` menu;\n * a host may also observe this to render its own. */\n readonly configMenuOpen: ReadonlySignal<boolean> = this._configMenuOpen;\n\n private clockTimer: ReturnType<typeof setInterval> | null = null;\n private started = false;\n private disposers: Array<() => void> = [];\n\n constructor(config: Partial<IdleScreensConfig>, plugins: SaverPlugin[]) {\n this.config = { ...DEFAULT_CONFIG, ...config };\n this.plugins = plugins;\n this.configMenu = resolveConfigMenu(this.config.configMenu);\n this.storage = this.config.storage ?? defaultStorage()!;\n this.idle = new IdleDetector(this.config.timeoutMs);\n this.selectionRng = createRng(this.config.seed >>> 0);\n\n const stored = this.storage.get('idleScreens.plugin');\n const initialId =\n (stored && plugins.some((p) => p.manifest.id === stored) && stored) ||\n this.config.defaultPluginId ||\n plugins[0]?.manifest.id ||\n '';\n this._activeId.value = initialId;\n }\n\n get pluginList(): Array<{ id: string; label: string }> {\n return this.plugins.map((p) => ({ id: p.manifest.id, label: p.manifest.label }));\n }\n\n /** Begin idle detection + listeners + debug hook. */\n init(): void {\n if (this.started || !hasWindow) return;\n this.started = true;\n\n if (hasDoc) {\n this._hidden.value = document.hidden;\n const onVis = (): void => {\n this._hidden.value = document.hidden;\n };\n document.addEventListener('visibilitychange', onVis);\n this.disposers.push(() => document.removeEventListener('visibilitychange', onVis));\n }\n\n const mq = hasWindow ? window.matchMedia('(prefers-reduced-motion: reduce)') : null;\n if (mq) {\n this._reducedMotion.value = mq.matches;\n const onMq = (): void => {\n this._reducedMotion.value = mq.matches;\n };\n mq.addEventListener('change', onMq);\n this.disposers.push(() => mq.removeEventListener('change', onMq));\n }\n\n // Sleep when idle fires (unless suppressed). `sleep()` reads `state` in its\n // guard; wrap it in `untracked` so this effect depends ONLY on the idle\n // signal — otherwise flipping `state` to awake in wake() (while idle is still\n // latched true) would re-trigger this effect and immediately re-sleep.\n this.idle.start();\n this.disposers.push(\n effect(() => {\n if (this.idle.idle.value) untracked(() => this.sleep());\n }),\n );\n\n if (this.config.sleepOnBlur) {\n const onBlur = (): void => this.sleep();\n window.addEventListener('blur', onBlur);\n this.disposers.push(() => window.removeEventListener('blur', onBlur));\n }\n\n // Optional built-in config-menu hotkey (⌘K / Ctrl+K by default).\n if (this.configMenu) {\n const hotkey = this.configMenu.hotkey;\n const onKey = (e: KeyboardEvent): void => {\n if (hotkey(e)) {\n e.preventDefault();\n this.toggleConfigMenu();\n }\n };\n window.addEventListener('keydown', onKey);\n this.disposers.push(() => window.removeEventListener('keydown', onKey));\n }\n\n // Drive the clock only while asleep + visible.\n this.disposers.push(\n effect(() => {\n const ticking = this._state.value === 'sleeping' && !this._hidden.value;\n if (ticking && this.clockTimer === null) {\n this._now.value = new Date();\n this.clockTimer = setInterval(() => {\n this._now.value = new Date();\n }, 1000);\n } else if (!ticking && this.clockTimer !== null) {\n clearInterval(this.clockTimer);\n this.clockTimer = null;\n }\n }),\n );\n\n this.installDebugHook();\n }\n\n destroy(): void {\n this.idle.stop();\n if (this.clockTimer !== null) {\n clearInterval(this.clockTimer);\n this.clockTimer = null;\n }\n for (const d of this.disposers) d();\n this.disposers = [];\n this.started = false;\n }\n\n private suppressed(): boolean {\n if (this.config.disableOnLocalhost && hasWindow && /^(localhost|127\\.|\\[::1\\])/.test(location.hostname)) {\n return true;\n }\n const url = hasWindow ? location.pathname + location.search : '';\n return this.config.suppress ? this.config.suppress(url) : false;\n }\n\n sleep(): void {\n if (this._state.value === 'sleeping' || this.suppressed()) return;\n this.pickPlugin();\n this._state.value = 'sleeping';\n }\n\n /** Sleep ignoring suppression rules (debug / manual). */\n forceSleep(): void {\n if (this._state.value === 'sleeping') return;\n this.pickPlugin();\n this._state.value = 'sleeping';\n }\n\n wake(): void {\n if (this._state.value === 'awake') return;\n this._state.value = 'awake';\n this.idle.markActive();\n }\n\n toggle(): void {\n if (this.isSleeping.value) this.wake();\n else this.forceSleep();\n }\n\n openConfigMenu(): void {\n this._configMenuOpen.value = true;\n }\n closeConfigMenu(): void {\n this._configMenuOpen.value = false;\n }\n toggleConfigMenu(): void {\n this._configMenuOpen.value = !this._configMenuOpen.value;\n }\n\n setPlugin(id: string): void {\n if (!this.plugins.some((p) => p.manifest.id === id)) return;\n this._activeId.value = id;\n this.storage.set('idleScreens.plugin', id);\n }\n\n private pickPlugin(): void {\n if (this.plugins.length === 0) return;\n switch (this.config.selection) {\n case 'random': {\n const i = this.selectionRng.int(0, this.plugins.length - 1);\n this._activeId.value = this.plugins[i]!.manifest.id;\n break;\n }\n case 'rotate': {\n const cur = this.plugins.findIndex((p) => p.manifest.id === this._activeId.value);\n const next = this.plugins[(cur + 1) % this.plugins.length]!;\n this._activeId.value = next.manifest.id;\n break;\n }\n case 'fixed':\n default:\n // Keep the current (persisted / menu-chosen) plugin. `defaultPluginId`\n // is only the INITIAL pick (see constructor); once the user chooses a\n // saver via setPlugin/the menu it sticks across sleeps.\n break;\n }\n }\n\n private installDebugHook(): void {\n if (!hasWindow) return;\n (window as unknown as { __idleScreens?: unknown }).__idleScreens = {\n sleep: () => this.forceSleep(),\n wake: () => this.wake(),\n toggle: () => this.toggle(),\n setPlugin: (id: string) => this.setPlugin(id),\n openMenu: () => this.openConfigMenu(),\n closeMenu: () => this.closeConfigMenu(),\n toggleMenu: () => this.toggleConfigMenu(),\n state: () => this._state.value,\n menuOpen: () => this._configMenuOpen.value,\n active: () => this.activePlugin.value?.manifest.id ?? null,\n plugins: this.pluginList,\n };\n }\n}\n","import { effect } from './reactive';\nimport { IdleScreensEngine } from './engine';\nimport { createRng } from './rng';\nimport type { IdleScreensConfig, PageContext, SaverInstance, SaverPlugin } from './types';\nimport type { WorkerInbound, WorkerOutbound } from './worker-protocol';\n\nconst STYLE = `\n :host { all: initial; }\n dialog.frame {\n position: fixed; inset: 0; width: 100%; height: 100%;\n max-width: none; max-height: none; margin: 0; border: 0; padding: 0;\n background: #0a0a0f; overflow: hidden; cursor: none; color: #fff;\n }\n dialog.frame[open] { animation: ss-in 0.5s ease; }\n dialog.frame.leaving { animation: ss-out 0.32s ease forwards; }\n dialog.frame.reduced { animation: none; }\n dialog.frame::backdrop { background: #0a0a0f; }\n dialog.frame.passthrough, dialog.frame.passthrough::backdrop { background: transparent; }\n @keyframes ss-in { from { opacity: 0; } to { opacity: 1; } }\n @keyframes ss-out { from { opacity: 1; } to { opacity: 0; } }\n .surface { position: absolute; inset: 0; display: block; width: 100%; height: 100%; }\n .surface > canvas { display: block; width: 100%; height: 100%; }\n /* Host-owned fallback markup (<x slot=\"fallback\">), shown only when the active\n saver fails to mount — the host decides what a broken saver looks like. */\n .fallback { position: absolute; inset: 0; display: none; place-items: center; }\n dialog.frame.show-fallback .fallback { display: grid; }\n .clock {\n position: absolute; top: 10px; right: 12px; text-align: right;\n font-family: 'Orbitron', system-ui, sans-serif; pointer-events: none;\n }\n .clock .day { font-size: 34px; opacity: 0.9; }\n .clock .time { font-size: 54px; }\n .hint {\n position: fixed; bottom: 26px; left: 50%; transform: translateX(-50%);\n color: rgba(230,230,230,0.6); font: 12px ui-monospace, monospace;\n letter-spacing: 0.25em; text-transform: uppercase; opacity: 0;\n transition: opacity 1s ease; pointer-events: none;\n }\n .hint.show { opacity: 1; }\n\n /* Built-in config menu: a normal (interactive) centered dialog, distinct from\n the cursor-hidden saver frame. */\n dialog.menu {\n position: fixed; inset: 0; margin: auto; border: 0; padding: 0;\n width: min(420px, calc(100vw - 32px)); max-width: none;\n background: transparent; color: #f2f2f5;\n }\n dialog.menu::backdrop { background: rgba(6,6,10,0.5); backdrop-filter: blur(2px); }\n .menu-card {\n background: #14141b; border: 1px solid rgba(255,255,255,0.12);\n border-radius: 14px; padding: 20px; box-shadow: 0 24px 60px rgba(0,0,0,0.5);\n font-family: system-ui, sans-serif;\n }\n .menu-title { font-size: 18px; font-weight: 600; margin: 0 0 14px; }\n .menu-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 14px; }\n .menu-row > span { font-size: 14px; opacity: 0.85; }\n .menu-select {\n flex: 1; max-width: 60%; padding: 7px 10px; border-radius: 8px;\n background: #0d0d12; color: #f2f2f5; border: 1px solid rgba(255,255,255,0.16);\n font-size: 14px;\n }\n .menu-actions { display: flex; justify-content: flex-end; }\n .menu-close {\n padding: 7px 16px; border-radius: 8px; cursor: pointer; font-size: 14px;\n background: #2a2a37; color: #f2f2f5; border: 1px solid rgba(255,255,255,0.14);\n }\n .menu-close:hover { background: #34344a; }\n`;\n\n/** Node-safe base: during SSR/prerender there is no `HTMLElement`, and importing\n * this module (for the engine/types) must not crash. The element is only ever\n * constructed/registered in the browser. */\nconst HostBase: typeof HTMLElement =\n typeof HTMLElement !== 'undefined'\n ? HTMLElement\n : (class {} as unknown as typeof HTMLElement);\n\n// Firefox shipped transferControlToOffscreen (~105) before module workers (~114).\n// The getter-probe detects {type:'module'} support without loading a real script.\nlet moduleWorkerDetected: boolean | undefined;\nfunction supportsModuleWorker(): boolean {\n if (moduleWorkerDetected !== undefined) return moduleWorkerDetected;\n moduleWorkerDetected = false;\n try {\n let probed = false;\n const url = URL.createObjectURL(new Blob([], { type: 'text/javascript' }));\n try {\n const w = new Worker(url, {\n get type() { probed = true; return 'module' as WorkerType; },\n } as WorkerOptions);\n w.terminate();\n } finally {\n URL.revokeObjectURL(url);\n }\n moduleWorkerDetected = probed;\n } catch {\n // ignore — browser doesn't support module workers\n }\n return moduleWorkerDetected;\n}\n\n/**\n * `<idle-screen>` — the framework-agnostic overlay (port of the Angular\n * ScreensaverComponent). Owns the top-layer `<dialog>`, mounts the active saver\n * into a canvas, shows the clock + \"press any key\" hint, fades in/out, wakes on\n * input with a 450ms arm-guard, and goes transparent for passthrough savers.\n *\n * Configure by setting the `.config` and `.plugins` properties (Angular can do\n * this via `[config]` / `[plugins]` with CUSTOM_ELEMENTS_SCHEMA).\n */\nexport class IdleScreenElement extends HostBase {\n private _engine: IdleScreensEngine | null = null;\n private ownsEngine = false;\n private _externalEngine: IdleScreensEngine | null = null;\n private _config: Partial<IdleScreensConfig> | null = null;\n private _plugins: SaverPlugin[] | null = null;\n\n private dialog!: HTMLDialogElement;\n private surface!: HTMLDivElement;\n private clockEl!: HTMLDivElement;\n private hintEl!: HTMLDivElement;\n private menuDialog: HTMLDialogElement | null = null;\n private menuSelect: HTMLSelectElement | null = null;\n private menuBuilt = false;\n\n private instance: SaverInstance | null = null;\n private worker: Worker | null = null;\n private cachedWorker: { worker: Worker; url: string } | null = null;\n private currentWorkerUrl: string | null = null;\n private cleanupWorkerHandlers: (() => void) | null = null;\n /** @internal Force the setTimeout-based rAF polyfill in Workers (for testing). */\n forceRafPolyfill = false;\n private mountToken = 0;\n private armed = false;\n private armTimer: ReturnType<typeof setTimeout> | null = null;\n private hintTimer: ReturnType<typeof setTimeout> | null = null;\n private closeTimer: ReturnType<typeof setTimeout> | null = null;\n private resizeTimer: ReturnType<typeof setTimeout> | null = null;\n private disposers: Array<() => void> = [];\n\n set config(c: Partial<IdleScreensConfig>) {\n this._config = c;\n this.maybeStart();\n }\n set plugins(p: SaverPlugin[]) {\n this._plugins = p;\n this.maybeStart();\n }\n /** Use an externally-owned, already-initialized engine (e.g. an Angular service\n * that also drives a config menu) instead of creating one from config+plugins. */\n set engine(e: IdleScreensEngine) {\n this._externalEngine = e;\n this.maybeStart();\n }\n /** The live engine (for host code / tests). */\n get idleEngine(): IdleScreensEngine | null {\n return this._engine;\n }\n /** Whether the currently mounted saver is running in a Web Worker. */\n get isWorker(): boolean {\n return this.worker !== null;\n }\n\n /** Request a pixel sample from the Worker to verify rendering.\n * Returns false if not in Worker mode or if the canvas has no content. */\n async sampleWorkerPixels(): Promise<boolean> {\n if (!this.worker) return false;\n const w = this.worker;\n return new Promise<boolean>((resolve) => {\n const handler = (e: MessageEvent<WorkerOutbound>): void => {\n if (e.data.type === 'sampled') {\n w.removeEventListener('message', handler);\n resolve(e.data.hasContent);\n }\n };\n w.addEventListener('message', handler);\n w.postMessage({ type: 'sample' } satisfies WorkerInbound);\n });\n }\n\n connectedCallback(): void {\n if (!this.shadowRoot) this.buildDom();\n this.maybeStart();\n }\n\n disconnectedCallback(): void {\n this.teardown();\n }\n\n private buildDom(): void {\n const root = this.attachShadow({ mode: 'open' });\n const style = document.createElement('style');\n style.textContent = STYLE;\n this.dialog = document.createElement('dialog');\n this.dialog.className = 'frame';\n this.surface = document.createElement('div');\n this.surface.className = 'surface';\n this.clockEl = document.createElement('div');\n this.clockEl.className = 'clock';\n this.hintEl = document.createElement('div');\n this.hintEl.className = 'hint';\n this.hintEl.textContent = 'press any key';\n // Host-owned fallback (AVAL-style): light-DOM children with slot=\"fallback\"\n // render here when a saver fails to mount, instead of a black screen.\n const fallback = document.createElement('div');\n fallback.className = 'fallback';\n const slot = document.createElement('slot');\n slot.name = 'fallback';\n fallback.append(slot);\n this.dialog.append(this.surface, fallback, this.clockEl, this.hintEl);\n root.append(style, this.dialog);\n\n for (const ev of ['pointerdown', 'pointermove', 'keydown', 'wheel', 'touchstart'] as const) {\n this.dialog.addEventListener(ev, () => this.onWakeInput(), { passive: true });\n }\n this.dialog.addEventListener('cancel', (e) => {\n e.preventDefault();\n this._engine?.wake();\n });\n }\n\n private maybeStart(): void {\n if (this._engine || !this.shadowRoot || typeof window === 'undefined') return;\n if (this._externalEngine) {\n this._engine = this._externalEngine; // caller owns lifecycle + init()\n this.ownsEngine = false;\n } else if (this._config && this._plugins) {\n this._engine = new IdleScreensEngine(this._config, this._plugins);\n this._engine.init();\n this.ownsEngine = true;\n } else {\n return;\n }\n const eng = this._engine;\n\n this.disposers.push(\n effect(() => {\n // Read reactive deps up front.\n const sleeping = eng.isSleeping.value;\n const active = eng.activePlugin.value;\n const passthrough = eng.activeIsPassthrough.value;\n if (sleeping && active) this.open(active, passthrough);\n else this.close();\n }),\n );\n\n // Clock chrome.\n this.disposers.push(\n effect(() => {\n const show = this._engine!.config.showClock && !eng.activeIsPassthrough.value;\n const now = eng.now.value;\n this.clockEl.style.display = show && eng.isSleeping.value ? 'block' : 'none';\n if (show) {\n const day = now.toLocaleDateString(undefined, {\n weekday: 'long',\n month: 'long',\n day: 'numeric',\n });\n const time = now.toLocaleTimeString();\n this.clockEl.innerHTML = `<div class=\"day\">${day}</div><div class=\"time\">${time}</div>`;\n }\n }),\n );\n\n // Optional built-in config menu (saver picker), opened via engine hotkey/API.\n if (eng.configMenu) {\n this.buildMenu(eng.configMenu);\n this.disposers.push(\n effect(() => {\n const open = eng.configMenuOpen.value;\n const d = this.menuDialog;\n if (!d) return;\n if (open && !d.open) {\n this.syncMenuSelection();\n d.showModal();\n } else if (!open && d.open) {\n d.close();\n }\n }),\n );\n // Keep the picker in sync if the active saver changes elsewhere.\n this.disposers.push(\n effect(() => {\n const id = eng.activePlugin.value?.manifest.id ?? '';\n if (this.menuSelect && this.menuSelect.value !== id) this.menuSelect.value = id;\n }),\n );\n }\n }\n\n private buildMenu(cfg: NonNullable<IdleScreensEngine['configMenu']>): void {\n if (this.menuBuilt || !this.shadowRoot) return;\n const eng = this._engine!;\n const d = document.createElement('dialog');\n d.className = 'menu';\n const card = document.createElement('div');\n card.className = 'menu-card';\n\n const title = document.createElement('div');\n title.className = 'menu-title';\n title.textContent = cfg.title;\n card.append(title);\n\n if (cfg.showPicker) {\n const row = document.createElement('label');\n row.className = 'menu-row';\n const label = document.createElement('span');\n label.textContent = 'Saver';\n const select = document.createElement('select');\n select.className = 'menu-select';\n for (const p of eng.pluginList) {\n const opt = document.createElement('option');\n opt.value = p.id;\n opt.textContent = p.label;\n select.append(opt);\n }\n select.addEventListener('change', () => {\n eng.setPlugin(select.value);\n if (cfg.previewOnPick) {\n // Close the menu first so the saver isn't stacked behind this modal,\n // then show the chosen saver right away.\n eng.closeConfigMenu();\n eng.forceSleep();\n }\n });\n row.append(label, select);\n card.append(row);\n this.menuSelect = select;\n }\n\n const actions = document.createElement('div');\n actions.className = 'menu-actions';\n const close = document.createElement('button');\n close.className = 'menu-close';\n close.type = 'button';\n close.textContent = 'Close';\n close.addEventListener('click', () => eng.closeConfigMenu());\n actions.append(close);\n card.append(actions);\n\n d.append(card);\n // Escape and backdrop click both close (without waking the saver).\n d.addEventListener('cancel', (e) => {\n e.preventDefault();\n eng.closeConfigMenu();\n });\n d.addEventListener('click', (e) => {\n if (e.target === d) eng.closeConfigMenu();\n });\n this.shadowRoot.append(d);\n this.menuDialog = d;\n this.menuBuilt = true;\n }\n\n private syncMenuSelection(): void {\n if (this.menuSelect) {\n this.menuSelect.value = this._engine?.activePlugin.value?.manifest.id ?? '';\n }\n }\n\n private pageContext(): PageContext {\n return {\n palette: () => [],\n victims: (selector: string) =>\n typeof document !== 'undefined'\n ? Array.from(document.querySelectorAll<HTMLElement>(selector))\n : [],\n };\n }\n\n private async open(plugin: SaverPlugin, passthrough: boolean, skipWorker = false): Promise<void> {\n const eng = this._engine!;\n this.dialog.classList.toggle('passthrough', passthrough);\n this.dialog.classList.toggle('reduced', eng.reducedMotion.value);\n if (!this.dialog.open) {\n this.dialog.classList.remove('leaving');\n this.dialog.showModal();\n this.arm();\n this.scheduleHint();\n window.addEventListener('resize', this.onResize);\n }\n // (Re)mount the active saver.\n const token = ++this.mountToken;\n await this.disposeInstance();\n const w = window.innerWidth;\n const h = window.innerHeight;\n const seed = eng.config.seed >>> 0;\n const dpr = typeof devicePixelRatio === 'number' ? devicePixelRatio : 1;\n\n const workerEligible = !skipWorker\n && plugin.manifest.workerReady\n && eng.config.workerUrl\n && typeof HTMLCanvasElement.prototype.transferControlToOffscreen === 'function'\n && supportsModuleWorker();\n\n if (workerEligible) {\n try {\n const inst = await this.openInWorker(plugin, eng.config.workerUrl!, w, h, seed, dpr, eng.reducedMotion.value, passthrough);\n if (token !== this.mountToken) {\n inst.dispose();\n return;\n }\n this.instance = inst;\n inst.setPaused(eng.reducedMotion.value);\n this.dialog.classList.remove('show-fallback');\n return;\n } catch {\n // Worker failed — fall through to main-thread mount\n await this.disposeInstance();\n if (token !== this.mountToken) return;\n }\n }\n try {\n const inst = await plugin.mount({\n host: this.surface,\n dpr,\n width: w,\n height: h,\n rng: createRng(seed),\n seed,\n reducedMotion: eng.reducedMotion.value,\n page: plugin.manifest.passthrough ? this.pageContext() : undefined,\n });\n if (token !== this.mountToken) {\n inst.dispose();\n return;\n }\n this.instance = inst;\n inst.setPaused(eng.reducedMotion.value);\n this.dialog.classList.remove('show-fallback');\n } catch (err) {\n // Saver failed to mount — show the host's fallback slot instead of a\n // black screen. The host owns what \"broken\" looks like.\n if (token !== this.mountToken) return;\n console.warn(`[idle-screen] saver \"${plugin.manifest.id}\" failed to mount:`, err);\n this.surface.replaceChildren();\n this.dialog.classList.add('show-fallback');\n }\n }\n\n private openInWorker(\n plugin: SaverPlugin,\n workerUrl: string,\n width: number,\n height: number,\n seed: number,\n dpr: number,\n reducedMotion: boolean,\n passthrough: boolean,\n ): Promise<SaverInstance> {\n const canvas = document.createElement('canvas');\n canvas.style.cssText = 'display:block;width:100%;height:100%';\n this.surface.appendChild(canvas);\n\n const offscreen = canvas.transferControlToOffscreen();\n\n // Reuse cached worker if URL matches, otherwise create new\n let worker: Worker;\n if (this.cachedWorker && this.cachedWorker.url === workerUrl) {\n worker = this.cachedWorker.worker;\n this.cachedWorker = null;\n } else {\n this.terminateCachedWorker();\n worker = new Worker(workerUrl, { type: 'module' });\n }\n this.worker = worker;\n this.currentWorkerUrl = workerUrl;\n\n const mountMsg: WorkerInbound = plugin.spec\n ? {\n type: 'mount-spec',\n canvas: offscreen,\n spec: plugin.spec,\n width, height, seed, dpr, reducedMotion,\n ...(this.forceRafPolyfill ? { forceRafPolyfill: true } : {}),\n }\n : {\n type: 'mount',\n canvas: offscreen,\n saverId: plugin.manifest.id,\n width, height, seed, dpr, reducedMotion,\n ...(this.forceRafPolyfill ? { forceRafPolyfill: true } : {}),\n };\n worker.postMessage(mountMsg, [offscreen]);\n\n let disposed = false;\n\n const proxy: SaverInstance = {\n setPaused: (p) => worker.postMessage({ type: 'pause', paused: p } satisfies WorkerInbound),\n resize: (w, h, newDpr) => worker.postMessage({ type: 'resize', width: w, height: h, dpr: newDpr ?? dpr } satisfies WorkerInbound),\n applyTrack: (track) => worker.postMessage({ type: 'track', track } satisfies WorkerInbound),\n dispose: () => {\n disposed = true;\n this.cleanupWorkerHandlers?.();\n this.cleanupWorkerHandlers = null;\n worker.postMessage({ type: 'dispose' } satisfies WorkerInbound);\n worker.terminate();\n this.worker = null;\n canvas.remove();\n },\n };\n\n return new Promise<SaverInstance>((resolve, reject) => {\n const onMessage = (e: MessageEvent<WorkerOutbound>): void => {\n if (e.data.type === 'mounted') {\n worker.removeEventListener('message', onMessage);\n worker.removeEventListener('error', onError);\n\n // Post-mount crash recovery: if the Worker errors mid-animation,\n // fall back to main-thread rendering.\n const onCrash = (ev: Event): void => {\n if (disposed) return;\n disposed = true;\n const msg = ev instanceof ErrorEvent ? ev.message : 'Worker messageerror';\n console.warn(`[idle-screen] Worker crashed mid-animation: ${msg}`);\n this.cleanupWorkerHandlers?.();\n this.cleanupWorkerHandlers = null;\n worker.terminate();\n this.worker = null;\n this.instance = null;\n this.surface?.replaceChildren();\n void this.open(plugin, passthrough, true);\n };\n worker.addEventListener('error', onCrash);\n worker.addEventListener('messageerror', onCrash);\n this.cleanupWorkerHandlers = () => {\n worker.removeEventListener('error', onCrash);\n worker.removeEventListener('messageerror', onCrash);\n };\n\n resolve(proxy);\n } else if (e.data.type === 'error') {\n worker.removeEventListener('message', onMessage);\n worker.removeEventListener('error', onError);\n reject(new Error(e.data.message));\n }\n };\n const onError = (e: ErrorEvent): void => {\n worker.removeEventListener('message', onMessage);\n worker.removeEventListener('error', onError);\n reject(new Error(e.message));\n };\n worker.addEventListener('message', onMessage);\n worker.addEventListener('error', onError);\n });\n }\n\n private close(): void {\n if (!this.dialog?.open) return;\n window.removeEventListener('resize', this.onResize);\n if (this.resizeTimer) { clearTimeout(this.resizeTimer); this.resizeTimer = null; }\n this.dialog.classList.remove('show-fallback');\n this.hintEl.classList.remove('show');\n if (this.hintTimer) clearTimeout(this.hintTimer);\n void this.disposeInstance();\n const reduced = this._engine?.reducedMotion.value;\n if (reduced) {\n this.dialog.close();\n return;\n }\n this.dialog.classList.add('leaving');\n if (this.closeTimer) clearTimeout(this.closeTimer);\n this.closeTimer = setTimeout(() => {\n if (this.dialog.open) this.dialog.close();\n this.dialog.classList.remove('leaving');\n }, 320);\n }\n\n private async disposeInstance(): Promise<void> {\n this.cleanupWorkerHandlers?.();\n this.cleanupWorkerHandlers = null;\n\n if (this.instance) {\n if (this.worker) {\n // Worker instance: send dispose but cache the worker for reuse\n this.worker.postMessage({ type: 'dispose' } satisfies WorkerInbound);\n this.cachedWorker = { worker: this.worker, url: this.currentWorkerUrl! };\n this.worker = null;\n } else {\n this.instance.dispose();\n }\n this.instance = null;\n } else if (this.worker) {\n this.worker.terminate();\n this.worker = null;\n }\n this.surface?.replaceChildren();\n }\n\n private terminateCachedWorker(): void {\n if (this.cachedWorker) {\n this.cachedWorker.worker.terminate();\n this.cachedWorker = null;\n }\n }\n\n private arm(): void {\n this.armed = false;\n if (this.armTimer) clearTimeout(this.armTimer);\n this.armTimer = setTimeout(() => {\n this.armed = true;\n }, 450);\n }\n\n private scheduleHint(): void {\n if (this.hintTimer) clearTimeout(this.hintTimer);\n this.hintEl.classList.remove('show');\n this.hintTimer = setTimeout(() => this.hintEl.classList.add('show'), 3000);\n }\n\n private readonly onResize = (): void => {\n if (this.resizeTimer !== null) clearTimeout(this.resizeTimer);\n this.resizeTimer = setTimeout(() => {\n this.resizeTimer = null;\n if (!this.instance || !this.dialog?.open) return;\n const newDpr = typeof devicePixelRatio === 'number' ? devicePixelRatio : 1;\n this.instance.resize(window.innerWidth, window.innerHeight, newDpr);\n }, 150);\n };\n\n private onWakeInput(): void {\n if (!this.armed) return; // grace period after sleeping\n this._engine?.wake();\n }\n\n private teardown(): void {\n window.removeEventListener('resize', this.onResize);\n if (this.resizeTimer) { clearTimeout(this.resizeTimer); this.resizeTimer = null; }\n void this.disposeInstance();\n this.terminateCachedWorker();\n if (this.armTimer) clearTimeout(this.armTimer);\n if (this.hintTimer) clearTimeout(this.hintTimer);\n if (this.closeTimer) clearTimeout(this.closeTimer);\n for (const d of this.disposers) d();\n this.disposers = [];\n if (this.ownsEngine) this._engine?.destroy(); // external engines are the caller's to destroy\n this._engine = null;\n }\n}\n\n/** Register the <idle-screen> custom element (idempotent). */\nexport function defineIdleScreen(tag = 'idle-screen'): void {\n if (typeof customElements !== 'undefined' && !customElements.get(tag)) {\n customElements.define(tag, IdleScreenElement);\n }\n}\n","import { createRng } from './rng';\nimport type { ControlTrack, SaverContext, SaverInstance, SaverPlugin } from './types';\n\n/** Main thread → Worker messages. */\nexport type WorkerInbound =\n | {\n type: 'mount';\n canvas: OffscreenCanvas;\n saverId: string;\n width: number;\n height: number;\n seed: number;\n dpr: number;\n reducedMotion: boolean;\n /** Display refresh rate (Hz) for the rAF polyfill on browsers that lack\n * Worker requestAnimationFrame (Safari). Defaults to 60. */\n refreshRate?: number;\n /** Force the setTimeout-based rAF polyfill even when native rAF exists.\n * Used by tests to verify the polyfill drives frames. */\n forceRafPolyfill?: boolean;\n }\n | {\n type: 'mount-spec';\n canvas: OffscreenCanvas;\n spec: unknown;\n width: number;\n height: number;\n seed: number;\n dpr: number;\n reducedMotion: boolean;\n refreshRate?: number;\n forceRafPolyfill?: boolean;\n }\n | { type: 'resize'; width: number; height: number; dpr: number }\n | { type: 'pause'; paused: boolean }\n | { type: 'track'; track: ControlTrack }\n | { type: 'sample' }\n | { type: 'dispose' };\n\n/** Worker → main thread messages. */\nexport type WorkerOutbound =\n | { type: 'mounted' }\n | { type: 'sampled'; hasContent: boolean }\n | { type: 'error'; message: string };\n\n/** Options for {@link runIdleWorker}. */\nexport interface RunIdleWorkerOpts {\n /** Spec compiler for `mount-spec` messages. Pass `compileSaver` from\n * `@idle-screens/schema` to enable schema-based savers in this Worker. */\n compiler?: (spec: unknown) => SaverPlugin;\n}\n\n/**\n * Run inside a dedicated Worker. Accepts a registry of worker-ready saver plugins\n * and listens for lifecycle messages from the main thread.\n *\n * Usage (in the Worker entry file):\n * ```ts\n * import { runIdleWorker } from '@idle-screens/core';\n * import { warp } from './warp';\n * runIdleWorker({ warp });\n * ```\n */\nexport function runIdleWorker(\n registry: Record<string, SaverPlugin>,\n opts?: RunIdleWorkerOpts,\n): void {\n let instance: SaverInstance | null = null;\n let activeCanvas: OffscreenCanvas | null = null;\n let usingPolyfill = false;\n let mountGen = 0;\n\n const post = (msg: WorkerOutbound): void => {\n self.postMessage(msg);\n };\n\n const installRafPolyfill = (refreshRate?: number): void => {\n const g = globalThis as Record<string, unknown>;\n const interval = refreshRate ? Math.round(1000 / refreshRate) : 16;\n g.requestAnimationFrame = (cb: FrameRequestCallback) =>\n setTimeout(() => cb(performance.now()), interval) as unknown as number;\n g.cancelAnimationFrame = (id: number) => clearTimeout(id);\n usingPolyfill = true;\n };\n\n if (typeof requestAnimationFrame === 'undefined') {\n installRafPolyfill();\n }\n\n const mountPlugin = (\n plugin: SaverPlugin,\n canvas: OffscreenCanvas,\n msg: {\n width: number; height: number; seed: number;\n dpr: number; reducedMotion: boolean;\n refreshRate?: number; forceRafPolyfill?: boolean;\n },\n gen: number,\n ): void => {\n if (msg.forceRafPolyfill) {\n installRafPolyfill(msg.refreshRate);\n } else if (usingPolyfill && msg.refreshRate) {\n installRafPolyfill(msg.refreshRate);\n }\n\n activeCanvas = canvas;\n const hostStub = new Proxy({} as HTMLElement, {\n get(_target, prop) {\n throw new Error(\n `Saver accessed host.${String(prop)} in a Worker — ` +\n `Workers have no DOM. Use ctx.surface instead of creating your own canvas.`,\n );\n },\n });\n const ctx: SaverContext = {\n host: hostStub,\n surface: canvas,\n dpr: msg.dpr,\n width: msg.width,\n height: msg.height,\n rng: createRng(msg.seed),\n seed: msg.seed,\n reducedMotion: msg.reducedMotion,\n };\n try {\n const result = plugin.mount(ctx);\n if (result instanceof Promise) {\n result.then((inst) => {\n if (gen !== mountGen) {\n inst.dispose();\n return;\n }\n instance = inst;\n post({ type: 'mounted' });\n }).catch((err: unknown) => {\n if (gen !== mountGen) return;\n post({ type: 'error', message: String(err) });\n });\n } else {\n if (gen !== mountGen) {\n result.dispose();\n return;\n }\n instance = result;\n post({ type: 'mounted' });\n }\n } catch (err: unknown) {\n if (gen !== mountGen) return;\n post({ type: 'error', message: String(err) });\n }\n };\n\n self.addEventListener('message', (raw: MessageEvent<WorkerInbound>) => {\n const msg = raw.data;\n switch (msg.type) {\n case 'mount': {\n const plugin = registry[msg.saverId];\n if (!plugin) {\n post({ type: 'error', message: `unknown saver: ${msg.saverId}` });\n return;\n }\n instance?.dispose();\n instance = null;\n const gen = ++mountGen;\n mountPlugin(plugin, msg.canvas, msg, gen);\n break;\n }\n case 'mount-spec': {\n if (!opts?.compiler) {\n post({ type: 'error', message: 'no compiler provided for mount-spec' });\n return;\n }\n try {\n const plugin = opts.compiler(msg.spec);\n instance?.dispose();\n instance = null;\n const gen = ++mountGen;\n mountPlugin(plugin, msg.canvas, msg, gen);\n } catch (err: unknown) {\n post({ type: 'error', message: String(err) });\n }\n break;\n }\n case 'resize':\n instance?.resize(msg.width, msg.height, msg.dpr);\n break;\n case 'pause':\n instance?.setPaused(msg.paused);\n break;\n case 'track':\n instance?.applyTrack?.(msg.track);\n break;\n case 'sample': {\n if (!activeCanvas) {\n post({ type: 'sampled', hasContent: false });\n return;\n }\n const c2d = activeCanvas.getContext('2d');\n if (!c2d) {\n post({ type: 'sampled', hasContent: false });\n return;\n }\n const cw = activeCanvas.width;\n const ch = activeCanvas.height;\n let hasContent = false;\n const COLS = 10;\n const ROWS = 10;\n for (let r = 0; r < ROWS && !hasContent; r++) {\n const y = Math.floor((ch * (r + 1)) / (ROWS + 1));\n for (let c = 0; c < COLS && !hasContent; c++) {\n const x = Math.floor((cw * (c + 1)) / (COLS + 1));\n const data = c2d.getImageData(x, y, 1, 1).data;\n if (data[0]! > 0 || data[1]! > 0 || data[2]! > 0 || data[3]! > 0) hasContent = true;\n }\n }\n post({ type: 'sampled', hasContent });\n break;\n }\n case 'dispose':\n mountGen++;\n instance?.dispose();\n instance = null;\n activeCanvas = null;\n break;\n }\n });\n}\n"],"mappings":";AA6MO,IAAM,sBAAsB,CAAC,OACjC,EAAE,WAAW,EAAE,YAAY,CAAC,EAAE,UAAU,CAAC,EAAE,YAAY,EAAE,IAAI,YAAY,MAAM;AAG3E,SAAS,kBACd,GACmC;AACnC,MAAI,MAAM,MAAO,QAAO;AACxB,QAAM,IAAsB,MAAM,QAAQ,MAAM,SAAY,CAAC,IAAI;AACjE,MAAI,EAAE,YAAY,MAAO,QAAO;AAChC,SAAO;AAAA,IACL,SAAS;AAAA,IACT,QAAQ,EAAE,UAAU;AAAA,IACpB,YAAY,EAAE,cAAc;AAAA,IAC5B,eAAe,EAAE,iBAAiB;AAAA,IAClC,OAAO,EAAE,SAAS;AAAA,EACpB;AACF;AAEO,IAAM,iBAAoC;AAAA,EAC/C,WAAW;AAAA,EACX,aAAa;AAAA,EACb,oBAAoB;AAAA,EACpB,iBAAiB;AAAA,EACjB,WAAW;AAAA,EACX,WAAW;AAAA,EACX,MAAM;AAAA,EACN,YAAY;AACd;;;ACtNO,SAAS,UAAU,MAAmB;AAC3C,MAAI,IAAI,SAAS;AACjB,QAAM,OAAO,MAAc;AACzB,SAAK;AACL,QAAK,IAAI,aAAc;AACvB,QAAI,IAAI,IAAK,MAAM;AACnB,QAAI,KAAK,KAAK,GAAG,SAAU;AAC3B,QAAI,IAAK,MAAM;AACf,QAAI,KAAK,KAAK,GAAG,UAAU;AAC3B,aAAS,IAAI,IAAK,MAAM,QAAS,KAAK;AAAA,EACxC;AACA,QAAM,MAAW;AAAA,IACf;AAAA,IACA,OAAO,CAAC,KAAK,QAAQ,OAAO,MAAM,OAAO,KAAK;AAAA,IAC9C,KAAK,CAAC,KAAK,QAAQ,MAAM,KAAK,MAAM,KAAK,KAAK,MAAM,MAAM,EAAE;AAAA,IAC5D,MAAM,CAAC,QAAQ,IAAI,KAAK,MAAM,KAAK,IAAI,IAAI,MAAM,CAAC;AAAA,IAClD,MAAM,CAAC,SAAS,WAAW,OAAO,KAAK,KAAK,OAAO,GAAG,UAAU,OAAO,CAAC;AAAA,EAC1E;AACA,SAAO;AACT;;;ACjCA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAGK;;;ACXP,SAAS,OAAO,GAAS,GAAmB;AAC1C,QAAM,IAAI,KAAK,IAAI,IAAI,KAAK,IAAI,IAAI;AACpC,UAAQ,GAAG;AAAA,IACT,KAAK;AACH,aAAO,KAAK,IAAI,IAAI;AAAA,IACtB,KAAK;AACH,aAAO,IAAI,KAAK,IAAI,IAAI;AAAA,IAC1B,KAAK;AAAA,IACL;AACE,aAAO;AAAA,EACX;AACF;AAEA,SAAS,KAAK,GAAW,GAAW,GAAmB;AACrD,SAAO,KAAK,IAAI,KAAK;AACvB;AAEA,SAAS,SAAS,GAA4C;AAC5D,QAAM,IAAI,qBAAqB,KAAK,EAAE,KAAK,CAAC;AAC5C,MAAI,CAAC,EAAG,QAAO;AACf,QAAM,IAAI,SAAS,EAAE,CAAC,GAAI,EAAE;AAC5B,SAAO,CAAE,KAAK,KAAM,KAAM,KAAK,IAAK,KAAK,IAAI,GAAG;AAClD;AAEA,SAAS,MAAM,KAAuC;AACpD,QAAM,IAAI,CAAC,MACT,KAAK,MAAM,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,CAAC,CAAC,CAAC,EACrC,SAAS,EAAE,EACX,SAAS,GAAG,GAAG;AACpB,SAAO,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC;AAC9C;AAEA,SAAS,UAAU,MAAc,GAAe,GAAe,GAAuB;AACpF,MAAI,SAAS,YAAY,OAAO,MAAM,YAAY,OAAO,MAAM,SAAU,QAAO,KAAK,GAAG,GAAG,CAAC;AAC5F,MAAI,SAAS,WAAW,OAAO,MAAM,YAAY,OAAO,MAAM,UAAU;AACtE,UAAM,KAAK,SAAS,CAAC;AACrB,UAAM,KAAK,SAAS,CAAC;AACrB,QAAI,MAAM,GAAI,QAAO,MAAM,CAAC,KAAK,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;AAAA,EAClG;AACA,SAAO,KAAK,IAAI,IAAI;AACtB;AAEA,SAAS,SACP,MACA,MACA,aACA,QACA,GACY;AACZ,MAAI,OAAO,WAAW,EAAG,QAAO;AAChC,MAAI,UAAU;AACd,MAAI,QAAQ;AACZ,aAAW,KAAK,QAAQ;AACtB,QAAI,IAAI,EAAE,GAAG;AACX,YAAM,YAAY,EAAE,OAAO,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,YAAY,EAAE,IAAI;AAC5E,UAAI,KAAK,UAAW,QAAO;AAC3B,YAAM,IAAI,OAAO,EAAE,QAAQ,cAAc,IAAI,cAAc,EAAE,IAAI,aAAa,EAAE;AAChF,aAAO,UAAU,MAAM,SAAS,EAAE,OAAO,CAAC;AAAA,IAC5C;AACA,cAAU,EAAE;AACZ,YAAQ,EAAE;AAAA,EACZ;AACA,SAAO;AACT;AAOO,SAAS,YACd,OACA,OACA,GAC4B;AAC5B,QAAM,SAAS,oBAAI,IAA0B;AAC7C,aAAW,KAAK,MAAM,QAAQ;AAC5B,UAAM,MAAM,OAAO,IAAI,EAAE,IAAI,KAAK,CAAC;AACnC,QAAI,KAAK,CAAC;AACV,WAAO,IAAI,EAAE,MAAM,GAAG;AAAA,EACxB;AACA,QAAM,UACJ,MAAM,QAAQ,MAAM,YAAY,MAAM,WAAW,IAAI,IAAI,MAAM,WAAW;AAE5E,QAAM,MAAkC,CAAC;AACzC,aAAW,CAAC,MAAM,GAAG,KAAK,OAAO,QAAQ,KAAK,GAAG;AAC/C,UAAM,UAAU,OAAO,IAAI,IAAI,KAAK,CAAC,GAAG,MAAM,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,IAAI,EAAE,CAAC;AACxE,QAAI,IAAI,IAAI,SAAS,IAAI,SAAS,IAAI,MAAM,IAAI,QAAQ,UAAU,QAAQ,OAAO;AAAA,EACnF;AACA,SAAO;AACT;AAGO,SAAS,cAAc,OAA+C;AAC3E,QAAM,MAAkC,CAAC;AACzC,aAAW,CAAC,MAAM,GAAG,KAAK,OAAO,QAAQ,KAAK,EAAG,KAAI,IAAI,IAAI,IAAI;AACjE,SAAO;AACT;;;AC3FO,IAAM,eAAN,MAAM,cAAa;AAAA,EAiBxB,YAA6B,WAAmB;AAAnB;AAAA,EAAoB;AAAA,EAApB;AAAA,EAhBZ,QAAQ,OAAO,KAAK;AAAA,EAC5B,OAAgC,KAAK;AAAA,EAEtC,QAA8C;AAAA,EAC9C,YAAY;AAAA,EACZ,UAAU;AAAA,EAElB,OAAwB,SAAS;AAAA,IAC/B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EAIiB,aAAa,MAAY,KAAK,WAAW;AAAA,EAE1D,QAAc;AACZ,QAAI,KAAK,WAAW,OAAO,WAAW,YAAa;AACnD,SAAK,UAAU;AACf,eAAW,KAAK,cAAa,QAAQ;AACnC,aAAO,iBAAiB,GAAG,KAAK,YAAY,EAAE,SAAS,KAAK,CAAC;AAAA,IAC/D;AACA,SAAK,SAAS;AAAA,EAChB;AAAA,EAEA,OAAa;AACX,QAAI,CAAC,KAAK,QAAS;AACnB,SAAK,UAAU;AACf,eAAW,KAAK,cAAa,QAAQ;AACnC,aAAO,oBAAoB,GAAG,KAAK,UAAU;AAAA,IAC/C;AACA,SAAK,MAAM;AAAA,EACb;AAAA;AAAA,EAGA,aAAmB;AACjB,QAAI,KAAK,MAAM,MAAO,MAAK,MAAM,QAAQ;AACzC,UAAM,MAAM,OAAO,gBAAgB,cAAc,YAAY,IAAI,IAAI,KAAK,IAAI;AAC9E,QAAI,MAAM,KAAK,YAAY,IAAK;AAChC,SAAK,YAAY;AACjB,SAAK,SAAS;AAAA,EAChB;AAAA,EAEQ,WAAiB;AACvB,SAAK,MAAM;AACX,SAAK,QAAQ,WAAW,MAAM;AAC5B,WAAK,MAAM,QAAQ;AAAA,IACrB,GAAG,KAAK,SAAS;AAAA,EACnB;AAAA,EAEQ,QAAc;AACpB,QAAI,KAAK,UAAU,MAAM;AACvB,mBAAa,KAAK,KAAK;AACvB,WAAK,QAAQ;AAAA,IACf;AAAA,EACF;AACF;;;ACxDA,IAAM,YAAY,OAAO,WAAW;AACpC,IAAM,SAAS,OAAO,aAAa;AAEnC,SAAS,iBAA+C;AACtD,SAAO;AAAA,IACL,KAAK,CAAC,MAAM;AACV,UAAI;AACF,eAAO,YAAY,OAAO,aAAa,QAAQ,CAAC,IAAI;AAAA,MACtD,QAAQ;AACN,eAAO;AAAA,MACT;AAAA,IACF;AAAA,IACA,KAAK,CAAC,GAAG,MAAM;AACb,UAAI;AACF,YAAI,UAAW,QAAO,aAAa,QAAQ,GAAG,CAAC;AAAA,MACjD,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF;AACF;AASO,IAAM,oBAAN,MAAwB;AAAA,EACpB;AAAA,EACQ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA,SAAS,OAAoB,OAAO;AAAA,EAC5C,QAAqC,KAAK;AAAA,EAC1C,aAAa,SAAS,MAAM,KAAK,OAAO,UAAU,UAAU;AAAA,EAEpD,YAAY,OAAO,EAAE;AAAA,EAC7B,eAAe;AAAA,IACtB,MACE,KAAK,QAAQ,KAAK,CAAC,MAAM,EAAE,SAAS,OAAO,KAAK,UAAU,KAAK,KAC/D,KAAK,QAAQ,CAAC,KACd;AAAA,EACJ;AAAA,EACS,sBAAsB;AAAA,IAC7B,MAAM,KAAK,aAAa,OAAO,SAAS,eAAe;AAAA,EACzD;AAAA,EAEiB,OAAO,OAAO,oBAAI,KAAK,CAAC,CAAC;AAAA,EACjC,MAA4B,KAAK;AAAA,EACzB,UAAU,OAAO,KAAK;AAAA,EAC9B,SAAkC,KAAK;AAAA,EAC/B,iBAAiB,OAAO,KAAK;AAAA,EACrC,gBAAyC,KAAK;AAAA;AAAA,EAG9C;AAAA,EACQ,kBAAkB,OAAO,KAAK;AAAA;AAAA;AAAA,EAGtC,iBAA0C,KAAK;AAAA,EAEhD,aAAoD;AAAA,EACpD,UAAU;AAAA,EACV,YAA+B,CAAC;AAAA,EAExC,YAAY,QAAoC,SAAwB;AACtE,SAAK,SAAS,EAAE,GAAG,gBAAgB,GAAG,OAAO;AAC7C,SAAK,UAAU;AACf,SAAK,aAAa,kBAAkB,KAAK,OAAO,UAAU;AAC1D,SAAK,UAAU,KAAK,OAAO,WAAW,eAAe;AACrD,SAAK,OAAO,IAAI,aAAa,KAAK,OAAO,SAAS;AAClD,SAAK,eAAe,UAAU,KAAK,OAAO,SAAS,CAAC;AAEpD,UAAM,SAAS,KAAK,QAAQ,IAAI,oBAAoB;AACpD,UAAM,YACH,UAAU,QAAQ,KAAK,CAAC,MAAM,EAAE,SAAS,OAAO,MAAM,KAAK,UAC5D,KAAK,OAAO,mBACZ,QAAQ,CAAC,GAAG,SAAS,MACrB;AACF,SAAK,UAAU,QAAQ;AAAA,EACzB;AAAA,EAEA,IAAI,aAAmD;AACrD,WAAO,KAAK,QAAQ,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,SAAS,IAAI,OAAO,EAAE,SAAS,MAAM,EAAE;AAAA,EACjF;AAAA;AAAA,EAGA,OAAa;AACX,QAAI,KAAK,WAAW,CAAC,UAAW;AAChC,SAAK,UAAU;AAEf,QAAI,QAAQ;AACV,WAAK,QAAQ,QAAQ,SAAS;AAC9B,YAAM,QAAQ,MAAY;AACxB,aAAK,QAAQ,QAAQ,SAAS;AAAA,MAChC;AACA,eAAS,iBAAiB,oBAAoB,KAAK;AACnD,WAAK,UAAU,KAAK,MAAM,SAAS,oBAAoB,oBAAoB,KAAK,CAAC;AAAA,IACnF;AAEA,UAAM,KAAK,YAAY,OAAO,WAAW,kCAAkC,IAAI;AAC/E,QAAI,IAAI;AACN,WAAK,eAAe,QAAQ,GAAG;AAC/B,YAAM,OAAO,MAAY;AACvB,aAAK,eAAe,QAAQ,GAAG;AAAA,MACjC;AACA,SAAG,iBAAiB,UAAU,IAAI;AAClC,WAAK,UAAU,KAAK,MAAM,GAAG,oBAAoB,UAAU,IAAI,CAAC;AAAA,IAClE;AAMA,SAAK,KAAK,MAAM;AAChB,SAAK,UAAU;AAAA,MACb,OAAO,MAAM;AACX,YAAI,KAAK,KAAK,KAAK,MAAO,WAAU,MAAM,KAAK,MAAM,CAAC;AAAA,MACxD,CAAC;AAAA,IACH;AAEA,QAAI,KAAK,OAAO,aAAa;AAC3B,YAAM,SAAS,MAAY,KAAK,MAAM;AACtC,aAAO,iBAAiB,QAAQ,MAAM;AACtC,WAAK,UAAU,KAAK,MAAM,OAAO,oBAAoB,QAAQ,MAAM,CAAC;AAAA,IACtE;AAGA,QAAI,KAAK,YAAY;AACnB,YAAM,SAAS,KAAK,WAAW;AAC/B,YAAM,QAAQ,CAAC,MAA2B;AACxC,YAAI,OAAO,CAAC,GAAG;AACb,YAAE,eAAe;AACjB,eAAK,iBAAiB;AAAA,QACxB;AAAA,MACF;AACA,aAAO,iBAAiB,WAAW,KAAK;AACxC,WAAK,UAAU,KAAK,MAAM,OAAO,oBAAoB,WAAW,KAAK,CAAC;AAAA,IACxE;AAGA,SAAK,UAAU;AAAA,MACb,OAAO,MAAM;AACX,cAAM,UAAU,KAAK,OAAO,UAAU,cAAc,CAAC,KAAK,QAAQ;AAClE,YAAI,WAAW,KAAK,eAAe,MAAM;AACvC,eAAK,KAAK,QAAQ,oBAAI,KAAK;AAC3B,eAAK,aAAa,YAAY,MAAM;AAClC,iBAAK,KAAK,QAAQ,oBAAI,KAAK;AAAA,UAC7B,GAAG,GAAI;AAAA,QACT,WAAW,CAAC,WAAW,KAAK,eAAe,MAAM;AAC/C,wBAAc,KAAK,UAAU;AAC7B,eAAK,aAAa;AAAA,QACpB;AAAA,MACF,CAAC;AAAA,IACH;AAEA,SAAK,iBAAiB;AAAA,EACxB;AAAA,EAEA,UAAgB;AACd,SAAK,KAAK,KAAK;AACf,QAAI,KAAK,eAAe,MAAM;AAC5B,oBAAc,KAAK,UAAU;AAC7B,WAAK,aAAa;AAAA,IACpB;AACA,eAAW,KAAK,KAAK,UAAW,GAAE;AAClC,SAAK,YAAY,CAAC;AAClB,SAAK,UAAU;AAAA,EACjB;AAAA,EAEQ,aAAsB;AAC5B,QAAI,KAAK,OAAO,sBAAsB,aAAa,6BAA6B,KAAK,SAAS,QAAQ,GAAG;AACvG,aAAO;AAAA,IACT;AACA,UAAM,MAAM,YAAY,SAAS,WAAW,SAAS,SAAS;AAC9D,WAAO,KAAK,OAAO,WAAW,KAAK,OAAO,SAAS,GAAG,IAAI;AAAA,EAC5D;AAAA,EAEA,QAAc;AACZ,QAAI,KAAK,OAAO,UAAU,cAAc,KAAK,WAAW,EAAG;AAC3D,SAAK,WAAW;AAChB,SAAK,OAAO,QAAQ;AAAA,EACtB;AAAA;AAAA,EAGA,aAAmB;AACjB,QAAI,KAAK,OAAO,UAAU,WAAY;AACtC,SAAK,WAAW;AAChB,SAAK,OAAO,QAAQ;AAAA,EACtB;AAAA,EAEA,OAAa;AACX,QAAI,KAAK,OAAO,UAAU,QAAS;AACnC,SAAK,OAAO,QAAQ;AACpB,SAAK,KAAK,WAAW;AAAA,EACvB;AAAA,EAEA,SAAe;AACb,QAAI,KAAK,WAAW,MAAO,MAAK,KAAK;AAAA,QAChC,MAAK,WAAW;AAAA,EACvB;AAAA,EAEA,iBAAuB;AACrB,SAAK,gBAAgB,QAAQ;AAAA,EAC/B;AAAA,EACA,kBAAwB;AACtB,SAAK,gBAAgB,QAAQ;AAAA,EAC/B;AAAA,EACA,mBAAyB;AACvB,SAAK,gBAAgB,QAAQ,CAAC,KAAK,gBAAgB;AAAA,EACrD;AAAA,EAEA,UAAU,IAAkB;AAC1B,QAAI,CAAC,KAAK,QAAQ,KAAK,CAAC,MAAM,EAAE,SAAS,OAAO,EAAE,EAAG;AACrD,SAAK,UAAU,QAAQ;AACvB,SAAK,QAAQ,IAAI,sBAAsB,EAAE;AAAA,EAC3C;AAAA,EAEQ,aAAmB;AACzB,QAAI,KAAK,QAAQ,WAAW,EAAG;AAC/B,YAAQ,KAAK,OAAO,WAAW;AAAA,MAC7B,KAAK,UAAU;AACb,cAAM,IAAI,KAAK,aAAa,IAAI,GAAG,KAAK,QAAQ,SAAS,CAAC;AAC1D,aAAK,UAAU,QAAQ,KAAK,QAAQ,CAAC,EAAG,SAAS;AACjD;AAAA,MACF;AAAA,MACA,KAAK,UAAU;AACb,cAAM,MAAM,KAAK,QAAQ,UAAU,CAAC,MAAM,EAAE,SAAS,OAAO,KAAK,UAAU,KAAK;AAChF,cAAM,OAAO,KAAK,SAAS,MAAM,KAAK,KAAK,QAAQ,MAAM;AACzD,aAAK,UAAU,QAAQ,KAAK,SAAS;AACrC;AAAA,MACF;AAAA,MACA,KAAK;AAAA,MACL;AAIE;AAAA,IACJ;AAAA,EACF;AAAA,EAEQ,mBAAyB;AAC/B,QAAI,CAAC,UAAW;AAChB,IAAC,OAAkD,gBAAgB;AAAA,MACjE,OAAO,MAAM,KAAK,WAAW;AAAA,MAC7B,MAAM,MAAM,KAAK,KAAK;AAAA,MACtB,QAAQ,MAAM,KAAK,OAAO;AAAA,MAC1B,WAAW,CAAC,OAAe,KAAK,UAAU,EAAE;AAAA,MAC5C,UAAU,MAAM,KAAK,eAAe;AAAA,MACpC,WAAW,MAAM,KAAK,gBAAgB;AAAA,MACtC,YAAY,MAAM,KAAK,iBAAiB;AAAA,MACxC,OAAO,MAAM,KAAK,OAAO;AAAA,MACzB,UAAU,MAAM,KAAK,gBAAgB;AAAA,MACrC,QAAQ,MAAM,KAAK,aAAa,OAAO,SAAS,MAAM;AAAA,MACtD,SAAS,KAAK;AAAA,IAChB;AAAA,EACF;AACF;;;AC5QA,IAAM,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAkEd,IAAM,WACJ,OAAO,gBAAgB,cACnB,cACC,MAAM;AAAC;AAId,IAAI;AACJ,SAAS,uBAAgC;AACvC,MAAI,yBAAyB,OAAW,QAAO;AAC/C,yBAAuB;AACvB,MAAI;AACF,QAAI,SAAS;AACb,UAAM,MAAM,IAAI,gBAAgB,IAAI,KAAK,CAAC,GAAG,EAAE,MAAM,kBAAkB,CAAC,CAAC;AACzE,QAAI;AACF,YAAM,IAAI,IAAI,OAAO,KAAK;AAAA,QACxB,IAAI,OAAO;AAAE,mBAAS;AAAM,iBAAO;AAAA,QAAwB;AAAA,MAC7D,CAAkB;AAClB,QAAE,UAAU;AAAA,IACd,UAAE;AACA,UAAI,gBAAgB,GAAG;AAAA,IACzB;AACA,2BAAuB;AAAA,EACzB,QAAQ;AAAA,EAER;AACA,SAAO;AACT;AAWO,IAAM,oBAAN,cAAgC,SAAS;AAAA,EACtC,UAAoC;AAAA,EACpC,aAAa;AAAA,EACb,kBAA4C;AAAA,EAC5C,UAA6C;AAAA,EAC7C,WAAiC;AAAA,EAEjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,aAAuC;AAAA,EACvC,aAAuC;AAAA,EACvC,YAAY;AAAA,EAEZ,WAAiC;AAAA,EACjC,SAAwB;AAAA,EACxB,eAAuD;AAAA,EACvD,mBAAkC;AAAA,EAClC,wBAA6C;AAAA;AAAA,EAErD,mBAAmB;AAAA,EACX,aAAa;AAAA,EACb,QAAQ;AAAA,EACR,WAAiD;AAAA,EACjD,YAAkD;AAAA,EAClD,aAAmD;AAAA,EACnD,cAAoD;AAAA,EACpD,YAA+B,CAAC;AAAA,EAExC,IAAI,OAAO,GAA+B;AACxC,SAAK,UAAU;AACf,SAAK,WAAW;AAAA,EAClB;AAAA,EACA,IAAI,QAAQ,GAAkB;AAC5B,SAAK,WAAW;AAChB,SAAK,WAAW;AAAA,EAClB;AAAA;AAAA;AAAA,EAGA,IAAI,OAAO,GAAsB;AAC/B,SAAK,kBAAkB;AACvB,SAAK,WAAW;AAAA,EAClB;AAAA;AAAA,EAEA,IAAI,aAAuC;AACzC,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAEA,IAAI,WAAoB;AACtB,WAAO,KAAK,WAAW;AAAA,EACzB;AAAA;AAAA;AAAA,EAIA,MAAM,qBAAuC;AAC3C,QAAI,CAAC,KAAK,OAAQ,QAAO;AACzB,UAAM,IAAI,KAAK;AACf,WAAO,IAAI,QAAiB,CAAC,YAAY;AACvC,YAAM,UAAU,CAAC,MAA0C;AACzD,YAAI,EAAE,KAAK,SAAS,WAAW;AAC7B,YAAE,oBAAoB,WAAW,OAAO;AACxC,kBAAQ,EAAE,KAAK,UAAU;AAAA,QAC3B;AAAA,MACF;AACA,QAAE,iBAAiB,WAAW,OAAO;AACrC,QAAE,YAAY,EAAE,MAAM,SAAS,CAAyB;AAAA,IAC1D,CAAC;AAAA,EACH;AAAA,EAEA,oBAA0B;AACxB,QAAI,CAAC,KAAK,WAAY,MAAK,SAAS;AACpC,SAAK,WAAW;AAAA,EAClB;AAAA,EAEA,uBAA6B;AAC3B,SAAK,SAAS;AAAA,EAChB;AAAA,EAEQ,WAAiB;AACvB,UAAM,OAAO,KAAK,aAAa,EAAE,MAAM,OAAO,CAAC;AAC/C,UAAM,QAAQ,SAAS,cAAc,OAAO;AAC5C,UAAM,cAAc;AACpB,SAAK,SAAS,SAAS,cAAc,QAAQ;AAC7C,SAAK,OAAO,YAAY;AACxB,SAAK,UAAU,SAAS,cAAc,KAAK;AAC3C,SAAK,QAAQ,YAAY;AACzB,SAAK,UAAU,SAAS,cAAc,KAAK;AAC3C,SAAK,QAAQ,YAAY;AACzB,SAAK,SAAS,SAAS,cAAc,KAAK;AAC1C,SAAK,OAAO,YAAY;AACxB,SAAK,OAAO,cAAc;AAG1B,UAAM,WAAW,SAAS,cAAc,KAAK;AAC7C,aAAS,YAAY;AACrB,UAAM,OAAO,SAAS,cAAc,MAAM;AAC1C,SAAK,OAAO;AACZ,aAAS,OAAO,IAAI;AACpB,SAAK,OAAO,OAAO,KAAK,SAAS,UAAU,KAAK,SAAS,KAAK,MAAM;AACpE,SAAK,OAAO,OAAO,KAAK,MAAM;AAE9B,eAAW,MAAM,CAAC,eAAe,eAAe,WAAW,SAAS,YAAY,GAAY;AAC1F,WAAK,OAAO,iBAAiB,IAAI,MAAM,KAAK,YAAY,GAAG,EAAE,SAAS,KAAK,CAAC;AAAA,IAC9E;AACA,SAAK,OAAO,iBAAiB,UAAU,CAAC,MAAM;AAC5C,QAAE,eAAe;AACjB,WAAK,SAAS,KAAK;AAAA,IACrB,CAAC;AAAA,EACH;AAAA,EAEQ,aAAmB;AACzB,QAAI,KAAK,WAAW,CAAC,KAAK,cAAc,OAAO,WAAW,YAAa;AACvE,QAAI,KAAK,iBAAiB;AACxB,WAAK,UAAU,KAAK;AACpB,WAAK,aAAa;AAAA,IACpB,WAAW,KAAK,WAAW,KAAK,UAAU;AACxC,WAAK,UAAU,IAAI,kBAAkB,KAAK,SAAS,KAAK,QAAQ;AAChE,WAAK,QAAQ,KAAK;AAClB,WAAK,aAAa;AAAA,IACpB,OAAO;AACL;AAAA,IACF;AACA,UAAM,MAAM,KAAK;AAEjB,SAAK,UAAU;AAAA,MACb,OAAO,MAAM;AAEX,cAAM,WAAW,IAAI,WAAW;AAChC,cAAM,SAAS,IAAI,aAAa;AAChC,cAAM,cAAc,IAAI,oBAAoB;AAC5C,YAAI,YAAY,OAAQ,MAAK,KAAK,QAAQ,WAAW;AAAA,YAChD,MAAK,MAAM;AAAA,MAClB,CAAC;AAAA,IACH;AAGA,SAAK,UAAU;AAAA,MACb,OAAO,MAAM;AACX,cAAM,OAAO,KAAK,QAAS,OAAO,aAAa,CAAC,IAAI,oBAAoB;AACxE,cAAM,MAAM,IAAI,IAAI;AACpB,aAAK,QAAQ,MAAM,UAAU,QAAQ,IAAI,WAAW,QAAQ,UAAU;AACtE,YAAI,MAAM;AACR,gBAAM,MAAM,IAAI,mBAAmB,QAAW;AAAA,YAC5C,SAAS;AAAA,YACT,OAAO;AAAA,YACP,KAAK;AAAA,UACP,CAAC;AACD,gBAAM,OAAO,IAAI,mBAAmB;AACpC,eAAK,QAAQ,YAAY,oBAAoB,GAAG,2BAA2B,IAAI;AAAA,QACjF;AAAA,MACF,CAAC;AAAA,IACH;AAGA,QAAI,IAAI,YAAY;AAClB,WAAK,UAAU,IAAI,UAAU;AAC7B,WAAK,UAAU;AAAA,QACb,OAAO,MAAM;AACX,gBAAM,OAAO,IAAI,eAAe;AAChC,gBAAM,IAAI,KAAK;AACf,cAAI,CAAC,EAAG;AACR,cAAI,QAAQ,CAAC,EAAE,MAAM;AACnB,iBAAK,kBAAkB;AACvB,cAAE,UAAU;AAAA,UACd,WAAW,CAAC,QAAQ,EAAE,MAAM;AAC1B,cAAE,MAAM;AAAA,UACV;AAAA,QACF,CAAC;AAAA,MACH;AAEA,WAAK,UAAU;AAAA,QACb,OAAO,MAAM;AACX,gBAAM,KAAK,IAAI,aAAa,OAAO,SAAS,MAAM;AAClD,cAAI,KAAK,cAAc,KAAK,WAAW,UAAU,GAAI,MAAK,WAAW,QAAQ;AAAA,QAC/E,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,UAAU,KAAyD;AACzE,QAAI,KAAK,aAAa,CAAC,KAAK,WAAY;AACxC,UAAM,MAAM,KAAK;AACjB,UAAM,IAAI,SAAS,cAAc,QAAQ;AACzC,MAAE,YAAY;AACd,UAAM,OAAO,SAAS,cAAc,KAAK;AACzC,SAAK,YAAY;AAEjB,UAAM,QAAQ,SAAS,cAAc,KAAK;AAC1C,UAAM,YAAY;AAClB,UAAM,cAAc,IAAI;AACxB,SAAK,OAAO,KAAK;AAEjB,QAAI,IAAI,YAAY;AAClB,YAAM,MAAM,SAAS,cAAc,OAAO;AAC1C,UAAI,YAAY;AAChB,YAAM,QAAQ,SAAS,cAAc,MAAM;AAC3C,YAAM,cAAc;AACpB,YAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,aAAO,YAAY;AACnB,iBAAW,KAAK,IAAI,YAAY;AAC9B,cAAM,MAAM,SAAS,cAAc,QAAQ;AAC3C,YAAI,QAAQ,EAAE;AACd,YAAI,cAAc,EAAE;AACpB,eAAO,OAAO,GAAG;AAAA,MACnB;AACA,aAAO,iBAAiB,UAAU,MAAM;AACtC,YAAI,UAAU,OAAO,KAAK;AAC1B,YAAI,IAAI,eAAe;AAGrB,cAAI,gBAAgB;AACpB,cAAI,WAAW;AAAA,QACjB;AAAA,MACF,CAAC;AACD,UAAI,OAAO,OAAO,MAAM;AACxB,WAAK,OAAO,GAAG;AACf,WAAK,aAAa;AAAA,IACpB;AAEA,UAAM,UAAU,SAAS,cAAc,KAAK;AAC5C,YAAQ,YAAY;AACpB,UAAM,QAAQ,SAAS,cAAc,QAAQ;AAC7C,UAAM,YAAY;AAClB,UAAM,OAAO;AACb,UAAM,cAAc;AACpB,UAAM,iBAAiB,SAAS,MAAM,IAAI,gBAAgB,CAAC;AAC3D,YAAQ,OAAO,KAAK;AACpB,SAAK,OAAO,OAAO;AAEnB,MAAE,OAAO,IAAI;AAEb,MAAE,iBAAiB,UAAU,CAAC,MAAM;AAClC,QAAE,eAAe;AACjB,UAAI,gBAAgB;AAAA,IACtB,CAAC;AACD,MAAE,iBAAiB,SAAS,CAAC,MAAM;AACjC,UAAI,EAAE,WAAW,EAAG,KAAI,gBAAgB;AAAA,IAC1C,CAAC;AACD,SAAK,WAAW,OAAO,CAAC;AACxB,SAAK,aAAa;AAClB,SAAK,YAAY;AAAA,EACnB;AAAA,EAEQ,oBAA0B;AAChC,QAAI,KAAK,YAAY;AACnB,WAAK,WAAW,QAAQ,KAAK,SAAS,aAAa,OAAO,SAAS,MAAM;AAAA,IAC3E;AAAA,EACF;AAAA,EAEQ,cAA2B;AACjC,WAAO;AAAA,MACL,SAAS,MAAM,CAAC;AAAA,MAChB,SAAS,CAAC,aACR,OAAO,aAAa,cAChB,MAAM,KAAK,SAAS,iBAA8B,QAAQ,CAAC,IAC3D,CAAC;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAc,KAAK,QAAqB,aAAsB,aAAa,OAAsB;AAC/F,UAAM,MAAM,KAAK;AACjB,SAAK,OAAO,UAAU,OAAO,eAAe,WAAW;AACvD,SAAK,OAAO,UAAU,OAAO,WAAW,IAAI,cAAc,KAAK;AAC/D,QAAI,CAAC,KAAK,OAAO,MAAM;AACrB,WAAK,OAAO,UAAU,OAAO,SAAS;AACtC,WAAK,OAAO,UAAU;AACtB,WAAK,IAAI;AACT,WAAK,aAAa;AAClB,aAAO,iBAAiB,UAAU,KAAK,QAAQ;AAAA,IACjD;AAEA,UAAM,QAAQ,EAAE,KAAK;AACrB,UAAM,KAAK,gBAAgB;AAC3B,UAAM,IAAI,OAAO;AACjB,UAAM,IAAI,OAAO;AACjB,UAAM,OAAO,IAAI,OAAO,SAAS;AACjC,UAAM,MAAM,OAAO,qBAAqB,WAAW,mBAAmB;AAEtE,UAAM,iBAAiB,CAAC,cACnB,OAAO,SAAS,eAChB,IAAI,OAAO,aACX,OAAO,kBAAkB,UAAU,+BAA+B,cAClE,qBAAqB;AAE1B,QAAI,gBAAgB;AAClB,UAAI;AACF,cAAM,OAAO,MAAM,KAAK,aAAa,QAAQ,IAAI,OAAO,WAAY,GAAG,GAAG,MAAM,KAAK,IAAI,cAAc,OAAO,WAAW;AACzH,YAAI,UAAU,KAAK,YAAY;AAC7B,eAAK,QAAQ;AACb;AAAA,QACF;AACA,aAAK,WAAW;AAChB,aAAK,UAAU,IAAI,cAAc,KAAK;AACtC,aAAK,OAAO,UAAU,OAAO,eAAe;AAC5C;AAAA,MACF,QAAQ;AAEN,cAAM,KAAK,gBAAgB;AAC3B,YAAI,UAAU,KAAK,WAAY;AAAA,MACjC;AAAA,IACF;AACA,QAAI;AACF,YAAM,OAAO,MAAM,OAAO,MAAM;AAAA,QAC9B,MAAM,KAAK;AAAA,QACX;AAAA,QACA,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,KAAK,UAAU,IAAI;AAAA,QACnB;AAAA,QACA,eAAe,IAAI,cAAc;AAAA,QACjC,MAAM,OAAO,SAAS,cAAc,KAAK,YAAY,IAAI;AAAA,MAC3D,CAAC;AACD,UAAI,UAAU,KAAK,YAAY;AAC7B,aAAK,QAAQ;AACb;AAAA,MACF;AACA,WAAK,WAAW;AAChB,WAAK,UAAU,IAAI,cAAc,KAAK;AACtC,WAAK,OAAO,UAAU,OAAO,eAAe;AAAA,IAC9C,SAAS,KAAK;AAGZ,UAAI,UAAU,KAAK,WAAY;AAC/B,cAAQ,KAAK,wBAAwB,OAAO,SAAS,EAAE,sBAAsB,GAAG;AAChF,WAAK,QAAQ,gBAAgB;AAC7B,WAAK,OAAO,UAAU,IAAI,eAAe;AAAA,IAC3C;AAAA,EACF;AAAA,EAEQ,aACN,QACA,WACA,OACA,QACA,MACA,KACA,eACA,aACwB;AACxB,UAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,WAAO,MAAM,UAAU;AACvB,SAAK,QAAQ,YAAY,MAAM;AAE/B,UAAM,YAAY,OAAO,2BAA2B;AAGpD,QAAI;AACJ,QAAI,KAAK,gBAAgB,KAAK,aAAa,QAAQ,WAAW;AAC5D,eAAS,KAAK,aAAa;AAC3B,WAAK,eAAe;AAAA,IACtB,OAAO;AACL,WAAK,sBAAsB;AAC3B,eAAS,IAAI,OAAO,WAAW,EAAE,MAAM,SAAS,CAAC;AAAA,IACnD;AACA,SAAK,SAAS;AACd,SAAK,mBAAmB;AAExB,UAAM,WAA0B,OAAO,OACnC;AAAA,MACE,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,MAAM,OAAO;AAAA,MACb;AAAA,MAAO;AAAA,MAAQ;AAAA,MAAM;AAAA,MAAK;AAAA,MAC1B,GAAI,KAAK,mBAAmB,EAAE,kBAAkB,KAAK,IAAI,CAAC;AAAA,IAC5D,IACA;AAAA,MACE,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,SAAS,OAAO,SAAS;AAAA,MACzB;AAAA,MAAO;AAAA,MAAQ;AAAA,MAAM;AAAA,MAAK;AAAA,MAC1B,GAAI,KAAK,mBAAmB,EAAE,kBAAkB,KAAK,IAAI,CAAC;AAAA,IAC5D;AACJ,WAAO,YAAY,UAAU,CAAC,SAAS,CAAC;AAExC,QAAI,WAAW;AAEf,UAAM,QAAuB;AAAA,MAC3B,WAAW,CAAC,MAAM,OAAO,YAAY,EAAE,MAAM,SAAS,QAAQ,EAAE,CAAyB;AAAA,MACzF,QAAQ,CAAC,GAAG,GAAG,WAAW,OAAO,YAAY,EAAE,MAAM,UAAU,OAAO,GAAG,QAAQ,GAAG,KAAK,UAAU,IAAI,CAAyB;AAAA,MAChI,YAAY,CAAC,UAAU,OAAO,YAAY,EAAE,MAAM,SAAS,MAAM,CAAyB;AAAA,MAC1F,SAAS,MAAM;AACb,mBAAW;AACX,aAAK,wBAAwB;AAC7B,aAAK,wBAAwB;AAC7B,eAAO,YAAY,EAAE,MAAM,UAAU,CAAyB;AAC9D,eAAO,UAAU;AACjB,aAAK,SAAS;AACd,eAAO,OAAO;AAAA,MAChB;AAAA,IACF;AAEA,WAAO,IAAI,QAAuB,CAAC,SAAS,WAAW;AACrD,YAAM,YAAY,CAAC,MAA0C;AAC3D,YAAI,EAAE,KAAK,SAAS,WAAW;AAC7B,iBAAO,oBAAoB,WAAW,SAAS;AAC/C,iBAAO,oBAAoB,SAAS,OAAO;AAI3C,gBAAM,UAAU,CAAC,OAAoB;AACnC,gBAAI,SAAU;AACd,uBAAW;AACX,kBAAM,MAAM,cAAc,aAAa,GAAG,UAAU;AACpD,oBAAQ,KAAK,+CAA+C,GAAG,EAAE;AACjE,iBAAK,wBAAwB;AAC7B,iBAAK,wBAAwB;AAC7B,mBAAO,UAAU;AACjB,iBAAK,SAAS;AACd,iBAAK,WAAW;AAChB,iBAAK,SAAS,gBAAgB;AAC9B,iBAAK,KAAK,KAAK,QAAQ,aAAa,IAAI;AAAA,UAC1C;AACA,iBAAO,iBAAiB,SAAS,OAAO;AACxC,iBAAO,iBAAiB,gBAAgB,OAAO;AAC/C,eAAK,wBAAwB,MAAM;AACjC,mBAAO,oBAAoB,SAAS,OAAO;AAC3C,mBAAO,oBAAoB,gBAAgB,OAAO;AAAA,UACpD;AAEA,kBAAQ,KAAK;AAAA,QACf,WAAW,EAAE,KAAK,SAAS,SAAS;AAClC,iBAAO,oBAAoB,WAAW,SAAS;AAC/C,iBAAO,oBAAoB,SAAS,OAAO;AAC3C,iBAAO,IAAI,MAAM,EAAE,KAAK,OAAO,CAAC;AAAA,QAClC;AAAA,MACF;AACA,YAAM,UAAU,CAAC,MAAwB;AACvC,eAAO,oBAAoB,WAAW,SAAS;AAC/C,eAAO,oBAAoB,SAAS,OAAO;AAC3C,eAAO,IAAI,MAAM,EAAE,OAAO,CAAC;AAAA,MAC7B;AACA,aAAO,iBAAiB,WAAW,SAAS;AAC5C,aAAO,iBAAiB,SAAS,OAAO;AAAA,IAC1C,CAAC;AAAA,EACH;AAAA,EAEQ,QAAc;AACpB,QAAI,CAAC,KAAK,QAAQ,KAAM;AACxB,WAAO,oBAAoB,UAAU,KAAK,QAAQ;AAClD,QAAI,KAAK,aAAa;AAAE,mBAAa,KAAK,WAAW;AAAG,WAAK,cAAc;AAAA,IAAM;AACjF,SAAK,OAAO,UAAU,OAAO,eAAe;AAC5C,SAAK,OAAO,UAAU,OAAO,MAAM;AACnC,QAAI,KAAK,UAAW,cAAa,KAAK,SAAS;AAC/C,SAAK,KAAK,gBAAgB;AAC1B,UAAM,UAAU,KAAK,SAAS,cAAc;AAC5C,QAAI,SAAS;AACX,WAAK,OAAO,MAAM;AAClB;AAAA,IACF;AACA,SAAK,OAAO,UAAU,IAAI,SAAS;AACnC,QAAI,KAAK,WAAY,cAAa,KAAK,UAAU;AACjD,SAAK,aAAa,WAAW,MAAM;AACjC,UAAI,KAAK,OAAO,KAAM,MAAK,OAAO,MAAM;AACxC,WAAK,OAAO,UAAU,OAAO,SAAS;AAAA,IACxC,GAAG,GAAG;AAAA,EACR;AAAA,EAEA,MAAc,kBAAiC;AAC7C,SAAK,wBAAwB;AAC7B,SAAK,wBAAwB;AAE7B,QAAI,KAAK,UAAU;AACjB,UAAI,KAAK,QAAQ;AAEf,aAAK,OAAO,YAAY,EAAE,MAAM,UAAU,CAAyB;AACnE,aAAK,eAAe,EAAE,QAAQ,KAAK,QAAQ,KAAK,KAAK,iBAAkB;AACvE,aAAK,SAAS;AAAA,MAChB,OAAO;AACL,aAAK,SAAS,QAAQ;AAAA,MACxB;AACA,WAAK,WAAW;AAAA,IAClB,WAAW,KAAK,QAAQ;AACtB,WAAK,OAAO,UAAU;AACtB,WAAK,SAAS;AAAA,IAChB;AACA,SAAK,SAAS,gBAAgB;AAAA,EAChC;AAAA,EAEQ,wBAA8B;AACpC,QAAI,KAAK,cAAc;AACrB,WAAK,aAAa,OAAO,UAAU;AACnC,WAAK,eAAe;AAAA,IACtB;AAAA,EACF;AAAA,EAEQ,MAAY;AAClB,SAAK,QAAQ;AACb,QAAI,KAAK,SAAU,cAAa,KAAK,QAAQ;AAC7C,SAAK,WAAW,WAAW,MAAM;AAC/B,WAAK,QAAQ;AAAA,IACf,GAAG,GAAG;AAAA,EACR;AAAA,EAEQ,eAAqB;AAC3B,QAAI,KAAK,UAAW,cAAa,KAAK,SAAS;AAC/C,SAAK,OAAO,UAAU,OAAO,MAAM;AACnC,SAAK,YAAY,WAAW,MAAM,KAAK,OAAO,UAAU,IAAI,MAAM,GAAG,GAAI;AAAA,EAC3E;AAAA,EAEiB,WAAW,MAAY;AACtC,QAAI,KAAK,gBAAgB,KAAM,cAAa,KAAK,WAAW;AAC5D,SAAK,cAAc,WAAW,MAAM;AAClC,WAAK,cAAc;AACnB,UAAI,CAAC,KAAK,YAAY,CAAC,KAAK,QAAQ,KAAM;AAC1C,YAAM,SAAS,OAAO,qBAAqB,WAAW,mBAAmB;AACzE,WAAK,SAAS,OAAO,OAAO,YAAY,OAAO,aAAa,MAAM;AAAA,IACpE,GAAG,GAAG;AAAA,EACR;AAAA,EAEQ,cAAoB;AAC1B,QAAI,CAAC,KAAK,MAAO;AACjB,SAAK,SAAS,KAAK;AAAA,EACrB;AAAA,EAEQ,WAAiB;AACvB,WAAO,oBAAoB,UAAU,KAAK,QAAQ;AAClD,QAAI,KAAK,aAAa;AAAE,mBAAa,KAAK,WAAW;AAAG,WAAK,cAAc;AAAA,IAAM;AACjF,SAAK,KAAK,gBAAgB;AAC1B,SAAK,sBAAsB;AAC3B,QAAI,KAAK,SAAU,cAAa,KAAK,QAAQ;AAC7C,QAAI,KAAK,UAAW,cAAa,KAAK,SAAS;AAC/C,QAAI,KAAK,WAAY,cAAa,KAAK,UAAU;AACjD,eAAW,KAAK,KAAK,UAAW,GAAE;AAClC,SAAK,YAAY,CAAC;AAClB,QAAI,KAAK,WAAY,MAAK,SAAS,QAAQ;AAC3C,SAAK,UAAU;AAAA,EACjB;AACF;AAGO,SAAS,iBAAiB,MAAM,eAAqB;AAC1D,MAAI,OAAO,mBAAmB,eAAe,CAAC,eAAe,IAAI,GAAG,GAAG;AACrE,mBAAe,OAAO,KAAK,iBAAiB;AAAA,EAC9C;AACF;;;ACtkBO,SAAS,cACd,UACA,MACM;AACN,MAAI,WAAiC;AACrC,MAAI,eAAuC;AAC3C,MAAI,gBAAgB;AACpB,MAAI,WAAW;AAEf,QAAM,OAAO,CAAC,QAA8B;AAC1C,SAAK,YAAY,GAAG;AAAA,EACtB;AAEA,QAAM,qBAAqB,CAAC,gBAA+B;AACzD,UAAM,IAAI;AACV,UAAM,WAAW,cAAc,KAAK,MAAM,MAAO,WAAW,IAAI;AAChE,MAAE,wBAAwB,CAAC,OACzB,WAAW,MAAM,GAAG,YAAY,IAAI,CAAC,GAAG,QAAQ;AAClD,MAAE,uBAAuB,CAAC,OAAe,aAAa,EAAE;AACxD,oBAAgB;AAAA,EAClB;AAEA,MAAI,OAAO,0BAA0B,aAAa;AAChD,uBAAmB;AAAA,EACrB;AAEA,QAAM,cAAc,CAClB,QACA,QACA,KAKA,QACS;AACT,QAAI,IAAI,kBAAkB;AACxB,yBAAmB,IAAI,WAAW;AAAA,IACpC,WAAW,iBAAiB,IAAI,aAAa;AAC3C,yBAAmB,IAAI,WAAW;AAAA,IACpC;AAEA,mBAAe;AACf,UAAM,WAAW,IAAI,MAAM,CAAC,GAAkB;AAAA,MAC5C,IAAI,SAAS,MAAM;AACjB,cAAM,IAAI;AAAA,UACR,uBAAuB,OAAO,IAAI,CAAC;AAAA,QAErC;AAAA,MACF;AAAA,IACF,CAAC;AACD,UAAM,MAAoB;AAAA,MACxB,MAAM;AAAA,MACN,SAAS;AAAA,MACT,KAAK,IAAI;AAAA,MACT,OAAO,IAAI;AAAA,MACX,QAAQ,IAAI;AAAA,MACZ,KAAK,UAAU,IAAI,IAAI;AAAA,MACvB,MAAM,IAAI;AAAA,MACV,eAAe,IAAI;AAAA,IACrB;AACA,QAAI;AACF,YAAM,SAAS,OAAO,MAAM,GAAG;AAC/B,UAAI,kBAAkB,SAAS;AAC7B,eAAO,KAAK,CAAC,SAAS;AACpB,cAAI,QAAQ,UAAU;AACpB,iBAAK,QAAQ;AACb;AAAA,UACF;AACA,qBAAW;AACX,eAAK,EAAE,MAAM,UAAU,CAAC;AAAA,QAC1B,CAAC,EAAE,MAAM,CAAC,QAAiB;AACzB,cAAI,QAAQ,SAAU;AACtB,eAAK,EAAE,MAAM,SAAS,SAAS,OAAO,GAAG,EAAE,CAAC;AAAA,QAC9C,CAAC;AAAA,MACH,OAAO;AACL,YAAI,QAAQ,UAAU;AACpB,iBAAO,QAAQ;AACf;AAAA,QACF;AACA,mBAAW;AACX,aAAK,EAAE,MAAM,UAAU,CAAC;AAAA,MAC1B;AAAA,IACF,SAAS,KAAc;AACrB,UAAI,QAAQ,SAAU;AACtB,WAAK,EAAE,MAAM,SAAS,SAAS,OAAO,GAAG,EAAE,CAAC;AAAA,IAC9C;AAAA,EACF;AAEA,OAAK,iBAAiB,WAAW,CAAC,QAAqC;AACrE,UAAM,MAAM,IAAI;AAChB,YAAQ,IAAI,MAAM;AAAA,MAChB,KAAK,SAAS;AACZ,cAAM,SAAS,SAAS,IAAI,OAAO;AACnC,YAAI,CAAC,QAAQ;AACX,eAAK,EAAE,MAAM,SAAS,SAAS,kBAAkB,IAAI,OAAO,GAAG,CAAC;AAChE;AAAA,QACF;AACA,kBAAU,QAAQ;AAClB,mBAAW;AACX,cAAM,MAAM,EAAE;AACd,oBAAY,QAAQ,IAAI,QAAQ,KAAK,GAAG;AACxC;AAAA,MACF;AAAA,MACA,KAAK,cAAc;AACjB,YAAI,CAAC,MAAM,UAAU;AACnB,eAAK,EAAE,MAAM,SAAS,SAAS,sCAAsC,CAAC;AACtE;AAAA,QACF;AACA,YAAI;AACF,gBAAM,SAAS,KAAK,SAAS,IAAI,IAAI;AACrC,oBAAU,QAAQ;AAClB,qBAAW;AACX,gBAAM,MAAM,EAAE;AACd,sBAAY,QAAQ,IAAI,QAAQ,KAAK,GAAG;AAAA,QAC1C,SAAS,KAAc;AACrB,eAAK,EAAE,MAAM,SAAS,SAAS,OAAO,GAAG,EAAE,CAAC;AAAA,QAC9C;AACA;AAAA,MACF;AAAA,MACA,KAAK;AACH,kBAAU,OAAO,IAAI,OAAO,IAAI,QAAQ,IAAI,GAAG;AAC/C;AAAA,MACF,KAAK;AACH,kBAAU,UAAU,IAAI,MAAM;AAC9B;AAAA,MACF,KAAK;AACH,kBAAU,aAAa,IAAI,KAAK;AAChC;AAAA,MACF,KAAK,UAAU;AACb,YAAI,CAAC,cAAc;AACjB,eAAK,EAAE,MAAM,WAAW,YAAY,MAAM,CAAC;AAC3C;AAAA,QACF;AACA,cAAM,MAAM,aAAa,WAAW,IAAI;AACxC,YAAI,CAAC,KAAK;AACR,eAAK,EAAE,MAAM,WAAW,YAAY,MAAM,CAAC;AAC3C;AAAA,QACF;AACA,cAAM,KAAK,aAAa;AACxB,cAAM,KAAK,aAAa;AACxB,YAAI,aAAa;AACjB,cAAM,OAAO;AACb,cAAM,OAAO;AACb,iBAAS,IAAI,GAAG,IAAI,QAAQ,CAAC,YAAY,KAAK;AAC5C,gBAAM,IAAI,KAAK,MAAO,MAAM,IAAI,MAAO,OAAO,EAAE;AAChD,mBAAS,IAAI,GAAG,IAAI,QAAQ,CAAC,YAAY,KAAK;AAC5C,kBAAM,IAAI,KAAK,MAAO,MAAM,IAAI,MAAO,OAAO,EAAE;AAChD,kBAAM,OAAO,IAAI,aAAa,GAAG,GAAG,GAAG,CAAC,EAAE;AAC1C,gBAAI,KAAK,CAAC,IAAK,KAAK,KAAK,CAAC,IAAK,KAAK,KAAK,CAAC,IAAK,KAAK,KAAK,CAAC,IAAK,EAAG,cAAa;AAAA,UACjF;AAAA,QACF;AACA,aAAK,EAAE,MAAM,WAAW,WAAW,CAAC;AACpC;AAAA,MACF;AAAA,MACA,KAAK;AACH;AACA,kBAAU,QAAQ;AAClB,mBAAW;AACX,uBAAe;AACf;AAAA,IACJ;AAAA,EACF,CAAC;AACH;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/types.ts","../src/rng.ts","../src/reactive.ts","../src/control-track.ts","../src/idle-detector.ts","../src/engine.ts","../src/idle-screen.element.ts","../src/worker-protocol.ts"],"sourcesContent":["import type { Rng } from './rng';\n\n/** How a parameter interpolates between control-track deltas. */\nexport type Ease = 'step' | 'linear' | 'smooth';\n\nexport type ParamType = 'number' | 'color' | 'bool' | 'enum';\nexport type ParamValue = number | string | boolean;\n\n/** One typed, ranged, interpolatable knob: an agent's steering surface. */\nexport interface ParamDef {\n type: ParamType;\n default: ParamValue;\n min?: number;\n max?: number;\n options?: string[];\n /** Default interpolation when a delta targets this knob. */\n ease?: Ease;\n}\n\nexport type ParamSpace = Record<string, ParamDef>;\n\n/** A sparse, timestamped, interpolatable parameter change. Agents stream THESE\n * (over AG-UI state-patches / MCP resource updates), never frames. */\nexport interface ParamDelta {\n /** ms from track start. */\n t: number;\n /** key in the saver's paramSpace. */\n path: string;\n value: ParamValue;\n ease?: Ease;\n /** ramp duration ms from the previous value (0 = instant). */\n dur?: number;\n}\n\n/** A recorded or live steering performance for a seeded program. */\nexport interface ControlTrack {\n program: string;\n seed: number;\n duration?: number;\n loop?: boolean;\n deltas: ParamDelta[];\n}\n\n/** Page-context seam: passthrough savers read/eat the live page through this,\n * rather than querying `document` directly. */\nexport interface PageContext {\n /** Sample dominant colors of the page (for palette-reactive savers). */\n palette(): string[];\n /** Visible page blocks a passthrough saver may transform (\"victims\"). */\n victims(selector: string): HTMLElement[];\n}\n\n/** What the host hands a saver when it mounts. */\nexport interface SaverContext {\n /** A full-viewport container the saver renders into. Canvas savers create a\n * canvas inside it; DOM savers (toasters, DVD, messages) append elements. The\n * host is cleared by the runtime on dispose. */\n host: HTMLElement;\n /** Pre-created rendering surface. When present, canvas savers should use this\n * instead of creating their own canvas. In a Worker this is an OffscreenCanvas. */\n surface?: HTMLCanvasElement | OffscreenCanvas;\n /** Device pixel ratio — use instead of reading window.devicePixelRatio. */\n dpr: number;\n width: number;\n height: number;\n /** Seeded PRNG. Use this, never Math.random(), for determinism. */\n rng: Rng;\n seed: number;\n reducedMotion: boolean;\n /** Present for passthrough savers (over the live page). */\n page?: PageContext;\n}\n\n/**\n * One deck of a mounted saver's practical composition stack, bottom-up.\n *\n * This is deliberately NOT the schema's layer concept (declared sprite\n * layers): it describes what a running instance is actually composed of, so\n * hosts and tooling can present and inspect the stack uniformly. A\n * passthrough saver is at minimum `page` + `surface`; a classic canvas saver\n * is just its `surface`; savers may further describe the logical draw passes\n * inside a surface. The model is intentionally small and open — future work\n * (multi-surface savers, per-pass toggles, cross-saver scenes) extends it\n * rather than replacing it.\n */\nexport interface SaverLayer {\n id: string;\n label: string;\n /** 'page' = the live document a passthrough saver performs on;\n * 'surface' = a rendering surface the instance owns (usually a canvas);\n * 'pass' = a logical draw pass inside the surface above it. */\n kind: 'page' | 'surface' | 'pass';\n /** The element that IS this layer, when one exists. Hosts may toggle its\n * visibility for inspection. A `page` layer has no element — the HOST\n * owns the document and binds it (the saver only borrows it). */\n el?: HTMLElement;\n description?: string;\n}\n\nexport interface SaverInstance {\n /** Freeze/unfreeze the render loop (paused, reduced-motion, or screensaver end). */\n setPaused(paused: boolean): void;\n resize(width: number, height: number, dpr?: number): void;\n /** Deterministic, frame-addressable render: draw the state at logical time `t`\n * (ms) for `seed`. Pure w.r.t. (program, seed, applied track, t). Optional. */\n renderFrame?(t: number, seed: number): void;\n /** Steer parameters over time. Optional. */\n applyTrack?(track: ControlTrack): void;\n /** Seek logical animation time (ms) for workbench preview. Optional. */\n previewAt?(t: number): void;\n /** Describe the practical composition stack, bottom-up. Optional.\n * (Named `composition`, not `layers`: schema-compiled instances already\n * carry their declared sprite `layers` as data.) */\n composition?(): SaverLayer[];\n /** Tear down; MUST restore any live-page mutations. */\n dispose(): void;\n}\n\n/** Self-describing metadata, readable WITHOUT executing the saver. */\nexport interface SaverManifest {\n id: string;\n label: string;\n /** One-line summary for catalogs / agent tooling (e.g. MCP `listSavers`). */\n description?: string;\n passthrough?: boolean;\n minBackend?: 'css' | 'canvas2d' | 'webgl2' | 'webgpu';\n costTier?: 'idle' | 'low' | 'medium' | 'high';\n motionIntensity?: 'calm' | 'moderate' | 'energetic';\n reducedMotionFallback?: 'static' | 'slow' | 'hide';\n palette?: string[];\n paramSpace?: ParamSpace;\n a11y?: { flashSafe?: boolean; notes?: string };\n provenance?: { prompt?: string; seed?: number; model?: string };\n /** Attribution for savers derived from licensed or third-party work — the\n * concept, reference implementation, or embedded assets. Hosts SHOULD show\n * this wherever the saver is showcased; the full ledger is CREDITS.md. */\n attribution?: {\n /** What this saver descends from, e.g. 'After Dark \"Messages\" — concept by Berkeley Systems'. */\n source: string;\n /** The licensing situation, ours and upstream, e.g. 'MIT port; reference CSS MIT (Bryan Braun)'. */\n license: string;\n /** Reference implementation or rights context. */\n url?: string;\n };\n thumbnail?: string;\n /** Saver renders on a provided surface (canvas/OffscreenCanvas) and avoids DOM\n * APIs, enabling Worker execution when the browser supports OffscreenCanvas. */\n workerReady?: boolean;\n /**\n * How the saver relates to time — a semantic claim about the program, not\n * an API flag (renderFrame's presence is the API).\n *\n * - 'closed-form': every frame is a pure function of (t, seed, params) —\n * compiled plans, phase integrals, triangle waves, CSS keyframes. With\n * `renderFrame` this means scrubbing, seek-back determinism, and\n * reproducible perception readings; without it (DOM/CSS savers) the\n * motion is still periodic and pure, just not pixel-addressable by us.\n * - 'simulated': state genuinely evolves by integration (fluid dynamics,\n * reaction-diffusion) — frames depend on history, sampling is the only\n * honest observation, and motion metrics between runs are meaningless.\n *\n * Tooling should prefer this over hardcoded per-saver capability lists.\n */\n timeModel?: 'closed-form' | 'simulated';\n}\n\n/** A registered saver: manifest + a (possibly lazy/async) mount factory. */\nexport interface SaverPlugin {\n manifest: SaverManifest;\n mount(ctx: SaverContext): SaverInstance | Promise<SaverInstance>;\n /** Original schema spec (JSON-serializable). When present, the element sends\n * a `mount-spec` message to the Worker instead of `mount`, so the Worker can\n * compile and run the spec without pre-registration in its registry. */\n spec?: unknown;\n}\n\n/** Engine configuration. */\nexport interface IdleScreensConfig {\n /** Idle time before sleeping, in ms. */\n timeoutMs: number;\n /** Also sleep when the window loses focus. */\n sleepOnBlur: boolean;\n /** Do not run on localhost (debug hooks bypass this). */\n disableOnLocalhost: boolean;\n /** Which registered saver to show. */\n defaultPluginId: string;\n /** How to pick across sleeps. */\n selection: 'fixed' | 'random' | 'rotate';\n /** Show the clock chrome (non-passthrough savers only). */\n showClock: boolean;\n /** Exact document title while asleep. */\n sleepTitle?: string;\n /** Master seed for plugin selection + the default saver seed. */\n seed: number;\n /** Return true for a URL where the saver must never sleep. */\n suppress?: (url: string) => boolean;\n /** Pluggable persistence (defaults to localStorage when available). */\n storage?: { get(key: string): string | null; set(key: string, value: string): void };\n /** URL of the idle-worker script. When set, savers with `workerReady: true`\n * render in a Web Worker via OffscreenCanvas. Omit to disable Worker rendering. */\n workerUrl?: string;\n /** Built-in, keyboard-opened config menu (saver picker). `true`/omitted =\n * enabled with ⌘K / Ctrl+K; `false` = no hotkey and no built-in menu (the\n * `configMenuOpen` signal + open/close API still work, so a host may render\n * its own). Pass an object to reconfigure. */\n configMenu?: boolean | ConfigMenuConfig;\n}\n\n/** Options for the built-in, keyboard-opened config menu. */\nexport interface ConfigMenuConfig {\n /** Master switch. Default true. */\n enabled?: boolean;\n /** Decides whether a keydown opens/toggles the menu. Default: ⌘K / Ctrl+K. */\n hotkey?: (e: KeyboardEvent) => boolean;\n /** Show the saver picker control. Default true. */\n showPicker?: boolean;\n /** Preview the picked saver immediately (sleep to show it). Default true. */\n previewOnPick?: boolean;\n /** Heading text. Default 'Screen Saver'. */\n title?: string;\n}\n\n/** Default menu hotkey: ⌘K (mac) / Ctrl+K, no other modifiers. */\nexport const DEFAULT_MENU_HOTKEY = (e: KeyboardEvent): boolean =>\n (e.metaKey || e.ctrlKey) && !e.altKey && !e.shiftKey && e.key.toLowerCase() === 'k';\n\n/** Normalize `configMenu` to a filled config, or null when disabled. */\nexport function resolveConfigMenu(\n c: boolean | ConfigMenuConfig | undefined,\n): Required<ConfigMenuConfig> | null {\n if (c === false) return null;\n const o: ConfigMenuConfig = c === true || c === undefined ? {} : c;\n if (o.enabled === false) return null;\n return {\n enabled: true,\n hotkey: o.hotkey ?? DEFAULT_MENU_HOTKEY,\n showPicker: o.showPicker ?? true,\n previewOnPick: o.previewOnPick ?? true,\n title: o.title ?? 'Screen Saver',\n };\n}\n\nexport const DEFAULT_CONFIG: IdleScreensConfig = {\n timeoutMs: 60_000,\n sleepOnBlur: true,\n disableOnLocalhost: false,\n defaultPluginId: '',\n selection: 'fixed',\n showClock: true,\n seed: 1,\n configMenu: true,\n};\n","/**\n * A tiny, fast, seedable PRNG (splitmix32). Deterministic: the same seed always\n * yields the same sequence, on any machine. This is what makes \"same program +\n * seed + control-track = identical frames\" hold. Savers take an `Rng` from their\n * `SaverContext` instead of calling `Math.random()`.\n */\nexport interface Rng {\n /** Next float in [0, 1). */\n next(): number;\n /** Float in [min, max). */\n range(min: number, max: number): number;\n /** Integer in [min, max] inclusive. */\n int(min: number, max: number): number;\n /** Random element of a non-empty array. */\n pick<T>(arr: readonly T[]): T;\n /** A fresh independent stream (e.g. per subsystem), derived from this seed. */\n fork(salt: number): Rng;\n}\n\nexport function createRng(seed: number): Rng {\n let a = seed >>> 0;\n const next = (): number => {\n a |= 0;\n a = (a + 0x9e3779b9) | 0;\n let t = a ^ (a >>> 16);\n t = Math.imul(t, 0x21f0aaad);\n t = t ^ (t >>> 15);\n t = Math.imul(t, 0x735a2d97);\n return ((t = t ^ (t >>> 15)) >>> 0) / 4294967296;\n };\n const rng: Rng = {\n next,\n range: (min, max) => min + (max - min) * next(),\n int: (min, max) => min + Math.floor(next() * (max - min + 1)),\n pick: (arr) => arr[Math.floor(next() * arr.length)] as (typeof arr)[number],\n fork: (salt) => createRng((seed ^ Math.imul(salt + 1, 0x9e3779b9)) >>> 0),\n };\n return rng;\n}\n","/**\n * Framework-agnostic reactivity. We re-export `@preact/signals-core` so the rest\n * of the engine uses the same `signal` / `computed` / `effect` primitives it did\n * as Angular signals, with near-identical semantics.\n */\nexport {\n signal,\n computed,\n effect,\n batch,\n untracked,\n type Signal,\n type ReadonlySignal,\n} from '@preact/signals-core';\n","import type { ControlTrack, Ease, ParamDelta, ParamSpace, ParamValue } from './types';\n\nfunction easeFn(e: Ease, p: number): number {\n const x = p <= 0 ? 0 : p >= 1 ? 1 : p;\n switch (e) {\n case 'step':\n return x >= 1 ? 1 : 0;\n case 'smooth':\n return x * x * (3 - 2 * x);\n case 'linear':\n default:\n return x;\n }\n}\n\nfunction lerp(a: number, b: number, p: number): number {\n return a + (b - a) * p;\n}\n\nfunction parseHex(c: string): [number, number, number] | null {\n const m = /^#?([0-9a-f]{6})$/i.exec(c.trim());\n if (!m) return null;\n const n = parseInt(m[1]!, 16);\n return [(n >> 16) & 255, (n >> 8) & 255, n & 255];\n}\n\nfunction toHex(rgb: [number, number, number]): string {\n const h = (v: number): string =>\n Math.round(Math.max(0, Math.min(255, v)))\n .toString(16)\n .padStart(2, '0');\n return `#${h(rgb[0])}${h(rgb[1])}${h(rgb[2])}`;\n}\n\nfunction lerpValue(type: string, a: ParamValue, b: ParamValue, p: number): ParamValue {\n if (type === 'number' && typeof a === 'number' && typeof b === 'number') return lerp(a, b, p);\n if (type === 'color' && typeof a === 'string' && typeof b === 'string') {\n const ca = parseHex(a);\n const cb = parseHex(b);\n if (ca && cb) return toHex([lerp(ca[0], cb[0], p), lerp(ca[1], cb[1], p), lerp(ca[2], cb[2], p)]);\n }\n return p >= 1 ? b : a; // bool / enum / step\n}\n\nfunction evalPath(\n dflt: ParamValue,\n type: string,\n defaultEase: Ease,\n deltas: ParamDelta[],\n t: number,\n): ParamValue {\n if (deltas.length === 0) return dflt;\n let prevVal = dflt;\n let prevT = -Infinity;\n for (const k of deltas) {\n if (t < k.t) {\n const rampStart = k.dur != null ? k.t - k.dur : prevT === -Infinity ? k.t : prevT;\n if (t <= rampStart) return prevVal;\n const p = easeFn(k.ease ?? defaultEase, (t - rampStart) / (k.t - rampStart || 1));\n return lerpValue(type, prevVal, k.value, p);\n }\n prevVal = k.value;\n prevT = k.t;\n }\n return prevVal; // after the last keyframe\n}\n\n/**\n * Sample a control track: given the saver's param space (defaults + types) and a\n * track, return the interpolated parameter values at logical time `t` (ms). Pure\n * and deterministic: identical `(space, track, t)` yields identical output.\n */\nexport function sampleTrack(\n space: ParamSpace,\n track: ControlTrack,\n t: number,\n): Record<string, ParamValue> {\n const byPath = new Map<string, ParamDelta[]>();\n for (const d of track.deltas) {\n const arr = byPath.get(d.path) ?? [];\n arr.push(d);\n byPath.set(d.path, arr);\n }\n const wrapped =\n track.loop && track.duration && track.duration > 0 ? t % track.duration : t;\n\n const out: Record<string, ParamValue> = {};\n for (const [path, def] of Object.entries(space)) {\n const deltas = (byPath.get(path) ?? []).slice().sort((a, b) => a.t - b.t);\n out[path] = evalPath(def.default, def.type, def.ease ?? 'linear', deltas, wrapped);\n }\n return out;\n}\n\n/** Default param values (the \"resting\" program before any track is applied). */\nexport function defaultParams(space: ParamSpace): Record<string, ParamValue> {\n const out: Record<string, ParamValue> = {};\n for (const [path, def] of Object.entries(space)) out[path] = def.default;\n return out;\n}\n","import { signal, type ReadonlySignal } from './reactive';\n\n/**\n * Detects user inactivity. `idle` flips true once no activity for `timeoutMs`.\n * Framework-agnostic port of the Angular IdleService: 6 activity events + a\n * single `setTimeout` (not a poll) whose reschedule is throttled to >=500ms so\n * frequent pointermove events do not thrash timers.\n */\nexport class IdleDetector {\n private readonly _idle = signal(false);\n readonly idle: ReadonlySignal<boolean> = this._idle;\n\n private timer: ReturnType<typeof setTimeout> | null = null;\n private lastReset = 0;\n private running = false;\n\n private static readonly EVENTS = [\n 'pointerdown',\n 'pointermove',\n 'keydown',\n 'wheel',\n 'touchstart',\n 'scroll',\n ] as const;\n\n constructor(private readonly timeoutMs: number) {}\n\n private readonly onActivity = (): void => this.markActive();\n\n start(): void {\n if (this.running || typeof window === 'undefined') return;\n this.running = true;\n for (const e of IdleDetector.EVENTS) {\n window.addEventListener(e, this.onActivity, { passive: true });\n }\n this.schedule();\n }\n\n stop(): void {\n if (!this.running) return;\n this.running = false;\n for (const e of IdleDetector.EVENTS) {\n window.removeEventListener(e, this.onActivity);\n }\n this.clear();\n }\n\n /** Force an activity pulse (resets the countdown, wakes from idle). */\n markActive(): void {\n if (this._idle.value) this._idle.value = false;\n const now = typeof performance !== 'undefined' ? performance.now() : Date.now();\n if (now - this.lastReset < 500) return; // throttle reschedules\n this.lastReset = now;\n this.schedule();\n }\n\n private schedule(): void {\n this.clear();\n this.timer = setTimeout(() => {\n this._idle.value = true;\n }, this.timeoutMs);\n }\n\n private clear(): void {\n if (this.timer !== null) {\n clearTimeout(this.timer);\n this.timer = null;\n }\n }\n}\n","import { computed, effect, signal, untracked, type ReadonlySignal } from './reactive';\nimport { IdleDetector } from './idle-detector';\nimport { createRng, type Rng } from './rng';\nimport {\n DEFAULT_CONFIG,\n resolveConfigMenu,\n type ConfigMenuConfig,\n type IdleScreensConfig,\n type SaverPlugin,\n} from './types';\n\nexport type EngineState = 'awake' | 'sleeping';\n\nconst hasWindow = typeof window !== 'undefined';\nconst hasDoc = typeof document !== 'undefined';\n\nfunction defaultStorage(): IdleScreensConfig['storage'] {\n return {\n get: (k) => {\n try {\n return hasWindow ? window.localStorage.getItem(k) : null;\n } catch {\n return null;\n }\n },\n set: (k, v) => {\n try {\n if (hasWindow) window.localStorage.setItem(k, v);\n } catch {\n /* private mode / disabled storage */\n }\n },\n };\n}\n\n/**\n * The framework-agnostic idle-screens state machine (port of the Angular\n * ScreensaverService). Owns: awake/sleeping state, plugin selection, the sleep\n * clock, reduced-motion + visibility, idle/blur triggers, and the\n * `window.__idleScreens` debug hook. It does NOT render; the `<idle-screen>`\n * element observes its signals.\n */\nexport class IdleScreensEngine {\n readonly config: IdleScreensConfig;\n private readonly plugins: SaverPlugin[];\n private readonly storage: NonNullable<IdleScreensConfig['storage']>;\n private readonly idle: IdleDetector;\n private readonly selectionRng: Rng;\n\n private readonly _state = signal<EngineState>('awake');\n readonly state: ReadonlySignal<EngineState> = this._state;\n readonly isSleeping = computed(() => this._state.value === 'sleeping');\n\n private readonly _activeId = signal('');\n readonly activePlugin = computed(\n () =>\n this.plugins.find((p) => p.manifest.id === this._activeId.value) ??\n this.plugins[0] ??\n null,\n );\n readonly activeIsPassthrough = computed(\n () => this.activePlugin.value?.manifest.passthrough ?? false,\n );\n\n private readonly _now = signal(new Date(0));\n readonly now: ReadonlySignal<Date> = this._now;\n private readonly _hidden = signal(false);\n readonly hidden: ReadonlySignal<boolean> = this._hidden;\n private readonly _reducedMotion = signal(false);\n readonly reducedMotion: ReadonlySignal<boolean> = this._reducedMotion;\n\n /** Resolved built-in config-menu options, or null when disabled. */\n readonly configMenu: Required<ConfigMenuConfig> | null;\n private readonly _configMenuOpen = signal(false);\n /** Whether the config menu is open. Drives the built-in `<idle-screen>` menu;\n * a host may also observe this to render its own. */\n readonly configMenuOpen: ReadonlySignal<boolean> = this._configMenuOpen;\n\n private clockTimer: ReturnType<typeof setInterval> | null = null;\n private started = false;\n private disposers: Array<() => void> = [];\n\n constructor(config: Partial<IdleScreensConfig>, plugins: SaverPlugin[]) {\n this.config = { ...DEFAULT_CONFIG, ...config };\n this.plugins = plugins;\n this.configMenu = resolveConfigMenu(this.config.configMenu);\n this.storage = this.config.storage ?? defaultStorage()!;\n this.idle = new IdleDetector(this.config.timeoutMs);\n this.selectionRng = createRng(this.config.seed >>> 0);\n\n const stored = this.storage.get('idleScreens.plugin');\n const initialId =\n (stored && plugins.some((p) => p.manifest.id === stored) && stored) ||\n this.config.defaultPluginId ||\n plugins[0]?.manifest.id ||\n '';\n this._activeId.value = initialId;\n }\n\n get pluginList(): Array<{ id: string; label: string }> {\n return this.plugins.map((p) => ({ id: p.manifest.id, label: p.manifest.label }));\n }\n\n /** Begin idle detection + listeners + debug hook. */\n init(): void {\n if (this.started || !hasWindow) return;\n this.started = true;\n\n if (hasDoc) {\n this._hidden.value = document.hidden;\n const onVis = (): void => {\n this._hidden.value = document.hidden;\n };\n document.addEventListener('visibilitychange', onVis);\n this.disposers.push(() => document.removeEventListener('visibilitychange', onVis));\n }\n\n const mq = hasWindow ? window.matchMedia('(prefers-reduced-motion: reduce)') : null;\n if (mq) {\n this._reducedMotion.value = mq.matches;\n const onMq = (): void => {\n this._reducedMotion.value = mq.matches;\n };\n mq.addEventListener('change', onMq);\n this.disposers.push(() => mq.removeEventListener('change', onMq));\n }\n\n // Sleep when idle fires (unless suppressed). `sleep()` reads `state` in its\n // guard; wrap it in `untracked` so this effect depends ONLY on the idle\n // signal — otherwise flipping `state` to awake in wake() (while idle is still\n // latched true) would re-trigger this effect and immediately re-sleep.\n this.idle.start();\n this.disposers.push(\n effect(() => {\n if (this.idle.idle.value) untracked(() => this.sleep());\n }),\n );\n\n if (this.config.sleepOnBlur) {\n const onBlur = (): void => this.sleep();\n window.addEventListener('blur', onBlur);\n this.disposers.push(() => window.removeEventListener('blur', onBlur));\n }\n\n // Optional built-in config-menu hotkey (⌘K / Ctrl+K by default).\n if (this.configMenu) {\n const hotkey = this.configMenu.hotkey;\n const onKey = (e: KeyboardEvent): void => {\n if (hotkey(e)) {\n e.preventDefault();\n this.toggleConfigMenu();\n }\n };\n window.addEventListener('keydown', onKey);\n this.disposers.push(() => window.removeEventListener('keydown', onKey));\n }\n\n // Drive the clock only while asleep + visible.\n this.disposers.push(\n effect(() => {\n const ticking = this._state.value === 'sleeping' && !this._hidden.value;\n if (ticking && this.clockTimer === null) {\n this._now.value = new Date();\n this.clockTimer = setInterval(() => {\n this._now.value = new Date();\n }, 1000);\n } else if (!ticking && this.clockTimer !== null) {\n clearInterval(this.clockTimer);\n this.clockTimer = null;\n }\n }),\n );\n\n this.installDebugHook();\n }\n\n destroy(): void {\n this.idle.stop();\n if (this.clockTimer !== null) {\n clearInterval(this.clockTimer);\n this.clockTimer = null;\n }\n for (const d of this.disposers) d();\n this.disposers = [];\n this.started = false;\n }\n\n private suppressed(): boolean {\n if (this.config.disableOnLocalhost && hasWindow && /^(localhost|127\\.|\\[::1\\])/.test(location.hostname)) {\n return true;\n }\n const url = hasWindow ? location.pathname + location.search : '';\n return this.config.suppress ? this.config.suppress(url) : false;\n }\n\n sleep(): void {\n if (this._state.value === 'sleeping' || this.suppressed()) return;\n this.pickPlugin();\n this._state.value = 'sleeping';\n }\n\n /** Sleep ignoring suppression rules (debug / manual). */\n forceSleep(): void {\n if (this._state.value === 'sleeping') return;\n this.pickPlugin();\n this._state.value = 'sleeping';\n }\n\n wake(): void {\n if (this._state.value === 'awake') return;\n this._state.value = 'awake';\n this.idle.markActive();\n }\n\n toggle(): void {\n if (this.isSleeping.value) this.wake();\n else this.forceSleep();\n }\n\n openConfigMenu(): void {\n this._configMenuOpen.value = true;\n }\n closeConfigMenu(): void {\n this._configMenuOpen.value = false;\n }\n toggleConfigMenu(): void {\n this._configMenuOpen.value = !this._configMenuOpen.value;\n }\n\n setPlugin(id: string): void {\n if (!this.plugins.some((p) => p.manifest.id === id)) return;\n this._activeId.value = id;\n this.storage.set('idleScreens.plugin', id);\n }\n\n private pickPlugin(): void {\n if (this.plugins.length === 0) return;\n switch (this.config.selection) {\n case 'random': {\n const i = this.selectionRng.int(0, this.plugins.length - 1);\n this._activeId.value = this.plugins[i]!.manifest.id;\n break;\n }\n case 'rotate': {\n const cur = this.plugins.findIndex((p) => p.manifest.id === this._activeId.value);\n const next = this.plugins[(cur + 1) % this.plugins.length]!;\n this._activeId.value = next.manifest.id;\n break;\n }\n case 'fixed':\n default:\n // Keep the current (persisted / menu-chosen) plugin. `defaultPluginId`\n // is only the INITIAL pick (see constructor); once the user chooses a\n // saver via setPlugin/the menu it sticks across sleeps.\n break;\n }\n }\n\n private installDebugHook(): void {\n if (!hasWindow) return;\n (window as unknown as { __idleScreens?: unknown }).__idleScreens = {\n sleep: () => this.forceSleep(),\n wake: () => this.wake(),\n toggle: () => this.toggle(),\n setPlugin: (id: string) => this.setPlugin(id),\n openMenu: () => this.openConfigMenu(),\n closeMenu: () => this.closeConfigMenu(),\n toggleMenu: () => this.toggleConfigMenu(),\n state: () => this._state.value,\n menuOpen: () => this._configMenuOpen.value,\n active: () => this.activePlugin.value?.manifest.id ?? null,\n plugins: this.pluginList,\n };\n }\n}\n","import { effect } from './reactive';\nimport { IdleScreensEngine } from './engine';\nimport { createRng } from './rng';\nimport type { IdleScreensConfig, PageContext, SaverInstance, SaverPlugin } from './types';\nimport type { WorkerInbound, WorkerOutbound } from './worker-protocol';\n\nconst STYLE = `\n :host { all: initial; }\n dialog.frame {\n position: fixed; inset: 0; width: 100%; height: 100%;\n max-width: none; max-height: none; margin: 0; border: 0; padding: 0;\n background: #0a0a0f; overflow: hidden; cursor: none; color: #fff;\n }\n dialog.frame[open] { animation: ss-in 0.5s ease; }\n dialog.frame.leaving { animation: ss-out 0.32s ease forwards; }\n dialog.frame.reduced { animation: none; }\n dialog.frame::backdrop { background: #0a0a0f; }\n dialog.frame.passthrough, dialog.frame.passthrough::backdrop { background: transparent; }\n @keyframes ss-in { from { opacity: 0; } to { opacity: 1; } }\n @keyframes ss-out { from { opacity: 1; } to { opacity: 0; } }\n .surface { position: absolute; inset: 0; display: block; width: 100%; height: 100%; }\n .surface > canvas { display: block; width: 100%; height: 100%; }\n /* Host-owned fallback markup (<x slot=\"fallback\">), shown only when the active\n saver fails to mount — the host decides what a broken saver looks like. */\n .fallback { position: absolute; inset: 0; display: none; place-items: center; }\n dialog.frame.show-fallback .fallback { display: grid; }\n .clock {\n position: absolute; top: 10px; right: 12px; text-align: right;\n font-family: 'Orbitron', system-ui, sans-serif; pointer-events: none;\n }\n .clock .day { font-size: 34px; opacity: 0.9; }\n .clock .time { font-size: 54px; }\n .hint {\n position: fixed; bottom: 26px; left: 50%; transform: translateX(-50%);\n color: rgba(230,230,230,0.6); font: 12px ui-monospace, monospace;\n letter-spacing: 0.25em; text-transform: uppercase; opacity: 0;\n transition: opacity 1s ease; pointer-events: none;\n }\n .hint.show { opacity: 1; }\n\n /* Built-in config menu: a normal (interactive) centered dialog, distinct from\n the cursor-hidden saver frame. */\n dialog.menu {\n position: fixed; inset: 0; margin: auto; border: 0; padding: 0;\n width: min(420px, calc(100vw - 32px)); max-width: none;\n background: transparent; color: #f2f2f5;\n }\n dialog.menu::backdrop { background: rgba(6,6,10,0.5); backdrop-filter: blur(2px); }\n .menu-card {\n background: #14141b; border: 1px solid rgba(255,255,255,0.12);\n border-radius: 14px; padding: 20px; box-shadow: 0 24px 60px rgba(0,0,0,0.5);\n font-family: system-ui, sans-serif;\n }\n .menu-title { font-size: 18px; font-weight: 600; margin: 0 0 14px; }\n .menu-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 14px; }\n .menu-row > span { font-size: 14px; opacity: 0.85; }\n .menu-select {\n flex: 1; max-width: 60%; padding: 7px 10px; border-radius: 8px;\n background: #0d0d12; color: #f2f2f5; border: 1px solid rgba(255,255,255,0.16);\n font-size: 14px;\n }\n .menu-actions { display: flex; justify-content: flex-end; }\n .menu-close {\n padding: 7px 16px; border-radius: 8px; cursor: pointer; font-size: 14px;\n background: #2a2a37; color: #f2f2f5; border: 1px solid rgba(255,255,255,0.14);\n }\n .menu-close:hover { background: #34344a; }\n`;\n\n/** Node-safe base: during SSR/prerender there is no `HTMLElement`, and importing\n * this module (for the engine/types) must not crash. The element is only ever\n * constructed/registered in the browser. */\nconst HostBase: typeof HTMLElement =\n typeof HTMLElement !== 'undefined'\n ? HTMLElement\n : (class {} as unknown as typeof HTMLElement);\n\n// Firefox shipped transferControlToOffscreen (~105) before module workers (~114).\n// The getter-probe detects {type:'module'} support without loading a real script.\nlet moduleWorkerDetected: boolean | undefined;\nfunction supportsModuleWorker(): boolean {\n if (moduleWorkerDetected !== undefined) return moduleWorkerDetected;\n moduleWorkerDetected = false;\n try {\n let probed = false;\n const url = URL.createObjectURL(new Blob([], { type: 'text/javascript' }));\n try {\n const w = new Worker(url, {\n get type() { probed = true; return 'module' as WorkerType; },\n } as WorkerOptions);\n w.terminate();\n } finally {\n URL.revokeObjectURL(url);\n }\n moduleWorkerDetected = probed;\n } catch {\n // ignore — browser doesn't support module workers\n }\n return moduleWorkerDetected;\n}\n\n/**\n * `<idle-screen>` — the framework-agnostic overlay (port of the Angular\n * ScreensaverComponent). Owns the top-layer `<dialog>`, mounts the active saver\n * into a canvas, shows the clock + \"press any key\" hint, fades in/out, wakes on\n * input with a 450ms arm-guard, and goes transparent for passthrough savers.\n *\n * Configure by setting the `.config` and `.plugins` properties (Angular can do\n * this via `[config]` / `[plugins]` with CUSTOM_ELEMENTS_SCHEMA).\n */\nexport class IdleScreenElement extends HostBase {\n private _engine: IdleScreensEngine | null = null;\n private ownsEngine = false;\n private _externalEngine: IdleScreensEngine | null = null;\n private _config: Partial<IdleScreensConfig> | null = null;\n private _plugins: SaverPlugin[] | null = null;\n\n private dialog!: HTMLDialogElement;\n private surface!: HTMLDivElement;\n private clockEl!: HTMLDivElement;\n private hintEl!: HTMLDivElement;\n private menuDialog: HTMLDialogElement | null = null;\n private menuSelect: HTMLSelectElement | null = null;\n private menuBuilt = false;\n\n private instance: SaverInstance | null = null;\n private worker: Worker | null = null;\n private cachedWorker: { worker: Worker; url: string } | null = null;\n private currentWorkerUrl: string | null = null;\n private cleanupWorkerHandlers: (() => void) | null = null;\n /** @internal Force the setTimeout-based rAF polyfill in Workers (for testing). */\n forceRafPolyfill = false;\n private mountToken = 0;\n private armed = false;\n private armTimer: ReturnType<typeof setTimeout> | null = null;\n private hintTimer: ReturnType<typeof setTimeout> | null = null;\n private closeTimer: ReturnType<typeof setTimeout> | null = null;\n private resizeTimer: ReturnType<typeof setTimeout> | null = null;\n private disposers: Array<() => void> = [];\n\n set config(c: Partial<IdleScreensConfig>) {\n this._config = c;\n this.maybeStart();\n }\n set plugins(p: SaverPlugin[]) {\n this._plugins = p;\n this.maybeStart();\n }\n /** Use an externally-owned, already-initialized engine (e.g. an Angular service\n * that also drives a config menu) instead of creating one from config+plugins. */\n set engine(e: IdleScreensEngine) {\n this._externalEngine = e;\n this.maybeStart();\n }\n /** The live engine (for host code / tests). */\n get idleEngine(): IdleScreensEngine | null {\n return this._engine;\n }\n /** Whether the currently mounted saver is running in a Web Worker. */\n get isWorker(): boolean {\n return this.worker !== null;\n }\n\n /** Request a pixel sample from the Worker to verify rendering.\n * Returns false if not in Worker mode or if the canvas has no content. */\n async sampleWorkerPixels(): Promise<boolean> {\n if (!this.worker) return false;\n const w = this.worker;\n return new Promise<boolean>((resolve) => {\n const handler = (e: MessageEvent<WorkerOutbound>): void => {\n if (e.data.type === 'sampled') {\n w.removeEventListener('message', handler);\n resolve(e.data.hasContent);\n }\n };\n w.addEventListener('message', handler);\n w.postMessage({ type: 'sample' } satisfies WorkerInbound);\n });\n }\n\n connectedCallback(): void {\n if (!this.shadowRoot) this.buildDom();\n this.maybeStart();\n }\n\n disconnectedCallback(): void {\n this.teardown();\n }\n\n private buildDom(): void {\n const root = this.attachShadow({ mode: 'open' });\n const style = document.createElement('style');\n style.textContent = STYLE;\n this.dialog = document.createElement('dialog');\n this.dialog.className = 'frame';\n this.surface = document.createElement('div');\n this.surface.className = 'surface';\n this.clockEl = document.createElement('div');\n this.clockEl.className = 'clock';\n this.hintEl = document.createElement('div');\n this.hintEl.className = 'hint';\n this.hintEl.textContent = 'press any key';\n // Host-owned fallback (AVAL-style): light-DOM children with slot=\"fallback\"\n // render here when a saver fails to mount, instead of a black screen.\n const fallback = document.createElement('div');\n fallback.className = 'fallback';\n const slot = document.createElement('slot');\n slot.name = 'fallback';\n fallback.append(slot);\n this.dialog.append(this.surface, fallback, this.clockEl, this.hintEl);\n root.append(style, this.dialog);\n\n for (const ev of ['pointerdown', 'pointermove', 'keydown', 'wheel', 'touchstart'] as const) {\n this.dialog.addEventListener(ev, () => this.onWakeInput(), { passive: true });\n }\n this.dialog.addEventListener('cancel', (e) => {\n e.preventDefault();\n this._engine?.wake();\n });\n }\n\n private maybeStart(): void {\n if (this._engine || !this.shadowRoot || typeof window === 'undefined') return;\n if (this._externalEngine) {\n this._engine = this._externalEngine; // caller owns lifecycle + init()\n this.ownsEngine = false;\n } else if (this._config && this._plugins) {\n this._engine = new IdleScreensEngine(this._config, this._plugins);\n this._engine.init();\n this.ownsEngine = true;\n } else {\n return;\n }\n const eng = this._engine;\n\n this.disposers.push(\n effect(() => {\n // Read reactive deps up front.\n const sleeping = eng.isSleeping.value;\n const active = eng.activePlugin.value;\n const passthrough = eng.activeIsPassthrough.value;\n if (sleeping && active) this.open(active, passthrough);\n else this.close();\n }),\n );\n\n // Clock chrome.\n this.disposers.push(\n effect(() => {\n const show = this._engine!.config.showClock && !eng.activeIsPassthrough.value;\n const now = eng.now.value;\n this.clockEl.style.display = show && eng.isSleeping.value ? 'block' : 'none';\n if (show) {\n const day = now.toLocaleDateString(undefined, {\n weekday: 'long',\n month: 'long',\n day: 'numeric',\n });\n const time = now.toLocaleTimeString();\n this.clockEl.innerHTML = `<div class=\"day\">${day}</div><div class=\"time\">${time}</div>`;\n }\n }),\n );\n\n // Optional built-in config menu (saver picker), opened via engine hotkey/API.\n if (eng.configMenu) {\n this.buildMenu(eng.configMenu);\n this.disposers.push(\n effect(() => {\n const open = eng.configMenuOpen.value;\n const d = this.menuDialog;\n if (!d) return;\n if (open && !d.open) {\n this.syncMenuSelection();\n d.showModal();\n } else if (!open && d.open) {\n d.close();\n }\n }),\n );\n // Keep the picker in sync if the active saver changes elsewhere.\n this.disposers.push(\n effect(() => {\n const id = eng.activePlugin.value?.manifest.id ?? '';\n if (this.menuSelect && this.menuSelect.value !== id) this.menuSelect.value = id;\n }),\n );\n }\n }\n\n private buildMenu(cfg: NonNullable<IdleScreensEngine['configMenu']>): void {\n if (this.menuBuilt || !this.shadowRoot) return;\n const eng = this._engine!;\n const d = document.createElement('dialog');\n d.className = 'menu';\n const card = document.createElement('div');\n card.className = 'menu-card';\n\n const title = document.createElement('div');\n title.className = 'menu-title';\n title.textContent = cfg.title;\n card.append(title);\n\n if (cfg.showPicker) {\n const row = document.createElement('label');\n row.className = 'menu-row';\n const label = document.createElement('span');\n label.textContent = 'Saver';\n const select = document.createElement('select');\n select.className = 'menu-select';\n for (const p of eng.pluginList) {\n const opt = document.createElement('option');\n opt.value = p.id;\n opt.textContent = p.label;\n select.append(opt);\n }\n select.addEventListener('change', () => {\n eng.setPlugin(select.value);\n if (cfg.previewOnPick) {\n // Close the menu first so the saver isn't stacked behind this modal,\n // then show the chosen saver right away.\n eng.closeConfigMenu();\n eng.forceSleep();\n }\n });\n row.append(label, select);\n card.append(row);\n this.menuSelect = select;\n }\n\n const actions = document.createElement('div');\n actions.className = 'menu-actions';\n const close = document.createElement('button');\n close.className = 'menu-close';\n close.type = 'button';\n close.textContent = 'Close';\n close.addEventListener('click', () => eng.closeConfigMenu());\n actions.append(close);\n card.append(actions);\n\n d.append(card);\n // Escape and backdrop click both close (without waking the saver).\n d.addEventListener('cancel', (e) => {\n e.preventDefault();\n eng.closeConfigMenu();\n });\n d.addEventListener('click', (e) => {\n if (e.target === d) eng.closeConfigMenu();\n });\n this.shadowRoot.append(d);\n this.menuDialog = d;\n this.menuBuilt = true;\n }\n\n private syncMenuSelection(): void {\n if (this.menuSelect) {\n this.menuSelect.value = this._engine?.activePlugin.value?.manifest.id ?? '';\n }\n }\n\n private pageContext(): PageContext {\n return {\n palette: () => [],\n victims: (selector: string) =>\n typeof document !== 'undefined'\n ? Array.from(document.querySelectorAll<HTMLElement>(selector))\n : [],\n };\n }\n\n private async open(plugin: SaverPlugin, passthrough: boolean, skipWorker = false): Promise<void> {\n const eng = this._engine!;\n this.dialog.classList.toggle('passthrough', passthrough);\n this.dialog.classList.toggle('reduced', eng.reducedMotion.value);\n if (!this.dialog.open) {\n this.dialog.classList.remove('leaving');\n this.dialog.showModal();\n this.arm();\n this.scheduleHint();\n window.addEventListener('resize', this.onResize);\n }\n // (Re)mount the active saver.\n const token = ++this.mountToken;\n await this.disposeInstance();\n const w = window.innerWidth;\n const h = window.innerHeight;\n const seed = eng.config.seed >>> 0;\n const dpr = typeof devicePixelRatio === 'number' ? devicePixelRatio : 1;\n\n const workerEligible = !skipWorker\n && plugin.manifest.workerReady\n && eng.config.workerUrl\n && typeof HTMLCanvasElement.prototype.transferControlToOffscreen === 'function'\n && supportsModuleWorker();\n\n if (workerEligible) {\n try {\n const inst = await this.openInWorker(plugin, eng.config.workerUrl!, w, h, seed, dpr, eng.reducedMotion.value, passthrough);\n if (token !== this.mountToken) {\n inst.dispose();\n return;\n }\n this.instance = inst;\n inst.setPaused(eng.reducedMotion.value);\n this.dialog.classList.remove('show-fallback');\n return;\n } catch {\n // Worker failed — fall through to main-thread mount\n await this.disposeInstance();\n if (token !== this.mountToken) return;\n }\n }\n try {\n const inst = await plugin.mount({\n host: this.surface,\n dpr,\n width: w,\n height: h,\n rng: createRng(seed),\n seed,\n reducedMotion: eng.reducedMotion.value,\n page: plugin.manifest.passthrough ? this.pageContext() : undefined,\n });\n if (token !== this.mountToken) {\n inst.dispose();\n return;\n }\n this.instance = inst;\n inst.setPaused(eng.reducedMotion.value);\n this.dialog.classList.remove('show-fallback');\n } catch (err) {\n // Saver failed to mount — show the host's fallback slot instead of a\n // black screen. The host owns what \"broken\" looks like.\n if (token !== this.mountToken) return;\n console.warn(`[idle-screen] saver \"${plugin.manifest.id}\" failed to mount:`, err);\n this.surface.replaceChildren();\n this.dialog.classList.add('show-fallback');\n }\n }\n\n private openInWorker(\n plugin: SaverPlugin,\n workerUrl: string,\n width: number,\n height: number,\n seed: number,\n dpr: number,\n reducedMotion: boolean,\n passthrough: boolean,\n ): Promise<SaverInstance> {\n const canvas = document.createElement('canvas');\n canvas.style.cssText = 'display:block;width:100%;height:100%';\n this.surface.appendChild(canvas);\n\n const offscreen = canvas.transferControlToOffscreen();\n\n // Reuse cached worker if URL matches, otherwise create new\n let worker: Worker;\n if (this.cachedWorker && this.cachedWorker.url === workerUrl) {\n worker = this.cachedWorker.worker;\n this.cachedWorker = null;\n } else {\n this.terminateCachedWorker();\n worker = new Worker(workerUrl, { type: 'module' });\n }\n this.worker = worker;\n this.currentWorkerUrl = workerUrl;\n\n const mountMsg: WorkerInbound = plugin.spec\n ? {\n type: 'mount-spec',\n canvas: offscreen,\n spec: plugin.spec,\n width, height, seed, dpr, reducedMotion,\n ...(this.forceRafPolyfill ? { forceRafPolyfill: true } : {}),\n }\n : {\n type: 'mount',\n canvas: offscreen,\n saverId: plugin.manifest.id,\n width, height, seed, dpr, reducedMotion,\n ...(this.forceRafPolyfill ? { forceRafPolyfill: true } : {}),\n };\n worker.postMessage(mountMsg, [offscreen]);\n\n let disposed = false;\n\n const proxy: SaverInstance = {\n setPaused: (p) => worker.postMessage({ type: 'pause', paused: p } satisfies WorkerInbound),\n resize: (w, h, newDpr) => worker.postMessage({ type: 'resize', width: w, height: h, dpr: newDpr ?? dpr } satisfies WorkerInbound),\n applyTrack: (track) => worker.postMessage({ type: 'track', track } satisfies WorkerInbound),\n dispose: () => {\n disposed = true;\n this.cleanupWorkerHandlers?.();\n this.cleanupWorkerHandlers = null;\n worker.postMessage({ type: 'dispose' } satisfies WorkerInbound);\n worker.terminate();\n this.worker = null;\n canvas.remove();\n },\n };\n\n return new Promise<SaverInstance>((resolve, reject) => {\n const onMessage = (e: MessageEvent<WorkerOutbound>): void => {\n if (e.data.type === 'mounted') {\n worker.removeEventListener('message', onMessage);\n worker.removeEventListener('error', onError);\n\n // Post-mount crash recovery: if the Worker errors mid-animation,\n // fall back to main-thread rendering.\n const onCrash = (ev: Event): void => {\n if (disposed) return;\n disposed = true;\n const msg = ev instanceof ErrorEvent ? ev.message : 'Worker messageerror';\n console.warn(`[idle-screen] Worker crashed mid-animation: ${msg}`);\n this.cleanupWorkerHandlers?.();\n this.cleanupWorkerHandlers = null;\n worker.terminate();\n this.worker = null;\n this.instance = null;\n this.surface?.replaceChildren();\n void this.open(plugin, passthrough, true);\n };\n worker.addEventListener('error', onCrash);\n worker.addEventListener('messageerror', onCrash);\n this.cleanupWorkerHandlers = () => {\n worker.removeEventListener('error', onCrash);\n worker.removeEventListener('messageerror', onCrash);\n };\n\n resolve(proxy);\n } else if (e.data.type === 'error') {\n worker.removeEventListener('message', onMessage);\n worker.removeEventListener('error', onError);\n reject(new Error(e.data.message));\n }\n };\n const onError = (e: ErrorEvent): void => {\n worker.removeEventListener('message', onMessage);\n worker.removeEventListener('error', onError);\n reject(new Error(e.message));\n };\n worker.addEventListener('message', onMessage);\n worker.addEventListener('error', onError);\n });\n }\n\n private close(): void {\n if (!this.dialog?.open) return;\n window.removeEventListener('resize', this.onResize);\n if (this.resizeTimer) { clearTimeout(this.resizeTimer); this.resizeTimer = null; }\n this.dialog.classList.remove('show-fallback');\n this.hintEl.classList.remove('show');\n if (this.hintTimer) clearTimeout(this.hintTimer);\n void this.disposeInstance();\n const reduced = this._engine?.reducedMotion.value;\n if (reduced) {\n this.dialog.close();\n return;\n }\n this.dialog.classList.add('leaving');\n if (this.closeTimer) clearTimeout(this.closeTimer);\n this.closeTimer = setTimeout(() => {\n if (this.dialog.open) this.dialog.close();\n this.dialog.classList.remove('leaving');\n }, 320);\n }\n\n private async disposeInstance(): Promise<void> {\n this.cleanupWorkerHandlers?.();\n this.cleanupWorkerHandlers = null;\n\n if (this.instance) {\n if (this.worker) {\n // Worker instance: send dispose but cache the worker for reuse\n this.worker.postMessage({ type: 'dispose' } satisfies WorkerInbound);\n this.cachedWorker = { worker: this.worker, url: this.currentWorkerUrl! };\n this.worker = null;\n } else {\n this.instance.dispose();\n }\n this.instance = null;\n } else if (this.worker) {\n this.worker.terminate();\n this.worker = null;\n }\n this.surface?.replaceChildren();\n }\n\n private terminateCachedWorker(): void {\n if (this.cachedWorker) {\n this.cachedWorker.worker.terminate();\n this.cachedWorker = null;\n }\n }\n\n private arm(): void {\n this.armed = false;\n if (this.armTimer) clearTimeout(this.armTimer);\n this.armTimer = setTimeout(() => {\n this.armed = true;\n }, 450);\n }\n\n private scheduleHint(): void {\n if (this.hintTimer) clearTimeout(this.hintTimer);\n this.hintEl.classList.remove('show');\n this.hintTimer = setTimeout(() => this.hintEl.classList.add('show'), 3000);\n }\n\n private readonly onResize = (): void => {\n if (this.resizeTimer !== null) clearTimeout(this.resizeTimer);\n this.resizeTimer = setTimeout(() => {\n this.resizeTimer = null;\n if (!this.instance || !this.dialog?.open) return;\n const newDpr = typeof devicePixelRatio === 'number' ? devicePixelRatio : 1;\n this.instance.resize(window.innerWidth, window.innerHeight, newDpr);\n }, 150);\n };\n\n private onWakeInput(): void {\n if (!this.armed) return; // grace period after sleeping\n this._engine?.wake();\n }\n\n private teardown(): void {\n window.removeEventListener('resize', this.onResize);\n if (this.resizeTimer) { clearTimeout(this.resizeTimer); this.resizeTimer = null; }\n void this.disposeInstance();\n this.terminateCachedWorker();\n if (this.armTimer) clearTimeout(this.armTimer);\n if (this.hintTimer) clearTimeout(this.hintTimer);\n if (this.closeTimer) clearTimeout(this.closeTimer);\n for (const d of this.disposers) d();\n this.disposers = [];\n if (this.ownsEngine) this._engine?.destroy(); // external engines are the caller's to destroy\n this._engine = null;\n }\n}\n\n/** Register the <idle-screen> custom element (idempotent). */\nexport function defineIdleScreen(tag = 'idle-screen'): void {\n if (typeof customElements !== 'undefined' && !customElements.get(tag)) {\n customElements.define(tag, IdleScreenElement);\n }\n}\n","import { createRng } from './rng';\nimport type { ControlTrack, SaverContext, SaverInstance, SaverPlugin } from './types';\n\n/** Main thread → Worker messages. */\nexport type WorkerInbound =\n | {\n type: 'mount';\n canvas: OffscreenCanvas;\n saverId: string;\n width: number;\n height: number;\n seed: number;\n dpr: number;\n reducedMotion: boolean;\n /** Display refresh rate (Hz) for the rAF polyfill on browsers that lack\n * Worker requestAnimationFrame (Safari). Defaults to 60. */\n refreshRate?: number;\n /** Force the setTimeout-based rAF polyfill even when native rAF exists.\n * Used by tests to verify the polyfill drives frames. */\n forceRafPolyfill?: boolean;\n }\n | {\n type: 'mount-spec';\n canvas: OffscreenCanvas;\n spec: unknown;\n width: number;\n height: number;\n seed: number;\n dpr: number;\n reducedMotion: boolean;\n refreshRate?: number;\n forceRafPolyfill?: boolean;\n }\n | { type: 'resize'; width: number; height: number; dpr: number }\n | { type: 'pause'; paused: boolean }\n | { type: 'track'; track: ControlTrack }\n | { type: 'sample' }\n | { type: 'dispose' };\n\n/** Worker → main thread messages. */\nexport type WorkerOutbound =\n | { type: 'mounted' }\n | { type: 'sampled'; hasContent: boolean }\n | { type: 'error'; message: string };\n\n/** Options for {@link runIdleWorker}. */\nexport interface RunIdleWorkerOpts {\n /** Spec compiler for `mount-spec` messages. Pass `compileSaver` from\n * `@idle-screens/schema` to enable schema-based savers in this Worker. */\n compiler?: (spec: unknown) => SaverPlugin;\n}\n\n/**\n * Run inside a dedicated Worker. Accepts a registry of worker-ready saver plugins\n * and listens for lifecycle messages from the main thread.\n *\n * Usage (in the Worker entry file):\n * ```ts\n * import { runIdleWorker } from '@idle-screens/core';\n * import { warp } from './warp';\n * runIdleWorker({ warp });\n * ```\n */\nexport function runIdleWorker(\n registry: Record<string, SaverPlugin>,\n opts?: RunIdleWorkerOpts,\n): void {\n let instance: SaverInstance | null = null;\n let activeCanvas: OffscreenCanvas | null = null;\n let usingPolyfill = false;\n let mountGen = 0;\n\n const post = (msg: WorkerOutbound): void => {\n self.postMessage(msg);\n };\n\n const installRafPolyfill = (refreshRate?: number): void => {\n const g = globalThis as Record<string, unknown>;\n const interval = refreshRate ? Math.round(1000 / refreshRate) : 16;\n g.requestAnimationFrame = (cb: FrameRequestCallback) =>\n setTimeout(() => cb(performance.now()), interval) as unknown as number;\n g.cancelAnimationFrame = (id: number) => clearTimeout(id);\n usingPolyfill = true;\n };\n\n if (typeof requestAnimationFrame === 'undefined') {\n installRafPolyfill();\n }\n\n const mountPlugin = (\n plugin: SaverPlugin,\n canvas: OffscreenCanvas,\n msg: {\n width: number; height: number; seed: number;\n dpr: number; reducedMotion: boolean;\n refreshRate?: number; forceRafPolyfill?: boolean;\n },\n gen: number,\n ): void => {\n if (msg.forceRafPolyfill) {\n installRafPolyfill(msg.refreshRate);\n } else if (usingPolyfill && msg.refreshRate) {\n installRafPolyfill(msg.refreshRate);\n }\n\n activeCanvas = canvas;\n const hostStub = new Proxy({} as HTMLElement, {\n get(_target, prop) {\n throw new Error(\n `Saver accessed host.${String(prop)} in a Worker — ` +\n `Workers have no DOM. Use ctx.surface instead of creating your own canvas.`,\n );\n },\n });\n const ctx: SaverContext = {\n host: hostStub,\n surface: canvas,\n dpr: msg.dpr,\n width: msg.width,\n height: msg.height,\n rng: createRng(msg.seed),\n seed: msg.seed,\n reducedMotion: msg.reducedMotion,\n };\n try {\n const result = plugin.mount(ctx);\n if (result instanceof Promise) {\n result.then((inst) => {\n if (gen !== mountGen) {\n inst.dispose();\n return;\n }\n instance = inst;\n post({ type: 'mounted' });\n }).catch((err: unknown) => {\n if (gen !== mountGen) return;\n post({ type: 'error', message: String(err) });\n });\n } else {\n if (gen !== mountGen) {\n result.dispose();\n return;\n }\n instance = result;\n post({ type: 'mounted' });\n }\n } catch (err: unknown) {\n if (gen !== mountGen) return;\n post({ type: 'error', message: String(err) });\n }\n };\n\n self.addEventListener('message', (raw: MessageEvent<WorkerInbound>) => {\n const msg = raw.data;\n switch (msg.type) {\n case 'mount': {\n const plugin = registry[msg.saverId];\n if (!plugin) {\n post({ type: 'error', message: `unknown saver: ${msg.saverId}` });\n return;\n }\n instance?.dispose();\n instance = null;\n const gen = ++mountGen;\n mountPlugin(plugin, msg.canvas, msg, gen);\n break;\n }\n case 'mount-spec': {\n if (!opts?.compiler) {\n post({ type: 'error', message: 'no compiler provided for mount-spec' });\n return;\n }\n try {\n const plugin = opts.compiler(msg.spec);\n instance?.dispose();\n instance = null;\n const gen = ++mountGen;\n mountPlugin(plugin, msg.canvas, msg, gen);\n } catch (err: unknown) {\n post({ type: 'error', message: String(err) });\n }\n break;\n }\n case 'resize':\n instance?.resize(msg.width, msg.height, msg.dpr);\n break;\n case 'pause':\n instance?.setPaused(msg.paused);\n break;\n case 'track':\n instance?.applyTrack?.(msg.track);\n break;\n case 'sample': {\n if (!activeCanvas) {\n post({ type: 'sampled', hasContent: false });\n return;\n }\n const c2d = activeCanvas.getContext('2d');\n if (!c2d) {\n post({ type: 'sampled', hasContent: false });\n return;\n }\n const cw = activeCanvas.width;\n const ch = activeCanvas.height;\n let hasContent = false;\n const COLS = 10;\n const ROWS = 10;\n for (let r = 0; r < ROWS && !hasContent; r++) {\n const y = Math.floor((ch * (r + 1)) / (ROWS + 1));\n for (let c = 0; c < COLS && !hasContent; c++) {\n const x = Math.floor((cw * (c + 1)) / (COLS + 1));\n const data = c2d.getImageData(x, y, 1, 1).data;\n if (data[0]! > 0 || data[1]! > 0 || data[2]! > 0 || data[3]! > 0) hasContent = true;\n }\n }\n post({ type: 'sampled', hasContent });\n break;\n }\n case 'dispose':\n mountGen++;\n instance?.dispose();\n instance = null;\n activeCanvas = null;\n break;\n }\n });\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED