Flow

Effects / SVG

Bauhaus shapes

Primary-colored circles, triangles and bars that slide, spin and settle into a balanced composition.

Prompt to build it

Build an animated Bauhaus composition. Use SVG with a red circle, blue triangle, yellow half-circle and black bars on #f1ece0, each on its own CSS transform loop with staggered delays and cubic-bezier easing. 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>Bauhaus shapes | Flow effect</title> <!-- Flow effect: Bauhaus shapes (https://flow.donta.io/effects/bauhaus-shapes) 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; } /* ── Bauhaus ──────────────────────────────────── */ .fx-bauhaus { background: #f1ece0; } .fx-bauhaus svg { width: 100%; height: 100%; } .fx-bauhaus svg * { transform-box: fill-box; transform-origin: center; } .fx-b1 { animation: fx-b-slide 5s cubic-bezier(.7,0,.3,1) infinite alternate; } .fx-b2 { animation: fx-spin 12s cubic-bezier(.7,0,.3,1) infinite; } .fx-b3 { animation: fx-b-pop 4s cubic-bezier(.7,0,.3,1) infinite alternate; } .fx-b4 { animation: fx-b-swing 6s cubic-bezier(.7,0,.3,1) infinite alternate; } @keyframes fx-b-slide { to { translate: 0 -38px; } } @keyframes fx-b-pop { 0% { scale: 0.6; } 100% { scale: 1.15; } } @keyframes fx-b-swing { to { rotate: 90deg; } } @keyframes fx-spin { to { rotate: 360deg; } } @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-bauhaus"><svg viewBox="0 0 200 150" preserveAspectRatio="xMidYMid slice" aria-hidden="true"> <rect x="18" y="20" width="6" height="110" fill="#161616"/> <rect x="18" y="124" width="170" height="6" fill="#161616"/> <circle class="fx-b1" cx="62" cy="96" r="22" fill="#e3312b"/> <polygon class="fx-b2" points="128,30 168,92 92,92" fill="#2346b8"/> <path class="fx-b3" d="M120 124 a24 24 0 0 1 48 0 z" fill="#f2b705"/> <rect class="fx-b4" x="70" y="40" width="34" height="6" fill="#161616"/> <circle cx="160" cy="112" r="5" fill="#161616"/> </svg></div> </div> </body> </html>

How it works

A few flat SVG primitives in red, yellow, blue and black on off-white, each with its own looping transform: rotate, translate, scale, staggered so the composition keeps rebalancing.

Guardrails

  • Use the shapes as framing, not behind text.
  • 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.