WebGPU screenshots with agent-browser

Use agent-browser to verify and capture vgpu previews that run WebGPU on Linux, including containers without a GPU. This complements Browser testing with Playwright WebGPU: use Playwright for API tests and this CDP automation recipe for visual captures.

Install and validate the environment

Install agent-browser (the verified version is v0.33.0). It automates Chromium through CDP. On Linux or in a container, install Vulkan and virtual-display dependencies before capturing screenshots:

Bash
1
2
3
npm i -g agent-browser@latest
apt-get install -y libvulkan1 mesa-vulkan-drivers xvfb xauth
agent-browser doctor --webgpu --headed

doctor runs a two-stage render and screenshot probe with a pixel check. In this sandbox, rendering passed with google swiftshader and the screenshot passed with rgb(255,0,0).

Do not use headless Chrome without --webgpu to verify WebGPU. It does not expose WebGPU by default and can silently produce a black canvas.

Choose the WebGPU mode

Always use --webgpu for the preset. It enables --enable-unsafe-webgpu on every platform. On Linux, it also selects software Vulkan through SwiftShader:

TypeScript
1
2
3
4
5
--enable-features=Vulkan
--use-angle=vulkan
--use-vulkan=swiftshader
--use-webgpu-adapter=swiftshader
--disable-vulkan-surface

SwiftShader does not require a GPU or /dev/dri. It is slower than hardware: wait about six seconds and two requestAnimationFrame calls before capturing heavy previews, especially fluid, fft-ocean, and raymarched-fractal.

On Linux, headless mode with --webgpu renders, but headless Chrome captures the canvas as black; this is an upstream limitation. Add --headed. If DISPLAY is absent and Xvfb is installed, agent-browser automatically starts a virtual display.

Bash
1
2
agent-browser --session vgpu-webgpu --webgpu --headed open http://localhost:3001/preview/gradient
agent-browser --session vgpu-webgpu --webgpu --headed screenshot gradient.png

To prefer hardware Vulkan when it is available, override the preset adapters with user arguments; user arguments win over the preset:

Bash
1
agent-browser --webgpu --args "--use-vulkan=native,--use-webgpu-adapter=default" open http://localhost:3001

You can also enable the preset through an environment variable or configuration:

Bash
1
2
AGENT_BROWSER_WEBGPU=1 agent-browser --headed open http://localhost:3001
# agent-browser.json: { "webgpu": true }

Capture and validate one preview

Isolate each job in a dedicated session and close it when finished. screenshot can succeed even when WebGPU failed and the image is black, so always validate pixels and application state.

Bash
1
2
3
4
5
6
7
8
9
SESSION=vgpu-webgpu
URL=http://localhost:3001/preview/gradient
 
agent-browser --session "$SESSION" --webgpu --headed open "$URL"
agent-browser --session "$SESSION" --webgpu --headed wait 6000
agent-browser --session "$SESSION" --webgpu --headed eval 'new Promise(resolve => requestAnimationFrame(() => requestAnimationFrame(resolve)))'
agent-browser --session "$SESSION" --webgpu --headed screenshot gradient.png
identify -format '%[fx:standard_deviation]\n' gradient.png
agent-browser --session "$SESSION" close

A low or zero standard deviation indicates a uniform or black capture. Also inspect vgpu error overlays: Preview error, WebGPU is not available, and No WebGPU adapter was found.

agent-browser does not support text= selectors. Use CSS selectors instead; a text= attempt can fail silently, which is another reason pixel validation must be the assertion of record.

agent-browser eval returns JSON-escaped output. Unescape it before grepping or parsing it:

Bash
1
2
META=$(agent-browser --session "$SESSION" --webgpu --headed eval 'JSON.stringify({ text: document.body.innerText, hasCanvas: Boolean(document.querySelector("canvas")), webgpu: Boolean(navigator.gpu) })')
printf '%s' "$META" | sed 's/\\"/"/g' | grep -E 'Preview error|WebGPU is not available|No WebGPU adapter was found'

Capture every vgpu preview

With the documentation server already running from apps/docs on port 3001, this recipe rendered and captured all ten /preview/<slug> previews through SwiftShader. The simplified loop waits for initialization, requires a canvas, captures, and rejects uniform pixels:

Bash
1
2
3
4
5
6
7
8
9
10
11
SESSION=vgpu-previews
BASE_URL=http://localhost:3001
for slug in gradient triangle-led-front anti-aliasing post-processing black-hole fluid instanced-rendering batch-rendering fft-ocean raymarched-fractal; do
  agent-browser --session "$SESSION" --webgpu --headed open "$BASE_URL/preview/$slug"
  agent-browser --session "$SESSION" --webgpu --headed wait 6000
  agent-browser --session "$SESSION" --webgpu --headed eval 'new Promise(resolve => requestAnimationFrame(() => requestAnimationFrame(resolve)))'
  agent-browser --session "$SESSION" --webgpu --headed eval 'JSON.stringify({hasCanvas:Boolean(document.querySelector("canvas")),webgpu:Boolean(navigator.gpu),text:document.body.innerText})' | sed 's/\\"/"/g' | grep -q '"hasCanvas":true'
  agent-browser --session "$SESSION" --webgpu --headed screenshot "$slug.png"
  identify -format '%[fx:standard_deviation]\n' "$slug.png" | awk '$1 > 50'
done
agent-browser --session "$SESSION" close

Do not omit pixel checks or error-overlay checks for individual previews. For a complete automation flow with logs, retries, navigator.gpu, and a WebGPU context check, keep this sequence and record console output and errors before closing the session.