<bg-wc>

API Reference

Complete documentation for the <bg-wc> web component.

Install

npm

npm install @profpowell/bg-wc

Then import the element. The component self-registers as <bg-wc> on import.

import '@profpowell/bg-wc';

From source / CDN

<script type="module" src="https://unpkg.com/@profpowell/bg-wc"> </script>

Or vendor the src/ directory and reference it directly — it ships as plain ES modules with no build step.

Quick start

Drop the element on any page that defines the usual VB color tokens (--color-primary, --color-accent, …). The component reads them at frame time.

<bg-wc preset="mesh-gradient" intensity="0.65"> <h1>Hero headline</h1> <p>Content sits above the rendered layer in the light DOM.</p> <img slot="fallback" src="hero.webp" alt=""> </bg-wc>

Nothing required beyond the preset attribute. The fallback slot shows when prefers-reduced-motion: reduce is active and the chosen preset has no staticFrame().

data-background behavior

For pages that don't want to introduce a new custom element into their markup, import the optional data-background binder. It scans for elements with a data-background attribute and injects a <bg-wc> behind that element's content via z-index: -1 inside an isolated stacking context. The namespace is distinct from VB's data-effect, so the two can coexist on the same element.

import '@profpowell/bg-wc/data-background'; <section data-background="aurora" data-background-intensity="0.7" data-background-speed="0.3" data-background-color-1="#4dffa1"> <h1>Northern lights, behind anything.</h1> <p>Existing children stay put; bg-wc slides in behind.</p> </section>

Attribute mapping

data-background is the preset name. Any other key starting with data-background- maps to the corresponding bg-wc attribute — or, for color overrides, the corresponding --bg-wc-color-* custom property:

data-background-*Maps to
data-backgroundThe preset attribute. Required.
data-background-intensityintensity attribute
data-background-speedspeed
data-background-densitydensity
data-background-seedseed
data-background-palettepalette
data-background-qualityquality
data-background-fitfit
data-background-motionmotion
data-background-pausedpaused
data-background-pixel-ratiopixel-ratio
data-background-color-1--bg-wc-color-1 CSS var
data-background-color-2--bg-wc-color-2
data-background-color-3--bg-wc-color-3
data-background-color-bg--bg-wc-color-bg
data-background-color-fg--bg-wc-color-fg
data-background-skipPresence skips binding (escape hatch).

New elements added to the page after first paint are auto-bound via a MutationObserver. To bind manually after disabling that observer (or in an SSR context), call bindDataBackgrounds(root) after import.

Attributes

All attributes are observed; changes after first render are applied without re-init for cheap params, and trigger a renderer swap for preset.

AttributeType / valuesDefaultNotes
presetpreset nameRequired. See the catalog.
palette"theme" | "rainbow" | "mono""theme"Honored by particles most strongly.
intensity0..10.5Preset-specific "how dramatic" knob.
speed0..51Time multiplier. 0 freezes.
density0..10.5Particle count / shader detail.
seedinteger0Deterministic randomness. Useful for screenshots.
pausedbooleanunsetPauses the RAF loop without unmounting.
pixel-rationumbermin(devicePixelRatio, 2)Lower it for cheaper rendering on big screens.
quality"low" | "med" | "high""med"Renderer-level hint.
fit"cover" | "contain" | "stretch""cover"How the surface sizes inside the host.
motion"auto" | "reduce" | "force""auto"auto honors prefers-reduced-motion.
textstringPayload for text presets (crawl / marquee / sinescroll / cascade). Lines split on |. Read fresh each frame.
modestringPreset-specific variant selector. mosaic: isometric, flat, sparse, stacked; doodles: family names; fly-through: space-delimited motion×profile×path×unit; explode: radial | cube. Changing it rebuilds css3d scenes. girih: 8fold/12fold/6fold; atomic: mixed/boomerangs/starbursts/harlequin; op-art: riley/cafewall/moire/drift.
use-themebooleanunsetUsed by system7; presence enables theme-token coloring instead of hard black/white.

Properties & methods

