Two days ago — Monday, the 10th of August — I launched Expressed on Product Hunt. If you want to know my state of mind that morning, read the commit log: no features, no fixes. Just session-length metrics and Grafana dashboards. After 291 days I was finally asking the question that mattered: is anyone using it? — so on the biggest day of the project I built myself a scrying pool and started staring into it.

I had already answered a different question months earlier. End of November I ran interviews; the idea was useful - but to whom, and how useful? So I decided to validate — and in the same breath decided that validation would only touch the idea. The features had to be fully production-ready before anyone saw them. That is distinctly not does it work? It is ship a finished copy, and it made for a much longer journey than I expected. In retrospect, that was a weakness of the whole plan. Build in public would have been the better choice.

The 291 days before that were, honestly, a campaign. There is a hero, allegedly me. There are 11 waypoints on the main road, 22 side quests (14 of them failed), and ten named monsters — five slain, five still out there. So instead of writing it up as an essay, I drew it as the map it always was.

Pan the map. Walk the road. Tap anything that looks dangerous. The joy in here is real, and so is the doubt — neither has been sanded off.

Nthe quiet winterthe three disastersthe codec minesa door marked “maybe”launch · 10 aug 2026how to read this map● a waypoint on the road (tap it)×a road that ended · ▲ abandoned campsthe green road is treasure carried homethe serpent is still down there

Pan sideways on a phone · tap any dot or label to travel there

Session Zero

23–25 October 2025 · 113 commits in the first week

A constitution, then a Host that grabs frames.

Open the journalwaypoint

The first real commit of the campaign is constitution.md — I literally began by writing a constitution. Within two days there was a party: a Host process, a separate CaptureWorker to grab the screen, and soon a separate OverlayWorker to draw on it. Viewing happened in a native desktop app. It all felt very correct, very architected.

Almost everything on this opening screen — the multi-process party, the native viewer, the framework choices — dies somewhere further along the road. I didn't know that yet. That's what the map is for.

The Framework That Lasted a Weekenddead end · 1 day

The viewer client was born on WinUI on October 24th. On October 25th its project file was renamed wholesale to WPF. One day from this is the client framework to it isn't — the fastest reversal of the whole campaign, and a gentle tutorial-level preview of the next nine months.

The Long Dead Roaddead end · 128 days too many

The native viewer client — the WPF app people were supposed to install to watch a session. It was made functionally obsolete on 22 November 2025, the day the web viewer reached feature parity. I deleted it on 30 March 2026.

That is 128 days of carrying a dead party member and telling myself it might still be useful. When the doubt hits — and it does — surely I could have taken a better path isn't a rhetorical flourish. There are 128 days of evidence sitting right there in the log. On the map this is the faint road that keeps going long after the party stopped walking it.

The Browser Wins

25 October – 18 November 2025

Ink over the screen; the viewer quietly moves into the browser.

Open the journalwaypoint

November was the first real dungeon, and it paid out the first real treasure. Annotations arrived — ink over your live screen, drawn by viewers from a browser. And on November 22nd came the quiet, pivotal moment of the entire campaign: the web viewer reached feature parity with the native client. The web version worked. Nobody would need to install anything to watch a session. From that day, the browser was the product's centre of gravity — even though (see the dead road above) I kept the native client on life support for four more months.

The Second Front Doordead end · 24 hours

A standalone web-client project, created October 30th, deleted October 31st. The idea was right and won completely — the packaging was wrong and died in a day. The browser path would live inside the Host itself, not as a project of its own.

The .NET 10 Forge

19–27 November 2025 · rewrite № 1

“Just before I throw the old one away.”

Open the journalforge — burn it down

I celebrated the browser's victory by burning the server down. There is a commit from November 19th titled, in full:

Just before I throw the old one awayae661f4 · 19 nov 2025

— a snapshot taken the way you'd save your game before a boss room. I stood up a new .NET 10 server next to the old one, and within a day the old one was deleted. A week later: “Gigantic rendering / performance improvement.” The day after that, pen input was ripped out of Blazor and rewritten in JavaScript, because latency is felt in the hand, not measured in a benchmark. Pen drawing worked. Drawing on your own screen, live, while someone across the world watches the stroke land in their browser — that one felt like magic. It still does.

