import { simulate } from './solver'; import { simulateGPU } from './gpu'; import type { BeadSystem, Excitation, SimOptions, SimResult } from './types'; export interface WorkerRequest { sys: BeadSystem; exc: Excitation; opt: SimOptions; gpu: boolean; } const buffers = (r: SimResult) => [r.audio, r.frames, r.frameTimes, r.energy, r.balance, r.contactForce, r.malletPos].filter((a) => a).map((a) => a!.buffer) as ArrayBuffer[]; self.onmessage = async (ev: MessageEvent) => { const { sys, exc, opt, gpu } = ev.data; const progress = (f: number) => self.postMessage({ type: 'progress', fraction: f }); const partial = (result: SimResult) => self.postMessage({ type: 'partial', result }, { transfer: buffers(result) }); try { let result: SimResult | undefined; let fallback: string | undefined; if (gpu) { try { const r = await simulateGPU(sys, exc, opt, progress, (p) => partial({ ...p, backend: `WebGPU (${(p as SimResult & { device: string }).device})` })); result = { ...r, backend: `WebGPU (${r.device})` }; } catch (e) { fallback = (e as Error).message ?? String(e); } } result ??= { ...simulate(sys, exc, opt, progress, (p) => partial({ ...p, backend: 'CPU', fallback })), backend: 'CPU', fallback }; self.postMessage({ type: 'done', result }, { transfer: buffers(result) }); } catch (e) { self.postMessage({ type: 'error', message: String(e) }); } };