Skip to content
animorio
IT
All components

The break-glass dialog

Dialogs, Transitions, Physics, SVGGSAP, CSS onlyAdvancedCompressed weight: Demo 14 KBGSAP 28 KBFreeDownload the zip

A console’s emergency access, behind glass: the button raises a pane of smoked glass that straightens on springs as the light runs across it, Cancel puts it back into the button, and Break glass brings a little hammer down: the glass cracks from where it is hit, holds a moment and falls in pieces that turn in depth and catch the light. The cracks are worked out at every blow and the pieces are copies of the dialog cut along them.

The code

A folder that runs on its own: index.html, style.css, script.js and the libraries from a CDN. The React and Vue tabs hold the same demo as a ready component, which switches its animations off when it leaves the page.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>The break-glass dialog</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/reddit-sans@5.3.0/index.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="stage">
    <!-- the break-glass dialog: Emergency access raises a pane of smoked glass that asks to break it. Cancel puts it
         back; Break glass swings the hammer, the glass cracks from where it is hit and falls in pieces, and the
         button becomes the emergency access with its countdown and End -->
    <div class="slot" data-slot data-autoclic>
      <button class="trigger" type="button" aria-haspopup="dialog" data-open>
        <svg class="hammer" viewBox="0 0 24 24" aria-hidden="true"><path d="M12.3 3.3 18.6 9.6 19.5 13.9 15.2 13 8.9 6.7z"/><path d="M13.1 10.9 4.6 19.4"/></svg>
        <span>Emergency access</span>
      </button>
      <div class="active" hidden data-active>
        <svg class="active__icon" viewBox="0 0 24 24" aria-hidden="true"><rect x="5" y="10.5" width="14" height="10" rx="2.2"/><path d="M8.2 10.5V7.4a3.8 3.8 0 0 1 7.3-1.5M12 14.4v2.4"/></svg>
        <span class="active__name">Admin access</span>
        <span class="active__clock"><span class="sr">Time left </span><span data-clock></span></span>
        <button class="active__end" type="button" data-end>End</button>
      </div>
      <span class="slot__pill" aria-hidden="true"></span>
    </div>
  </main>

  <div class="layer" hidden data-layer>
    <div class="layer__scrim" data-scrim></div>
    <div class="pane" role="alertdialog" aria-modal="true" aria-labelledby="pane-title" aria-describedby="pane-text" tabindex="-1" data-pane>
      <div class="glass" data-glass>
        <div class="glass__icon" aria-hidden="true">
          <svg viewBox="0 0 24 24"><path d="M12 3.4 18.8 6v5.6c0 4.1-2.8 7.4-6.8 8.9-4-1.5-6.8-4.8-6.8-8.9V6z"/><circle cx="12" cy="10.6" r="1.7"/><path d="M12 12.3v3"/></svg>
        </div>
        <h2 class="glass__title" id="pane-title">Break glass?</h2>
        <p class="glass__text" id="pane-text">You’ll get full admin rights for <span data-minutes></span> minutes. Everything you do is recorded, and the security team is told straight away.</p>
        <p class="glass__meta">
          <svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="8.2"/><path d="M12 7.6V12l2.9 1.8"/></svg>
          <span>Ends on its own at <time data-ends></time></span>
        </p>
        <div class="glass__actions">
          <button class="btn btn--quiet" type="button" data-cancel>Cancel</button>
          <button class="btn btn--break" type="button" data-confirm>
            <svg class="hammer" viewBox="0 0 24 24" aria-hidden="true" data-hammer><path d="M12.3 3.3 18.6 9.6 19.5 13.9 15.2 13 8.9 6.7z"/><path d="M13.1 10.9 4.6 19.4"/><circle class="hammer__tip" cx="19.2" cy="13.6" r="0.4" data-tip/></svg>
            <span>Break glass</span>
          </button>
        </div>
        <span class="glass__sheen" aria-hidden="true" data-sheen></span>
      </div>
      <div class="pane__shards" aria-hidden="true" data-shards></div>
      <svg class="pane__cracks" aria-hidden="true" data-cracks></svg>
    </div>
  </div>
  <p class="sr" aria-live="polite" data-live></p>

  <script src="https://cdn.jsdelivr.net/npm/gsap@3.15.0/dist/gsap.min.js"></script>
  <script src="script.js"></script>
