LuminaWall is a WebGL background package for landing pages, app shells, hero sections, and immersive panels. It mounts an animated shader preset into any container element and keeps the canvas pinned to that element's bounds.
It supports:
- Plain HTML / vanilla JavaScript via
createWallpaper() - React via
LuminaWall - Runtime preset switching by preset name
- Shared global controls plus preset-specific custom controls
| Section | Link |
|---|---|
| Installation | Installation |
| Repository Layout | Repository Layout |
| Quick Start | Quick Start |
| Vanilla JavaScript | Vanilla JavaScript |
| React | React |
| Package Exports | Package Exports |
| Core API | Core API |
| React API | React API |
| Core API Reference | Core API Reference |
createWallpaper(target, options) |
createWallpaper(target, options) |
setConfig(update) |
setConfig(update) |
| Preset Helpers | Preset Helpers |
| React API Reference | React API Reference |
LuminaWall |
LuminaWall |
| Configuration Model | Configuration Model |
CreateWallpaperOptions |
CreateWallpaperOptions |
| Render Policy | Render Policy |
| Performance Instrumentation | Performance Instrumentation |
| Global Controls | Global Controls |
| Preset Catalog | Preset Catalog |
LIQUID_GLASS |
LIQUID_GLASS |
MONO_TOPOLOGY |
MONO_TOPOLOGY |
WINDOWS_BLOOM |
WINDOWS_BLOOM |
MARBLE_METAMORPHOSIS |
MARBLE_METAMORPHOSIS |
BAUHAUS_GRID |
BAUHAUS_GRID |
ISO_SLABS |
ISO_SLABS |
SOLAR_PLASMA |
SOLAR_PLASMA |
CYBER_GRID |
CYBER_GRID |
MOLTEN_CHROME |
MOLTEN_CHROME |
DEEP_COSMOS |
DEEP_COSMOS |
SPECTRAL_DRIFT |
SPECTRAL_DRIFT |
| Building a Preset Picker | Building a Preset Picker |
| Layout Notes | Layout Notes |
| Browser Support | Browser Support |
| Troubleshooting | Troubleshooting |
| Nothing renders | Nothing renders |
| Background renders but content disappears behind it | Background renders but content disappears behind it |
| A preset looks wrong after switching | A preset looks wrong after switching |
| License | License |
npm install luminawallsrc/ package source published to npm
demo/ local demo app that consumes the package source
dist/ generated package build output
For local development in this repo:
npm run devThat starts the demo app from demo/. The npm package itself is built only from src/.
<div id="hero" style="position: relative; width: 100%; height: 100vh;">
<div style="position: relative; z-index: 1; color: white;">
Your content
</div>
</div>
<script type="module">
import { createWallpaper } from 'luminawall';
const hero = document.getElementById('hero');
const wallpaper = createWallpaper(hero, {
preset: 'DEEP_COSMOS',
});
wallpaper.setConfig({
preset: 'SPECTRAL_DRIFT',
customValues: {
chromaSeparation: 0.9,
driftIntensity: 1.1,
},
});
</script>import { LuminaWall } from 'luminawall/react';
export function Hero() {
return (
<LuminaWall
preset="MARBLE_METAMORPHOSIS"
style={{ minHeight: '100vh' }}
customValues={{ tileSize: 0.72 }}
>
<section
style={{
minHeight: '100vh',
display: 'grid',
placeItems: 'center',
color: 'white',
}}
>
Your content
</section>
</LuminaWall>
);
}import {
PRESETS,
PRESET_IDS,
createDefaultConfig,
createWallpaper,
getPresetById,
isPresetType,
resolveWallpaperConfig,
} from 'luminawall';import { LuminaWall } from 'luminawall/react';Mounts a wallpaper canvas into target and stretches it to fill the element.
const wallpaper = createWallpaper(targetElement, {
preset: 'LIQUID_GLASS',
renderPolicy: {
pauseWhenHidden: true,
pauseWhenOffscreen: true,
quality: 'high',
},
});Returns a WallpaperInstance with:
canvas: the mountedHTMLCanvasElementgetConfig(): returns the active resolved configsetConfig(update): updates the current configresize(): recomputes size from the target elementcapture(type?, quality?): exports the current frame as a data URLdestroy(): removes the canvas and listeners
Accepts either a partial config object or an updater function.
wallpaper.setConfig({
preset: 'CYBER_GRID',
intensity: 2,
});
wallpaper.setConfig((current) => ({
speed: current.speed + 0.05,
}));If preset changes, LuminaWall resets to that preset's defaults first and then applies your overrides.
When preset changes, LuminaWall now recompiles only that preset's fragment shader and swaps the material. Normal config updates stay on the existing material and only update uniforms.
PRESETS: full preset metadata, including descriptions and custom controlsPRESET_IDS: array of valid preset idsgetPresetById(id): returns metadata for one presetisPresetType(value): runtime type guard for preset idscreateDefaultConfig(id): returns the resolved default config for that presetresolveWallpaperConfig(options): expands partial options into a fullWallpaperConfig
LuminaWall mounts the wallpaper into its root div and renders children above the canvas.
Props:
- All
CreateWallpaperOptionsfields className?: stringstyle?: React.CSSPropertiescontentClassName?: stringchildren?: React.ReactNode
Example:
<LuminaWall
preset="WINDOWS_BLOOM"
className="hero"
style={{ minHeight: 720 }}
customValues={{ ribbonDensity: 0.75, curlAmount: 1.1 }}
>
<HeroContent />
</LuminaWall>interface CreateWallpaperOptions {
preset: PresetType;
primaryColor?: string;
secondaryColor?: string;
tertiaryColor?: string;
complexity?: number;
speed?: number;
intensity?: number;
grain?: number;
scale?: number;
contrast?: number;
customValues?: Record<string, number>;
renderPolicy?: {
pauseWhenHidden?: boolean;
pauseWhenOffscreen?: boolean;
quality?: 'high' | 'balanced' | 'performance';
};
instrumentation?: {
enabled?: boolean;
sampleIntervalMs?: number;
logToConsole?: boolean;
onSample?: (metrics: WallpaperPerformanceMetrics) => void;
};
}If you only pass preset, LuminaWall uses that preset's built-in defaults.
pauseWhenHidden: pauses rendering when the tab is hidden. Defaulttrue.pauseWhenOffscreen: pauses rendering when the target leaves the viewport. Defaulttrue.quality: opt-in internal pixel ratio tier. Defaulthigh.
quality is intentionally conservative:
high: full default qualitybalanced: moderate pixel-ratio reduction for heavier presetsperformance: stronger pixel-ratio reduction for constrained devices
Preset visuals stay the same by default. Lower quality tiers are explicit tradeoffs for sites that need more headroom on weaker hardware.
Instrumentation is optional and intended for local development and profiling.
Reported metrics include:
- FPS
- average frame time
- rendered canvas size
- effective pixel ratio
- current preset
- WebGL context loss count
Example:
const wallpaper = createWallpaper(target, {
preset: 'DEEP_COSMOS',
instrumentation: {
enabled: true,
sampleIntervalMs: 1000,
onSample: (metrics) => {
console.log(metrics.fps, metrics.averageFrameTime);
},
},
});These controls are shared across presets, though some presets hide or relabel a few of them.
| Option | Meaning |
|---|---|
primaryColor |
Main palette color |
secondaryColor |
Secondary palette color |
tertiaryColor |
Accent / highlight color |
complexity |
Detail level, density, or structural variation |
speed |
Animation speed multiplier |
intensity |
Brightness, glow, or effect strength |
grain |
Added surface noise |
scale |
Zoom / framing |
contrast |
Post-process contrast |
customValues |
Preset-specific parameters |
Each preset section below lists:
- Description
- Default configuration
- Preset-specific custom options
- Hidden or relabeled global controls
Liquid Glass
Viscous molten glass with refractive distortion and iridescence.
Default config:
primaryColor:#e0f2fesecondaryColor:#fce7f3tertiaryColor:#38bdf8complexity:0.6speed:0.2intensity:1.1grain:0scale:0.8contrast:1.1customValues.waveScale:0.7customValues.iridescence:0.5
Custom options:
waveScale: Wave Scale, range0.3to2, step0.01, default1iridescence: Iridescence, range0to1.5, step0.01, default0.8
Global control labels:
complexityis labeled asComplexity
Mono Topology
Elegant topographic contour lines with a monochrome, product-hero look.
Default config:
primaryColor:#f5f5f5secondaryColor:#1a1a1atertiaryColor:#888888complexity:0.5speed:0.08intensity:1grain:0.01scale:1contrast:1customValues.lineWeight:0.5customValues.elevation:0.6
Custom options:
lineWeight: Line Weight, range0.1to1, step0.01, default0.5elevation: Elevation Range, range0.2to1.5, step0.1, default0.6
Global control labels:
complexityis labeled asZoom
Ribbon Bloom
Flowing ribbon sculpture inspired by the Windows 11 wallpaper style.
Default config:
primaryColor:#b4d5e8secondaryColor:#0078d4tertiaryColor:#4fc3f7complexity:0.5speed:0.12intensity:1.2grain:0scale:3contrast:1customValues.ribbonDensity:0.6customValues.curlAmount:0.7
Custom options:
ribbonDensity: Ribbon Density, range0.2to1, step0.01, default0.6curlAmount: Stretch, range0to1.5, step0.01, default0.7
Hidden global controls:
intensity
Global control labels:
complexityis labeled asRibbon Width
Marble Metamorphosis
Flowing organic marble patterns with liquid metal refraction and depth.
Default config:
primaryColor:#2a2a3esecondaryColor:#d4af37tertiaryColor:#a8a8c0complexity:0.68speed:0.18intensity:1.3grain:0.01scale:0.2contrast:1.15customValues.tileSize:0.6
Custom options:
tileSize: Tile Size, range0.2to1.5, step0.01, default0.6
Global control labels:
complexityis labeled asSeed
Bauhaus Grid
Kinetic minimalist grid with mid-century geometric primitives.
Default config:
primaryColor:#F5F5F0secondaryColor:#002FA7tertiaryColor:#E95C20complexity:0.4speed:0.15intensity:1grain:0scale:1.2contrast:1.1
Custom options:
- None
Hidden global controls:
complexityintensity
Iso Slabs
3D isometric slabs with architectural lighting and scale.
Default config:
primaryColor:#1A1A1AsecondaryColor:#333333tertiaryColor:#FFD700complexity:0.6speed:0.1intensity:1.2grain:0scale:1.8contrast:1.3
Custom options:
- None
Hidden global controls:
complexityintensity
Solar Plasma
High-energy ribbons of light flowing like liquid silk.
Default config:
primaryColor:#9B2226secondaryColor:#EE9B00tertiaryColor:#FFFFFFcomplexity:0.7speed:0.2intensity:1grain:0scale:1.2contrast:1
Custom options:
- None
Hidden global controls:
complexity
Global control labels:
intensityis labeled asBrightness
Cyber Grid
Retro-futurist synthwave landscape with an infinite grid.
Default config:
primaryColor:#000000secondaryColor:#FF00FFtertiaryColor:#FFD700complexity:0.5speed:0.2intensity:1.5grain:0scale:1contrast:1.2
Custom options:
- None
Hidden global controls:
complexity
Global control labels:
intensityis labeled asGlow
Molten Chrome
Metallic fluid with high reflectivity and liquid motion.
Default config:
primaryColor:#94a3b8secondaryColor:#1e293btertiaryColor:#f1f5f9complexity:0.8speed:0.15intensity:2.5grain:0.05scale:1.2contrast:2
Custom options:
- None
Global control labels:
complexityis labeled asComplexity
Deep Cosmos
Vibrant nebula clouds with dynamic coloring and layered starfields.
Default config:
primaryColor:#0a0a1asecondaryColor:#b24bf3tertiaryColor:#00ffc8complexity:0.75speed:0.12intensity:1.4grain:0.04scale:0.38contrast:1.15customValues.cloudScale:0.55customValues.starDensity:0.42
Custom options:
cloudScale: Cloud Scale, range0.1to2, step0.1, default0.55starDensity: Star Density, range0to1, step0.01, default0.42
Mesh Gradient
Drifting color waves with chromatic separation and prismatic interference.
Default config:
primaryColor:#ebebffsecondaryColor:#ff6bb5tertiaryColor:#0bcdfecomplexity:0.6speed:0.22intensity:1.2grain:0scale:0.5contrast:1.15customValues.chromaSeparation:0.65customValues.driftIntensity:0.75
Custom options:
chromaSeparation: Chromatic Separation, range0.2to1.5, step0.01, default0.65driftIntensity: Drift Intensity, range0.2to1.5, step0.01, default0.75
If you want to let users switch presets dynamically:
import { PRESETS, createWallpaper } from 'luminawall';
const wallpaper = createWallpaper(container, { preset: 'LIQUID_GLASS' });
for (const preset of PRESETS) {
const button = document.createElement('button');
button.textContent = preset.name;
button.onclick = () => {
wallpaper.setConfig({ preset: preset.id });
};
picker.appendChild(button);
}If you need per-preset custom sliders, use each preset's customizations metadata from PRESETS.
- The target element must have a measurable size. Set an explicit height or place it in a layout that computes one.
- LuminaWall automatically sets the target to
position: relativewhen needed. - The canvas is mounted absolutely and fills the container.
- In plain HTML, overlay content should use normal flow or
position: relative; z-index: 1.
LuminaWall relies on WebGL and modern ESM package support. Current Chromium, Firefox, Safari, and Edge versions are the practical target.
LuminaWall now compiles the active preset shader only, rather than shipping one combined fragment shader to every instance. That reduces shader compile pressure and lowers driver risk on weaker or stricter browser environments.
- Confirm the container has a real width and height.
- Confirm the browser supports WebGL.
- Check that the container is attached to the DOM before calling
createWallpaper(). - If the browser blocks or disables WebGL, LuminaWall now falls back to a no-op instance so the page keeps rendering without the wallpaper.
- Use
instrumentation.onSampleduring development to identify presets that are unsafe at your target canvas size and device pixel ratio.
- Put overlay content in a positioned layer above the canvas.
- In plain HTML,
position: relative; z-index: 1is usually enough.
- When switching presets, LuminaWall resets to that preset's defaults first.
- Reapply your custom overrides after setting the new
preset.
MIT
