Skip to content

Add js/wasm (WebGL2) backend for the opengl package#127

Closed
fisherevans wants to merge 3 commits into
gopxl:mainfrom
fisherevans:remote-primortal-fork
Closed

Add js/wasm (WebGL2) backend for the opengl package#127
fisherevans wants to merge 3 commits into
gopxl:mainfrom
fisherevans:remote-primortal-fork

Conversation

@fisherevans
Copy link
Copy Markdown

@fisherevans fisherevans commented Apr 21, 2026

Summary

Adds a parallel WebGL2 backend to the `opengl` package under the `js && wasm` build tag so pixel can target the browser. The existing GLFW + go-gl files gain `//go:build !js`; new `*_wasm.go` siblings implement:

  • Window — creates/attaches to an HTML canvas, owns the WebGL2 context, drives the render loop via `requestAnimationFrame`, handles WebGL context loss by reloading the page, auto-syncs the canvas backing store to CSS size × `devicePixelRatio` each frame so resize/fullscreen transitions propagate into `window.Bounds()`.
  • Input — keyboard and mouse via DOM events (`keydown`, `keyup`, `mousedown`, `mouseup`, `mousemove`, `wheel`, `mouseenter`, `mouseleave`, `blur`, `contextmenu`) mapped onto pixel's `Button` constants, fed through the same `internal.InputHandler` the desktop backend uses, and surfaced through the existing `Pressed` / `JustPressed` / `MouseScroll` / callback APIs.
  • Gamepads — polled each frame via the HTML5 Gamepad API (`navigator.getGamepads()`). Standard-layout pads are remapped so button and axis order match the desktop GLFW backend (including promoting LT/RT from analog buttons to the trigger axes); non-standard pads pass through as raw indices.
  • Cursor / Monitor — browser-appropriate shims (cursor via CSS, monitor stubbed).
  • Run — replaces GLFW's `mainthread.Run` with a direct call under WASM.

The only desktop-visible change is explicit float literals (`0.0`, `2.0`) added to two of pixel's internal shaders — GLSL ES 300 is stricter about int→float conversion than 330 core, so the change lets the same source compile for both targets.

Dependencies

Depends on companion WASM branches of glhf and mainthread:

Test plan

  • Desktop builds unchanged (`go build ./...`, `go test ./...` — two `tests/` floating-point failures are pre-existing on upstream `main`).
  • `GOOS=js GOARCH=wasm go build ./...` succeeds against the companion glhf + mainthread WASM branches.
  • `GOOS=js GOARCH=wasm go test -c` compiles all packages cleanly.
  • Exercised end-to-end: game boots in a browser with keyboard, mouse, and gamepad input working.

Fisher Evans and others added 3 commits April 20, 2026 22:16
Adds a parallel WebGL2 backend under the `js && wasm` build tag so pixel
can target the browser without touching desktop code paths. The existing
GLFW + go-gl files are tagged `!js`; new `*_wasm.go` siblings implement
Window, Canvas, input (keyboard/mouse via DOM events), and stubs for
cursor/joystick/monitor.

Also refactors a few desktop call sites off the raw `go-gl/gl` package
and onto glhf wrappers (`BlendFuncSeparate`, `BlendEquation`,
`ActiveTexture`) so the same source compiles for both targets. Two of
pixel's internal shaders gained explicit float literals (`0.0`, `2.0`)
so GLSL ES 300 — which is stricter about int->float conversion than
330 core — accepts them unchanged.

Depends on companion WASM branches of glhf and mainthread. Desktop
behavior is unchanged.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The PR description claimed mouse input was wired through DOM events,
but input_dom_wasm.go only installed keyboard listeners. Add mousedown /
mouseup / mousemove / mouseenter / mouseleave / wheel / contextmenu
handlers, map MouseEvent.button to pixel.MouseButtonN, and fire all
user-registered callbacks (button, char, mouse moved/entered, scroll)
so game code that sets them sees the same events as on desktop.

Also drop the unused internal.InputHandler{} shim and its stale "not
wired up yet" comment, and add a WebAssembly section to the top-level
README describing how to load the canvas, which features are stubbed,
and the required build command. Adjust the "Missing features" list so
the HTML5 backend isn't still called out as missing.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Polls navigator.getGamepads() once per UpdateInput and feeds the results
through the same internal.JoystickState machinery the desktop backend uses.
Standard-layout pads are remapped so button / axis order matches the GLFW
backend (including promoting LT/RT from analog buttons to the trigger
axes); non-standard pads pass through as raw indices so applications can
still address them.
@fisherevans fisherevans force-pushed the remote-primortal-fork branch from 2264bd3 to 399d77d Compare April 21, 2026 02:18
@fisherevans fisherevans marked this pull request as ready for review April 21, 2026 02:48
@fisherevans fisherevans deleted the remote-primortal-fork branch April 21, 2026 02:55
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