How this site is built
standingwater.io has had a few lives. The first two were Gatsby sites: one started from an HTML5 UP template, then a playful, colorful version I built from scratch.
In May 2022, my dog Sky died. The day she passed, I sat down to write about her, and Gatsby's development server refused to start. I wrote the post anyway, pushed it, and hoped Netlify would build it. It did, but I was done fighting broken dependencies just to write. So I wrote my own static site generator, modeled on the wonderfully simple Sergey, and named it bluesky, after her. I started it in C, switched to C++ after two weeks of struggling, and by September 2022 this site was running on it.
I've been fascinated by parsers ever since I fumbled my way into
hand-writing them, with no idea what I was doing, to process texts for
anno.wiki. In 2023 I had an
idea for a language: C, plus the smallest possible version of classes.
Structs get methods, and . and -> mean the
same thing. I called it c′ (c-prime: the derivative of C, so its files
end in .dcdx).
I always meant to build it myself. I read Crafting Interpreters, and bought Engineering a Compiler and the dragon book. I spent a year wanting to learn compilers and performance properly, and yak shaved my way into the math underneath it all with cheap experiments instead of just focusing on compilers. Then I got nerd sniped by epic poetry and learning Latin, and the compiler books stayed on the shelf.
In 2026, after spending a lot of time using Claude Code for some new personal experiments and projects, on a lark I asked Claude to try building c′.
cprime, a c′
compiler forked from Rui Ueyama's
chibicc that now compiles
itself (the receiver ended up being called ego).
What a let down. Here's a Hello, World:
#include <stdio.h>
struct Greeter {
char *name;
void greet(void);
};
void Greeter.greet(void) {
printf("Hello, %s!\n", ego.name);
}
int main(void) {
struct Greeter g = {"world"};
g.greet();
return 0;
}
From there I thought, let's get it self-hosting! No sooner asked than done. Then let's rewrite bluesky in c′! Et voilà : skyblue, a rewrite of bluesky in c′ 😞. (Jack Dorsey took bluesky out from under me! 🤬) No matter, her name actually was Sky Blue Sendker. But once that was done, all that was left was for it to rewrite standingwater.io in skyblue.
🫲 Atque ecce. 🫱
This is all very bittersweet. A mountain of effort in 15 minutes to get the thing I dreamed of for 3–5 years. But we're all figuring out what we're good for these days. You can see some of my new projects on the projects page. AI assisted projects are clearly marked.
So anyway, today this site is built by skyblue, which is compiled by cprime, which bootstraps itself from C on every deploy to Netlify via GitHub. Here's what's under this paragraph, from the top down. skyblue pulled each excerpt out of the real source when it built this page, and the button at the top lifts the page off the files it was made from.
-
the template src/_imports/main.html
<main class="page"> <sky-slot name="content" /> </main>This paragraph is in the
contentslot of the site's main template. -
skyblue, in c′ skyblue/src/render.dcdx
void Render.slot(Node *node) { if (!ego.slots) { node.loc.warn("<sky-slot> only has a value in a template"); return; } Slot *slot = ego.slots.get(node.name); if (slot) { slot.used = true; ego.out.push(slot.html); } }skyblue fills the slot with this method.
egois theRenderit's called on. -
cprime, in c′ cprime/parse.dcdx
Member *Type.method(Token *tok) { if (ego.kind != TY_STRUCT) return NULL; for (Member *m = ego.methods; m; m = m.next) if (m.name.len == tok.len && !strncmp(m.name.loc, tok.loc, tok.len)) return m; return NULL; }ego.slots.get(…)is a method call, and this is how cprime finds the method. The compiler is written in c′ too. -
cprime's stage 0, in C cprime/bootstrap/parse.c
static Member *get_method(Type *ty, Token *tok) { if (ty->kind != TY_STRUCT) return NULL; for (Member *m = ty->methods; m; m = m->next) if (m->name->len == tok->len && !strncmp(m->name->loc, tok->loc, tok->len)) return m; return NULL; }The first cprime is compiled from a frozen copy written in plain C. Here's the same function, before c′.
-
bedrock build.sh
#!/bin/bash # Netlify runs this (see netlify.toml). skyblue is written in c′, so build # the compiler first; it bootstraps from C, so only cc and make are needed. set -euo pipefail git submodule update --init make -C cprime make -C skyblue ./skyblue/skyblue -i src -o buildNetlify runs this on every push:
ccbuilds stage 0, stage 0 builds cprime, cprime builds skyblue, and skyblue builds this page.