Zoroaster

Researcher & developer

A model that reads English Wikipedia's edit history and tries to call what the world does next, as a dated prophecy published every night.

The first stage ranks pages. Trained on 133 million revisions across 9.7 million pages — three years of edit history, some 22GB of dumps streamed a page at a time so memory never depends on the size of the corpus — a gradient-boosted model scores every recently edited page by how likely it is to burst tomorrow: far more edits than usual, from at least two separate editors. On the held-out months 74 of its top 100 pages drew a lasting edit the next day, against 58 for the best simple rule, and in a live backtest about one in five of each day's top 100 burst as predicted, twice what ranking by yesterday's edit count manages. Every feature is strictly point-in-time, computed from days before the one being scored — a rule worth a test of its own, since an early version leaked the future through its burst scores and flattered itself nicely.

The second stage writes. Qwen2.5-0.5B and 1.5B, fine-tuned with QLoRA on a single 8GB card, learn to produce the text an edit actually inserted, given the page, the date, and which of its linked pages were bursting the day before. Fine-tuning cuts the perplexity of real inserted text from 15.6 to 6.6 at the smaller size and 5.3 at the larger. The useful negative result: what helps is the neighbouring page's name — a singer's page gaining "She performed at the 2026 Winter Olympics opening ceremony" — while summarising what actually changed on that neighbour adds nothing measurable.

The site is the part that can be wrong in public. Each night a 7B model reads the day's top pages and the week's stories from Wikipedia's current events portal as they stood at midnight, resolves every date relative to the day ahead, and writes at most ten dated predictions. Guardrails drop any that name an individual, that have an organization doing or suffering harm, or that merely restate their evidence; one that invents a number its sources never gave goes back to be rewritten. Everything is labelled a machine-generated forecast rather than news, a judge grades each prediction on its due date (not yet published, while it is checked against hand grades), and a "how the prophet works" page shows the ranked pages beside how the previous day's list actually turned out.

  • Python
  • LightGBM
  • PyTorch
  • QLoRA
  • Parquet

Read today's prophecy Source

The Zoroaster home page: five dated predictions under a machine-generated-forecast disclaimer The pages ranked likeliest to burst, with probabilities and how the previous day turned out

Novateria: The New World

Game designer & developer

A party-based, turn-based RPG set in a fantasy version of the colonial New World — and the largest game project I have taken on.

Novateria follows a company of adventurers across dangerous, half-mapped territory in search of a lost colony. It takes its cues from Divinity: Original Sin and Baldur's Gate: you control up to four characters at once, and combat is turn-based with a deep pool of items and abilities.

The project is in active development in Unity. I am looking for volunteers on every front — art, code, and design — so get in touch if you would like to be part of it.

  • Unity
  • C#

Project site

Stele

Designer & developer

A handout generator for tabletop games. Type your text, pick a material, and get back a weathered inscription or an aged document — chipped marble, scorched paper, faded runes.

Start from a medium — marble, sandstone, granite, slate, clay tablet, bronze plaque, wood, paper, parchment, papyrus — then choose a colour, a shape, and a hand to write in, anywhere from Roman capitals and blackletter to copperplate, typewriter, runes, and cuneiform.

The damage is the point. One dial ages the whole piece, or you can layer specific kinds: chips, cracks, lichen, verdigris, burns, water stains, ink blots, tears, folds. Fade eats into the writing itself, and a brush lets you paint wear exactly where you want it. Wrap words in [[…]] to mark them for destruction or {{…}} to keep damage off them, so the unreadable parts of a handout are the parts you chose.

It all renders in the browser: the weathering is GLSL shader work over a WebGL canvas, with no image library and no server behind it. Finished pieces export as 300 DPI PNGs — transparent, if they are headed for a virtual tabletop — or as multi-page ZIPs, full-size PDFs, or a shareable link.

  • TypeScript
  • WebGL
  • GLSL
  • Vite

Try it Source DM Tools shelf

The Stele editor, with a carved marble epitaph beside its controls A burnt, water-stained letter generated by Stele, with part of the text lost to the flames

Jabberwock

Designer & developer

Lorem ipsum for tabletop games: filler text in real and invented languages that looks and sounds like the genuine article and means absolutely nothing.

Pick a language — English, French, Latin, Welsh, Finnish, Old Norse, Old English, Enochian — or a fantasy one: Elvish built out of French, Dwarvish out of Old Norse, Orc out of its own sounds. Apart from real English and French, every word is invented, but the text keeps the rhythm, the punctuation, and the little everyday words of the language behind it, so it reads as that language to anyone, including someone who actually speaks it. Middle English and Shakespearean English keep whan, quod, thou and hath real and invent everything else, which is the trick Jabberwocky pulls.

