053

Kinetic Shutter Blinds

£10 or the whole Vault, £99

Slices a hero design across a bank of 3D venetian louvres that crack open under the cursor in a proximity wave, revealing a second layer behind and a third printed on their reverse.

Observer intermediate
6 more details
3d-transformshover-effectmicro-interactionphysicsstaggervelocity-reactive

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

Updated

About this effect

A kinetic shutter blinds effect that prints your hero design across a bank of 3D venetian louvres. You supply one flat artwork; the script slices it across the slats so the closed blind reads as a single seamless composition. As the cursor sweeps the stage, nearby slats pivot open on their hinge axis in a smooth proximity wave, letting the layer behind show through the gaps.

Read the full effect overview

Each slat carries a real light model: a cast shadow on the slat below that deepens with its angle, a glint along its top edge as it catches the light, and a touch of translateZ depth. When the pointer leaves, the bank swings shut centre-out with an elastic settle and the artwork reassembles seamlessly.

Four behaviours ship behind optional external buttons: the proximity wave, a click-anywhere impulse ripple that propagates across the bank, a motorised full-open, and a 180-degree flip that turns the blind over to a second design printed on the reverse of the slats.

Kinetic Shutter Blinds - GSAP animation effect preview

What's included

8 items
  • Automatic artwork slicing: supply one flat hero layer and the script builds and aligns the louvre bank from it
  • Proximity wave driven by GSAP Observer with Gaussian falloff, so slats near the pointer open furthest
  • Velocity response: faster sweeps push the wave wider and deeper across the bank
  • Per-slat light model with angle-driven cast shadows and a specular glint along each top edge
  • Impulse ripple that propagates outward from any clicked slat, overshoots, and settles elastically
  • Flip preset that rotates the whole bank 180 degrees to a second artwork on the reverse of the slats
  • Configurable via data attributes: slat count, wave angle, wave spread, and full-open angle
  • Static closed-blind fallback without JavaScript and under prefers-reduced-motion, plus full keyboard control

Perfect for

5 use cases
  • Editorial and campaign heroes where a bold typographic poster tears open to reveal a second message
  • Venue, bar, and restaurant sites playing day and night states against each other with the flip
  • Portfolio and agency landing pages that want one physical, tactile signature interaction above the fold
  • Product launches revealing the product layer behind a teaser layer as visitors explore
  • Photography and interior sites where light through blinds is the brand's visual language

How it works

3 sections

The component is a stage holding three flat layers you author as normal markup: the front artwork, an underlay revealed through open slats, and an optional reverse artwork. On init the script clones the front and reverse layers into each slat of a generated louvre bank, offsetting every clone by its slat index so the bank renders the artwork seamlessly, and keeps the slice geometry current on resize through two CSS variables.

A GSAP Observer instance watches pointer and touch movement. Each move projects the pointer onto the bank and eases every slat toward an angle weighted by a bell curve centred on the pointer, with sweep speed widening and deepening the wave. Shadow opacity and edge-glint intensity come from each slat's own angle, so all four behaviours share one light model.

Ripples propagate by per-slat delay with distance decay, overshoot in the opposite direction, and settle with a spring. The flip turns each hinge a half-turn with a small stagger; backface-visibility swaps which sliced artwork shows. Everything runs with a single setup and teardown path and a reduced-motion branch that leaves the flat artwork in place, and cleanup kills observers, listeners and tweens.

Plugins Observer
Difficulty Intermediate
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 Kinetic Shutter Blinds 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.

2. Add before closing </body> tag:

Code snippet omitted: it ships with the download.

3. Add to your <body>:

Code snippet omitted: it ships with the download.

You author each layer as one flat, full-bleed composition. On init the script builds the louvre bank and slices the front (and reverse) artwork across it automatically; there is no per-slat markup to write.

4. Optional preset buttons, anywhere on the page:

Code snippet omitted: it ships with the download.

The script wires any [data-shutter-preset] buttons it finds and keeps their aria-pressed state current. Without them the component simply stays in wave mode.