</body>
</html>

Playground

Change values, colours and text with the controls and watch the animation respond live. Or write in the code yourself. Then download the folder with your changes.

36 values to change

Or ask Claude Code for it

With the Animorio connector, Claude Code takes it from here, guide included, and fits it into your project. Paste this request:

Take “The break-glass dialog” from Animorio and fit it into my site

What it does

On a black background a dark pill 56 pixels tall with a red emergency hammer and the words Emergency access; with the mouse over it the hammer lifts, ready. Pressed, its words go and a pane of smoked glass rises from the button, tilted back and a little smaller: it straightens on a spring, goes just past upright and back, and as its tilt changes the reflection of a lamp runs across it. On the glass: a red shield, Break glass?, the explanation (admin rights for 60 minutes, everything recorded, the security team told), the time the access ends on its own and the buttons Cancel and Break glass. Cancel, Escape or a tap outside put it away: the pane tilts back again, the reflection runs across once more, and it shrinks into the button, which takes back its words with a small bounce. Break glass lifts and brings down the hammer in the button: where its point lands the glass cracks, first the rays running to the edges, then the rings round the hit, with a few hairline cracks to the side; the pane shudders from the blow, every piece moves by a pixel and takes a light of its own, so the words break along the cracks. A moment later the glass falls: first the little pieces round the hit, which break inwards, then the others, which turn in depth, show their broken edges and flash when they face the light. The button turns red and, once no piece passes in front of it, says Admin access with an open padlock, the time left (60:00, 59:59…) and End, which closes the access and puts it back as it was.

How it works

A pane on springs

The dialog has four measures, its height, its scale and the two tilts rotateX and rotateY, and each is a damped spring, x'' = −ω²(x − target) − 2ζω·x', in steps of 1/240 of a second on GSAP’s ticker, with the step limited to 1/30. Opening, it starts 34 pixels lower, at 0.9 and tilted back 32 degrees: the tilt has ω = 7.2/RISE and ζ = 0.42, so it goes a little past and back, the height and scale ω = 8/RISE and ζ = 0.78. Closing, the targets become 26 pixels, 0.62 and 30 degrees, with ζ = 0.9 and the pane fading in PUT_AWAY seconds. When the springs are still the loop sleeps.

The light on the glass

The reflection is a light diagonal band with mix-blend-mode: screen, inside the glass. It has no timing of its own: its place comes from the tilt, translateX = −130% + 12.5·rotateX − 8·rotateY, so it runs across the pane as it straightens, as it goes back into the button and when the blow makes it shudder, and at rest it stays outside. The button’s words fade before the glass is opaque, so they never show through it.

The cracks, worked out at every blow

The blow is the hammer’s point (a spot marked in its drawing) once it has gone up to −40 degrees and down to 18. From there RAYS rays run out at slightly uneven angles, with a point on every ring and between two rings more points that stray by two pixels; the rings are RINGS, from 15 pixels to 84% of the distance to the farthest corner, at radii growing geometrically. A sector closes on a ring with a chance of 0.7 (always on the first, which makes the little pieces of the hit); if the arc is wider than 130 pixels it splits in two with a new ray starting there. Every arc that closes a sector closes a piece, then cut by the glass’s four sides with Sutherland and Hodgman.

Drawing the cracks

In an SVG over the glass every crack is two strokes, a dark one and a light one half a pixel higher, with a different opacity for each crack, plus a few short hairlines branching off the rays. They draw with stroke-dashoffset: the rays at 2600 pixels a second, each from its own ring, the rings in 0.06 seconds when the crack reaches them. The pieces are cut along the same points, so the cracks and the broken words match.

Real pieces

Every piece is a copy of the glass (without ids or data-, its buttons out of the Tab order) cut with clip-path: polygon(), its transform-origin on its centroid, an SVG with only its broken edges and a light of its own. During HOLD they move by a whole pixel and change their light a little. Then they let go from the hit outwards, at 2200 pixels a second: a push of (50 + 260·nearness²)·BURST, a speed inwards of up to 640 pixels a second near the hit, spins on three axes, gravity GRAVITY. The piece’s normal, turned by rotateX and rotateY, against the vector halfway between lamp and eye, to the fiftieth power, gives the flash of its shine.

