Projects

Things I have built or am building. The unbuilt ones are at the bottom, still arguments.

Airbnb analytics pipeline

personal build, on GitHub

The kind of data system a real company runs, built by me from scratch on Airbnb listing data: messy data in, clean layered tables out, with history preserved.

The technical version

dbt + Snowflake. Medallion architecture from bronze to gold, incremental models at every layer, slowly changing dimension snapshots, and custom Jinja macros.

Movie-ratings warehouse

personal build, on GitHub

Most company dashboards sit on the same classic blueprint for organizing data. I built that blueprint from scratch, end to end, on movie-ratings data, with the tools companies use today.

The technical version

MovieLens data as a Kimball star schema in dbt + Snowflake: dimensions, facts, marts, SCD2 snapshots, documentation.

Machine learning projects

public, on GitHub

Earlier builds from my machine-learning training: predicting customer churn and hospital readmissions, finding language patterns in tweets, and clustering countries by development indicators. Built before AI wrote the code, which I am told counts for something now.

The technical version

Python, pandas, scikit-learn. Classification with threshold tuning and documented precision-recall trade-offs (churn, readmission), NLP text analysis (tweets), and unsupervised clustering (world indicators).

Superflip

live, playable in the browser

A Rubik's-style cube you solve from the keyboard, one key per turn. It scrambles itself the way a competition does, starts the clock on your first turn, stops the moment the cube is solved, and keeps every solve so you can watch yourself get slower under pressure. No account, no server, nothing leaves your browser.

The technical version

Vanilla ES modules, no build step, three.js vendored. Cube state is integer permutation math with no DOM in reach; the renderer runs behind the model and collapses queued turns under load, so input latency does not depend on the frame budget and the renderer cannot corrupt a solve. Solved-detection is exact up to whole-cube rotation, so the clock stops on the turn that finishes the solve rather than the turn that happens to match a canonical layout.

Scrambles are WCA random-state, the competition standard, from cubing.js, with a local fallback that labels itself when the module does not arrive. Averages follow the WCA trimmed rule with DNF semantics carried through Ao5, Ao12 and best-average records. Two keyboard presets, every action rebindable and persisted, JSON export and import, and every solve kept as a full move log in standard notation with per-move timestamps. 162 assertions cover the move algebra, the averages, and the real modules in a real browser.

The source is public and MIT licensed: the repo.

This website

you are looking at it

Hand-rolled HTML, CSS, a little JavaScript for the theme switch, and a cube on the home page that wakes up on request (a 3D library loads only if you poke it). No frameworks, no tracking. Four designs were built and argued over by AI reviewers before one won. There is also a version of this site written for AI agents: llms.txt.

How it was made

Designed by me, code written with Claude as the pair; every line read before it shipped. One shared HTML structure, competing stylesheets, adversarial review rounds on every word of copy, and an automated check that blocks anything that should not be public. The motion went through the same reviewers; most of it did not survive.

The source is public, in case any of that sounds like a claim: the repo.

Morsel

concept, unbuilt

A rating app where the unit is dish times restaurant, not the restaurant. "Best pani puri in Dallas" should be an answerable query; a restaurant's 4.2-star average is noise at dish level. Survived three rounds of AI reviewers trying to kill it, revised each time. Not building it yet.

Should I build it? Tell me.