The Quiet Winter

December 2025 – February 2026 · 3 commits in two months

Fog, snow, no encounters. The doubt matures.

Open the journalwaypoint

Then: nothing. December produced two commits. January produced one. On the map this is a long, empty, snowed-in stretch of road, and it would be easy to cut it from the story — but it's where the next decision grew. Back in November I'd left myself a note that the worker-process structure was asymmetric: a polite way of writing I think the party is wrong. All winter that doubt sat there. In February, it hatched.

One Process

18 February – 2 March 2026 · rewrite № 2

The party of three becomes one character with all the classes.

Open the journalforge — burn it down

The separate Capture, Overlay and Server processes were folded into one app. The workers became libraries; their executables left the building. The multi-process architecture I'd so carefully constituted in October — deleted, in the largest structural rewrite so far. This is also where MSIX packaging appeared and the downloadable client binaries came off the Host: the shape of the real product, emerging by subtraction.

☠ The Adaptive Oozemonster · slain after 134 days

Born here: a self-tuning capture-quality controller that measured throughput and adjusted itself. Clever, alive — and it slowly spread its assumptions into capture, display, telemetry and tests until nothing around it could be reasoned about. It survived 134 days. When I finally disabled it as an experiment in July, the whole organism turned out to be replaceable by two static numbers: a relay upload ceiling and a recording FPS floor. Four and a half months of adaptive machinery, beaten by two constants. I wrote it a death certificate (ADR-0033) and mopped the floor.

The Relay and the Code

March 2026 · 241 commits — the busiest month of the campaign

An outbound tunnel, six digits, and a word repeated three times.

Open the journalgate

March built the topology the product still runs on today: the Host dials out through a tunnel, a Relay in the cloud issues a six-digit code, and viewers reach the session with that code and nothing else. No firewall incantations, no downloads. Waystations followed over the months — Sydney, then Europe, then the US — and in fairness the relay line is the only quest in the whole campaign that never once went wrong. It just kept adding waystations.

The gate condition was darker: the native client had to actually die before this topology made sense. Both happened this month.

☠ The Trihydramonster · victorious, still alive

Over four days in late March, three separate branches attacked the operator UI — a React client, a “new UI”, another React attempt. All three are still in the repository. All three end with a final commit whose entire message is one word:

Disasterfeature/react-client · feature/new-ui · feature/react-ui — three branches, three tombstones, march 2026

Three heads, three attempts, three identical last words. The monster won. The WPF shell it was guarding is still the operator UI today.

Building the Waystationssuccess · never a setback

Sydney first, then configurable relays, then dynamic ones, then AU / EU / US1 by launch. Included here mostly as proof that one quest line can just… go well. It's the only one that did.

The Platform Split

15 April – 13 May 2026

Cut the codebase three ways; build a road to the Mac.

Open the journalwaypoint

The codebase was cut into a portable core plus native shells per platform — and then the Mac version happened in one furious week in late April: screen capture, overlay, the lot. The first architecture decision records were written the moment the Mac forced real decisions. The lesson of this era, learned the hard way from the chimera below: don't unify platforms. Split harder, and share the middle.

The unfinished rope: the Mac still can't record a movie. The bridge is built; the last plank isn't. It's the single largest known gap in the product, and it's still on the horizon roads today.

☠ Maui, the Two-Headed Chimeramonster · slain

It promised one body for every platform. One head was a phone app that would find your session over Bluetooth so nobody had to type the code — it lived thirteen days, until I admitted that typing six digits was never the problem. The other head promised a single host binary for Windows and macOS; it never even merged. Both heads cut. The winning move was the exact opposite of what the chimera sold.

Recording is Invented

7–31 May 2026

The product grows a second job: not just showing your screen, but keeping it.

Open the journalgate — opens the mines

A recording library was carved out of the core, and the operator finally got a proper Session Control window. The UI redesigned itself twice in a fortnight — a sharing carousel shipped and was thrown away four days later for a flat pane. The commit that introduced the carousel ends in a question mark:

