Skip to content
John HiemstraCreative

Design Engineering

I build the systems that let teams ship consistent, high-quality UI across code, visuals, and content. The case studies below show how.

— John Hiemstra, product engineer

  • ~50% less UI dev time from a shared component library
  • 5 component systems across enterprise and studio
  • 2 production sites on Tailor

Read the case studies

What I believe about design engineering

Design-inline systems

My approach to design systems is what I call design-inline. The system develops directly in strongly typed reusable code, Figma stays a just-enough tool for working ideas through, and the system itself becomes the contract both humans and agents build against. Heavy design-tool work creates export cycles and tool-lock; design-inline work ships to users.

Systems as governance, not component dumps

A design system earns its keep through governance, not through how pretty the Figma file looks. Private registry publishing, semantic versioning, deprecation models, and clear contribution paths are what let a system actually hold a quality bar as the team grows. The pretty parts are table stakes; the governance is the product.

Code, visual, and content as one craft

Modern design-engineering sits at the convergence of code standards, visual standards, and content standards. AI-assisted development has made that convergence more urgent, not less — because the tools generate across all three surfaces, the system has to govern across all three too. Skills, evals, and feedback loops are the mechanism; taste is the goal.

AI content governance · family wellness brand · 2026⁠–⁠present

Keeping AI output on brand when the brand is a person's voice

The problem

The brand publishes a podcast, a science blog, and the social clips cut from both. Generative tools made each episode's reels, quote cards, titles and summaries fast to produce, and just as fast to get wrong: a placeholder title, a paraphrased quote, a claim with no source. Each one spends the guest's words and the brand's trust.

The decision

I didn't ban the tools, and I didn't trust free generation and hope a reviewer caught the drift. I wrote the standards down as gates: code that fails a run loudly before anything irreversible happens — a render, an upload, a schedule write — and a studio of role-specialized agents, each with a named checkpoint. A direct quote is never edited, only cut. A factual claim ships only with a source that says it. A person reads every quote before anything publishes.

The system

Each gate has one definition, and every phase that needs it calls the same one. A title that breaks a rule goes back to the model with the broken rule named; if the rewrite fails, code repairs it; if that fails, a plain title stands in. The run records every change, so the person reading sees what changed and why.

The gate loop for generated content Written standards feed generation. Each output meets a gate. A failing output goes back to the model with the broken rule named. After two tries, code repairs it, and a plain fallback title stands in if repair fails. Only then does a person read it, and only then does it publish. StandardsGenerateGatePerson readsPublish fails: the rule is named Two tries, then repair in code
Python
def assert_real_title(episode_title: str, episode_code: str) -> None:
    """RULE: never advance/render/ship an episode with a missing or placeholder
    title. …
    Fail loudly here instead — before the counter bump and schedule write."""
    if not is_real_title(episode_title):
        raise GateFailure(
            f"{episode_code}: refusing to proceed — episode_title is "
            f"missing/placeholder ({episode_title!r}). …"
        )
The title gate, from content_gates.py. One definition; every phase calls it before it writes.
ensure() never fails a run. A heading that breaks a rule is fixed, in order:
  1. the model rewrites it, told exactly which rule it broke (up to `tries` asks);
  2. code repairs it: "&" to "and", the banned marks removed, or the title's own half before/after a colon or dash;
  3. a plain title that always passes: "<first name> in Conversation", or "In Conversation".
Every change is recorded on the quote (`title_check`) and in the report, so the read shows what was changed and why.
The route-back, from quote_title.py: the failing rule travels with the retry.

What it proved

Adoption evidence

The pipeline runs on its own server and turns each episode into reels, quote cards, a blog draft and a show summary. Gates are added where a failure proves the need: an episode once finished its first phase titled “TBD,” and every phase now shares one title gate because of it.

What I'd do differently

Write the gates before the first run, not after the first failure. Most of the gates in this pipeline exist because something got past us once.

Full-stack design engineering · a principal and an agent team · 2026⁠–⁠present

Owning the whole stack of design decisions

The problem

Every custom site for a small business started from scratch. Each one rebuilt its own design system, and a lesson learned on one client stayed in that client's repo.

The decision