MemberTypeBehavior
.presetstringReflects the preset attribute.
.pausedbooleanReflects the paused attribute.
.pause()() => voidPauses the render loop.
.resume()() => voidResumes the render loop.
.snapshot()() => Promise<Blob>Returns a PNG snapshot of the current frame.
.readyPromise<void>Resolves when the active preset's first frame has rendered.
const el = document.querySelector('bg-wc'); await el.ready; const blob = await el.snapshot(); const url = URL.createObjectURL(blob); console.log('PNG ready:', url);

Events

EventDetailWhen
bg-wc:ready{ preset, renderer }First frame rendered.
bg-wc:preset-changed{ from, to }After a successful preset swap.
bg-wc:error{ phase, error }Compile, load, or runtime error. Element transitions to the fallback slot.
bg-wc:visibility{ visible: boolean }IntersectionObserver gate flipped.
el.addEventListener('bg-wc:ready', (e) => { console.log('preset:', e.detail.preset, 'renderer:', e.detail.renderer); });

CSS custom properties

Tokens are read once per frame via getComputedStyle() — theme switches reflect within one RAF tick without re-init.

Tokens the component reads

TokenUsed forFallback
--color-backgroundCanvas backdrop / clear colortransparent
--color-foregroundDefault particle / line color#1a1a1a
--color-primaryPrimary tint in shaders#3b82f6
--color-accentAccent tint#ec4899
--color-infoTertiary tint (mesh-gradient, aurora, …)#10b981
--color-successConfetti palette#22c55e
--color-warningConfetti palette#f59e0b
--color-errorConfetti palette#ef4444

Component-namespaced overrides

For when you want to feed a specific value without changing the global theme. Each one wins over the corresponding semantic token for that instance:

OverrideBeats
--bg-wc-color-1--color-primary
--bg-wc-color-2--color-accent
--bg-wc-color-3--color-info
--bg-wc-color-bg--color-background
--bg-wc-color-fg--color-foreground
--bg-wc-speedspeed attribute
--bg-wc-densitydensity
--bg-wc-intensityintensity
--bg-wc-pixel-ratiopixel-ratio
--bg-wc-z-indexInternal canvas stacking

Shadow parts

The internal <canvas> is exposed as part="canvas":

bg-wc::part(canvas) { image-rendering: pixelated; /* useful for the retro look */ filter: hue-rotate(20deg); }

Preset catalog

Each preset is its own dynamic import — loaded once on first use and cached. The kernel ships only the element class, the RAF loop, the renderer wrappers, and the token resolver.

WebGL shader presets

NameVisualTokens used
ditherAnimated halftone between two colorsprimary, accent
noiseDrifting fractal noise, two-color tintforeground, background
mesh-gradientStripe-style soft blob heroprimary, accent, info, background
warpDisplacement-warped gridprimary, background
wavesFour sine-displaced color bandsprimary, accent, info, background
lavaMetaball lava lampprimary, accent, background
plasmaDemoscene plasma, sum of sinesprimary, accent, info
auroraVertical curtain noise + baseline ribbonprimary, accent, info, background
tunnelInfinite polar zoom with ring bandingprimary, accent, background
causticsWarped sin/cos fields for bright veinsprimary, accent, background
glitchRGB-shift datamosh with per-row displacementprimary, accent, background
rainbowFlowing spectral hue sweep (owns its palette)— (not theme-tinted)
halftoneRotated dot-grid halftone over an animated toneprimary, background
kaleidoscopeMirrored angular folds with a rotating patternprimary, accent, info
vhs80s analog video: wobble, chroma bleed, tracking noiseprimary, accent, background
synthwaveOutrun neon perspective grid + banded sunprimary, accent, info, background
crtCRT tube: barrel curve, scanlines, RGB phosphor maskprimary, accent, background
gameboy4-tone handheld with ordered dither + pixelationprimary, background
copperbarsAmiga demoscene metallic copper barsprimary, accent, info, background
topologyAnimated topographic contour linesprimary, accent, background
cellsAnimated Voronoi cells with darkened bordersprimary, accent, background
shineDiagonal sheen sweep over a quiet gradientprimary, accent, background
conicRotating angular gradient (spotlight border / loader)primary, accent, info, background
grainFilm-grain overlay; transparent, blend over content— (monochrome speckle)
trenchDeath Star trench run: square perspective corridorprimary, accent, background
marbleDomain-warped marble veins (mallsoft / luxe)primary, accent, background
bendayPop-art Ben-Day dots over flat color blocksprimary, accent, info
comicPop-art radial action burst + shock ringsprimary, accent, info
decoArt-deco sunburst rays (Nagel / Gatsby)primary, accent, info, background
blissWindows-XP hills, sky, drifting cloudsprimary, info, background

