Files
Brandon ThomasandClaude Opus 5.5 8f2058a124 M0.13: web render workers — pipeline renders off the main thread
Renders run in dedicated module Web Workers, each a second instance of the app's wasm module
(index.html compiles it once and posts the WebAssembly.Module to worker.js). A job crosses as
JSON (WireJob: source, settings, request); the worker reads originals and cached thumbnails from
browser storage itself, keeps decoded sources and per-view stage caches, and transfers RGBA back.
Jobs follow the worker that decoded the photo; the loupe waits for it. No wasm threads or
SharedArrayBuffer needed; falls back to inline rendering if no worker starts (?workers=0).

Thumbnail disk cache on the web: thumbs/<key>.jpg in OPFS/IndexedDB with an index on the main
thread, pruned to the desktop budget (2 GB → 80 %, LRU).
ui-egui: RenderOffload hook in the Renderer (queue/priorities/dedup stay in the UI).
engine: RenderJob.origin + MediaCache::origin_ref; preview: encode_jpeg/decode_jpeg public.
xtask web: copies worker.js; --serve sends COOP/COEP/CORP (documented in docs/web.md).

Headless Chrome, cold load + grid scroll, 24 demo photos: main-thread busy 12.4 s → 0.7–1.1 s,
long tasks 23 (max 1.1 s) → 0; grid filled in 6.3–8.4 s vs 13–16 s; slider job 4 ms.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 08:36:15 -04:00

16 lines
649 B
JavaScript

// LightCraft render worker: a second instance of the app's wasm module that renders jobs posted
// by the page (see apps/lightcraft-web/src/workers.rs). The first message carries the compiled
// WebAssembly.Module and the storage backend kind; the module then takes over `onmessage`.
import init, { worker_main } from "./lightcraft_web.js";
self.onmessage = async (e) => {
self.onmessage = null;
try {
await init({ module_or_path: e.data.module });
worker_main(e.data.store);
} catch (err) {
// surfaces as the Worker's `error` event on the page, which falls back to inline rendering
setTimeout(() => { throw err; });
}
};