Skip to content

feat: wasmbox client backend (js/wasm) — one app runs native AND in wasmdesk - #8

Merged
tannevaled merged 1 commit into
mainfrom
feat/wasmbox-backend
Aug 9, 2026
Merged

feat: wasmbox client backend (js/wasm) — one app runs native AND in wasmdesk#8
tannevaled merged 1 commit into
mainfrom
feat/wasmbox-backend

Conversation

@tannevaled

Copy link
Copy Markdown
Contributor

Summary

Adds a third, additive backend behind the existing Open/Run/Backend
API: a wasmbox external-client backend (GOOS=js/wasm) that lets a
go-widgets app run as a client of the wasmdesk/wasmbox
browser compositor, speaking wasmbox's existing client wire protocol
(docs/protocol.md). One go-widgets application now runs unchanged natively
(X11/Wayland) AND inside wasmdesk.

The wasmdesk/wasmbox repository is not modified — this is purely a
client-side backend plus a worker shim; the compositor hosts it unchanged.

What's here

  • internal/wasmbox/protocol.go — sovereign, transport-agnostic codec:
    hello/welcome/commit/input/set_title/request_close/closed
    encode+decode, SAB damage-rectangle maths, and input → toolkit.Event
    mapping (mirroring the X11/Wayland backends: mousedown→Click, drag-vs-move,
    wheel→Scroll±1, printable key→KeyDown+Char, named key→KeyDown, modifiers
    dropped). No syscall/js dependency — builds on every GOOS, 100%-covered.
  • internal/wasmbox/client_js.go (//go:build js && wasm) — the
    syscall/js transport implementing Backend: allocates the w×h×4
    SharedArrayBuffer, posts hello (SAB handle + stride) over the per-client
    MessagePort, awaits welcome, paints the root into the SAB and posts
    commit — whole-surface, or (a DamageRenderer root, e.g.
    toolkit/scene.HostRoot) only the damaged rectangles. Drains input,
    handles set_title/request_close/closed.
  • open_js.go (//go:build js && wasm) — Open returns the wasmbox
    backend; the non-linux stub is re-gated !linux && !(js && wasm) so the js
    path is real (no longer ErrUnsupported).
  • clients/gowidgets/{worker.js,build.sh} + cmd/gowidgetsclient — a
    minimal worker shim and a tiny go-widgets app (VBox + Label + Button) built to
    wasm that a wasmbox compositor spawns via wasmboxSpawnExternal.

Tests + verification

  • Protocol codec: 100% statement coverage (internal/wasmbox, verified with
    -race, CGO=1) — factored so it is pure and testable on any GOOS.

  • CI: added GOOS=js GOARCH=wasm to the cross-build (build + vet) matrix and
    extended the 100% coverage gate to internal/wasmbox. Existing X11 / Wayland /
    codec coverage + the full cross-build matrix stay green.

  • Live browser proof (headless Chromium via Playwright): test/probe-wasmbox.mjs
    loads test/harness.html — a protocol-faithful wasmbox compositor stand-in —
    served by wasmbox's unmodified cmd/serve (COOP/COEP for
    SharedArrayBuffer). It asserts the go-widgets tree rendered (41 600
    non-background canvas px) and that an injected click round-tripped to a
    toolkit.Event (a new commit; counter 0→1; label pixels changed).
    Screenshot committed: test/wasmbox-live-proof-2026-08-09.png.

    Note: the proof runs against a protocol-faithful harness compositor (the
    exact client-facing wire), not the full Ruby wasmbox desktop — chosen for a
    reliable, reviewable capture. The transport it exercises is the real one.

Horodate: 2026-08-09 21:12 CEST

🤖 Generated with Claude Code

…asmdesk

Add a third, additive backend behind the existing Open/Run/Backend API: a
wasmbox external-client backend (GOOS=js/wasm) that lets a go-widgets app run
as a client of the wasmdesk/wasmbox browser compositor, speaking wasmbox's
existing client wire protocol (docs/protocol.md). One go-widgets application now
runs unchanged natively (X11/Wayland) AND inside wasmdesk. The wasmbox
repository is NOT modified — this is purely a client-side backend + worker shim.

internal/wasmbox:
  - protocol.go: sovereign, transport-agnostic codec (hello/welcome/commit/
    input/set_title/request_close/closed encode+decode, SAB damage-rect maths,
    input→toolkit.Event mapping mirroring the X11/Wayland backends). No
    syscall/js dependency — builds on every GOOS, unit-tested to 100%.
  - client_js.go (//go:build js && wasm): syscall/js transport implementing
    Backend (Run/Close/Size/String). Allocates the w×h×4 SharedArrayBuffer,
    posts hello over the per-client MessagePort, awaits welcome, paints the root
    into the SAB and posts commit — whole-surface, or (DamageRenderer root, e.g.
    scene.HostRoot) just the damaged rects. Drains input → toolkit.Event.

open_js.go (//go:build js && wasm): Open returns the wasmbox backend; the
non-linux stub is now gated !linux && !(js && wasm) so the js path is real.

clients/gowidgets/{worker.js,build.sh} + cmd/gowidgetsclient: a minimal worker
shim and a tiny go-widgets app (VBox + Label + Button) built to wasm that a
wasmbox compositor spawns via wasmboxSpawnExternal.

CI: add GOOS=js GOARCH=wasm to the cross-build (build+vet) matrix; extend the
100% coverage gate to internal/wasmbox. Existing X11/Wayland/codec coverage +
cross-build stay green.

Live browser proof: headless Chromium (Playwright) against test/harness.html
(a protocol-faithful wasmbox compositor stand-in) served by wasmbox's unmodified
cmd/serve (COOP/COEP). Asserts the go-widgets tree rendered (sampled canvas
pixels) and that an injected click round-trips to a toolkit.Event (counter 0→1);
screenshot committed (test/wasmbox-live-proof-2026-08-09.png).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@tannevaled
tannevaled merged commit 5d51bef into main Aug 9, 2026
20 checks passed
@tannevaled
tannevaled deleted the feat/wasmbox-backend branch August 9, 2026 19:39
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.

1 participant