Vector / arcade presets (Canvas2D)

Glowing phosphor lines on a dark field — the Vectrex / arcade-vector look.

NameVisualTokens used
asteroidsDrifting, rotating wireframe rocksprimary, background
wireframeRotating wireframe globe + equatorial trenchprimary, accent, background
spirographAnimated hypotrochoid rosettesprimary, accent, info, background
incomingWireframe ships warping toward a turret crosshairprimary, accent, background
tempestTempest polygonal tube: spokes + receding ringsprimary, accent, info, background
fireworksVector fireball bursts (Star Wars arcade)primary, accent, info, semantic palette

Text presets (Canvas2D)

Type as the background. Set the copy with the text attribute; all honor palette="rainbow|theme|mono".

NameVisualTokens used
crawlStar Wars-style perspective text crawlprimary, foreground, background
marqueeScrolling vector ticker (outline type)primary, accent, info, foreground
sinescrollDemoscene sine-wave scrollerprimary, accent, info, foreground
cascadeLetters drop & bounce in, hold, loopprimary, accent, info, foreground

Dataviz presets (Canvas2D)

Animated chart backgrounds — pair with an opaque content panel on top.

NameVisualTokens used
tradesTrading terminal: scrolling ticker columns + candlesprimary, success, error, foreground
dashboardStreaming area-line, bouncing bars, sweep gaugeprimary, accent, info, foreground
vectormapNode map with arcs + traveling packetsprimary, accent, info, foreground
scatterDrifting clusters of varied vector glyphsprimary, accent, info, foreground
waveformStacked waveform ridgelines (Joy-Division plot)primary, accent, background
wordcloudDrifting, breathing word cloud (reads text)primary, accent, info

Canvas2D particle presets

NameVisualTokens used
starsSlow-drifting starfield (parallax at intensity > 0.5)foreground, background
snowFalling flakes with horizontal driftforeground, background
confettiContinuous drop in semantic paletteprimary, accent, success, warning, error
networkConnected-dots meshprimary, foreground
particlesGeneric drift — honors palette.per palette
pulseConcentric rings from centerprimary, accent, info
tetrisAmbient falling tetrominoesprimary, accent, info, success, warning, error
matrixFalling digital rain with glyph trailsprimary, foreground, background
mystifyWindows "Mystify" bouncing polyline screensaverprimary, accent, info, background

Canvas2D pattern & geometric presets

NameVisualTokens used
mosaic Refined squares. mode: isometric (default), flat, sparse, stacked. primary, accent, background
ribbons Bezier wave ribbons with crisp top-edge strokes. primary, accent, info, background
source Faded HTML source listing. Set text attribute to override with custom source. primary, foreground, background
system7 Drifting Mac windows on 50% stipple. Add use-theme to honor theme tokens; otherwise black-on-white. primary, background (when use-theme set)
atomic Mid-century atomic-age shapes — boomerangs, kidneys, starbursts. mode: mixed (default), boomerangs, starbursts, harlequin. primary, accent, info, background

Dimensional / CSS-3D presets

Built with DOM + CSS 3D transforms (the css3d renderer) rather than a canvas, so they compose with theme tokens and pause cleanly. Motion lives in CSS keyframes; snapshot() returns null for these. Use density to scale scene complexity and speed for tempo.

NameVisualTokens used
fly-through A rotating tunnel of theme-colored segments. mode composes space-delimited axes: motion orbit (default, rotates the whole tunnel in view) | fly (camera flies through it); profile ring (default) | corridor | hex | tube; path straight | helix | wave; unit cube | sphere | pyramid | card. palette="spectrum" for a rainbow instead of theme colors. primary, accent, info
explode A field of particles over a floor grid that bursts outward and reassembles. mode: radial (default scatter) | cube (axis-aligned burst). seed fixes the scatter. primary, background, foreground

Ornamental presets