Ask for prose, a conversation between two to four speakers, an inscription, or a page of names. Any of it can carry a respelling under each word for reading aloud at the table — lay-RAHN — or IPA, and every language comes with a note on how to voice it. The browser will read it out loud if you would rather it did. Everything comes from a seed, so the same settings give the same passage and a share link recreates it exactly, and each language keeps its vocabulary from one session to the next.

You can rename the languages for your own setting, or build a new one from scratch — its sounds, how they form syllables, where the stress lands, how it is spelled, whose rhythm it borrows — with sample words updating as you turn the dials. Settings and languages save to a file or travel in a link. Finished text opens straight into Stele to become a weathered handout, and every source text it draws its flow from is public domain.

  • TypeScript
  • React
  • Vite

Try it Source DM Tools shelf

The Jabberwock generator with a passage of invented Elvish A Dwarvish inscription with a pronunciation respelling under every word

Sator

Designer & developer

Anagrams for tabletop puzzles: scramble a password, a name, or a clue, hand the players the letters, and make them work it back.

Scrambles come at a difficulty. Easy keeps the words and their first letters; medium moves every letter; hard runs the words together and parts old neighbours, so no two letters that sat side by side still do. They can be reshaped into a set number of words or a pattern of lengths like 3-4-3, and made pronounceable enough to read aloud — RATIONSESTARDARDISED… rather than NKLEEOESFIITTSARHOE… When the letters cannot do what you asked, because AAB has nowhere to put its second A, it says so and shows the closest it can manage.

It will also find phrases of real words that use every letter — DORMITORY gives DIRTY ROOM — out of a word list you pick plus any names from your own game, or help you write an anagram by hand, showing the letters still unused and the words that would fit in them.

Any line then becomes a puzzle. The card measures how much the clue gives away — letters left in place, old neighbours, pieces of the answer still whole — and lists the other answers the same letters spell, so you can decide which of them you would accept. Add a riddle, decide how many hints the players may take, then show them the clue in large tiles, send a player link that checks guesses without holding the answer, print tiles to cut up and scatter, or pass it to Stele to be carved in granite. The whole puzzle lives in the URL, compressed, so the page never spells the password out during a screen share and a puzzle built before the session comes back with the link.

  • TypeScript
  • React
  • Vite

Try it Source DM Tools shelf

Sator listing scrambles of the phrase SPEAK FRIEND AND ENTER A Sator puzzle card: the answer, the clue in letter tiles, a riddle, hints, and buttons to show or print it

Kart Racing Game

Game designer & developer

A browser kart racer through a procedurally generated world, written in raw WebGL with no game engine underneath it.

Everything runs in the browser and everything is built from the ground up: primitives, hierarchical modeling, Blinn-Phong lighting, texture and bump mapping, plus collision detection, kart physics, and particle effects.

Each level is generated with randomized terrain, trees, obstacles, orbs, road segments, and clouds. Clear a level and the next one raises the difficulty by scattering more orbs to collect and more obstacles to dodge.

  • WebGL
  • JavaScript

Play it Source

Interactive Graphics Demo

Programmer

A hands-on WebGL scene for poking at computer graphics fundamentals — every part of it is adjustable from the page.

The scene supports a range of primitives that can be added, scaled, rotated, and translated freely. Objects can be parented to one another, so changing a rotation speed moves an entire hierarchy at once.

It also implements the Blinn-Phong lighting model with two light sources, while the stars behind the scene read as a third. Objects carry textures, bump maps, and in some cases animated textures, all swappable at runtime.

  • WebGL
  • JavaScript

Try the demo Source

Ray Tracing Demo

Programmer

A compact ray tracer in WebGL, covering materials, reflection, and refraction.

An interactive page that walks through the basic principles of ray tracing: how rays meet surfaces, how different materials respond, and what reflection and refraction do to the image.

  • WebGL

Try the demo Source

Reflective and refractive spheres rendered by the ray tracer

Artificial Frame Generator

Software developer

Software that invents the frames between frames, interpolating new video from the footage around it.

The generator estimates interstitial frames from neighboring ones using Farneback optical flow, Canny edge detection, and motion blur.

Testing it was pleasantly self-checking: pull frames out of an existing clip, regenerate them, then compare the reconstruction against the originals mathematically.

  • OpenCV
  • Optical flow

Source

RPG MegaMart v3

Software developer

An open-source rewrite of RPG MegaMart as a static site anyone can fork and run for free.

V3 strips the shop down to HTML and JavaScript. Fork the repository, fill in your items from the template, and you have a storefront for your table — hosted on GitHub Pages at no cost, with no account or backend to maintain.

  • HTML
  • JavaScript
  • GitHub Pages

See an example Source

RPG MegaMart v3 storefront template

RPG MegaMart v2

Software developer

