Build a landing page from one image
The Studio's most complete output is not the bare effect — it is a whole landing page composed around it: masthead, feature trio, quote, call to action, all coloured from the image itself and paced against the assembly. One command produces it. This guide is the judgement that goes around that command.
node cli.mjs product.jpg --theme editorial --brief page.json --out landing.html
1 — Size the grid before anything else
Start with a dry run: --emit json writes no file and reports
the grid, instance count, and a tier — ok (up to 60,000 instances,
comfortable on anything), amber (to 200,000, fine on desktops), or
red (beyond that, for audiences whose GPUs you know). Iterate
--rows here until the tier matches your audience. With the
default full-image faces, sharpness comes from the texture rather than the
grid, so rows beyond about 256 rarely earn their cost.
node cli.mjs product.jpg --rows 144 --emit json
2 — Pick a voice
Three page voices are built in, and they are genuinely different designs, not colourways: editorial sets a serif masthead with airy spacing; technical is monospaced and gridded, with a live readout of the assembly fraction; poster runs condensed capitals over solid accent blocks. The examples page shows all three composed from the same image — pick by looking, not by name.
3 — Write the brief
--brief page.json carries the copy and imagery: headline,
dek, tagline, a feature trio, an optional gallery and full-bleed band, the
quote, the reveal caption, and the call to action. Every field is optional,
and anything missing renders as a visible placeholder rather than
being silently dropped — a themed page with placeholders is a to-do list you
can see. Two rules the brief enforces on your behalf:
- Every image needs alt text. A supplied image with no
altthrows and no page is written. Decorative images are still expressible — passalt: ""and mean it. - The reveal has no placeholder. The payoff beat exists to show the finished photograph; leave the caption out and you get one clean viewport of picture.
For one-off tweaks, shorthand flags such as --headline,
--dek and --cta "Label=https://…" override the
brief file without editing it.
4 — Steer the palette, if you must
By default the page's entire colour system is extracted from your image —
quantized, derived in OKLCH, and held to WCAG AA by construction: body text
at least 4.5:1, accent at least 3:1. Four flags steer it, and all four land
upstream of that enforcement:
--bg forces the background and re-derives everything around it,
--scheme dark|light overrides what the image implies,
--tint gives a tonal steer, and --accent injects a
brand colour. A legible brand accent is used verbatim; an illegible one is
moved as little as possible, and the page's own HTML comments record exactly
what shifted and why. If you need different colours, use these flags or
change the image — never hand-edit the generated values.
5 — Look before you ship
A clean exit code cannot tell you whether your headline survives the noise behind it. Probe the finished page:
node cli.mjs product.jpg --theme editorial --brief page.json \
--probe 0,0.5,1 --probe-dir ./probes --out landing.html --force
This opens the page headlessly, scrolls the camera to each assembly
fraction, waits for it to settle, and writes a screenshot per stop. Fraction
0 should read as scattered noise, fraction 1 as the recognisable image — and
the frames near 0.5–0.7, peak chaos, are where text fails first. Open the
PNGs and look. If a section is drowning, give it a different beat in the
brief or lengthen the track with --scroll.
What you ship
The output is one self-contained HTML file: image embedded, styles
inlined, no build step, no framework, and a single external request for the
pinned three.js library. It honours prefers-reduced-motion,
keeps working without WebGL, and reads as designed over the flat background
alone. Host it anywhere that serves static files. If you would rather mount
the effect inside a page you already have, that is the
embedding guide.