Flow

Effects / SVG

Risograph print

Flat spot-color shapes with slight misregistration and grain, like a risograph poster.

Prompt to build it

Build a risograph-style sun-and-sea poster. Use SVG shapes in fluorescent pink, blue and yellow with mix-blend-mode multiply, a slight drifting misregistration, and an feTurbulence grain overlay. 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>Risograph print | Flow effect</title> <!-- Flow effect: Risograph print (https://flow.donta.io/effects/risograph-print) 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; } /* ── Risograph ────────────────────────────────── */ .fx-riso { background: #f4ecd8; } .fx-riso svg { width: 100%; height: 100%; } .fx-riso .ink { mix-blend-mode: multiply; } .fx-riso .drift-a { animation: fx-misreg 2.4s steps(3) infinite alternate; } .fx-riso .drift-b { animation: fx-misreg 3.1s steps(3) infinite alternate-reverse; } .fx-riso .sun-rays { transform-box: view-box; transform-origin: 100px 62px; animation: fx-spin 30s linear infinite; } @keyframes fx-misreg { to { translate: 1.5px -1px; } } @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-riso"><svg viewBox="0 0 200 150" preserveAspectRatio="xMidYMid slice" aria-hidden="true"> <defs><filter id="riso-grain"><feTurbulence type="fractalNoise" baseFrequency="0.9" numOctaves="2" stitchTiles="stitch"/><feColorMatrix values="0 0 0 0 0.3 0 0 0 0 0.25 0 0 0 0 0.2 0 0 0 0.2 0"/></filter></defs> <g class="ink drift-a sun-rays" fill="#ff4a3d"><rect x="98" y="14" width="4" height="14" transform="rotate(0 100 62)"/><rect x="98" y="14" width="4" height="14" transform="rotate(30 100 62)"/><rect x="98" y="14" width="4" height="14" transform="rotate(60 100 62)"/><rect x="98" y="14" width="4" height="14" transform="rotate(90 100 62)"/><rect x="98" y="14" width="4" height="14" transform="rotate(120 100 62)"/><rect x="98" y="14" width="4" height="14" transform="rotate(150 100 62)"/><rect x="98" y="14" width="4" height="14" transform="rotate(180 100 62)"/><rect x="98" y="14" width="4" height="14" transform="rotate(210 100 62)"/><rect x="98" y="14" width="4" height="14" transform="rotate(240 100 62)"/><rect x="98" y="14" width="4" height="14" transform="rotate(270 100 62)"/><rect x="98" y="14" width="4" height="14" transform="rotate(300 100 62)"/><rect x="98" y="14" width="4" height="14" transform="rotate(330 100 62)"/></g> <circle class="ink drift-a" cx="100" cy="62" r="28" fill="#ff4a3d"/> <path class="ink drift-b" d="M0 98 Q25 88 50 98 T100 98 T150 98 T200 98 V150 H0Z" fill="#2f6fdb"/> <path class="ink drift-a" d="M0 112 Q25 104 50 112 T100 112 T150 112 T200 112 V150 H0Z" fill="#ffd23f" opacity="0.85"/> <text class="ink drift-b" x="16" y="24" font-size="16" font-weight="800" fill="#2f6fdb" font-family="var(--display, sans-serif)">RISO</text> <rect width="200" height="150" filter="url(#riso-grain)"/> </svg></div> </div> </body> </html>

How it works

Overlap two or three spot-color layers with mix-blend-mode: multiply, offset them by a pixel or two that drifts over time, and add an SVG noise grain.

Guardrails

  • Keep misregistration small (≤3px) so edges stay readable.
  • 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.