118

Silk Background

£10 or the whole Vault, £99

A GSAP and WebGL silk background: a sheet of satin drifts in slow folds behind your content, the pointer moves the light across its sheen, and press and hold sends ripples out under the cloth.

advanced
4 more details
webgl-shaderorganic-motionpointer-trackingambient

This demo reads better at your own screen size than in the frame below:

Released

About this effect

A background that reads as a material rather than a gradient: a sheet of deep emerald satin lying loose behind your content. Long folds drift, bend, merge and part, slowly enough that the motion is felt more than watched. The light on it behaves like light on real satin: highlights stretch along the weave into long, bright streaks on the crowns of the folds, and the valleys fall into soft shadow, so even a still frame looks like cloth.

Read the full effect overview

The pointer is the light. Move it and the sheen rakes across the folds, catching ridges you could not see a moment before; the light follows with a little weight rather than snapping to the cursor. Press and hold and a ripple lifts from the pointer and rolls outward across the whole sheet, fading as it travels, and while you hold, another follows every second or so. Presses stack, so quick clicks send overlapping rings. Let go and the cloth settles back into its slow drift in under a second.

Your headline sits on a quieter stretch of cloth: behind any element you mark, the folds flatten and the sheen dims, so body copy holds its contrast even at the brightest moment. One colour drives the whole material. Change it in CSS and the highlights and shadows follow, so a navy, oxblood or charcoal silk still looks lit. Visitors without WebGL or JavaScript, and anyone who prefers reduced motion, see a baked still of the satin at its best light.

Silk Background - GSAP animation effect preview

What's included

13 items
  • Real satin in WebGL: slow folds with long, anisotropic highlights along the weave and soft shadow in the valleys
  • The pointer is the light: its sheen rakes across the folds and follows with weight
  • Press and hold for ripples: they lift from the pointer and roll outward, fading as they travel
  • Repeated presses stack into overlapping rings; release settles in under a second
  • Calm zones: behind marked content the folds flatten and the sheen dims, keeping body copy readable at peak brightness
  • One CSS colour drives the material; sheen and shadow are derived from it unless you set them
  • Fold size, flow speed and overall intensity each set from one data attribute
  • Touch: the light drifts on its own between touches, drag to move it, tap to send a ripple
  • Keyboard: arrow keys move the light, Space or Enter sends a ripple
  • Works in any positioned container, from a full-screen hero to a single card
  • Pauses off screen and in hidden tabs, and stops drawing entirely when flow and drift are switched off
  • Baked still for reduced motion, no WebGL and no JavaScript
  • Small API: set the light, send a ripple, pause and play

Perfect for

5 use cases
  • Fashion, bedding, fragrance and jewellery landing pages that want a tactile, premium ground
  • Hotel, spa and hospitality heroes
  • Product launches and waitlist pages with one line of type centre stage
  • Event invitations and gala pages
  • Portfolio and studio sites that want a background with texture rather than a flat colour

How it works

3 sections

A three.js WebGL shader draws the satin each frame as a lit surface. The folds are long ridges whose shape is pushed around by slow noise, so they never repeat. The surface is shaded with an anisotropic highlight, stretched along the weave and tight across it, which is what makes satin look like satin, plus soft occlusion in the valleys and a fine dither so the dark folds never band.

GSAP plays the timed moments: the reveal as the cloth fades up out of its own shadow, each ripple's lift, travel and decay, and the swell under a held press with its release. GSAP's media queries switch between pointer, touch and reduced-motion behaviour, and its context tears everything down. A frame loop on GSAP's ticker owns the continuous motion: the slow drift of the folds and the light's weighted chase of the pointer.

The background stops drawing when it leaves the screen or the tab is hidden, and goes fully idle once settled when flow and drift are switched off.

Difficulty Advanced
Includes HTML + JS + CSS source, documentation, AI setup prompt, lifetime updates

Lighthouse, as measured

Google Lighthouse on this effect's demo, from the latest scan. A measurement of the demo as shipped, not a promise for your page.

