AI CSS Animations

Variable Font Waves

A grid of one repeated word whose letterforms breathe through real weight and width axes: ripples, sweeps and a roving focus point flow across the grid before a headline sets itself, with a live axis readout.

Written and rendered by AI CSS Animations Oct 12, 2026

Type
prompt
Made with
Claude Opus 5.5 in Claude Code
Built in
HTML/CSS
Topics
Kinetic type
What Claude made from the prompt below in Claude Code: one HTML file rendered frame by frame to video. Silent preview.

About this style

Variable fonts arrived with OpenType 1.8 in 2016, a format jointly developed by Apple, Google, Microsoft and Adobe that lets one font file hold continuous design axes such as weight and width. Animating those axes makes letterforms change shape rather than just move, which is why foundries use it to show off their families and brands use it for responsive, living identities. The craft lies in smooth, structured fields of change rather than noise.

The prompt

<inputs>
If I don't give you something, use the default and don't ask.
- Grid word: default "FLEX"
- Headline: default "Type that breathes."
- Brand line: default "Softgrid Type Co."
- Palette: default ground #14143A, type #F3F1FF, accent #FF6A4D
- Length: default 10 seconds
</inputs>

<direction>
A specimen film for a variable font: the letterforms change shape, axis values flowing like a field across a grid.

Font: Roboto Flex (Google Fonts), requesting opsz 8–144, wdth 25–151 and wght 100–1000. Change shape only through font-variation-settings; the real axes are the point. Texture: none, flat ground.

Grid: 6 rows × 5 columns of the grid word, uppercase, in fixed 336×140 px cells filling the area inside 120 px margins, each centered. Size the type once so its widest state (wdth 151, wght 1000) fits with 12 px to spare.

Field: each cell's axes are a function of column, row and t. Weight spans 100–1000; width spans 25–151 and runs a quarter-cycle behind weight, so forms swell, stretch, thin, then condense, like breathing rather than pulsing. Waves are smooth sines; no cell completes a cycle in under 1.4 s. Amplitude envelopes ease over 0.6–1.0 s (easeInOutSine) so phases blend instead of jumping.

Color: the accent appears only in the focus beat, tinting cells above 85% weight.

Readout: Roboto Mono 400, 18 px, bottom left, live wght and wdth as integers: the center cell's, then the headline's from 7.6 s. The headline stays readable at least 2 s.

Authentic: continuous interpolation, hairline-to-black extremes, a grid that stays aligned while forms move. Cheap: rainbow cells, structureless noise.

Banned: scale or skew transforms on words, -webkit-text-stroke, blur, glow, rotation, per-frame jitter, a second accent, anything flashing more than 3 times per second.
</direction>

<structure>
Default 10 s:
- 0.0–1.0: grid fades in at wght 100 / wdth 25, rows staggered 0.06 s.
- 1.0–3.4: radial ripple: rings of heavy, wide forms travel outward from center, wavelength about three cells, period 1.6 s.
- 3.4–5.2: a diagonal sweep, top left to bottom right, then one whole-grid breath (wght 100 → 1000 → 300, 1.4 s).
- 5.2–7.0: focus beat: a point on a smooth Lissajous path swells nearby cells to wght 1000 / wdth 151 with a Gaussian falloff.
- 7.0–8.0: the field damps out; cells settle at wght 300 / wdth 75 and dim to 25%.
- 7.6–8.8: the headline sets centered at 140 px, from wght 100 / wdth 151 to wght 800 / wdth 100; brand line below in Roboto Mono.
- 8.8–10.0: hold.

Other lengths: scale phases proportionally, keeping the period limit.
</structure>

<build>
- One self-contained index.html, no libraries (three.js from a CDN only when a style truly needs 3D); a 1920×1080 (16:9) stage scaled to fit the window; designed for 60fps.
- window.seek(t), t in seconds, computes every visual from t alone: no CSS transitions or animations, no setTimeout/setInterval, no state carried between frames. Any randomness comes from a seeded PRNG keyed to the frame.
- No ?render in the URL: drive seek from requestAnimationFrame so it plays in a browser. With ?render: don't start that loop.
- Google Fonts via <link>; await document.fonts.load() for each face before assigning window.seek.
- Plain DOM; write font-variation-settings, opacity and color in seek.
</build>

<check>
Before showing me, step through one frame per second and look at each. Fix overlaps, clipped or cramped text and anything off-style. Check no word overflows its cell at the widest, heaviest state and the dimmed grid never fights the headline. Confirm the final frame holds.
</check>

Ours, and free to use under CC0: copy it, change it, ship it. No credit needed.

Similar prompts