Colophon
How this site works
Every version of this portfolio tells the same facts. What changes is the shape: you describe the page you’d like, a decision model picks parts from a catalog, strict validators check its choices, and a deterministic fallback is always ready if anything goes wrong.
- 17shellslayout archetypes
- 96section renderings16 intro · 16 experience · 16 impact · 16 projects · 16 skills · 16 contact
- 4motion kitsStill, Subtle, Kinetic, Scenes
- 4palettes× 8 type pairs × 2 densities
- 384precomputed pages384 distinct compositions
Diagram
Watch a spec come together
Each row is one decision. The ticks are the options the catalog allows at that point (only renderings that fit the chosen shell, only motion kits it supports), and the lit one is what this page got. These are real precomputed pages.
VisitorRecruiter · Calm · Paper · Still · Brief
- Known parts
- Required sections
- Canonical order
- Fits the shell
- Motion supported
- Type suits the shell
- Within budget
- Unique among 384
- 01
You describe a portfolio
The home page is a textbox (“Describe the portfolio you’d like to see”) and two buttons: Just the résumé and Surprise me. A description is capped at 280 characters and stripped of invisible characters. Everyday words set only what they speak to: “dark” picks a dark palette, “no motion” keeps things still, “quick” keeps it brief. Anything you don’t mention is left to the composer.
- 02
A decision model assembles it from a catalog
A page is a spec: one shell (the layout archetype that owns navigation and page flow), one rendering per section (intro, experience, impact, projects, optional skills, contact), a motion kit and tokens (palette, type pair, density). Every part in the catalog has a plain-language description and tags.
A decision model reads your words and those descriptions and picks one candidate from each group, with a confidence for each choice. It never writes code or markup, only ids from the catalog, so it can’t invent a part that doesn’t exist. It has a hard four-second budget; a timeout, an error or a low-confidence answer hands the job to the fallback. Two looks at once are possible too: 11 shells can lend their backdrop to another layout, and a mixtape draws its sections in 2–4 of 16 worlds.
- 03
Validators have the final word
Whatever the model picks,
validateSpecchecks it: known parts, required sections present and not duplicated, canonical order (experience right after the intro, projects later), every rendering compatible with its shell, a motion kit the shell supports and a type pair that suits it.Then the heavy-effect budget: every part has a weight (0, 1, 2: from free CSS to canvas, WebGL or pinned scroll scenes), and a page’s shell, renderings, motion kit and any borrowed backdrop must add up to 5 or less. So a WebGL map never shares a page with a scroll-choreographed keynote and a 3D scene. Anything that fails is repaired slot by slot from the fallback’s picks.
- 04
384 precomputed pages, no two alike
Surprise me opens one of 384 static pages, one for every combination of five picks (who’s visiting, vibe, palette, motion, time to spare). They’re composed ahead of time, validated (384 of 384 pass as stored or repaired), and checked for uniqueness: no two share a composition (384 distinct specs across 15 shells). The hand-tuned presets like /topo and /line1 are the canonical, shareable editions.
- 05
A deterministic fallback, always
The site never depends on the model. A plain TypeScript composer scores every part’s tags against the picks and the words in your description (with a small synonym table), respects the same compatibility rules and budget, and returns a valid spec in milliseconds. It fills any slot the model left empty, runs when the model is slow or unavailable, and stands in at build time for any stored spec that no longer validates.
- 06
Speed rules
Per-page CSS. A page downloads the base stylesheet plus the CSS of the parts it actually renders, nothing else. It used to be one bundle of every shell and rendering (about 57 KB gzipped of part CSS on every page); now a typical portfolio page ships roughly 11–21 KB of CSS in total, and the build fails if a page is missing a part’s styles or loads another shell’s.
Lazy effects. Canvas and WebGL effects load after first paint, and only once their element scrolls into view; the animation library loads only on pages whose motion kit needs it, never when you’ve asked your system for reduced motion. Everything except the live composer and the pages it links to is static HTML.
- 07
Off-topic requests and safety
Off-topic. If there’s no edition for what you asked (“underwater”, a recipe, a question), you still get the closest match, with an honest note saying so rather than a pretend theme. Unmatched descriptions are kept for 90 days, without any identifying info, to decide which editions to build next.
Your words stay yours. Your description only steers which catalog parts are chosen; it is never run as instructions and never rendered for anyone else. Shared links carry the spec, not the prompt: your own tab remembers what you typed, and everyone else sees “Built from a visitor’s description”.
Guard rails. Abusive descriptions hit a small server-side blocklist and are never composed, cached or stored. Requests are same-origin only, rate-limited per IP and checked by an invisible bot test, and a daily and monthly spend cap on model calls quietly switches to the fallback once it’s reached.