Hi 👋

I'm Michael Sendker, a software developer from The Other Bay Area (Tampa Bay).

I find the pain points in how companies build and test their software, and engineer them away. If you want to know more about me, check my about page, or look through my projects.

If you want to see about hiring me, and my one man developer agency Standing Water LLC, please email me: m at standingwater dot io.

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′.

Five minutes later...

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;
}
cprime/examples/hello.dcdx

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.

  1. the template src/_imports/main.html

            <main class="page">
              <sky-slot name="content" />
            </main>
    

    This paragraph is in the content slot of the site's main template.

  2. 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. ego is the Render it's called on.

  3. 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.

  4. 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′.

  5. 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 build
    

    Netlify runs this on every push: cc builds stage 0, stage 0 builds cprime, cprime builds skyblue, and skyblue builds this page.