Build Guide
How This Was Plotted
A specific, honest write-up of the GRAIN edition of the Nomadic Owls site: the riso-print references it borrows from, the CSS/JS techniques doing the work, and where the illusion is thinner than the real thing.
Concept & Inspiration
GRAIN treats the agency's work like a riso-printed zine rather than a glossy SaaS landing page. Risograph printers (Riso Kagaku duplicators, originally office stencil printers) became a zine-and-studio favourite because they can only lay down one flat spot color per pass, from a drum of soy-based ink, onto uncoated paper. Every extra color is a separate pass, and the paper feed is never perfectly aligned twice — so real riso prints have slightly offset color layers, visible paper grain, and a flat, poster-like palette instead of continuous-tone color. The brief for this direction was to fake that print run in the browser: limited spot colors, a fixed off-white "stock", registration marks like you'd find on a press sheet, and content labelled like plates in a job log rather than sections in a template.
The Structural Gimmick
Instead of generic "sections", the page is framed as a print job: a job-ticket header (job
number, stock, run count), numbered "plates" with printed labels (data-plate-label
pseudo-elements sitting on the top border of each section, like a running head on a spec sheet),
fixed crosshair registration marks in the four viewport corners, and a colophon footer with a
literal spot-color swatch legend (RGB values included, like a print spec sheet would list Pantone
numbers).
Misregistration Effect
Real riso misregistration happens because each color pass is a separate mechanical run through
the printer. To fake it on text, headings get a data-text attribute matching their
own content; two ::before/::after pseudo-elements duplicate that text
in riso red and riso blue, offset by 2–3px with transform: translate(), and
composited with mix-blend-mode: multiply underneath the true black glyphs. The result
reads as a colored fringe around the letterforms, exactly like an under-inked or shifted riso
pass. The same offset-plus-multiply trick is applied to the owl illustration: it's rendered twice,
once tinted by a red background layer and once by a blue one, each nudged a couple of pixels in
opposite directions, so the line art itself appears to mis-register along with the type.
Stroke-Drawing / "Plotting" Animation
Decorative dividers, card frames, and the owl's picture frame are plain SVG shapes
(<path>, <rect>) with a .plot-path class. On
load, a small script measures each shape with getTotalLength(), sets
stroke-dasharray to that length, and starts stroke-dashoffset at the
same value so the line is fully retracted. An IntersectionObserver then adds an
is-drawn class once a shape scrolls into view, which transitions
stroke-dashoffset to 0 — the line appears to draw itself exactly
once, like a pen plotter tracing a job. Content blocks fade/slide in alongside the linework using
the same observer and a shared .reveal class, so the whole plate feels like it's
being pulled off the press as you scroll.
Per the brief, motion stays mechanical and restrained: one reveal per element, no looping, no
easing that overshoots. prefers-reduced-motion: reduce is checked before any of this
runs; if it matches, the script skips priming the dash arrays entirely and adds
is-drawn to every reveal element immediately; everything renders fully drawn on
first paint with zero animation.
Grain & Paper Texture
The paper-grain overlay is a CSS-only SVG filter: an <feTurbulence type="fractalNoise">
primitive generates procedural noise (no input image needed), piped through
<feColorMatrix> to control its alpha, then applied via filter:
url(#grainFilter) to a fixed, full-viewport, black, mix-blend-mode: multiply
layer at low opacity. A second fixed layer adds a very fine repeating radial-gradient dot pattern
for a halftone feel. Both sit above the content but below the registration marks, and neither
intercepts pointer events.
Typography & Color
Display and UI type is Courier Prime (self-hosted via
@fontsource/courier-prime) — a typewriter/plotter-pen feel for headings, nav,
labels and numerals. Long-form copy (manifesto, descriptions, excerpts) is set in
Lora (@fontsource/lora) for a warmer, more readable serif that
doesn't fight the mono display type. The palette is capped at three riso spot colors plus black
ink on an off-white "paper" background (#f4f1e9):
- Riso Red R255 G59 B48 · Scr. 45°
- Riso Blue R13 G90 B201 · Scr. 105°
- Riso Yellow R255 G212 B0 · Scr. 90°
- Key Black R28 G26 B21 · Scr. 15°
Riso red at full saturation (#ff3b30) only clears WCAG AA at large/bold text sizes
against the paper color, so it's reserved for display headings, numerals, and swatch chips. Any
small colored text (links, table numerals) uses a darkened text-safe variant,
--riso-red-ink: #ad2c0d, which passes AA at body size. Riso blue
(#0d5ac9) clears AA at both sizes as-is. Riso yellow (#ffd400) is the
worst offender — even at large bold sizes it barely clears 1:1 against the paper stock —
so it's used only for swatch chips and decorative fills (never as text); the one spot where a
numeral needed to read in "yellow" (the Technical SEO plate number), a darkened
--riso-yellow-ink: #8a6800 stands in instead.
Generated Imagery
Two images were generated with Higgsfield's gpt_image_2 model, within a two-image
budget shared across all ten art directions of this project:
- Owl illustration (
owl-plotter.png) — prompt: "A single-line pen-plotter style illustration of an owl, clean black line art, no shading, minimal continuous vector line drawing, technical pen plotter aesthetic, white background", 3:4 aspect ratio (closest available option to the brief's 4:5). Used in the hero as a duotone plate: the same black-line PNG is layered twice over solid red and blue backgrounds withmix-blend-mode: multiplyand offset viatransform, producing the misregistered duotone look without any manual color separation. - Plotter linework texture (
plotter-linework.png) — prompt: "Abstract pen-plotter geometric line art pattern, continuous single-color thin black line drawing, technical hatching and contour lines, no color, white background, elegant generative plotter art texture", 3:2 aspect ratio. Used at low opacity, multiply-blended, as a background layer behind the manifesto plate.
Honest Tradeoffs
1. The duotone/misregistration effect is a CSS approximation, not a real color
separation. A genuine riso print posterizes an image into discrete halftone layers per
ink color, each with its own screen angle. Here we're relying on the fact that the source
illustration is pure black line art on white, so multiply blending against a flat
spot color "just works" for a two-tone look. It wouldn't hold up for a photograph or a
multi-tone illustration without real preprocessing (posterization, halftone screening) that's
impractical to do losslessly in the browser at build time.
2. The "plotting" animation draws decorative vector shapes, not the artwork
itself. Because the owl is a rasterized PNG (not an inline SVG path we control), the
stroke-dashoffset technique is applied to the frame around it and to divider/rule elements, not
to the owl's actual linework. The illustration itself reveals via the standard
.reveal fade/slide, not a literal pen trace. Getting a true per-stroke plot of the
artwork would require the source as vector paths (e.g. an SVG export or a traced line-art file),
which was out of scope for a two-image budget.