043

Cloth Drape

£5

A hanging fabric banner you can grab, drag and swing: a soft-body cloth simulation that warps your artwork across it and shades its own folds.

advanced
6 more details
physicscanvasdraggablemomentumpointer-effectstouch-drag
Cloth Drape - GSAP animation effect preview

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

About this effect

Real fabric, hanging from grommets, in a canvas element. Grab it anywhere and the sheet deforms locally while the whole thing follows with weight; let go and it swings, ripples and takes its time coming back to rest.

Read the full effect overview

One input drives four visible channels at once: the mesh deforms, your artwork warps with it, the folds shade from their own surface normals, and a soft cast shadow tracks the sheet across the wall behind. Whip it hard and it snaps taut, throws a travelling ripple across the weave and billows toward you.

It is a hand-written soft body on GSAP's ticker: verlet particles, distance constraints, no physics library, no WebGL. Point it at any image with one data attribute.

What's included

10 items
  • Verlet particle mesh with structural, shear and bend constraints, relaxed several times per fixed step, written from scratch with no physics library
  • Grommet pinning: pin as many or as few points along the top edge as you like and the fabric sags into real catenaries between them
  • Grabbing takes a patch of fabric, not a single vertex, so a pull makes a fold instead of a spike, and release inherits your pointer's velocity
  • Per-vertex lighting from the mesh's own normals, painted as a separate light layer and composited in one pass, so folds shade smoothly with no visible triangle seams
  • Your artwork is warped as a real triangle mesh with per-triangle affine mapping, and the triangles are depth-sorted so a fold that doubles over paints in the right order
  • Cast shadow rendered from the sheet's live silhouette, so it moves, stretches and softens with the fabric
  • Two material presets, silk and canvas, switchable from any button, plus per-instance control of gravity, damping, bend, stretch limit and wind
  • Ambient wind keeps the sheet alive at rest without ever reading as jitter, and a gust button or Enter throws a full billow through it
  • Fixed 120Hz timestep with an accumulator, so the fabric behaves identically at 60Hz and 144Hz
  • Full keyboard path: the sheet is focusable, arrow keys push it and Enter sends a gust

Perfect for

5 use cases
  • Exhibition, festival and gallery sites where the poster itself should be the thing visitors play with
  • Fashion and textile brands that want their print shown on something that behaves like fabric
  • Hero sections and campaign microsites needing one tactile, memorable interaction above the fold
  • Product pages for printed goods: banners, flags, tapestries, scarves, tote prints
  • 404 and coming-soon pages where a toy earns the wait

How it works

5 sections

The sheet is a grid of verlet particles. Each fixed 1/120s step integrates gravity and a two-wave wind field, then relaxes three sets of distance constraints over several passes: structural links along the weave, shear links across each cell that stop the grid collapsing into a parallelogram, and bend links that skip a neighbour and are what resist creasing. A final pass hard-limits how far any structural link may stretch, which is what makes a hard whip snap taut and sends a ripple travelling across the fabric rather than letting it behave like elastic.

This is a deliberately different physics class from the impulse-based rigid body solver in Physics Word Pile. That effect resolves contacts between separate solid objects with restitution and friction; this one has no contacts at all, and its behaviour comes entirely from relaxing a mesh of constraints toward its rest shape. Both run on GSAP's ticker with a fixed timestep and an accumulator, and neither uses a physics library, but nothing else is shared.

Rendering is a canvas triangle mesh rather than a grid of CSS 3D divs. Three points define an affine transform exactly, so each triangle clips to its own shape and draws the image through that transform, which warps the artwork genuinely; a div grid can only translate and rotate whole cells and shows a seam at every join. Triangles are grown by a fraction of a pixel before clipping so neighbours overlap, and are depth-sorted each frame so a fold that doubles over paints back to front.

Lighting is computed per vertex from face normals averaged across the cells that share it, then painted into a separate opaque light layer and composited over the sheet once with soft-light. Because that layer is opaque, overlapping triangles replace rather than accumulate, which is what stops the mesh printing as a grid; because the light value is linear across a triangle, one linear gradient per triangle reproduces it exactly and the shading comes out smooth rather than faceted.

GSAP drives the wind envelope: a gust is a tween on a single proxy value with a power3.out tail, so it arrives instantly and dies away instead of switching off.

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

Lighthouse, as measured

Google Lighthouse on this effect's demo, 15 September 2026. 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 Cloth Drape 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.

£5 Standard license, unlimited projects

Browse free effects

Documentation

Quick Start

1. Add to your HTML <head>:

Code snippet omitted: it ships with the download.

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

Code snippet omitted: it ships with the download.

3. Add the markup to your <body>:

Code snippet omitted: it ships with the download.

4. Optional buttons, anywhere on the page:

Code snippet omitted: it ships with the download.

Using It With Your Own Design

What the effect actually requires. Three things:

  1. A container carrying data-cloth-drape. It must be position: relative (or absolute/fixed) and should be overflow: hidden, because a hard whip briefly throws the fabric outside the box.
  2. One <img> inside it carrying data-cloth-art. Its rendered box is the region the mesh spans. Size the image in CSS and the fabric follows; there is no JavaScript sizing to keep in sync.
  3. These two rules, which are the CSS the effect cannot supply for itself:

Code snippet omitted: it ships with the download.

Anything layered over the fabric needs pointer-events: none. The canvas sits behind whatever wraps the image, so a wrapper with a background, a rail, a caption or a decorative overlay will silently swallow every pointerdown aimed at the fabric and nothing can be grabbed. This is the single most likely thing to go wrong when you restyle it.

