A generative editorial poster tool: fill a few fields and it lays out an oversized Helvetica headline that bleeds off the canvas, drops a photo on a grid, and stamps eyebrow / index / meta captions — all driven by a seed, so every "specimen" is reproducible, tweakable, and shareable.
Built with Vite + vanilla JS + DOM/CSS (no WebGL — real font metrics give the
crispest type). PNG export via html-to-image. No backend, no framework.
Origin: a recreation of Nguyen Le's "more random experiment shit / type is still slop" clip, which is itself a small poster-layout app. See Background.
Feature-complete first build. Runs locally with npm run dev; everything under
Controls works, as do PNG export and deep links. Nothing is half-wired, so it's
safe to pick up cold. Open ideas live under Roadmap. See CHANGELOG.md for the
full list of what shipped.
npm install
npm run dev # opens http://localhost:5173npm run build → static site in dist/; npm run preview serves it.
- Style —
A(Auto, seed picks) or1Bleed ·2Stack ·3Vertical ·4Index.Shufflemints a new seed;Surpriseswaps in a fresh exhibition + random settings. - Composition — case (As typed / ALL CAPS), Upright / Sideways, intensity (Tame / Loud / Feral → how hard the type bleeds & tilts), Grid on / off.
- Canvas — 3:4 · A4 · 4:5 · 1:1.
- Background — Light / Dark.
- Typeface — system Helvetica Neue (default), condensed, serif, mono, Upload font (.ttf/.otf/.woff), or Sync local (Chrome's Local Font Access).
- Image — Replace / Remove the photo.
- Content — index, eyebrow, title, headline, two meta columns.
‹ Prev / Next › walk the seed history · Pause/Play the autoplay loop ·
Regenerate a new specimen · Export PNG (3× resolution). Clicking the poster
also regenerates.
State is URL-encoded, so any specimen is shareable / bookmarkable:
?style=3&bg=dark&intensity=feral&ratio=4:5&sideways=true&seed=12345
A pinned seed loads paused on that exact poster.
src/
main.js orchestration: store ⇄ sidebar ⇄ renderer, autoplay, export, I/O, deep links
state.js store + seed history + pub/sub
layout.js the generative engine — (content, options, seed) → layout spec
render.js paints a spec into #poster (calc(var(--pw|ph)) sizing for export safety)
sidebar.js the control panel, two-way bound to the store
content.js default + preset editorial content (for Surprise)
fonts.js typeface stacks, font upload, local-font sync
rng.js seeded RNG (mulberry32)
export.js PNG export (html-to-image)
placeholder.js offline default image (inline SVG)
styles/ app.css (chrome) · poster.css (the poster)
reference/ frames from the source clip, used while matching — LOCAL ONLY (gitignored)
The source clip looked like a kinetic-type effect, but on inspection it was a
screen recording of a layout tool. That reframed the build: the goal is crisp
editorial typography and faithful grid composition, so DOM/CSS beats WebGL/GLSL
here (in-shader type goes soft). The generative engine is seed-driven so the tool
doubles as a "directions" explorer — Shuffle/Surprise/autoplay throw out
variations fast. Reference frames are kept out of git.
- More layout templates + smarter optical line-breaking and headline sizing.
- Multi-image / image-grid compositions; duotone & halftone photo treatments.
- Color themes beyond mono (seeded accent palettes).
- Variable-font weight/width axes; per-element manual nudge & drag-to-reposition.
- Save/load named presets; a "copy deep link" button.
- Batch export / contact sheet; WebM/MP4 capture of the autoplay loop.
- A nicer default placeholder image; responsive drawer sidebar for small screens.
Inspired by Nguyen Le's poster experiments on X. Helvetica Neue is the system font (not bundled). MIT-spirited personal project — reuse freely.