This puts the control into the carousel. Does this work?e1589a9 · 26 may 2026 — four days later, the answer was no

Small experiments died fast here: auto-start recording when sharing (recording someone without them pressing record is a feature exactly once), a separate stroke-mirror layer for the movie (two sources of truth about where the ink is — capture already had it), a media-server sidecar for live pixels (the relay got a frame cache instead). And one experiment didn't die small: this gate opens the single longest, deepest quest of the campaign. Keep walking.

⛏ The Codec Mines

14 May – 11 July 2026 · 58 days underground · the deepest shaft on the map

Six complete encoder architectures, built and thrown away. The seventh stuck.

The descent — six abandoned campsepic

Every camp on the way down was honestly better than the one before it. None of them was right:

  • Camp 1 — record everything, encode at the end (the user waits at the end)
  • Camp 2 — zero-copy GPU spike (a dream, parked; it comes back later)
  • Camp 3 — thousands of PNGs fed to ffmpeg (thousands. of PNGs.)
  • Camp 4 — raw video piped to an external ffmpeg.exe (an .exe the user must download)
  • Camp 5 — smarter pipe, honest frame rate (still a subprocess)
  • Camp 6 — everything in-process, bundled libraries, no download. SHIPPED.

On June 10th the whole thing moved in-process, audio joined the movie, and the commit from the next day says it with more honesty than I could fake:

That is a LOT of work - but worth it, the audio is now processed correctly, auto-balanced with desktop/background and we no longer require any download22f2668 · 11 jun 2026

Video recording finally, finally worked. By July it even did zero-copy encode on NVIDIA hardware — frames going from screen to encoder without ever touching the CPU. There were weeks where I'd have told you that was a fantasy.

The mine's bestiary — three audio monstersall slain

The Silent Loopback — recordings with no sound at all, because the mixer waited forever for a silent desktop to produce audio that was never coming. Slain by making the mixer drive time itself.

The Drifting Soundtrack — audio and video, never quite together. Slain, and a golden test now stands over the grave so it cannot silently return.

The “Preparing Recording…” Hang — the same three words on screen turned out to be two completely different bugs, months apart. One of them I blamed on the encoder for weeks. It was never the encoder.

☠ The Final Boss: the Semaphore That Never Signalsmonster · routed around, still alive

When a catch-up encode finished and the NVIDIA hardware encoder was disposed, the dispose would sometimes never return. Not slowly — never. Native stack walks all ended in the same place: deep inside the driver, waiting on a kernel semaphore with a count of zero that nothing would ever signal. Only the driver could release it. It never did.

I attacked it six times. The casualty list:

  1. Flush before finalize — doubled the hang rate
  2. Shared graphics device — 60% pass
  3. Shared device + aggressive GC — 80%, still flaky
  4. GPU event-query drain — no better than baseline
  5. Full by-the-book teardown — worse than the GC hack
  6. Push the watchdog deeper — broke back-to-back recordings

Six broken weapons on the floor in front of a boss whose health bar hadn't moved. The turn came when I identified the blocking object for what it was: driver-owned, kernel-mode, shared across sessions. No user-mode spell would ever release it. The fight was unwinnable on its own terms — so I stopped fighting on its terms. The movie is fully finalized before the encoder is ever disposed; a three-second watchdog ships the finished file and walks out of the mine while the encoder stays wedged behind us; the catch-up path retreats to software encoding entirely. Ten out of ten on the regression harness.

Six architectures were thrown away in this quest and every one was replaced by something better. This monster is the only problem in the entire campaign that could not be solved by building a better thing. It is still down there. The XP came from refusing the fight.

In-Proc, In Tune, Renamed

9–30 June 2026

The mines pay out; the product changes its name mid-campaign.

Open the journalwaypoint

The recording quest returned to the main road carrying its prize, and the relay learned to cache frames instead of pushing them naively. Then the product renamed itself: 2Reflect became Expressed — new name in the code, the DNS, the UI. Except the Microsoft Store package identity is immutable, forever, and the git repository still carries the old name. The rename is permanently 95% complete. The hero changed his name mid-campaign and the world's ledgers will always remember the old one. I've decided to find that funny.

