Liquid metallic surface in WebGL: 4-octave simplex FBM, finite-difference normals, diffuse-specular shading and iridescence, 3 palettes.
WebGLShaderMetal
Hover or click the scene to interact
This effect is free — the Atmosphere category contains 57 effects total, including 10 free. Effect.Labs has 811 vanilla effects. Explore the category →
WhenAs a hero section background on a B2B or SaaS landing page signaling 'cutting-edge technology' without external images or video.
WhyThe animated silver shader replaces an HD video: 0 network requests, ~1.5 KB of JS, 100% GPU-rendered. It draws the eye without distracting from the main CTA.
Settingssettings.color = 'silver' (default), settings.speed = 0.7 for slow, premium movement, settings.lightAngle = 30 for dramatic raking light.
Pro
€49
/ month
Unlimited effects
Priority support
API access
② Product component — Pro plan / premium pricing card
WhenAs the background of a 'Pro Plan' card or high-end product tile, visually distinguishing it from standard offers.
WhyThe gold palette turns a static golden background into a living surface and reinforces perceived value without any external asset.
③ Full-screen background — Luxury watch or tech brand hero
WhenAs a hero section or product page background for a brand positioned around luxury, precision, or materiality — watchmaking, high-end audio, metal credit cards, premium physical products.
WhyThe animated metallic surface embodies the brand's material: liquid metal covers 100% of the frame with no UI element shrinking its impact. The effect is the background — not decoration layered on top.
Settingssettings.color = 'gold' for a warm, precious tone, settings.speed = 0.5 (imperceptibly slow movement), settings.distortion = 0.7 (visible ripples), settings.lightAngle = 20 for raking light that sculpts every relief.
How it works
A fullscreen WebGL 1 quad drives the effect. At init, two GLSL shaders (minimal vertex + fragment) are compiled and linked; a Float32Array of 4 vertices (−1/+1) forms the triangle-strip covering the entire canvas. Uniforms u_res and u_time are updated each frame via requestAnimationFrame. The canvas is sized to the actual physical DPR (devicePixelRatio, capped at 2) via gl.viewport, and a resize listener recalibrates dynamically.
The surface is entirely generated in the fragment shader using classic 2D simplex noise (Ashima Arts, MIT license). An FBM (fractal brownian motion) function chains 4 octaves: each octave doubles the spatial frequency and halves the amplitude, accumulating a height field h = fbm(uv × 2 + vec2(t, t×0.7)). u_distortion controls global amplitude (0.6 default), u_speed the temporal scroll rate.
The surface normal vector is estimated by finite differences: two FBM samples offset by ε = 0.01 in x and y reconstruct normal = normalize(vec3(Δh/Δx, Δh/Δy, 1)). A diffuse term (normal · lightDir dot product) and a specular highlight at power 32 (Phong model) are blended with an iridescence factor — 0.5 + 0.5 × sin(h×8 + t×2) — to interpolate the three color stops of the active palette. A radial vignette (1 − 0.4 × |uv|) darkens the edges. An IntersectionObserver pauses rendering when the canvas leaves the viewport.
Accessibility
prefers-reduced-motion: reduce → initMetal() returns immediately; the canvas stays blank and no loop runs. The shader comment mentions a 'CSS gradient fallback via @media' but no @media (prefers-reduced-motion) rule is defined in the delivered CSS — add one as needed.
The canvas in the provided HTML has no aria-hidden or role attribute: add aria-hidden="true" if purely decorative, or wrap it in a role="img" aria-label="Animated metallic surface" if it carries meaning.
The effect is purely passive (no pointer or keyboard interaction) — no focus management required.
WebGL fallback: if WebGL is unavailable, the canvas is hidden (style.display = 'none') with no alternative message — overlaid text content stays visible.
Browser compatibility
Requires WebGL 1 (no optional extensions) — present in all modern browsers since 2015. Zero external dependencies.
Chrome 56+✓ Full
Firefox 51+✓ Full
Safari 15+✓ Full
Edge 79+✓ Full
Mobile iOS✓ WebGL OK
Android Chrome✓ Full
Without WebGL, the canvas is silently hidden (display:none) — no fatal JS error. Any overlaid text or UI content remains fully visible.
The code
Copy the three blocks into your page. No dependencies.
Light direction in degrees (passed to radians() in the shader). 0 = raking horizontal; 90 = zenithal; 180 = backlit.
PALETTES (JS object)
3 presets
Add a custom palette: PALETTES.copper = { a:[0.25,0.10,0.03], b:[0.80,0.45,0.20], c:[0.60,0.28,0.10] }, then settings.color = 'copper'. Values are linear [0,1] per channel.
FBM octaves (shader line)
4
In the FS, the loop for (int i=0;i<4;i++) — change 4 to 2 (faster, coarser texture) or 6 (fine detail, slightly more GPU load).
FAQ
The description says 'Perlin' but the code uses 'simplex' — what's the difference?
The fragment shader implements 2D simplex noise by Ken Perlin (Ashima Arts variant, MIT license), not classic square-grid Perlin noise. Simplex uses a triangular grid: it eliminates directional artifacts along grid axes and is roughly 2× cheaper in 2D. The category card uses 'Perlin' as a common shorthand.
Does the effect work on integrated GPUs (Intel Iris, Apple M-series)?
Yes. The shader is intentionally lightweight: highp float, 4 FBM octaves, a single draw call, no GL extensions. It runs comfortably at 60 fps on integrated GPUs. The IntersectionObserver pauses rendering off-screen to avoid wasting resources.
Can <code>lightAngle</code> be animated in real time for a rotating-light effect?
settings.lightAngle is read every frame in the render loop. An external RAF that does settings.lightAngle += 0.3 produces continuous light rotation. Combined with settings.color = 'gold', it simulates a golden metal rotating under a spotlight.