Accessibility
100
Best practices
100

No performance score, on purpose. That figure depends on how you deploy: your server's compression and caching, your CDN, the connection and the device doing the test, none of which the code controls. The same page can score very differently on two consecutive runs, so measure it where it will live.

Paid effect

Purchase to unlock the code.

Buying Silk Background opens the HTML, CSS and JavaScript source, the full documentation, an AI setup prompt for your editor, and every update we ship to it. Standard license: unlimited personal and commercial projects. Every paid product is tested for desktop and mobile layouts, reduced-motion handling, animation cleanup and keyboard controls wherever there is something to operate.

£10 Standard license, unlimited projects

Browse free effects

Or the whole library: the Vault, £99, one payment.

Documentation

Quick Start

1. Add to your HTML <head>:

Code snippet omitted: it ships with the download.

The inline script is not optional. The layer carries a baked still of the satin for visitors without JavaScript or WebGL and for anyone who prefers reduced motion. Without this probe every visitor would download that image and see it for the half second three.js takes to arrive, then watch it swap for the canvas. The probe runs before first paint and stamps html.gl when a canvas is coming; the stylesheet drops the still under that class, so it is never even requested. The effect removes the class again if it cannot build a renderer after all.

2. Put the layer inside any positioned container, before your content:

Code snippet omitted: it ships with the download.

data-silk-calm marks content that should sit on a quieter stretch of cloth. Put it on the box that holds your text (up to four elements per layer).

3. Add before the closing </body> tag:

Code snippet omitted: it ships with the download.

Why the import map rather than a plain <script src> for three.js: three ships as ES modules only, and its old UMD build logs a deprecation warning on every page load. The shim imports it as a module (dynamically, so a blocked CDN falls back to the still instead of a blank layer), puts it on window, and then loads script.js as an ordinary script, so the effect itself stays a plain file you can drop into any build (or none).

Already using three.js as a module? Skip the shim and make sure window.THREE is set before script.js runs:

Code snippet omitted: it ships with the download.

Using It With Your Own Design

What the effect needs from your markup: a positioned container (relative, absolute or fixed) holding the [data-silk] layer and your content. The layer fills the container with position: absolute; inset: 0, at any size, so it works on a full-viewport hero or a single card. Your content needs position: relative (or any z-index context) to sit above it. The layer takes no pointer events; the container listens for the pointer instead, so the light follows the cursor over your text and buttons too.

What is only the demo's styling: everything under DEMO in style.css: the .stage box and the cue line. Replace it wholesale.

CSS the effect depends on:

  • The container must have a real size. The canvas is sized from the layer, which takes the container's box. A container with no height gives a canvas of no height.
  • The .silk block (position: absolute; inset: 0, overflow: hidden, pointer-events: none), .silk__canvas, and the .gl .silk rule that drops the still.
  • The two still images in img/, referenced from .silk and its portrait media query.
  • On touch screens the container needs touch-action: pan-y so vertical swipes still scroll the page. The script sets it inline while it runs if you have not.

Colours are custom properties on .silk, read once at start and handed to the shader, so a restyle never touches the script:

Code snippet omitted: it ships with the download.

Any CSS colour works (hex, rgb(), oklch(), color-mix()). Deep, saturated colours look most like satin: emerald, navy, oxblood, aubergine, charcoal. The derived sheen is the base colour taken most of the way to white, and the derived shadow is the base at a fifth of its brightness, which is why a navy or oxblood silk still gets convincing highlights without any other setting. A pale silk (champagne, ivory) works too; its highlight is held back automatically so it does not blow out.

If you change the colour, re-bake the still. The still images are a frame of the emerald satin. Screenshot your restyled layer with the content hidden (a landscape frame around 2400 x 1350 and a portrait one around 780 x 1690) and save them over img/silk-still.webp and img/silk-still-portrait.webp. Until you do, reduced-motion and no-WebGL visitors see the emerald still; the layer's background colour underneath is always your --silk-color.