NameVisualTokens used
girih Islamic periodic star-polygon strapwork lattice. mode: 8fold (default), 12fold, 6fold. primary, accent, info, background
mandala Layered concentric, counter-rotating radial symmetry; petal motifs keyed to ring, colors cycling outward. primary, accent, info, background
op-art Optical illusion with false motion. mode: riley (default), cafewall, moire, drift. foreground, background

Reduced motion

prefers-reduced-motion: reduce triggers the same code path as motion="reduce" on the element:

  1. If the fallback slot has content → show the slot, hide the canvas.
  2. Else if the preset declares a staticFrame() method → render one frame at time=0, seed=seed, then halt the RAF loop.
  3. Else → hide the canvas and let the host's CSS background show through.

All shipped presets implement staticFrame().

Performance

Many instances on one page

Browsers cap simultaneous WebGL contexts (commonly ~16). Each shader-preset <bg-wc> holds one context, so a page that mounts more than that at once (a full catalog grid, a poster wall) will see the browser drop the oldest contexts. Canvas2D presets are not affected.

Two ways to stay under the cap:

import { listGroups } from '@profpowell/bg-wc/presets/index'; for (const { id, label, presets } of listGroups()) { console.log(label, presets.map(p => p.name)); } // Gradients ['mesh-gradient','waves','plasma','rainbow','shine'] // Patterns ['dither','halftone','warp','topology','cells','kaleidoscope'] // …

Recipes

Halftone overlay on flat shapes

<div class="poster"> <svg class="shapes">...</svg> <bg-wc preset="noise" intensity="0.7" style="position:absolute; inset:0; mix-blend-mode:multiply; opacity:0.18; --bg-wc-color-fg:#000; --bg-wc-color-bg:#fff;"> </bg-wc> </div>

Two layered presets (aurora behind stars)

<div class="sky"> <bg-wc preset="aurora"></bg-wc> <bg-wc preset="stars" style="--bg-wc-color-bg: transparent;"></bg-wc> </div>

The top layer must declare a transparent background or its Canvas2D clearRect + bg-fill will mask the layer below.

Section background via data-background

<section data-background="caustics" data-background-intensity="0.8" data-background-density="0.45" data-background-speed="0.55"> <h1>Six metres down.</h1> </section>

Hot-swap presets at runtime

el.setAttribute('preset', 'plasma'); await el.ready; // resolves once the new preset's first frame renders console.log(el.preset); // 'plasma'

Snapshot to file

const blob = await el.snapshot(); const a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = `${el.preset}.png`; a.click();

Conic spotlight border

Put a conic behind a panel inset by a hair; only the rim shows, so the border sweeps with light. No @property shim required.

<div class="glow-card"> <bg-wc preset="conic" speed="1.6"></bg-wc> <div class="inner">Card content</div> </div> <style> .glow-card { position: relative; border-radius: 18px; padding: 1.5px; overflow: hidden; isolation: isolate; } .glow-card > bg-wc { position: absolute; inset: -60%; z-index: 0; } /* oversize so corners stay covered */ .glow-card .inner { position: relative; z-index: 1; background: var(--surface); border-radius: 16.5px; padding: 28px; } </style>

Scroll-linked background

The component re-reads --bg-wc-intensity / --bg-wc-speed (and color tokens) every frame, so driving them from a scroll handler is all it takes.

const hero = document.querySelector('bg-wc'); addEventListener('scroll', () => { const p = Math.min(1, scrollY / innerHeight); hero.style.setProperty('--bg-wc-intensity', (0.45 + p * 0.5).toFixed(3)); hero.style.filter = `hue-rotate(${Math.round(p * 80)}deg)`; }, { passive: true });

Whole-page film grain

<bg-wc preset="grain" intensity="0.5" style="position:fixed; inset:0; z-index:100; pointer-events:none; mix-blend-mode:soft-light; opacity:0.6;"> </bg-wc>

Browser support

Targets Chromium, Firefox, and Safari at current stable versions. Requires WebGL1 (universally available) for shader presets; Canvas2D presets work anywhere a custom element is registered.

Optional features and their graceful degradations:

FeatureFallback if unavailable
WebGL2WebGL1 context attempted automatically.
OffscreenCanvasMain-thread rendering. No behavioral change.
navigator.getBattery()Battery-aware pause is skipped.
backdrop-filterGlass effects in some demos lose blur; layout intact.
ElementInternals.states:focus-within child-focus state is skipped.