Skip to content

fix(web): explain missing WebGPU adapter instead of panicking#3

Open
proggeramlug wants to merge 1 commit into
mainfrom
fix/web-webgpu-adapter-message
Open

fix(web): explain missing WebGPU adapter instead of panicking#3
proggeramlug wants to merge 1 commit into
mainfrom
fix/web-webgpu-adapter-message

Conversation

@proggeramlug

@proggeramlug proggeramlug commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

What

A user on macOS Sequoia reported the web build dying at boot. Console showed No WebGPU/WebGL adapter found, a wall of Rust stack traces, a wasm unreachable trap, and a misleading bloom engine init timed out.

It is not a Chrome feature flag. WebGPU is on by default in Chrome since 113. Having navigator.gpu is not the same as having an adapterrequestAdapter() still returns null when graphics acceleration is off (chrome://settings/system), the GPU is blocklisted, or the browser is in a VM / remote session. wgpu picks its backend once, in Instance::new, purely on whether navigator.gpu is defined (wgpu-29 api/instance.rs:74), so it commits to WebGPU, finds no adapter, and panics inside the wasm.

This probes requestAdapter() before booting the engine and, when it comes back empty, stops with a message that names the likely causes and points at chrome://gpu.

Before → after on an adapter-less browser:

before after
panicked at src/lib.rs:92 + wasm unreachable + init timed out "This browser can't provide a WebGPU adapter… graphics acceleration switched off / blocklisted GPU / VM session. Open chrome://gpu."

The WebGL2 fallback is plumbed but gated off

Hiding navigator.gpu from the wasm is what routes wgpu to wgpu-core → WebGL2, and that route now works as far as the renderer. It cannot render: Renderer::new_impl eagerly builds 14 compute pipelines, storage buffers and a 64KB joint uniform, and WebGL2 (GLES 3.0) has no compute shaders or storage buffers at all. An automatic fallback would trade one crash for another, so it's behind WEBGL2_FALLBACK_SUPPORTED = false, with ?renderer=gl to force the attempt. Flip it when the engine gains a downlevel / 2D-only init path.

Engine-side prerequisites (display handle, GL device limits, swapchain usage): Bloom-Engine/engine#87.

build-web.sh --engine-src

Needed to ship any unpublished engine fix to the web. The default path builds bloom_web from node_modules/@bloomengine/engine, and the published 0.4.16 tarball's Rust source does not compile — its web crate calls 3D model APIs (EngineState.models, Renderer::cache_model_if_static, staging::take_model) that the shared crate bundled in the same tarball doesn't expose. Only its prebuilt pkg/ works, which is why --skip-bloom builds succeed and full rebuilds fail. Worth fixing in the published package separately.

Verification

Drove the deployed https://bloomengine.dev/jump/ in a real headless Chrome, both paths:

  • Normal: renderer: webgpu, engine initializes, game boots and plays into level 1 (screenshotted).
  • No adapter (requestAdapter stubbed to return null — the reporter's exact failure): no panics, no wasm trap, no bogus timeout; the explanation renders.

Summary by CodeRabbit

  • New Features

    • Added automatic GPU backend detection, selecting WebGPU or WebGL2 based on browser support.
    • Added support for forcing WebGL rendering with the renderer=gl URL option.
    • Loading status now displays the selected graphics backend.
  • Bug Fixes

    • Improved startup error messages with clearer, multi-line guidance when graphics support is unavailable or initialization fails.
  • Documentation

    • Updated build script help text and usage guidance for building from an engine checkout.

A user on macOS Sequoia hit a wall of Rust stack traces and a misleading
"bloom engine init timed out". The cause: Chrome exposes `navigator.gpu` (on by
default since 113) but returns no adapter — graphics acceleration off, a
blocklisted GPU, or a VM/remote session. wgpu decides its backend in
Instance::new purely on whether `navigator.gpu` is defined, so it commits to
WebGPU, finds no adapter, and panics inside the wasm.

Probe requestAdapter() before booting the engine and, when it comes back empty,
stop with a message that names the likely causes and points at chrome://gpu.

The WebGL2 route is plumbed here too (hiding `navigator.gpu` is what routes wgpu
to wgpu-core), but it is gated off: Bloom's renderer eagerly builds compute
pipelines, which WebGL2 cannot run, so an automatic fallback would only swap one
crash for another. Flip WEBGL2_FALLBACK_SUPPORTED once the engine has a
downlevel path; `?renderer=gl` forces the attempt meanwhile.

Also add `build-web.sh --engine-src`, which builds bloom_web from the ../engine
checkout. The default path cannot carry an unpublished engine fix: it compiles
from the npm tarball, whose bundled Rust source does not compile (its web crate
calls 3D model APIs the shared crate it ships with doesn't expose) — only its
prebuilt pkg/ works.
@coderabbitai

coderabbitai Bot commented Jul 11, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The build script adds --engine-src to select a sibling engine checkout. Browser startup now probes WebGPU and WebGL2 availability, selects a backend, reports it during loading, and displays formatted errors when initialization fails.

Changes

Web runtime setup

Layer / File(s) Summary
Engine source selection
build-web.sh
Adds --engine-src, updates help and comments, and switches BLOOM_WEB between the packaged engine path and ../engine/native/web.
GPU backend probing and boot errors
web/bloom_ffi.js
Selects WebGPU or WebGL2 based on browser support and the renderer=gl override, reports the selected backend, and formats boot and timeout errors.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant BrowserURL
  participant selectGpuBackend
  participant NavigatorGPU
  participant WebGL2
  participant EngineBoot
  participant LoadingUI
  BrowserURL->>selectGpuBackend: read renderer=gl override
  selectGpuBackend->>NavigatorGPU: requestAdapter()
  NavigatorGPU-->>selectGpuBackend: WebGPU adapter or unavailable
  selectGpuBackend->>WebGL2: check WebGL2 support when needed
  WebGL2-->>selectGpuBackend: backend availability
  selectGpuBackend-->>EngineBoot: return webgpu, webgl2, or none
  EngineBoot->>LoadingUI: show backend or formatted error
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Clearly describes the main web change: probing for a WebGPU adapter and showing a helpful error instead of panicking.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/web-webgpu-adapter-message

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@build-web.sh`:
- Line 28: Update the --help branch in the build script’s argument handling to
print only the comment header, changing the sed range from lines 2–16 to the
range ending at line 13 so shell commands are excluded.
- Around line 42-47: Ensure the --engine-src path uses the sibling engine
checkout consistently: update the patch_engine_web.js and perry compile steps to
read from the same $BLOOM_WEB/../engine source used to rebuild pkg/, rather than
node_modules/@bloomengine/engine. Alternatively, use node_modules for all three
steps, but do not mix engine checkouts.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: ee488de1-4dd6-40f8-8c87-003184a636d3

📥 Commits

Reviewing files that changed from the base of the PR and between 91dc0af and 602164c.

📒 Files selected for processing (2)
  • build-web.sh
  • web/bloom_ffi.js

Comment thread build-web.sh
--engine-src) engine_src=true ;;
--serve) serve=true ;;
-h|--help) sed -n '2,15p' "$0"; exit 0 ;;
-h|--help) sed -n '2,16p' "$0"; exit 0 ;;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

--help prints shell code, not just the header.

The comment header ends at line 13 (--serve); line 14 is blank and line 15 is set -euo pipefail. sed -n '2,16p' therefore dumps set -euo pipefail (and trailing blank lines) into the help output. Narrow the range to the comment block.

🩹 Proposed fix
-    -h|--help) sed -n '2,16p' "$0"; exit 0 ;;
+    -h|--help) sed -n '2,13p' "$0"; exit 0 ;;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
-h|--help) sed -n '2,16p' "$0"; exit 0 ;;
-h|--help) sed -n '2,13p' "$0"; exit 0 ;;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@build-web.sh` at line 28, Update the --help branch in the build script’s
argument handling to print only the comment header, changing the sed range from
lines 2–16 to the range ending at line 13 so shell commands are excluded.

Comment thread build-web.sh
Comment on lines +42 to +47
if $engine_src; then
BLOOM_WEB="$JUMP_DIR/../engine/native/web"
else
BLOOM_WEB="$JUMP_DIR/node_modules/@bloomengine/engine/native/web"
[ -d "$BLOOM_WEB" ] || BLOOM_WEB="$JUMP_DIR/../engine/native/web"
fi

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Inspect the patch target and how perry/cp consume the engine on the --engine-src path.
fd -a 'patch_engine_web.js' --exec sed -n '1,40p' {}
fd -a 'build-web.sh' --exec sed -n '60,80p' {}

Repository: Bloom-Engine/jump

Length of output: 2586


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- build-web.sh outline ---'
ast-grep outline build-web.sh --view expanded || true

echo '--- build-web.sh relevant slice ---'
nl -ba build-web.sh | sed -n '1,120p'

echo '--- search for engine-src and patch_engine_web usage ---'
rg -n --no-heading --line-number --context 2 'engine-src|patch_engine_web|perry compile|BLOOM_WEB' .

Repository: Bloom-Engine/jump

Length of output: 287


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- engine package.json web target ---'
fd -a 'package.json' node_modules/@bloomengine/engine 2>/dev/null | head -n 5 | xargs -r -I{} sh -c 'echo "FILE: {}"; nl -ba "{}" | sed -n "1,220p"'

echo '--- sibling engine checkout hint ---'
fd -a 'package.json' ../engine 2>/dev/null | head -n 5 | xargs -r -I{} sh -c 'echo "FILE: {}"; nl -ba "{}" | sed -n "1,220p"'

Repository: Bloom-Engine/jump

Length of output: 194


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- locate build-web.sh in repo ---'
git ls-files | rg '^build-web\.sh$|/build-web\.sh$'

echo '--- inspect node_modules engine manifest if present in repo ---'
fd -a 'package.json' 'node_modules/@bloomengine/engine' 2>/dev/null | head -n 1 | xargs -r -I{} sh -c 'echo "FILE: {}"; nl -ba "{}" | sed -n "1,160p"'

Repository: Bloom-Engine/jump

Length of output: 268


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- build-web.sh lines 1-140 ---'
sed -n '1,140p' build-web.sh | cat -n

printf '%s\n' '--- patch_engine_web.js ---'
sed -n '1,120p' store/tools/patch_engine_web.js | cat -n

Repository: Bloom-Engine/jump

Length of output: 6665


--engine-src should keep the engine build on one checkout. This path rebuilds pkg/ from ../engine, but patch_engine_web.js and perry compile still read node_modules/@bloomengine/engine. That leaves dist/web/pkg and the game WASM built against different engine ABIs. Point the patch/compile steps at the sibling checkout too, or keep all three steps on node_modules.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@build-web.sh` around lines 42 - 47, Ensure the --engine-src path uses the
sibling engine checkout consistently: update the patch_engine_web.js and perry
compile steps to read from the same $BLOOM_WEB/../engine source used to rebuild
pkg/, rather than node_modules/@bloomengine/engine. Alternatively, use
node_modules for all three steps, but do not mix engine checkouts.

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