
The vacuum-sealed chat
Chat, Physics, SVG, Transitions, Text
NewFree
The code block of the docs of an SDK for trail maps, with JavaScript, Python, Go and cURL tabs and the colours of the inks of a hiking map. Choosing a language drops a ripple under its tab that spreads through the code in rings: each letter goes under, changes into the new language and comes back up bigger and darker on the crest, and an echo comes back from the bottom edge. Copy puts the code on the clipboard and the selection floods out from under the button like a lake on a map, its shore following the shape of the lines; then it drains away.
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 rippling code</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/martian-mono@5.3.0/wdth.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/instrument-sans@5.3.0/wdth.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- a code block from the docs of a trail-map SDK: choosing a language drops a ripple into the code from under its
tab, and each letter goes under in the trough and comes up in the new language; Copy floods the code with a
selection shaped like a lake on a map, which drains back into the button -->
<section class="snippet" aria-label="Get a trail with the Fellmap SDK" data-snippet data-autoclic>
<header class="snippet__bar">
<div class="tabs" data-tabs-wrap>
<div class="tabs__row" role="tablist" aria-label="Language" data-tabs></div>
<div class="tabs__row tabs__ink" aria-hidden="true" data-ink></div>
</div>
<button class="copy" type="button" data-copy>
<svg class="copy__icon" viewBox="0 0 20 20" aria-hidden="true">
<path class="copy__back" d="M13 6.5V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h1.5" data-back/>
<path class="copy__front" d="M9 7h6a2 2 0 0 1 2 2v6a2 2 0 0 1-2 2H9a2 2 0 0 1-2-2V9a2 2 0 0 1 2-2Z" data-front/>
</svg>
<span class="copy__label" data-label>Copy</span>
</button>
</header>
<div class="code" role="tabpanel" id="code-panel" tabindex="0" data-panel>
<div class="code__inner" data-inner>
<svg class="code__lake" aria-hidden="true" data-lake-svg>
<defs>
<!-- the selection: the lines' rectangles blurred and cut at half their alpha (they melt into one shape
with rounded shores, inside and outside corners alike), then an eroded copy lighter inside -->
<filter id="lake" filterUnits="userSpaceOnUse" x="0" y="0" width="100%" height="100%" color-interpolation-filters="sRGB" data-lake-filter>
<feGaussianBlur in="SourceAlpha" stdDeviation="4.5" result="blur"/>
<feColorMatrix in="blur" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 -11" result="goo"/>
<feFlood class="lake__shore" result="shoreInk"/>
<feComposite in="shoreInk" in2="goo" operator="in" result="shore"/>
<feMorphology in="goo" operator="erode" radius="1.3" result="inside"/>
<feFlood class="lake__water" result="waterInk"/>
<feComposite in="waterInk" in2="inside" operator="in" result="water"/>
<feMerge>
<feMergeNode in="shore"/>
<feMergeNode in="water"/>
</feMerge>
</filter>
</defs>
<g filter="url(#lake)" data-lake></g>
</svg>
<div class="code__grid" aria-hidden="true" data-grid></div>
</div>
<pre class="sr" data-text></pre>
</div>
<p class="sr" aria-live="polite" data-live></p>
</section>
</main>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.15.0/dist/gsap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.15.0/dist/MorphSVGPlugin.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.
29 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 rippling code” from Animorio and fit it into my siteA regex for each language (the language is guessed from the tab's name) cuts the code into words, and a word belongs to the language if it is in a list, is a function if a bracket follows, a name after a dot, a class if it starts with a capital, a constant if it is all capitals. Each character becomes an inline-block cell as wide as one Martian Mono character, measured once: the font is monospaced and its width does not change with the weight, so each cell knows where it is (column times width, row times height) without measuring anything. Tabs go to the next column of four; on a phone long lines wrap with two spaces of indent, after a space, a comma or a bracket.
A ring that starts under the tab: at a distance s behind its front the water is −sin(2πs/WAVE)·e^(−s/0.6WAVE) high, less far from where it fell (divided by √(1+d/220)), so the trough comes first and the crest after. In the trough the letter shrinks, drops in weight down to 140 and fades; at the bottom it changes text and colour; on the crest it grows by 16%, rises in weight up to 800 (the wght axis of the variable font) and lifts a few pixels. Ripples still travelling add up, and the newest is the only one that changes the letters.
The bottom edge works as a mirror: for each ripple there is a second source, the same one mirrored below the edge, sending a fainter ring (ECHO) upwards. It is worked out like the first one, and it does not change the letters.
During a change the grid has as many rows as the longer of the two codes, and each cell knows what it shows and what it will become; a cell that has to disappear becomes a space, so the letters after it do not move. The block keeps its height and takes it to the new one following the ripple: at once if it grows, once the ripple has passed if it shrinks. When the ripple is over the rows are written again, clean.
A rectangle per row, from the first column to the last letter, inside an SVG group with the filter: feGaussianBlur blurs, feColorMatrix cuts the alpha at half (0 0 0 24 −11) and the rectangles melt into one shape with rounded corners inside too; feMorphology erodes a copy by 1.3 pixels for the light water, and what is left outside is the shore. Each rectangle opens where an ellipse reaches it, growing from under the button and squashed by ACROSS between the rows, with a little random delay per row.
Copy writes to the clipboard with navigator.clipboard, or else with a hidden field and execCommand, or else selects the code; the confirmation goes through aria-live. The word keeps still the letters in common (Cop) and changes the tail in a slot that widens; the icon folds with MorphSVG. The tabs are a tablist with the arrows, Home and End; the pill is a dark copy of the row cut with clip-path inset to the chosen tab. A click from a script (the preview) presses Copy the first time and every third, and otherwise goes to the next tab.
| Name | File | Default | What it changes |
|---|---|---|---|
SAMPLES | script.js | [['JavaScript', "import { Fellmap } …"], ['Python', …], ['Go', …], ['cURL', …]] | The tabs: the language's name and its code. The name also says how to colour it (py, go, curl or shell, otherwise JavaScript); Go's tabs stay in the copied code. |
SPEED | script.js | 600 | How fast the ripple spreads, in pixels a second. |
WAVE | script.js | 140 | The wavelength, in pixels: the longer it is, the more letters are in the trough and on the crest together. |
SWELL | script.js | 1 | How much the letters grow, thicken and fade on the ripple (0 = the code just changes). |
ECHO | script.js | 0.4 | How strong the ring coming back from the bottom edge is (0 = no echo). |
FLOOD | script.js | 0.8 | The seconds the lake takes to flood the code. |
COPIED | script.js | 1.6 | The seconds the code stays selected and the button says Copied. |
COPIED_LABEL | script.js | 'Copied' | What the button says once the code is on the clipboard. |
For the documentation of an SDK or an API with examples in several languages, the install page of a tool (npm, pnpm, yarn), a developer's blog, a guide with the same example written in different ways.
Under 480 pixels the code goes down to 12 pixels and narrows on Martian Mono's width axis (75%), so about 45 characters fit on a row; longer lines wrap with two spaces of indent, and nothing spills sideways. The tabs narrow a little too (font-stretch 92%) to fit on one row with Copy at 390 pixels. Taps do not wait for a double tap (touch-action manipulation).
The new code comes in with a fade, without a ripple; the pill jumps to the chosen tab; the lake appears all at once with a fade and goes the same way; the icon and the word change without moving, the button does not shrink when pressed and there is no entrance.
GSAP 3.15.0, MorphSVG (GSAP) 3.15.0, Martian Mono (font variabile) 5.3.0, Instrument Sans (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 13 KB; the libraries: GSAP + MorphSVG 37 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.