Using It With Your Own Design

What the effect requires of your markup:

  • The [data-shutter] container needs position: relative, a fixed aspect or height, overflow: hidden, and a perspective value (the stylesheet sets 1100px; lower is more dramatic, higher is flatter).
  • Each artwork layer must be a flat composition that fills the stage (position: absolute; inset: 0). The script clones it into every slat, so anything inside it is duplicated: keep layers self-contained and avoid id attributes inside them.
  • The underlay sits at z-index: 1, artwork layers at 2, and the script-built slat bank at 3. If you restyle from scratch, preserve that ordering, and keep inset: -18px (or similar overscan) on the underlay so its edges never show during its little parallax drift.

What is demo dressing you can delete: everything inside the three layers. The listening-room copy, the signal-orange underlay, the sun span, and the chalk reverse are all content; swap them for your own composition, photography included. The layer classes (shutter__underlay, shutter__art) carry the structural CSS; the inner classes (art-title, underlay-glow, and so on) are just the demo's typography.

Non-obvious CSS the effect depends on:

  • The slice geometry runs on two CSS variables the script maintains on the container (--shutter-h, --shutter-unit) plus --slat-i on each slat. The .shutter__slice rule turns those into each clone's offset; keep it if you rename things.
  • The painted louvre lines on the flat artwork (.shutter__art--front::after) exist so the closed blind still reads as a blind before JavaScript runs, without JavaScript at all, and under reduced motion. The script-built bank draws its own divisions, so the overlay is removed under .is-built.
  • Never put a CSS filter or backdrop-filter on the container, a slat, or a hinge: filters force transform-style to flatten and the 3D collapses (both faces render at once).
  • .shutter__hinge deliberately overdraws by a pixel (inset: -0.5px 0) so sub-pixel gaps never open between resting slats.
  • The reverse artwork ships hidden; the effect shows it only through the slat clones. Point a visible control at it with aria-controls (the demo's Flip button does) so the relationship survives without JavaScript.

Options & Attributes

All on the [data-shutter] container unless noted.

Attribute Values Default Description
data-shutter-slats integer >= 4 12 Number of louvre slats the bank is built from
data-shutter-max-angle degrees 78 Peak wave angle at the pointer (capped at 88 internally)
data-shutter-spread number 2.2 Gaussian width of the wave, in slats; higher opens more of the bank at once
data-shutter-open-angle degrees 84 Angle the Open preset (and ArrowUp) motors every slat to
data-shutter-preset (on buttons) wave | ripple | open | flip wave Marks an external button as a mode switch

Behaviours

  • Wave (default): pointer and touch movement opens nearby slats with Gaussian falloff; sweep speed widens and deepens the wave. Leaving the stage swings the bank shut centre-out with an elastic settle. Clicking any slat fires a ripple from that row.
  • Ripple: pressing anywhere fires an impulse that propagates outward with distance decay, overshoots, and settles elastically.
  • Open: motors every slat to the full-open angle with a top-down stagger, exposing the underlay.
  • Flip: rotates every slat 180 degrees to the reverse artwork. Selecting Wave or Ripple flips back first.

Accessibility

  1. Reduced motion: under prefers-reduced-motion: reduce the script never builds the slat bank, leaving the flat front artwork (with its painted louvre lines) as a fully designed static state. The CSS also zeroes animation and transition durations.
  2. No JavaScript: same story; the front artwork is the component's default render, so nothing is blank if the CDN is blocked.
  3. Keyboard: the stage is focusable. ArrowUp/ArrowLeft opens the louvres, ArrowDown/ArrowRight closes them, and Space/Enter fires a centre ripple. Preset buttons are real <button> elements with aria-pressed state.
  4. Screen readers: the slat bank and its clones are aria-hidden; the flat source layers stay in the accessibility tree, so the page reads as its content rather than as twelve fragments per layer.

Dependencies

  • GSAP 3.15.0 (gsap.min.js)
  • Observer plugin 3.15.0 (Observer.min.js)
  • Fonts (demo only): Mona Sans

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