Backgrounds

Choose the full-viewport background that sits behind your tiles — from an ambient blob to a GPU-rendered seascape or a looping video clip — with a live preview in System Settings.

Overview

Suwu renders a full-viewport background behind the tile grid. It is chosen in System Settings → Appearance and stored per browser, so the shell, the tiles, and the background all come back the way you left them.

Backgrounds are pluggable: each declares its own tunable parameters, and some ship both a CPU and a WebGPU implementation. Suwu picks the GPU one when your browser supports WebGPU and falls back to the CPU one when it does not. A GPU-only background simply renders nothing on a browser without WebGPU.

Choosing a Background

Open Settings from the gear icon in the header and switch to the Background tab:

  • Live preview — a small preview above the selector shows exactly what the selected background looks like, sized to the current window's aspect ratio. It updates as soon as you change the selection or a parameter.
  • Primary selector — lists the backgrounds available to the shell. Engine-backed shader backgrounds are grouped under a single WebGPU entry.
  • WebGPU selector — when the WebGPU group is selected, a second selector chooses which engine background to run.
  • Credit — backgrounds ported from external work show the author, a link, and any license note below the preview.
WebGPU availability

WebGPU requires a secure context (HTTPS or localhost) and a supporting browser. GPU-only backgrounds show a Preview needs WebGPU note when it is unavailable. Everything else keeps working — the shell falls back to a CPU background.

Built-in Backgrounds

Background Backend Notes
Ambient Blob CPU + WebGPU The default. Soft drifting colour fields; the CPU path automatically replaces the GPU one when WebGPU is unavailable.
Video CPU Plays a short muted clip you upload. See Video Clips.
Matrix Rain WebGPU Falling columns of glyphs with a bright head and fading trail.
Interactive Fluid WebGPU A compute-driven fluid that reacts to the pointer.
Seascape WebGPU An animated ocean horizon (port of the Shadertoy by Alexander Alekseev aka TDM).
Atmospheric Landscape WebGPU Layered terrain and haze (port of the Shadertoy by TekF).
Rainforest WebGPU A dense procedural forest (Inigo Quilez, used with permission).
Cosmos in Crystal WebGPU A refracted crystal interior (port of the Shadertoy by nayk).

Per-Background Settings

Each background controls its own parameters, shown below the selector. Common ones include:

  • Palette — Ambient Blob can match the active theme or force a light or dark palette.
  • Animation speed — scales the motion of a shader background.
  • Detail — caps the shader render budget in megapixels (Low / Medium / High / Ultra / Native), trading sharpness for GPU cost.
  • Colour and opacity — tint controls, such as the mask drawn over a video.

A parameter change restarts the backend so the new value takes effect. Shader backgrounds share one animation clock, so changing a parameter does not snap the animation back to the start.

Video Clips

The Video background plays short, muted clips without a network round trip:

  • Upload — pick MP4, WebM, or Matroska files. Each clip is copied into this browser's private storage (OPFS) with a thumbnail, so it stays available across reloads and is never uploaded to the server.
  • Fit — Auto-crop (cover) fills the viewport and crops the overflow, or Stretch to fill distorts the clip to the viewport.
  • Playback speed — from 0.25× to 2×.
  • Smooth loop — crossfades the last two seconds into the start to hide the jump at the loop point. Off by default and skipped for clips shorter than four seconds.
  • Mask — a colour and opacity tint drawn over the video. The default is the same translucent white as the tile panel, so the tiles stay readable.

Clips longer than 30 seconds are flagged as too long for a background. Decoding is done lazily with backpressure, so memory stays bounded regardless of clip length; load and codec failures are reported on the canvas itself.

Your Own Backgrounds

WebGPU backgrounds are files, not compiled-in code. A background is just a directory, and installing it registers it — no rebuild, no plugin install. Five worked examples ship in the repository, and they are the ones the install catalog offers:

# one, several, or all of them
suwu install --github matrix-rain
suwu install --github --kind background --all

# see the list first
suwu install --list

# or install from a zip whose root is background/webgpu/<id>/…
suwu install --background matrix-rain.zip

Everything lands in ~/.suwu/background/webgpu/<id>/ and is served from then on. Open System Settings — it re-reads the background list on every open, so the new one is in the selector straight away. From a checkout, a hand copy works too:

cp -r examples/background/webgpu/matrix-rain ~/.suwu/background/webgpu/

Each background keeps its own label and parameters. A directory with the same id as a built-in overrides it, and deleting a directory unregisters the background (a stored selection then falls back to the ambient blob). Set SUWU_BACKGROUNDS_DIR to serve a background tree from somewhere else entirely — useful while developing one.

Directory layout

A background directory looks like this:

<dataDir>/background/webgpu/<id>/
  background.json        # metadata and parameters — required
  scene.js               # ESM module: export default create(api) -> { start }
  shaders/*.wgsl         # authored WGSL (entries have @fragment / @compute)
  shaders/*.shader.js    # generated artifacts, committed alongside the WGSL
  • background.json — id (must equal the directory name), label, engine, an optional credit block for ports, and a params array of number, boolean, select, text, or color controls. An invalid manifest is skipped, never fatal.
  • scene.js — exports create(api) returning { start(ctx, params) }. Everything the engine offers (the scene builders, the GPU background starter, storage and texture assets, the compute helpers) arrives through api; never import a bare specifier, because the browser cannot resolve one.
  • shaders/*.shader.js — the compiled form of each WGSL entry. There is no WGSL resolver in the browser, so these artifacts are generated ahead of time and shipped with the background.

Compiling shaders

The WGSL compiler is embedded in the suwu binary, so there is no Node toolchain to install. Compile every entry shader — any file with @fragment or @compute — and redirect it to its sibling:

suwu background build shaders/matrix.wgsl > shaders/matrix.shader.js

Imports are resolved for you (relative .wgsl files and the bundled standard library), so only entries need compiling; helper modules are inlined. Diagnostics go to stderr with a non-zero exit and nothing is written to stdout, which makes the > redirect safe.

One more thing to know

Background modules are served as static files, so the manifest and scene files are reachable by anything that can reach the server. Keep anything sensitive out of a background directory — the only thing they should hold is shaders and a scene.

Performance

  • WebGPU first — when the browser and context support it, Suwu runs the GPU backend and moves the work off the main thread.
  • CPU fallback — Ambient Blob and Video have canvas-based backends that keep rendering without WebGPU. The CPU path is frame-capped and pauses while the tab is hidden or the window is blurred.
  • Reduced motion — when prefers-reduced-motion: reduce is set, backgrounds settle to a static frame instead of animating.
  • Detail caps — shader backgrounds render to a bounded megapixel budget, so a 4K viewport does not cost proportionally more.

Debug Overrides

To force a backend for testing, append a query parameter to the URL:

?bg=gpu    # force the WebGPU backend
?bg=cpu    # force the CPU fallback
?bg=auto   # automatic (default)

You can also persist a choice with localStorage.setItem('suwu.bg', 'cpu'). The background itself is always chosen in System Settings.

Tip

A subtle CPU-friendly background keeps the interface fast on low-power machines. Use the live preview to judge a choice before committing, and dial the tile glass alpha up if a busy background hurts readability.