
The vacuum-sealed chat
Chat, Physics, SVG, Transitions, Text
NewFree
The card where a running app asks to read your health data and shows what it would see: Sunday’s run, the heart rate at rest, the sleep, the weight. What you switch off is blacked out right where it is: the letters swell, heavier and wider, and their ink runs along the words until they are one wet bar, which then dries; switched back on, the ink draws back into the letters. On sharing, the app’s yellow runs like a highlighter over the values it will read, and the track in its icon grows a stretch for each one.
A folder that runs on its own: index.html, style.css, script.js and the libraries from a CDN.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>The redacted permissions</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/archivo@5.3.0/wdth.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the card where a running coach app asks to read your health data. Each kind of data shows what the app
would see; switched off, the words swell into a bar of wet ink that dries, switched on the ink draws back
into the letters. Shared, the app's yellow runs like a highlighter over the values left in clear, the
track in its icon grows, and the card says what was shared. The rows are made by script.js, from KINDS -->
<section class="permit" aria-labelledby="permit-title" data-permit data-autoclic>
<header class="permit__head">
<span class="app" aria-hidden="true" data-app>
<svg class="app__mark" viewBox="0 0 48 48" focusable="false">
<g transform="rotate(-24 24 24)">
<path class="app__lap app__lap--ghost" d="M24 36H30A12 12 0 0 0 30 12H18A12 12 0 0 0 18 36Z" />
<path class="app__lane" d="M24 30.5H30A6.5 6.5 0 0 0 30 17.5H18A6.5 6.5 0 0 0 18 30.5Z" />
<path class="app__lap" d="M24 36H30A12 12 0 0 0 30 12H18A12 12 0 0 0 18 36Z" data-route />
</g>
</svg>
</span>
<h2 class="permit__title" id="permit-title" data-title>Share your health data with <span data-app-name>Pacenote</span></h2>
<p class="permit__text" data-text><span class="permit__line"><span data-app-name>Pacenote</span> plans your runs from what you share.</span> <span class="permit__line">What you keep stays on this phone, blacked out.</span></p>
</header>
<ul class="kinds" data-kinds></ul>
<div class="actions" data-actions>
<div class="actions__row">
<button class="btn btn--quiet" type="button" data-needed>Only what’s needed</button>
<button class="btn btn--quiet" type="button" data-all>Allow all</button>
</div>
<button class="btn btn--main" type="button" data-share><span>Share with <span data-app-name>Pacenote</span></span></button>
</div>
<div class="actions actions--done" hidden data-done>
<p class="done__note">
<svg class="done__mark" viewBox="0 0 20 20" aria-hidden="true" focusable="false"><path d="M5 10.5l3.2 3.2L15 6.6" /></svg>
<span data-note>Shared just now. Change it any time.</span>
</p>
<button class="btn btn--quiet btn--big" type="button" data-change>Change what’s shared</button>
</div>
<p class="sr" role="status" aria-live="polite" aria-atomic="true" data-live></p>
</section>
</main>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.15.0/dist/gsap.min.js"></script>
<script src="script.js"></script>
</body>
</html>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.
38 values to change
With the Animorio connector, Claude Code takes it from here, guide included, and fits it into your project. Paste this request:
Take “The redacted permissions” from Animorio and fit it into my siteEach value is SVG text with one tspan per letter (the outline of HTML text, -webkit-text-stroke, has pointed corners and grows spikes when thickened), and each letter has its own amount of ink, from 0 to 1. In the first half the letter gains weight (Archivo’s wght axis from 600 to 900) and all the way through width (wdth from 88 to 112), so the letters after it move along and the ink seems to spread. The real ink is the letter’s outline, in the same colour, with round corners (stroke-linejoin round): an outline two radii wide is the letter grown by a disc of that radius in every direction, and grown enough it closes the holes in the letters and the gaps.
Under the letters there is a band through the middle of the small letters, as thick at each letter as that letter is inked: the letters’ middles come from getStartPositionOfChar and getEndPositionOfChar on every frame (the letters widen), and the edge is a closed Catmull-Rom curve, round at the ends. While the ink runs, the band thins towards the front; at rest, the swollen letters stick out of it a little where they are tall or hang below the line, and those are the bumps.
Fresh ink has a colour between --ink and --wet (WET says how much) and a shine: a blurred white line along the band’s top edge, broken like the reflection of a window; in DRY seconds it dries. While there is ink the group goes through a filter with a low frequency feTurbulence and a feDisplacementMap as strong as the ink, which makes the edges wave; clean words are drawn without the filter.
The switches are real buttons with role switch and aria-checked, named after their row, and the whole row can be tapped. Switching off, the letters ink up one after another in SWEEP seconds with back.out; switching on, the ink goes back to zero with a back.out that takes it below zero, and for a moment the letters are under their weight. Only what’s needed and Allow all change the rows one after another, 0.13 seconds apart; with the mouse, over a clear row the weight goes up by 110, over a blacked out one the ink goes down to 0.9.
Share: the switches fade away to the right, and over each shared value a yellow band runs in MARK seconds, from the start of the letters to as far as it has got, a little uneven and cut at a slant at the ends like a highlighter, under the letters. At the end of each stroke the track in the icon (stroke-dashoffset) reaches the share of data shared, and the icon squashes and comes back with elastic.out. The title and the lines fade with a touch of blur, change, and their height slides from the old to the new while they are invisible, so the card does not jump.
Tab goes from the switches to the buttons, Space or Enter turn them on and off, and the focus ring shows only to who uses the keys. Each row tells the screen reader its value, or that it is blacked out and stays on the phone; the final choice and the quick choices are announced in an aria-live region, and the focus moves to Change what’s shared and then back to Share. The preview’s click (detail 0) uncovers everything, blacks out what is not needed, turns heart rate on, shares, opens again, and so on; if the card is still moving, the click waits.
| Name | File | Default | What it changes |
|---|---|---|---|
APP | script.js | 'Pacenote' | The name of the app that asks, in the title, the button and the confirmation. |
KINDS | script.js | [{ name: 'Workouts', value: '8.4 km run on Sunday', needed: true }, …] | The data the app asks for: the name, what it would see and whether it cannot do without it (needed: no switch, never blacked out). |
SWELL | script.js | 1 | How far the ink spreads round the letters: 0.6 tight, 1.6 blotchy. |
SWEEP | script.js | 0.62 | The seconds the ink takes to run along a value, and to draw back. |
WET | script.js | 0.75 | How much the fresh ink shines (0: matte from the start). |
DRY | script.js | 1.3 | The seconds the ink takes to dry. |
MARK | script.js | 0.42 | The seconds the app’s yellow takes to run over a value it will read. |
For any app that asks to see personal data: health, contacts, calendar, location, photos, accounts; for the link between two services that shows what will pass from one to the other; for a privacy page, or a form that lets you hide its delicate fields before sending it.
The card takes the width of the screen less the margins (358 pixels at 390) and stays the same; the whole row is a target for the finger, the switches are 48 by 30, and the two small buttons narrow their letters a little (the width axis) so that Only what’s needed fits in half the row. The hint on hover is there only with a mouse.
The card does not rise and the ink is already there; switching on or off, the ink appears or goes at once with a short fade, without running, without the shine and without the knob stretching. On sharing, the yellow fades in on all the values together, the track in the icon is at its point straight away and the words change with a fade.
GSAP 3.15.0, Archivo (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 12 KB; the libraries: GSAP 28 KB.
Tested on 6 October 2026
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.
With your account’s email and password.
or with your email
You’re signed in as .
With your account, you can download the zip of every animation and every pack, for free.