3ep.dev

One site instead of four

I have been meaning to build this for a while. My small apps kept accumulating domains: Yetly had one, Chalk was about to get one. Each of them wanted a landing page, a privacy policy and terms of use, and I was maintaining four separate static sites to say roughly the same thing four times.

So everything moved here. Each app gets a folder, its own page, and its own paperwork, and I get one thing to maintain.

The whole publishing pipeline

Adding a post is writing a markdown file:

---
title: "Post title"
date: 2026-08-13
summary: "One line for the list and the RSS feed."
draft: false
---

Then a commit and a push. That is it. There is no CMS, no database, no admin panel, and no login page whose password I would inevitably lose. Git already does versioning, review and history better than anything I would have bolted on, and the one feature every CMS advertises, “edit from anywhere”, turns out to mean “edit from anywhere you happen to have your laptop”, which is where I was going to write from anyway.

Apps work the same way. One markdown file per app, some structured frontmatter for the screenshots and the pricing, and the body is the prose. Setting draft: true keeps a half-finished one visible while I am working and out of the build when I am not, which is where Chalk’s page lived until it was ready.

The site is Astro, which ships no JavaScript unless a page asks for it. Most of these pages ask for none.

Rules I gave myself

The brief was “not AI slop”, which is easier to say than to enforce, so it turned into a list of specific things I was not allowed to do.

No fake terminal chrome. No boot logs, no traffic lights, no $ ls empty states. I like the structure of an operating system, the sectioned paths and the screen-printed panel labels, but the costume version of that idea has been done to death.

No status dots. At one point this site had a pulsing green “available for a chat” indicator, which is both a lie and a cliché, and it was the first thing to go.

No control that does not work. An early version of the player had a beautiful synthetic waveform and a duration that read — : —. It looked great and it was completely fictional, so it got deleted. If something is drawn on the page, it does something.

There was also a city clock at the bottom for about an hour. We do not talk about the city clock.

The part I actually enjoyed

The /sound section has a player, and I did not want the usual bar graph bouncing to nothing in particular.

What is drawn is a flow field. Particles drift left to right, and the vertical push on each one is the energy of the track in the frequency band at that particle’s own position. The filaments they leave behind are the real spectral shape of the song. Change the audio file and the picture changes with it, because there is nothing decorative in the loop.

The first version computed all of that in the browser, which was fine for the 24-second placeholder I was testing with and a genuine problem for a real 2:42 track, because it downloaded and decoded all 3.9MB before drawing a single pixel. So the analysis moved to a build script, and the page now loads 31KB of precomputed frequency bands. The song itself only downloads if you press play.

There was one more thing wrong with it that I only noticed because someone pointed at the screen: pausing changed the picture. Playing accumulated trails frame over frame, while pausing cleared the canvas and redrew bare dots, so the two states were two different images made by two different code paths. They are one code path now, and pausing just stops calling it.