Skip to content

web: add standalone web worker example - #962

Open
Fristender wants to merge 2 commits into
david-vanderson:mainfrom
Fristender:feat/web-standalone-split
Open

web: add standalone web worker example#962
Fristender wants to merge 2 commits into
david-vanderson:mainfrom
Fristender:feat/web-standalone-split

Conversation

@Fristender

@Fristender Fristender commented Aug 16, 2026

Copy link
Copy Markdown

This requires #961 to be merged first.

Adds a third web target, web-standalone, that runs the whole dvui app inside a Web Worker: WASM + WebGL on an OffscreenCanvas, events delivered via SharedArrayBuffer + Atomics, frames returned to the main thread as transferred ImageBitmaps. Includes JSPI support so the blocking event loop doesn't starve the worker event loop.

Review guide

  • web-common.js:96-128 — shared-memory protocol constants (signal flag, cursors, canvas info, 256-slot event ring, 4 KiB string area). Contract between the two new files; check offsets add up (TOTAL_SHARED_SIZE = 9472).
  • web-standalone.js:33-77dvuiStandalone() entry: canvas lookup, dvui_debug flag, SharedArrayBuffer/Atomics/COOP-COEP preflight checks.
  • web-standalone.js:105-148pushEvent/pushString: ring-full drop policy, 32-bit wrap tricks, string-area wraparound (best-effort, no synchronization with worker reads — worth a look).
  • web-standalone.js:158-261 — DOM listeners mirroring web.js (mouse/wheel/key/IME/touch), each pushing ring events.
  • web-standalone.js:264-318 — messages from worker: bitmap, cursor, text_input, open_url, download, clipboard_set, panic.
  • web-worker.js:43-119 — JSPI detection, suspending wasmWaitEventJspi/wasmSleepJspi, MessageChannel macrotask yield, Edge STATUS_ACCESS_VIOLATION rationale comment.
  • web-worker.js:153-186drainEvents(): key/text events read strings from the shared string area and re-enter wasm via add_event.
  • web-worker.js:201-260 — init: OffscreenCanvas creation, wasm instantiate, main() via WebAssembly.promising when JSPI is available.
  • web.zig:42-45 and web.zig:804-836 — new wasm_wait_event extern, InitOptions/initWindow(), waitEventTimeout(), and renderPresent() now shipping the bitmap.
  • web-standalone.zig:30-46 — SDL-standalone-shaped main(): init → frame → waitEventTimeout loop.
  • build.zig:998-1006, build.zig:1036-1058, build.zig:1657-1704 — separate export-symbol list, separate backend module, and addWebStandaloneExample().

Known gaps vs. web-app (no feature parity yet)

  1. File dialog / file picker — worker inherits the no-op stubs (web-common.js:1073-1081); web-app has the real <input type="file"> + filesCache implementation (web.js:213-265). dvui.dialogs file open is a silent no-op in standalone.
  2. Clipboard copy fallback — standalone only uses navigator.clipboard.writeText (web-standalone.js:299-303); web-app falls back to hidden-input execCommand("copy") for non-secure contexts (web.js:267-283).
  3. prefers-reduced-motion — hardcoded to "no preference" (web-worker.js:330-332); web-app queries matchMedia (web.js:199-211). Not yet forwarded through the shared buffer.
  4. wasm_refresh — no-op in worker mode (web-worker.js:266-268); web-app uses it to schedule requestAnimationFrame renders (web.js:329-332). Async operations that expect to trigger a repaint won't.
  5. Window options ignoredinitWindow() discards size/min/max/vsync/title/icon (web.zig:822-825); size comes from CSS, title/icon from the HTML.
  6. platform string — sent in the init message (web-standalone.js:325) but never consumed in web-worker.js.
  7. No quit path — the example's main_loop runs forever (web-standalone.zig:38-45); nothing maps to "window closed".
  8. Panic UX — standalone alert()s (web-standalone.js:304-307) vs. console-only in web-app.

@Fristender Fristender changed the title Feat/web standalone split web: add standalone web worker example Aug 16, 2026
@Fristender
Fristender marked this pull request as draft August 16, 2026 22:49
@Fristender
Fristender marked this pull request as ready for review August 17, 2026 06:06
@MichaelBelousov

Copy link
Copy Markdown
Collaborator

@Fristender is this PR worth renaming to like implement part of a web worker example? I feel like some of the missing features are worth emphasizing that it isn't done?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants