171

Prism Glass Hero

£7
or the whole Vault, £99
Open in new tab

A WebGL launch hero with a solid 3D glass object floating over your own headline and photograph, refracting them with real per-channel dispersion. Grab it and throw it: it flies on its momentum, bounces off the edges and springs home, and the faster it moves the further the type splits into a spectrum. Prism, lens, torus or your own logo extruded from an SVG.

advanced
8 more details
webgl-shaderrefractionchromatic-aberrationthrowspring-physicsvelocity-reactivepointer-tiltmorphing

Released

About this effect

A complete launch hero (brand row, headline, lede and photograph) with a solid piece of glass floating in front of it. The glass is a real 3D object, not a blurred card or an SVG filter: it bends whatever is behind it through its own curved faces, so the headline magnifies, flips and stretches as it passes behind the bevels, and splits into red, green and blue where the glass is turning hardest.

Read the full effect overview

Grab it and throw it. It flies off on the speed of your hand, spinning, bounces off the edges of the hero and springs back to its home, and while it is moving fast the dispersion swells with its speed, so a hard throw smears the type into a streak of spectrum. At rest it sways slowly and tilts toward the pointer, and its highlight follows the cursor like a light in the room.

Four shapes: a rounded prism, a thick lens and a torus that morph smoothly into each other, and your own logo, extruded into glass from the SVG already in your markup. The hero behind it is your HTML and CSS: the effect reads its layout and paints it into the scene, so changing the copy, fonts or photograph changes what the glass refracts, and the same markup is the fallback without JavaScript, without WebGL and under reduced motion.

Prism Glass Hero - GSAP animation effect preview

What's included

10 items
  • A solid 3D glass object with true screen-space refraction of the content behind it, not a frosted card or a flat SVG displacement
  • Real spectral dispersion: white light passing straight through stays white, and only the bent edges fan out into colour
  • Throw physics: drag it, release it, and it carries your hand's speed, spins, bounces off the edges and springs home
  • Speed-driven spectrum: the faster the glass moves, the further the colours split and smear along its direction of travel
  • A full-quality tier on desktop and a lighter tier for touch devices, with an automatic step down if a machine cannot keep up
  • Prism, lens and torus share one vertex grid and morph smoothly into each other; the logo preset extrudes your own SVG mark into bevelled glass, holes included
  • Your real hero is the backdrop: headline, lede, logo and photograph are read from your HTML and CSS, so editing the markup changes what the glass bends
  • A soft shadow and a fringed crescent of focused light thrown onto the hero on the side away from the cursor
  • Keyboard operable: the glass is a focusable button, arrow keys flick it and Enter changes its shape
  • The composed hero is the fallback without JavaScript, without WebGL and under reduced motion, and stays in the accessibility tree while the canvas is live

Perfect for

5 use cases
  • SaaS and product launch heroes that need one memorable first viewport
  • Brand reveals where the company's own mark becomes a physical glass object
  • Agency and studio landing pages selling craft and polish
  • Architecture, design and materials brands where glass and light are the subject
  • Campaign and sale pages that need something visitors play with before they scroll

How it works

3 sections

Your hero is what bends

The hero is ordinary HTML and CSS: your headline, lede, logo and photograph. Whatever the browser lays out is what sits behind the glass, so changing the copy, the fonts or the image changes what the glass magnifies, flips and splits, and the same markup is the static hero for visitors without WebGL or with reduced motion.

Glass that reads as glass

The glass bends the hero through its curved faces, so type stretches and flips as it passes behind a bevel, and colour splits only where the glass curves hardest. Long studio highlights slide along the bevels as the cursor moves, the rim always carries a thin spectral fringe, and a shadow and a bright fringed caustic fall on the hero beside it.

Throw it, morph it

Drag and release: the glass keeps your hand's speed, spins, bounces off the edges of the hero and only then glides home, and the faster it travels the further the colours smear along its path. Prism, lens and torus melt into each other, and the logo shape turns the SVG mark in your markup into bevelled glass. GSAP plays the entrance and the shape changes; the throw runs in the frame loop.

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.

The Vault opens this source and the whole library.

Each product gives you the HTML, CSS and JavaScript source, the full documentation and an AI setup prompt, licensed for 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.

One payment, over 300 products, and future additions to the library.

Documentation

Quick Start

1. Add to your HTML <head>:

In your downloadThe working code for this step, in index.html.

The inline script is required. The hero markup is the fallback for no JavaScript, no WebGL and reduced motion, and without this probe it would paint for the half second three.js takes to arrive and then be replaced by the canvas. The probe runs before first paint, stamps html.gl when a canvas is coming, and the stylesheet hides the hero under that class until the canvas has drawn it. No JavaScript, no class, and the hero shows as normal.

2. Add the hero anywhere in your <body>:

In your downloadThe working code for this step, in index.html.

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

In your downloadThe working code for this step, in index.html.

The script reads the hero, drops a canvas in front of it and hides the hero once the canvas is actually there.

If either download fails (three.js or GSAP), the shim and the script both hand the page back to your hero, so a blocked CDN never leaves a black stage.

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 your hero instead of a blank stage), puts it on window, and then loads assets/script.js as an ordinary script, so the effect 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 assets/script.js runs:

In your downloadThe working code for this step, in script.js.

Choosing Your Images

This effect has a real content requirement, and ignoring it is the main way to make it look broken. Glass only shows you what it bends, so it needs something with edges behind it. Over a flat colour it is nearly invisible, which is true of real glass too.

  • Dense, high-contrast structure works; soft gradients do not. Type, architecture, weaves, foliage, grids and product edges all bend legibly. Skies, bokeh and smooth studio backdrops show nothing.
  • Light content on a dark ground, or dark on light. Dispersion is a colour split along contrast edges; mid-grey on mid-grey splits into mud.
  • Rest the glass mostly over the photograph. Over bare ground glass shows only its highlights. The demo parks it about two thirds over the photo, where the last word of the headline runs onto it, so at rest it bends both. Set the home with --glass-x and --glass-y (see Options).
  • Images must be readable by the page. The hero is painted into a canvas the glass samples, and browsers refuse to hand WebGL an image from another origin unless that origin sends CORS headers. Serve photos from your own domain, or from a CDN that sends Access-Control-Allow-Origin and add crossorigin="anonymous" to the <img>. An image that fails this check is left out of the glass (the hero markup still shows it) rather than breaking the effect.
  • Ungraded photographs. The glass adds its own tint, shadow and caustic; a heavily graded image goes muddy under them.

Test by throwing the glass hard across the busiest part of the hero, not at rest.

Using It With Your Own Design

What the effect needs from your markup: a root with data-prism-glass containing one data-prism-glass-source element. Everything inside the source is painted into the scene: text (any element, any font the page has loaded, any colour, letter-spacing and text-transform), <img> elements (with their object-fit: cover, object-position and corner radius), inline <svg> marks, and elements with a solid background colour. Gradients, borders, shadows and CSS filters are not painted. An inline <svg data-prism-logo> anywhere in the root enables the Logo shape; without one, the Logo button hides itself. Shape buttons are any <button data-prism-shape="..."> inside the root.

What is only the demo's styling: the .hero-brand, .hero-copy, .hero-photo layout, the Halvard copy, the colours and the Mona Sans type are a demonstration hero. Replace them with your own layout entirely; the effect reads whatever the browser lays out. The prompt line and the shape switcher in .prism-glass__chrome are optional.

