← Building2026Live

This portfolio

A portfolio that's also a small product: a visual editor I share with Claude Code, with saves built so neither of us overwrites the other.

The visual editor composing a page

01 – The idea

Makes the invisible legible.

That's the homepage headline—and the through-line of my work. Design is where the instinct started, and this site makes it literal. The little ticks, exposed grids, ruler-like link underlines, and elevation markers on images are visual jokes about the structure designers work with every day: columns, measurements, alignment, constraints. The machinery that makes something feel intuitive, even when nobody notices it.

Product work runs on the same machinery. I want to zoom from the big-picture architecture down to the smallest interaction without losing the coherence of the whole.

Structure, but somewhere you'd want to spend time

The colors soften the precision. Sky blue, deep green, and warm paper are meant to feel like sky, trees, and the materials of making things.

Role
Concept, art direction, product requirements
Team
Me + Claude Code
Editor
Puck, running only on my machine
Built with
Next.js, published on Vercel

The apostrophe hops over MO'B when you hover, and the footer insists apostrophes are valid in last names. Plenty of forms still disagree.


02 – The editor

I've worked in WYSIWYG editors for decades, and I wanted to compose pages visually: columns, grids, images, and text where they go. Writing pages in MDX turned every layout change into a coding task, and I didn't want to run a hosted CMS to avoid it. So I built a small editor, treating it as a product with one demanding user.

What I ruled out
  • TinaCMS: form-based editing in a sidebar, not on the page.

  • Squarespace: it leaves the codebase behind.

  • WordPress with Beaver Builder: the strongest alternative (I built Verblio's marketing site on it), but a second system to run.

  • A custom editor from scratch, Craft.js, and hosted builders (Builder.io, Plasmic, Makeswift).

The visual editor open on the Tab Splits build page: a drawer of layout and content blocks on the left, the page itself in the middle, and the Page panel with its title, summary, status and slug fields on the right.
The editor, open on a build page. Blocks on the left, the real page in the middle, its header fields on the right.

What the editor does

Compose
columns, grids, images and text from one shared set of blocks, on preset layouts.
Edit in place
type on the page itself; header fields write back to each page's frontmatter.
Save to Git
pages are files in the repository, so every change is a reviewable diff.
Stay local
the editor exists only on my machine. Every deployment returns 404 for it.

03 – Three decisions and what they taught me

Decision 01

A CMS without CMS infrastructure

Pages are files in Git, edited with Puck on my machine and prerendered at build time.

The full story

The call

No database, no hosted editor, and no monthly cost. The live site stays fully static, and every change is a reviewable diff.

What made it work

Layouts are presets pinned in a lock file and checked before every build, so authors pick layouts rather than invent them, and a code change can't silently re-lay-out a saved page. Saves write stable, sorted JSON, so a diff shows only what changed.

Decision 02

Fixed composition where it matters

Most pages are composed freely from shared blocks. The homepage isn't.

The full story

What prompted it

An earlier, fully editable homepage felt too sleepy.

The call

The homepage's character comes from how the parts overlap: the name crossing the horizon, the portrait pulled up to cross it too, the ordered entrance, the numbers counting up. Making those draggable would mean guardrails on every knob, and one stray drag could break the composition. So its layout lives in code, and the editor exposes only its copy.

Decision 03

Safe for two editors

I edit pages visually while Claude Code edits the same files in code, so every save has to be trustworthy.

The full story

The guarantees

Saves refuse to overwrite files changed since the page opened. Unsaved edits are backed up in the browser. Edits made during a save stay unsaved. A failed save puts its files back.

What happened

Early on, the editor seemed to wipe work in progress every few minutes. The likeliest cause was Chrome discarding a background tab, but the real gap was that unsaved edits lived only in the tab's memory. They now back up to the browser, and reopening offers Restore or Discard.

Rejected

Autosave to disk. It would write files constantly, make noisy diffs, and race Claude Code's edits.

Deliberately not built

  • An editor on the live site.

  • Routes for content that doesn't exist yet.

Results so far

  • 14

    pages, every one composed in the editor

  • 4

    case studies migrated from MDX in a single day

  • 15

    block types, shared by every page

04 – How

I developed the visual concept, art-directed its execution, and defined the product and interaction requirements; Claude Code implemented and iterated on it. The decision logs record the alternatives I rejected and the times I overruled Claude's proposals.

Concept
the visual language, from "makes the invisible legible" down to the apostrophe.
Art direction
how every page and block should look and behave.
Requirements
the product and interaction requirements for the site and its editor.
Review
evaluated approaches, challenged proposals, and reviewed the results.
Tools, constraints & technical notes

Where to look

  • The editor's guard: it exists only under npm run dev, and its write routes refuse cross-site requests.

  • What a save guarantees, including its one known gap: the two file writes aren't a single atomic step.

  • Content checks that run before every build. If they fail, the deploy fails.

  • Pinned layouts, so a change can't silently re-lay-out saved pages.

Caught along the way

  • Comments were content. Converting the case studies from MDX, a word-for-word diff of old and new text caught a dozen design-artifact notes that a naive conversion would have published. They became "Note to self" blocks, visible in the editor and never rendered.

  • Tailwind drops CSS it can't see. Class names built from template strings were silently removed, so they're written out in full.

Stack: Next.js 16, TypeScript, Tailwind CSS, and Puck, prerendered and hosted on Vercel.

Design · AI