WGC Only, and a Price Tag

1–19 July 2026 · rewrite № 4 · versions 0.2.37 → 1.0.10 in four days

Capture is rebuilt; the product learns to charge.

Open the journalforge — burn it down

July rewrote capture and invented the commercial layer at the same time. A whole GPU capture subsystem was built on July 5th and deleted on July 8th — a three-day kingdom — in favour of one capture path to rule them all. The Adaptive Ooze was finally put down the same week. Licensing, a free tier, tier limits and a first-run tour all landed in a single fortnight, and the version line sprinted from 0.2.37 to 1.0.10 in four days. The product was suddenly, unmistakably, a product.

A Door Marked “Maybe a Different Game”open · never merged

Mid-July, a two-day experiment: crop a recording down to a clip. The commit that opens it asks the real question out loud — “I'm still not sure if this should be a separate product, so trying it out.” The branch was parked, eight commits ahead, and hasn't been touched since. On the map it's a treasure chest sitting at the end of a road nobody finished walking: a little door into what might be a different game entirely. It's still closed. For now.

The Summoned Partysuccess · a working method

Six machine-named branches appear in two bursts in July, each carrying exactly one ticket — several AI agents attacking the same task in isolated worktrees, best result merged, the rest left where they fell. Three merged, three abandoned. Not a feature: a way of working. Summoned figures walking beside the party, half of whom fade.

The Tollgatebuilt — then opened

Five weeks building freemium enforcement. Then, on August 9th — one day before launch — the decision the previous post is all about:

Free almost same as pro - going with pure validation stage to begin with1c88b13 · 9 aug 2026

I built the tollgate and then wedged the barrier open, because with zero users the only question that matters is whether anyone finds the road worth walking at all.

Go Live

2–10 August 2026 · launch: Monday, Product Hunt

Three relays, an endcap on the movie, and a scrying pool.

Open the journalwaypoint · you are here

The last stretch: session auth rewritten to fix multi-client reconnect, a third relay region, the last traces of the old name scrubbed from DNS, Product Hunt images checked in, and the recordings got an endcap — a closing card on the movie, a small bow on 58 days of mining.

And then launch day itself, when the only commits are metrics and dashboards. Because the question had changed, and I knew it.

☠ Still out there — the surviving bestiary5 of 10 monsters alive

🐉The TDR Wyrm — eats the display driver when a session ends. Four crash dumps, same address, every time. The app survives it every time; the driver does not. Undefeated. Documented, tolerated, circling the map's edge.

👻The Fluent Revenant — someone else's bug, living in this process (a known WPF framework issue). Can't be killed from inside this repo; there's a ward chalked on every dispatcher door instead.

The Poison Pill — a licensing state that remembers you were unlicensed and re-seeds itself on restart. Documented and navigated around, not fixed.

The Semaphore — still at the bottom of the mines, wedged, walled off, walked past.

🐍The Trihydra — technically victorious. The operator UI it defended is still WPF, and a plan to storm it again someday sits written at the edge of the map.

291days
1,221commits
22side quests · 14 failed
10monsters · 5 still alive
6encoders thrown away
12projects created & deleted
4complete rewrites
18branches left as tombstones

Two days later

The launch was Monday. Today is Wednesday. The dashboards are live, and I look at them more often than I should. Will it really find traction? I don’t know. Nine and a half months — and I’m only at “validate”? That thought arrives most days around coffee, and the 128-day dead road and the six discarded encoders nod along helpfully from the log. I’m genuinely not convinced yet that this isn’t just a fancy idea I happen to love — I shipped it free precisely because that’s the fastest way to find out.

A campaign journal is supposed to end with the dragon dead and the treasure divided. This one ends with the party standing outside the dungeon in daylight, honestly not knowing whether anyone will visit the place they spent 291 days building. What happens next isn’t mine to write. It belongs to whoever does — or doesn’t — show up.

If you want to be part of that: Expressed Starter is free, on Windows — draw on your screen while others watch from a browser, and record the whole thing. Run a real session and tell me whether it survives contact with your world.

The dice are out of my hand. They’re still rolling.