I built Tailor, a platform I own end to end: React 19 and React Router 7, server-rendered, on the front; FastAPI and Postgres behind; and a scaffold that generates a complete, independent site for each client. I passed on a hosted page builder, and on shipping client packages the client would have to patch later. The client's repo is entirely theirs. A lesson from any build becomes a Tailor release every site gets.

The system

A strictly typed component surface, governed by a written house UI canon of 24 numbered rules: contrast, hit areas, five options at most in any menu, titles and actions that never scroll away. Decisions are recorded as architecture decision records, and work passes a local quality gate before it merges. I build it with Claude Code and a team of role-specialized agents — product, frontend, backend, test, security, design — each working to the same written policies.

How Tailor produces a client site Definitions for themes, fonts and modules feed a scaffold. The scaffold generates one client's site in its own repository: Postgres, then a FastAPI service, then server-rendered React Router 7 pages. Every site can export and import its content. A lesson from any site becomes a Tailor release that every site gets. Definitionsthemes · fonts · modules Scaffold One client's site, in its own repo PostgresFastAPI React Router 7server-rendered Export and import: the client leaves with everything A lesson from any site becomes a release

What it proved

Adoption evidence

Two production sites run on it, one of them an online shop taking live orders. From the first commit on April 30 to October 14, 2026: 3,124 commits, 112 architecture decision records, and version 1.0.0 released on October 1. The page you are reading is a Tailor page.

What I'd do differently

Test the checks as hard as the code. A deploy check once misread its own output and reported a failure that wasn't there; the rollback it set off took a live shop offline for thirteen minutes. Every check now prints evidence that it ran and what it read.

Document system for a consulting practice · 2026⁠–⁠present

One brand kit, every client deliverable

The problem

John Hiemstra Creative produces branded client documents: proposals, reports, audits and presentations. Each one had to read as the practice's own work, not a template, without a production designer on staff to lay it out.

The decision

I built a shared base instead of a template per document: one stylesheet, one component set, one pagination engine, and a skill per document type that carries its structure and voice. I passed on a page-layout tool, and on scale-to-fit. Content that doesn't fit flows onto the next sheet; it is never shrunk.

The system

common.css sets the US-Letter sheet, the masthead and the footer; components.css adds the shared blocks — stat rows, bars, figures, fail-and-fix tables. pack.py paginates, and the render scripts compose the sheets into a PDF. The proposal, report and content-development skills all stand on that base.

One base, several kinds of document A shared base of one stylesheet, one component set, a paginator and a PDF renderer. Proposals, reports and content-development documents extend it. A line of ingredient references reuses the same sheet geometry and assembly under its own brand sheet. Shared basecommon.css · components.css · pack.py · render to PDF ProposalsReports Contentdevelopment Ingredientrefs, own brand sheet

What it proved

Adoption evidence

Proposals, reports and content-development documents all extend the same base without forking it. A line of ingredient references for the family wellness brand reuses the sheet geometry and the assembly script under its own brand sheet.

What I'd do differently

Write the voice rules alongside the layout rules. The pagination canon was set in July; the canon for how we present our own work came in October, after a long round of steering a draft from internal and self-congratulatory to sharp and useful to the reader.

Working standards

Code

  • TypeScript in strict mode
  • UI composed from data and config, not one-off components
  • Component conventions documented beside the code
  • Shared components owned and versioned; no package a client is left to patch
  • Releases tagged; significant decisions recorded
  • A local quality gate before every merge: tests, a cold review, a security review
  • Automated accessibility checks in the gate
  • No dependency added without a recorded reason

Visual

  • Type, spacing and color as tokens
  • Spacing on a consistent base unit
  • Semantic color tokens above the raw palette; light accents never carry text
  • WCAG 2.2 AA contrast throughout
  • Motion restrained, and switched off when a reader asks for reduced motion
  • Print layouts designed, not left to the browser
  • Five options at most in any menu; titles and actions never scroll away

Content

  • Voice rules written per surface
  • Every factual claim carries a source that says it
  • A direct quote is never edited, only cut
  • Content lives beside the code it describes
  • AI output passes gates before a person reads it, and a person reads it before it ships
  • Reviewer load is a design input
  • Content changes versioned like code

Contact

John Hiemstra · product engineer · Sarasota, FL

LinkedIn · create@johnhiemstra.com