A live web app where tabletop players design magic items, publish them, and sell them to each other in shared stores.

Anyone can build items for their game — Dungeons & Dragons, Monster of the Week, Uncharted Worlds — customize them fully, and make them public for other groups to browse. Gather the items you want into a store, add your players, and let them shop.

The first version of this was a PHP prototype running off a laptop on my local network. V2 rebuilt it properly on .NET Core with an MVC structure and a PostgreSQL database.

  • .NET Core
  • PostgreSQL
  • MVC

Visit the site

The RPG MegaMart item catalog

Film Pitch Bot

Software developer

A bot that pitches movies that do not exist, complete with a cast list and a poster.

The bot samples real films from TMDb's free API, runs text prediction over that small sample to assemble a title, logline, and short cast list, then rewrites the result with OpenAI and generates a poster through Craiyon or DALL·E. Occasionally the poster request gets rejected for whatever the description managed to say. The survivors get posted.

  • TMDb API
  • OpenAI
  • DALL·E

Read the pitches Source

A generated film pitch with poster art

The Juice Press

Software developer

A satire publication with a stable of writers and, yes, a custom quiz builder.

The Juice Press gives contributors a place to draft, edit, and publish satirical articles and quizzes, with the quiz format built from scratch rather than bolted on.

Visit the site

The Juice Press home page

Cluest

Lead engineer, project manager & game designer

A mobile treasure hunting game that turns the places around you into clues for your friends to chase.

Cluest uses the phone's location services to build hunts out of real places. Save a spot, attach a hint, and it becomes a clue; string enough clues together and you have a treasure hunt to send to a friend. They enter hunt mode, and each clue they find points toward the next. New players are matched with friends automatically through Facebook.

Choosing the stack took longer than I expected — Android Studio, AWS, and Apache were all on the table. React Native won because it meant a single simultaneous release on Android and iOS, and Firebase handled the backend, scaling, and authentication. Learning all of it at once over a couple of months was a slog, and worth it.

  • React Native
  • Firebase
  • Facebook API

Source

Robot Vision with OpenCV

Programmer & team lead

A run of projects on teaching a robot to see: image manipulation from scratch, then object detection, then robots acting on what they find.

The groundwork was writing the algorithms by hand in Java — rotations, translations, blurs, masks, edge detection, along with color correction, detection, equalization, grayscaling, and histograms.

From there we moved to OpenCV in Python. First color detection with runtime-adjustable HSV tolerances, then differencing a rolling average of recent frames to pick out motion as it happened. Then object detection with Canny edges and contours, which we tested by counting Skittles and M&Ms by color — genuinely hard when a candy matches the background or overlaps another of the same color, and a useful lesson in how much tolerance tuning real vision takes.

The last stretch put it on hardware in MSU's robotics lab. Blur, edges, and thresholding got a robot following a solid line quickly; a dotted line took adding center-of-mass tracking of the filtered objects in frame, and a 180° sweep at the end of the trail to confirm it had actually finished. Next it searched for a human face, adjusted its distance until it was comfortable conversational range, greeted the person, and tracked their face — restarting the hunt if they left frame for more than fifteen seconds. The final program combined everything: navigate an obstacle course by distinguishing obstacles from safe path, find a person, take an item from them, and retrace the route.

  • Python
  • OpenCV
  • Java

Image processing I Image processing II Line following Face finding

Color detection with adjustable tolerances Counting candy by color with contour detection The lab robot running a vision program

Cat's Conundrum

Programmer & project lead

Four months, two mechanical engineers, one electrical engineer, a $200 cap, and a remote-controlled vehicle built from nothing to run an obstacle course.

The Cat's Conundrum course is about twenty interchangeable tiles with an obstacle on each, scored on a base value plus multipliers for how hard a line you take through them. Our job was a vehicle inside strict size limits that could take as many points as possible in ten minutes.

Testing pushed us to treads over wheels, and to Bluetooth for control so the app could run on several phones as a hedge against failure. Four motors working in pairs let the treads skid-steer through tight turns.

I wrote the controller app in Java with Android Studio and kept it deliberately plain: two vertical sliders, one per side of the vehicle, snapping back to zero when released, plus a handful of buttons. On the other end an Arduino Nano ran my C++, decoding the character arrays the app pushed over a Bluetooth module against the vehicle's current state.

It paid off on the day. The run went better than any of our tests — light, nimble, and rugged enough for the terrain, with batteries that never sagged enough to cost us torque. The precision of those two sliders turned out to be the real edge: fine speed adjustments none of the competing vehicles could make, on exactly the obstacles that were worth the most.

  • Java
  • Android
  • Arduino C++

App & Arduino source

The second prototype of the vehicle The vehicle running the obstacle course Early sketch of the controller app layout