fuzzyworld

explodorama / files / src / ui / scenes.ts

scenes.ts

1.4 KB · history · blame

1import { generateScene, type Scene, type SceneKind } from '../sim/demo'
2
3/**
4 * Scenes for the demo and the dialogs' clips, made in a Web Worker (sim/scene-worker.ts) so the
5 * page never waits on one (PLAN.md §13c). Where a worker can't be made, on the page instead.
6 */
7let worker: Worker | null = null
8try {
9 worker = new Worker(new URL('../sim/scene-worker.ts', import.meta.url), { type: 'module' })
10} catch {
11 worker = null
12}
13
14let nextId = 0
15const waiting = new Map<number, { kind: SceneKind; seed: number; done: (scene: Scene | null) => void }>()
16worker?.addEventListener('message', (e: MessageEvent<{ id: number; scene: Scene | null }>) => {
17 waiting.get(e.data.id)?.done(e.data.scene)
18 waiting.delete(e.data.id)
19})
20// A worker that fails (a script that wouldn't load) answers nothing: what waits on it, and all
21// after, is made here.
22worker?.addEventListener('error', () => {
23 worker = null
24 for (const { kind, seed, done } of waiting.values()) done(generateScene(kind, seed))
25 waiting.clear()
26})
27
28/** A scene of `kind` from `seed`, when it is ready; null if none was found. */
29export function makeScene(kind: SceneKind, seed: number): Promise<Scene | null> {
30 if (!worker) return Promise.resolve(generateScene(kind, seed))
31 const id = nextId++
32 return new Promise((resolve) => {
33 waiting.set(id, { kind, seed, done: resolve })
34 worker!.postMessage({ id, kind, seed })
35 })
36}