Keys, access and the preview

It is an alertdialog with aria-modal, aria-labelledby and aria-describedby: opening, the focus goes to Cancel, Tab goes round the two buttons, Escape puts it away, the button behind is inert; closing, the focus goes back to the button, or to End after the blow. The button turns red as the glass falls, and its words come once no piece is in front of it any more; the time left is rewritten only when the second changes, and at zero the access ends by itself. An aria-live region says so. A click from a script on the button’s frame (the library’s preview) opens, then once puts it away and once breaks it, and ends the access, going by the state and not by a fixed list.

Values to change

NameFileDefaultWhat it changes
RISEscript.js0.62The seconds the pane takes to come up and settle.
PUT_AWAYscript.js0.34The seconds Cancel takes to put the pane back into its button.
RAYSscript.js11How many cracks run out from where the hammer lands.
RINGSscript.js5How many rings of cracks go round the hit.
HOLDscript.js0.4The seconds the cracked pane holds together before it falls.
GRAVITYscript.js3200How fast the pieces fall, in pixels a second squared.
BURSTscript.js1How hard the blow throws the pieces: 0 they just drop, 2 twice as hard.
DIMscript.js0.62How dark the page goes behind the glass, from 0 to 1.
MINUTESscript.js60How many minutes the emergency access lasts.

Try them in the Playground

When to use it

For actions that are rarely taken and should cost one more gesture: an emergency access, deleting an account or a project, shutting a service down, a factory reset. The breaking glass says it is not a confirmation like the others; for everyday confirmations there is the dialog from its button.

On phones

The pane takes the width of the screen less 16 pixels a side (358 at 390) and the explanation runs to three lines; the button stays 56 tall and the two on the glass 46. With a finger a tap opens, a tap outside puts it away, and the pieces fall past the bottom of the screen without scrolling it or spilling sideways.

With reduced motion

The pane does not rise or tilt: the button’s words fade and the glass appears in its place with a fade, and leaves the same way. The hammer does not move; pressing Break glass the cracks appear all at once, already drawn, then the cracked glass fades and only after that does the access appear, with a fade too.

Pitfalls

  • The moment the glass cracked every piece moved by fractions of a pixel and turned by a few tenths of a degree: the browser resampled the letters and the whole dialog went blurry. Now the pieces move by whole pixels and do not turn, and the crack shows in the slightly different light each one takes.
  • In the first hundredths of a second the pane, still half see-through, let the words Emergency access show beneath it: two texts one over the other. The button’s words fade in 0.1 seconds as soon as it is pressed, and the glass is solid a moment later.
  • The falling pieces passed in front of the words Admin access as soon as they appeared. The button now turns red at once, but its words wait until no piece is in front of it, measuring the pieces’ boxes against its own.
  • A flat white light on a turning piece made it look like a grey sheet of paper. The shine is a gradient across the piece itself (the light layer is the size of its box), weaker, and only near the right angle.
  • A point in a corner of the glass lies on two sides: checking one side only, the broken edge of a corner piece was drawn along the straight edge, outside the rounded corner. The sides are now bits, and the edges’ SVG is cut with inset(0 round 24px).
  • The drawn cracks and the cuts of the pieces must go through the same points, the ones that stray between one ring and the next too: otherwise the words break a little away from the line. Every ray keeps its in-between points and both use them.
  • With reduced motion the access appeared under the fading cracked glass, and after End the button came back empty because its words had stayed at zero opacity. Now the glass fades first and then the access appears, and coming back the words take their opacity back.
  • The library’s preview always clicks the same frame: with a fixed list of steps (open, cancel, open, break, end) one real click out of turn was enough to stall it. The script looks at the state: closed it opens, open it alternates cancel and break, with the access on it ends it.

Libraries

GSAP 3.15.0, Reddit Sans (font variabile) 5.3.0.

Compressed with gzip, the three demo files weigh 14 KB; the libraries: GSAP 28 KB.

Testing

Tested on 6 October 2026

  • Desktop: Done
  • Phone: Done
  • Reduced motion: Done
  • Safari on iPhone: To do

License

Use it in your own projects and in your clients’ projects. Do not resell it or redistribute it as is. GSAP stays under its own Standard license. Full license.

All components