Things I've made.

A product I ship and run, the agent pipelines that move it forward, and a workshop of small tools I built because I wanted them. Further down: the way I work, wired into the page you're reading.

The rest of the workshop lives at codeberg.org/litozor, backed up to GitHub when it's working.

The way I work.

Five habits I keep coming back to in serious work. Each one is wired into the site you're reading: the column on the right is the receipt, pulled straight from the source. Open devtools any time and check.

№ 01 Systems

I build in rings.

I split a system into rings: the most important things in the middle, the optional things on the outside. You should be able to peel off any feature without breaking the core. This site is wired exactly that way: a tiny kernel at the center, mode renderers in the middle, optional features at the edge.

The bus doesn't know about modes; modes don't know about features; features don't know about each other. Coupling is what makes systems brittle; the boundary is where I draw the line.

assets/
├── kernel/    bus, router, mode
├── modes/     terminal · swiss
├── features/  indicator · snippets
│              banner · keys · sim
└── tokens/    palette + base
№ 02 Speed

Every byte earns its place.

I treat dependencies and code lines like ingredients: every one has to earn its spot. This site has no third-party libraries, no build step, and every file stays small enough to read in one sitting.

Constraints aren't about being a purist; they're how I keep the codebase legible six months later. First time I cut a feature to keep a file small, I realized I didn't need it. Fast is a side-effect of small.

deps
0
files
16
longest
149 lines
average
61 lines
fonts
system
build
none
№ 03 Craft

Source is the product.

Open devtools right now. The HTML, CSS, and JavaScript you'll see is the same code I edited. No compiler in between, no Shadow DOM hiding things. Every file opens with a short comment naming what it's for, what it depends on, and what it deliberately won't do.

The reader I'm writing for is a senior engineer poking around for ten minutes. Comments explain why something is the way it is; names handle the what.

/*
 * mode-manager.js - owns <html data-mode>.
 *   Wraps swap in a View Transition with
 *   reduced-motion fallback. Emits 'mode:change'.
 * Dependencies: ./event-bus.js
 * Invariants: data-mode set inline before paint.
 * Non-goals: no UI; no scheduling.
 */
№ 04 Proof

Numbers over adjectives.

"Faster" is unfalsifiable. "P99 dropped from 412ms to 89ms after dropping the N+1 query" isn't. When I claim something about performance, I want a number behind it and a script that reproduces it. Otherwise the optimization didn't really happen.

This site has a budget too: the table on the right. They're not impressive numbers, just ones I picked on purpose and then held myself to.

metrictarget
first paint< 100 ms
transfer< 50 KB
CLS0
INP1 frame
fontssystem
№ 05 Care

Code is for the next reader.

In three months I'll read this code as a stranger. Header comments, honest names, and notes about why are the breadcrumbs I leave for that stranger.

Files stay small enough to hold in one head. When a file gets fat, split it; don't compress it.

/*
 * file.js - one-line purpose.
 * Dependencies: ...
 * Invariants: ...
 * Non-goals: ...
 */
Patterns

Habits I keep coming back to.

Things I tried and dropped.

Six decisions on this site that lost. The version that shipped is better because of the version that didn't.

  1. Separate tags per mode.

    First sketch had <terminal-header> and <swiss-header> as distinct elements; the router would swap tags on mode change. Killed it the first time I switched modes mid-interaction: swapping tags throws out the DOM node, so focus, scroll position, and any in-flight transition reset with it. Now there's one <site-header> shell and a per-mode renderer registry; the element survives the swap, only its innards change.

  2. One renderer with if (mode === ...) branches.

    Considered a single mode-aware function per shell. Dropped it because adding a third mode would mean editing every renderer: modes coupled through every shell. The registry inverts that: each mode owns its own file and registers itself. (Adding Blueprint mode later is a new file, not a sweep through old ones.)

  3. Shadow DOM.

    The obvious choice for custom elements. Pulled it out anyway. The page told one story and devtools told another, and the thesis of this site is that the source is the product. View-source has to match what's actually rendering. Renderers now write straight to host.innerHTML.

  4. A Proxy-based observable store.

    Started sketching one for cross-component state and stopped about thirty lines in. The actual need was "late subscribers should see the current value." The event bus solves that in forty lines by replaying the last published value to new subscribers in a microtask. (The fancier option was solving a problem I didn't have.)

  5. Mode from prefers-color-scheme.

    The first cut had no toggle: read matchMedia and pick terminal or swiss off the OS theme. But the modes aren't dark vs light; they're different readings of the page, which the OS theme doesn't control. A ?mode= URL param came next: shareable, but it doesn't survive a click to the next page and clutters every link. Now an explicit choice persists to localStorage, and an inline <head> script replays it before first paint so the switch never flashes.

  6. Project content as a JSON manifest.

    Card data started as one content.json: title, summary, tags, body as an HTML string. Editing prose inside JSON strings is miserable, so I tried the other direction: a markdown file per project with frontmatter and a hand-written parser, ~90 lines, not CommonMark. But for the dozen hand-curated cards this site actually has, that meant a loader, a parser, and a content/ tree standing between me and a list that fits on one screen. Dropped the whole pipeline. Each project is now plain HTML in the page, and Ctrl+U shows the card exactly as written.

At scale

Where I've put this to work.

If a team treats the work like this, I'd love to talk. About · linh@lelinh.dev · codeberg.org/litozor · GitHub (backup, when it's working) · LinkedIn