Work
Things I've made.
A product I ship and run, a real-time 3D editor and runtime I am building in Zig, and a workshop of small tools I wrote because I wanted them to exist.
Running in production.
-
When.
When. is a period tracker that writes into the calendar you already have open, whether that is Google, Notion or CalDAV, so there is no second app to remember to check. You log the day a period starts, and from a few of those it works out the shape of your cycle and puts each predicted phase on the calendar as an ordinary event you can see next to everything else in your week. Because the calendar is the only place anything is kept, we never hold cycle data ourselves, and that single constraint went on to settle almost every architectural question that came after it. The whole thing is TypeScript and is server-rendered with Preact, which gives us React's component model and hooks for a fraction of the bytes a server-rendered page would otherwise have to ship. Anna and I created it together, and I run it end to end.
getwhen.net · live · €4/mo after a 14-day trial -
Self-hosted stack
Around twenty services run on a machine in my flat, covering photos, files, music, documents, media and search, and between them they replace most of the subscriptions I would rather not keep paying for. Every service runs as a rootless Podman container behind Caddy, which puts a real name and HTTPS in front of each one instead of a port number, and the only route in from outside the house is a Cloudflare Zero Trust tunnel, so nothing sits on a public hostname waiting to be found by a scanner. Restic takes care of the backups on a timer. The whole setup is a bootstrap script and a compose file per stack, which is what makes it something I can rebuild on a new machine rather than a box I am afraid to touch.
podman · caddy · zero trust · restic
A real-time 3D editor and runtime, in Zig.
This is an editor and a runtime sitting on top of a Vulkan renderer, both written in Zig. You build a scene visually, placing entities and their components and adjusting them through an inspector alongside the lights, meshes, physics and UI, and the result serialises out to a .zon file. A separate runtime then reads that file back and drives the whole application from it without containing a single line of code specific to the scene, so the data is what describes the application while the runtime stays entirely general.
There are three executables built over one shared engine module and a single entity-component-system world: the editor itself, the generic runtime, and a scene wired up by hand that exercises the render and interaction paths an empty scene would quietly leave untested. It is the closest thing I have to a hard real-time problem at the moment, because a frame budget, a GPU and a compiler all have to be satisfied at once and none of them will negotiate. It is also the codebase my model fleet works against, which means the verification step runs against a real compiler instead of a benchmark that was designed to be passed.
Private while it's in progress.
Small tools, written to be read.
-
baker
baker is a static site bundler and HTTP server that compiles down to a single Zig binary with nothing else to install. It bakes an entire site into one
Zig.binfile and then serves straight out of it, handling Brotli and gzip compression, ETags and 304 responses as it goes, and it will pick up a freshly baked site on a SIGHUP without the process ever going down. -
zremdic
zremdic is a key-value cache written in Zig for latency rather than for features, and it speaks UDP so that a lookup costs exactly one datagram in each direction. The store is sharded with one worker per core, and the atomic operations give you exactly-once semantics on top of a transport that promises nothing at all, along with TTLs and LRU eviction. On loopback it holds about 210k operations a second at roughly 19μs. It is a cache rather than a database, so values live in memory only and a restart starts you over.
Zig · ~210k ops/sec -
zhecs
zhecs is an entity component system small enough that you can read the whole of it in an afternoon and come away knowing how it works. Components are ordinary Zig types and there is no registration step to remember, while entities that share a set of components are stored together in contiguous columns so that iterating over them stays friendly to the cache. Systems run in ordered phases, and a million entities step in about 19 ms per chunk.
Zig · 1M entities -
swr
swr renders HTML inside a SharedWorker, built on top of ssw. Views are just functions that return HTML strings, and because the render happens once in the worker and is then broadcast out to every open tab, output that has not actually changed is skipped rather than being sent on to repaint a tab for no reason. It comes with around 65 integration tests.
TypeScript -
ssw
ssw keeps state in step across every open tab without asking much of you in return. A SharedWorker holds the single source of truth while each tab keeps an optimistic mirror it can read from straight away, and the acknowledgements come back batched instead of one message at a time. It is around 3.5 KB gzipped, and the tests run against real MessageChannels rather than against a mock of one.
TypeScript · 3.5 KB -
wiki-art-downloader
wiki-art-downloader pulls an artist's entire catalogue down from WikiArt as JPGs. It needs Node 18 or newer and has no dependencies at all, it walks the eight CDN shards in parallel so a large catalogue does not take all evening, and it will show you a dry run before it writes anything or pick up a half-finished download by skipping the files it already has.
Node · zero deps
The rest of the workshop is at codeberg.org/litozor, mirrored to GitHub.
How the site is built.
The site is plain HTML, CSS and ES modules, with no framework, no build step, no bundler and nothing at all to install at runtime. Every JavaScript and CSS file stays under 150 lines and opens with a header setting out what it does and what it must never do, and a script in the repo checks both of those mechanically so that the rules cannot quietly rot as the site grows.
One set of pages carries two different reads of the same material. Brief is the short version and gives you the claims, the numbers and a way to reach me inside a single screen, while Deep puts back the architecture and the tradeoffs for anyone who wants to know how something was actually built. Both versions sit in the HTML at the same time, which means that with JavaScript turned off you simply get all of it.
assets/ ├── kernel/ bus, router, mode ├── modes/ brief/ · deep/ renderers └── features/ indicator, shortcuts, hints
Source: github.com/Linh35/lelinh.dev