data-state="live" is added by the script once it starts. Gating the image-hiding rule on it is deliberate: with JavaScript off, or under prefers-reduced-motion, no canvas is ever created and the plain <img> is what a visitor sees. Make that a presentable state — the demo lays a set of soft fold gradients over the image to suggest drape, which is worth copying.

Give the sheet room below it. A whip stretches the fabric a few percent longer than its rest size and swings it a good distance sideways. In the demo the banner is about 62% of the stage width and starts near the top, leaving roughly a tenth of the stage height clear underneath. Size it to fill the frame and the interesting part gets clipped.

Your artwork should be a real image file. It is drawn with drawImage several hundred times a frame, so give it sensible pixel dimensions (roughly twice its rendered size is plenty) and always set width/height attributes so the layout does not jump before it loads. Cross-origin images are fine as long as they do not need to be read back — nothing here calls getImageData.

What is only the demo's styling and can be deleted wholesale: the gallery wall and floor gradients, the hanging rail, the grommet discs, the toolbar, the material switcher and the gust button. The script never reads any of them. The grommet discs are positioned in CSS at the same percentages as data-cloth-pins; if you change one, change the other.

Options

Set on the [data-cloth-drape] container.

Attribute Values Default Description
data-cloth-pins Comma-separated fractions 01 0.06,0.5,0.94 Where along the top edge the fabric is fixed. Fewer pins means deeper sag between them; 0,1 gives a two-corner hang, 0,0.25,0.5,0.75,1 a taut banner
data-cloth-gravity Any number (px/s²) 1700 Downward acceleration. Low feels like chiffon, high like a wet tarpaulin
data-cloth-damping 0.951 0.99 How much velocity survives each step. Below about 0.97 the fabric stops swinging almost immediately
data-cloth-bend 01 0.18 Stiffness of the links that skip a neighbour, which is what resists creasing. Above about 0.6 the sheet reads as card, not cloth
data-cloth-stretch 11.1 1.02 Hard limit on how far a thread may stretch. This is the taut snap; raise it and the fabric behaves like elastic
data-cloth-wind 0 disables 1 Multiplier on both the ambient breeze and gusts
data-cloth-shading 01.5 1 Strength of the fold lighting. 0 leaves the artwork completely flat
data-cloth-shadow true, false true Whether the cast shadow is drawn
data-cloth-cell Any number (px) 38 (42 on touch) Target mesh cell size. Smaller means finer folds and more triangles; this is the performance dial
data-cloth-label Any string see below Accessible name for the canvas

About data-cloth-cell

Everything expensive scales with the triangle count, and the triangle count is the sheet's area divided by the square of this number. The default puts a 620x410 banner at roughly 370 triangles, which is comfortable everywhere. Halve the cell size and you quadruple the work for folds most visitors will not notice. The mesh is clamped to 18 cells in each direction whatever you ask for.

Presets

[data-cloth-preset] buttons apply a whole material at once. Two ship:

Preset Feel
silk Light, loose, keeps moving. Deep sag, generous stretch, strong response to wind
canvas Heavy and stiff. Barely sags, thuds to a stop, mostly ignores the breeze

The script sets aria-pressed on every preset button and data-cloth-material on the container, so you can style the active state and the fabric together.

Markup Hooks

Attribute Where Required Description
data-cloth-drape Container Yes Marks the fabric container
data-cloth-art An <img> inside it Yes The artwork, and the box the mesh spans
data-cloth-gust Any button No Sends a full gust through the fabric. Multiple buttons are fine
data-cloth-preset Any button No Applies a material preset by name
data-cloth-canvas Canvas Created by the script. Style it with this attribute
data-state="live" Container Added once the simulation is running. Gate your image-hiding CSS on it
data-grabbing Container Present while the fabric is held. Useful for a grabbing cursor
data-cloth-material Container The name of the active preset

Accessibility

  • Reduced motion: under prefers-reduced-motion: reduce no simulation runs, no canvas is created and no listeners are attached. The artwork stays as a static, fully legible image.
  • No JavaScript: identical to the above. Nothing is hidden by CSS that only JavaScript reveals.
  • Keyboard: the canvas is focusable. Arrow keys push the fabric in that direction, which is the keyboard equivalent of a tug; Enter or Space sends a gust. The gust and preset buttons are real <button> elements.
  • Focus visible: the focused canvas takes an inset outline, so it is visible against the artwork rather than lost on the wall behind.
  • Labels: the canvas gets an accessible name from data-cloth-label, and the artwork's own alt text stays in the document.

The fabric is a toy, not a reading surface. Put the message in real copy nearby as well as on the banner.

Performance

  • One gsap.ticker callback drives everything; the ticker is removed on teardown.
  • Simulation runs on a fixed 1/120s step with an accumulator, capped at four steps per frame, so a slow frame cannot start a catch-up spiral.
  • Rendering is one clipped drawImage and one gradient fill per triangle, plus a single composite for the lighting. The default mesh is around 370 triangles.
  • Touch devices get a coarser mesh and one fewer constraint pass automatically.
  • The cast shadow is drawn into a canvas a seventh of the size and scaled back up, which buys a wide blur for almost nothing.
  • Device pixel ratio is capped at 2.
  • One sheet per page is the intended use. If you want several, raise data-cloth-cell and profile.

Dependencies

Required:

  • GSAP 3.12+ (core only — no plugins)

Optional:

  • None

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

Your cart

Your cart is empty

The Vault £99

The Vault library, plus future additions to the library.