Flow

Effects / CSS

Kinetic typography

Big type that moves: words slide, stretch, swap and loop in rhythm.

Prompt to build it

Build a kinetic typography block on yellow. Show a looping marquee band ('TYPE IN MOTION') and a huge word that cycles through MOVE / LOUD / BOLD with a vertical slide every 1.2s. Make it responsive, cap devicePixelRatio at 2, pause when off-screen, and show a still frame when prefers-reduced-motion is set. No external libraries.

Tested code

One self-contained HTML file with no libraries: the same code that runs above. Your AI gets it from Flow's get_effect tool.

Show the code
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Kinetic typography | Flow effect</title> <!-- Flow effect: Kinetic typography (https://flow.donta.io/effects/kinetic-typography) Self-contained: no libraries. Copy the .fx-stage element, the CSS and the script into your project and size .fx-stage however you like. --> <style> :root { --display: "Bricolage Grotesque", ui-sans-serif, system-ui, sans-serif; --body: ui-sans-serif, system-ui, sans-serif; } html, body { margin: 0; min-height: 100%; background: #0e0e10; display: grid; place-items: center; } .fx-stage { width: min(100vw, 960px); } /* Stage that every effect fills. Container units (cqw/cqmin) size the art. */ .fx-stage { position: relative; aspect-ratio: 4 / 3; overflow: hidden; border-radius: 16px; container-type: size; background: #111; isolation: isolate; } .fx-fill { position: absolute; inset: 0; } .fx-fallback { position: absolute; inset: 0; } .fx-center { display: grid; place-items: center; } /* ── Kinetic typography ───────────────────────── */ .fx-kinetic { background: #ffe14d; color: #141414; display: grid; grid-template-rows: auto 1fr auto; } .fx-marquee { overflow: hidden; white-space: nowrap; border-block: 0.6cqmin solid #141414; font: 800 4.4cqmin/1 var(--display); letter-spacing: 0.08em; padding: 1.6cqmin 0; } .fx-marquee span { display: inline-block; animation: fx-marquee 8s linear infinite; } .fx-marquee-rev span { animation-direction: reverse; } @keyframes fx-marquee { to { translate: -50% 0; } } .fx-words { height: 22cqmin; overflow: hidden; align-self: center; text-align: center; } .fx-words div { animation: fx-words 3.6s cubic-bezier(.8,0,.2,1) infinite; } .fx-words b { display: block; height: 22cqmin; font: 800 22cqmin/1 var(--display); letter-spacing: -0.06em; } @keyframes fx-words { 0%, 26% { translate: 0 0; } 33%, 59% { translate: 0 -22cqmin; } 66%, 92% { translate: 0 -44cqmin; } 100% { translate: 0 -66cqmin; } } @media (prefers-reduced-motion: reduce) { .fx-stage *, .fx-stage *::before, .fx-stage *::after { animation-play-state: paused !important; } } </style> </head> <body> <div class="fx-stage"> <div class="fx-fill fx-kinetic" aria-hidden="true"> <div class="fx-marquee"><span>TYPE IN MOTION TYPE IN MOTION TYPE IN MOTION TYPE IN MOTION TYPE IN MOTION TYPE IN MOTION TYPE IN MOTION TYPE IN MOTION TYPE IN MOTION TYPE IN MOTION TYPE IN MOTION TYPE IN MOTION </span></div> <div class="fx-words"><div><b>MOVE</b><b>LOUD</b><b>BOLD</b><b>MOVE</b></div></div> <div class="fx-marquee fx-marquee-rev"><span>TYPE IN MOTION TYPE IN MOTION TYPE IN MOTION TYPE IN MOTION TYPE IN MOTION TYPE IN MOTION TYPE IN MOTION TYPE IN MOTION TYPE IN MOTION TYPE IN MOTION TYPE IN MOTION TYPE IN MOTION </span></div> </div> </div> </body> </html>

How it works

Heavy display type in a marquee band plus a word that swaps on a timed loop with a quick vertical slide; everything uses transforms only.

Guardrails

  • Keep the real message in static text for screen readers (aria-live off).
  • Respect prefers-reduced-motion: show a still frame instead of the animation.
  • Pause when off-screen or when the tab is hidden (IntersectionObserver + visibilitychange).
  • Keep text off busy animated areas, or give it a solid backing that passes WCAG contrast.
  • One showpiece effect per page. If everything moves, nothing stands out.