Contrast. Behind data-silk-calm content the folds flatten, the sheen dims and the cloth is held at or below a fixed brightness (relative luminance 0.13, or the base colour's own if that is brighter), so chalk-white body copy keeps 4.5:1 at the brightest moment. The cap is designed for light text on a deep silk. With a pale silk use dark text and measure again.

Options

Attribute Values Default Description
data-silk (present) Marks the layer
data-silk-flow 0 and up 1 Speed of the drifting folds. 0 freezes the folds; the light and ripples still work
data-silk-drift 0 on 0 stops the light moving on its own. With no pointer it rests high on the left
data-silk-fold 0.4 to 3 1 Fold size. 2 gives folds twice as large, 0.6 a finer, busier cloth
data-silk-intensity 0 to 1 1 Scales the whole response: how far the light follows the pointer, the ripples and the sheen
data-silk-calm (present) On content in the same container: quiets the cloth behind it (up to four elements)
data-silk-keys (present) On a focusable ancestor: enables the keyboard controls below

With both data-silk-flow="0" and data-silk-drift="0" the canvas stops drawing as soon as the light settles, and only wakes for input.

Behaviour

  • Load: the cloth fades up out of its own shadow while the light swings in from beyond the top left corner, over about 1.6 seconds.
  • Pointer: the light follows the cursor with weight, a little behind it, raking the sheen across the folds. When the pointer leaves the container the light drifts on its own again (or returns to rest, with drift off).
  • Press and hold: a ripple lifts from the pointer and rolls outward across the whole sheet, fading as it travels, while the cloth swells gently under the pointer. Holding sends another ripple every 0.85 seconds. Up to six ripples run at once; quick presses stack. Release and the swell settles in 0.9 seconds. Presses on links, buttons and form fields are ignored.
  • Touch: the light drifts on its own; drag to move it, and it returns to its drift 2.5 seconds after your finger lifts. Tap to send one ripple.
  • Calm zones: behind marked content the folds flatten and the sheen dims, and the transition into them is soft, so the cloth reads as one sheet.

Accessibility

  • Reduced motion: no canvas at all. The layer shows the baked still of the satin, a designed frame at its best light. No autonomous motion of any kind.
  • Without JavaScript, or without WebGL: the same still. It is never hidden until a canvas actually exists.
  • Keyboard: with data-silk-keys on a focusable ancestor, arrow keys jump the light a step across the cloth (it does not glide), and Space or Enter sends a ripple from the light. The light returns to its drift six seconds after the last key.
  • Screen readers: the layer and its canvas are aria-hidden; nothing in them is content.

Dependencies

Dependency Version Required
three.js 0.180.0 Yes, as an ES module (see Quick Start)
GSAP core 3.12+ (the demo is built against 3.15.0) Yes: the load reveal, each ripple's lift, travel and decay, the swell under a held press, the ticker the frame loop runs on, matchMedia branching and teardown

No GSAP plugins. GSAP plays the timed values; the frame loop owns the continuous ones (the drifting folds and the light's chase of the pointer); the shader turns both into satin each frame. Everything used from three.js (WebGLRenderer, ShaderMaterial, PlaneGeometry, OrthographicCamera) is long-stable API, so pinning a different version is a one-line change in the import map.

Browser Support

Anything with WebGL, which is every current browser. Support is probed before three.js is asked for a renderer: three logs its own failure to the console as errors before it throws, so a visitor with WebGL disabled would otherwise get a console full of red on a page that had quietly fallen back. Probed first, that visitor gets the still and a clean console. In a browser too old for import maps the module never runs, and the still is again what shows.

Performance

One draw call per frame: a single full-screen pass. The loop runs only while the layer is on screen and the tab is visible. Pixel ratio is capped at 2 (1.5 on touch devices). The satin is smooth, so it holds up well at lower resolution.

To buy back frames on low-end hardware, set data-silk-flow="0" and data-silk-drift="0": the canvas then draws only while the light or a ripple is moving, instead of continuously.

Worked examples, the events and programmatic API, and the class reference ship with the download, alongside the full source.