feat: wasmbox client backend (js/wasm) — one app runs native AND in wasmdesk - #8
Merged
Conversation
…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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a third, additive backend behind the existing
Open/Run/BackendAPI: a wasmbox external-client backend (
GOOS=js/wasm) that lets ago-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/wasmboxrepository is not modified — this is purely aclient-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/closedencode+decode, SAB damage-rectangle maths, and
input → toolkit.Eventmapping (mirroring the X11/Wayland backends: mousedown→Click, drag-vs-move,
wheel→Scroll±1, printable key→KeyDown+Char, named key→KeyDown, modifiers
dropped). No
syscall/jsdependency — builds on every GOOS, 100%-covered.internal/wasmbox/client_js.go(//go:build js && wasm) — thesyscall/jstransport implementingBackend: allocates the w×h×4SharedArrayBuffer, postshello(SAB handle + stride) over the per-clientMessagePort, awaitswelcome, paints the root into the SAB and postscommit— whole-surface, or (aDamageRendererroot, e.g.toolkit/scene.HostRoot) only the damaged rectangles. Drainsinput,handles
set_title/request_close/closed.open_js.go(//go:build js && wasm) —Openreturns the wasmboxbackend; the non-linux stub is re-gated
!linux && !(js && wasm)so the jspath is real (no longer
ErrUnsupported).clients/gowidgets/{worker.js,build.sh}+cmd/gowidgetsclient— aminimal 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=wasmto the cross-build (build + vet) matrix andextended 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.mjsloads
test/harness.html— a protocol-faithful wasmbox compositor stand-in —served by wasmbox's unmodified
cmd/serve(COOP/COEP forSharedArrayBuffer). It asserts the go-widgets tree rendered (41 600non-background canvas px) and that an injected click round-tripped to a
toolkit.Event(a newcommit; 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