CSS the effect depends on:

  • The root must have a real size. The canvas is sized from .prism-glass's clientWidth and clientHeight; in the demo it is position: absolute; inset: 0 inside a 100svh stage. Give it a height of 0 and you get a canvas of 0.
  • The hero must keep its layout while hidden. .gl .prism-glass__source and .prism-glass.is-live .prism-glass__source hide it with clip-path: inset(50%), which keeps its boxes measurable and its text in the accessibility tree. Never change this to display: none, or there is nothing to measure.
  • The root's background-color is the ground the hero is painted on. Set it to your page colour.
  • touch-action: pan-y on .prism-glass keeps vertical page scrolling working on touch; the generated .prism-glass__handle (the invisible button over the glass) has touch-action: none so a finger can drag the glass.
  • .prism-glass__chrome is hidden until .is-live, and fades in once the glass has landed (.is-settled): without WebGL there is no glass to change.
  • Optional image scrim: --image-scrim (0 to 1) and --image-scrim-width (a fraction of the image's width) on an <img> or any ancestor lay the root's ground colour over the image's left edge, so type running onto the photo stays legible. The effect paints the scrim into the scene; the demo's .hero-photo__frame::after draws the same gradient for the fallback hero. Set --image-scrim: 0 to turn it off.

Options

Set on the [data-prism-glass] root.

Attribute Values Default Description
data-shape prism, lens, torus, logo prism The starting shape
data-ior 1.1 to 2 1.5 Index of refraction: how hard the glass bends what is behind it
data-dispersion 0 and up 1 Colour split at the edges. 0 is colourless glass; 2 to 3 is a showpiece
data-thickness 0 and up 1 Scales how far the refraction displaces the image (magnification)
data-throw 0 and up 1 Multiplies the release speed of a throw. 0 disables dragging (click still changes the shape)
data-idle-spin 0 and up 1 Strength of the slow idle sway. 0 holds the glass still at rest (useful for captures)
data-drift 0 and up 1 On touch devices the glass drifts on a slow figure of eight between touches. 0 turns it off
data-caustic 0 to 1 1 Strength of the shadow and caustic thrown onto the hero
data-intro 0, 1 1 The load sequence: the photo wipes up and the hero masks in line by line, then the glass sweeps in across the headline and lands on its home. 0 starts at rest
data-depth 0.1 to 0.6 0.26 Extrusion depth of the logo, relative to its width
data-quality auto, high, low auto auto uses the full-quality glass on mouse devices, checks the frame rate once the intro settles and steps down to the light tier if needed. Touch devices start on the light tier

Set in CSS on .prism-glass (re-read on every resize, so media queries work):

Property Default Description
--glass-x 0.6 (0.6 on phones) Home of the glass, as a fraction of the root's width
--glass-y 0.42 (0.52 on phones) Home of the glass, as a fraction of the root's height
--glass-size 0.25 (0.28 on phones) Radius of the glass, as a fraction of the root's shorter side

Example: your logo, colourless, no throwing

In your downloadThe working code for this step, in index.html.

Example: a bigger lens parked on the photograph on phones

In your downloadThe working code for this step, in style.css.

About the logo shape

Any single-colour SVG with filled <path> elements works: M, L, H, V, C, S, Q, T, A and Z, absolute or relative. Holes are found by nesting, so the winding direction in your file does not matter. Convert strokes and text to outlines first (in Figma, Illustrator or Inkscape: Outline Stroke, Create Outlines). Bold marks read best as glass: a stroke thinner than about a tenth of the logo's width is mostly bevel and shows little refraction, and thin wordmarks read poorly. A compact symbol beats a full wordmark.

Accessibility

  • Reduced motion: the WebGL scene never starts. The hero stays exactly as your markup and CSS compose it, a complete static hero with headline, copy and photograph. Turning reduced motion on while the page is open tears the scene down and shows the hero.
  • Without JavaScript, or without WebGL: the same hero, for the same reason. One fallback, three failure modes, and it is never hidden until a canvas has actually been created.
  • Screen readers: while the canvas is live the hero is clipped rather than removed, so the real headline and copy remain in the accessibility tree. The canvas itself is aria-hidden.
  • Keyboard: the glass is a focusable button with a visible focus ring. Arrow keys flick it (the same physics as a throw), Enter or Space changes the shape, and shape changes are announced through a polite live region. The shape switcher buttons use aria-pressed.
  • Touch: a finger on the glass drags and throws it; anywhere else on the hero scrolls the page.

Dependencies

Dependency Version Required
three.js 0.180.0 Yes, as an ES module (see Quick Start)
GSAP core 3.12+ (demo built against 3.15.0) Yes: matchMedia branching, teardown, the intro timeline and the shape-change morph

No GSAP plugins. The renderer owns the frame loop: the throw physics, the pointer tilt and light, the idle sway and the speed-driven dispersion are continuous values computed each frame, and GSAP plays only the timed sequences.

Everything the effect uses (WebGLRenderer, ShaderMaterial, BufferGeometry, ExtrudeGeometry, Shape, CanvasTexture, WebGLRenderTarget, PerspectiveCamera) is long-stable three.js 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 as console 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 simply gets the hero and a clean console.

Import maps are supported everywhere current. In a browser old enough to lack them the module never runs, window.THREE is never set, and the hero is again what shows.

Performance

The loop does not run at all while the hero is off screen, and the painted hero is only refreshed during the intro, on resize and when fonts finish loading, so at rest the cost is the glass itself. Pixel ratio is capped at 2 (1.5 on touch devices).

To buy back frames on low-end hardware, set data-quality="low" first; it is most of the cost. Then lower --glass-size, because the glass's cost grows with the area it covers.

Also in your download: the full source, worked examples, the events and programmatic API, and the class reference.

£7