Resume

benadams.

These are some of
 the things I've built

(that weren't my job)

Six otters paddling a raft through white water between two boulders, with a merit badge and a near-miss card on screen

A full boat through a sunny rapid, close enough to a rock to earn a near-miss.

In development

Middle Fork Rafting Simulator

Multiplayer whitewater. One raft, everyone paddles.

A multiplayer rafting game built in Godot. You and a boat of friends, all river otters in oversized helmets, paddle a procedurally generated Idaho canyon and carry a job's cargo to its take-out. The water is modelled to real ranges, and the otters are cartoons.

  • Jobs. Pick a cargo (wedding cake, beehive, watermelon, piano) and run it to the take-out flag. A hard hit costs you a tier of cake.
  • Join by code. A three-word trip code or a link puts a friend in your boat, even on a trip already on the water. If the host leaves, the trip carries on.
  • Real rapids. A canyon generated from a seed. Rocks wrap boats, holes keep them, waves launch them.
  • Nobody stays stuck. Throw bags and rope hauls for rescues, and a bird that carries a stranded swimmer back to the raft.
Godot 4GDScriptMultiplayerHost-authoritative netcodeProcedural generation
Meet at the put-in →itch.io page

Prognosticator

Command Center

One home screen links every tool: Now Playing, Effect Picks, the Disperser, Lights, Gear Setup, Scene Controls and your playlists and tags. Import a Spotify playlist and Prognosticator downloads each track from YouTube, then pulls BPM and key from VirtualDJ.

ElectronReactTypeScriptNodeGodotDMXOBSTailwindVirtualDJ
Command Center

Command Center

hobbit.house

Phone control app for a living room mini PC. Launch games and streaming apps, run a music visualizer on the TV, and control lights, Kodi and cameras. A QR code turns a guest's phone into a game controller.

ReactDockerLinuxMQTT
Smart light controls

Smart light controls

View on GitHub

Prognosticator: visualizer scenes

The lighting rig has a second home. Prognosticator sends its beat grid and DMX output to a Godot visualizer, so every light cue also plays in a venue that does not exist.

A hazy room with thin pink laser lines crossing it, blue, yellow and pink par cones, and crowd silhouettes in the foreground.

The booth-mirror lens looks out over the crowd through haze, with laser sheets and pars in pink, blue and yellow.

Warehouse

An endless, procedurally generated club that the Godot visualizer builds out of code and lights only with DMX values. The same rig, action or Effect Picks card that drives the real fixtures drives its 104 virtual ones, as volumetric beams and shadow-casting spotlights in haze, while a camera rides through rooms and tunnels and cuts on the beat.

Godot 4GDScriptDMXBeat syncProcedural generationSpout
Mario seen from behind running across Jolly Roger Bay's sandy ground, with a coin bank glowing at left, a pink star light and a vertical laser.

Mario runs toward a bank of coins working as blinders, under star pars and a laser, in the level's own blue haze.

Super Mario 64

The warehouse's DMX kit re-skinned onto Super Mario 64: pars are Power Stars, movers are cannon heads, lasers are Amps, and the lava is eight pars. The open-source decomp port runs as a library inside Godot, which draws every frame the game produces. All 45 areas have a lighting plot and a DJ Peach at the decks, and an autopilot plays Mario on the beat while a director cuts between nine lenses. Bring your own ROM.

Godot 4GDScriptGDExtensionCDMXBeat sync
The testq status page: eight CPU slots and two GPU slots all in use, five running jobs across mfrs and prognosticator worktrees with progress bars, five queued jobs with estimated start times and what each is waiting for, and recent results including one marked killed: stalled

testq

One queue for every Godot run on the machine.

The warehouse, the SM64 scene and the rafting game all test and capture on one PC, from a couple of dozen worktrees that each think they have it to themselves. Two suites starting in the same minute slowed each other enough to fail anything timed against the wall clock, and those failures read exactly like real ones. testq is a small daemon that holds the machine's slots, and every run script asks it before launching an engine.

  • Outside every project. A capture in the DJ app and a physics suite in the game are two engines on one box, and neither repo can see the other's. The queue belongs to neither.
  • Shortest first. Estimates come from each job's own history, so a twenty-second test does not sit behind two eleven-minute suites. A job that has waited long enough ages to the front.
  • Hung runs get killed. An engine that stalls or overruns its limit is stopped and its slot handed back. A client that dies has its slots reclaimed in about five seconds.
  • A page and a tray dot. What is running, what is queued and roughly when it starts, with every finished run kept in SQLite to pick out the jobs that only sometimes pass.
PythonSQLiteNodeBashPowerShellGodot
Source on GitHub →

Scrandle

A weekly game built from my friends' dinner photos. Ten pairs of plates: pick the one the channel rated higher, then see the ratings and who cooked each.

Next.jsTypeScriptTailwindCloudflare R2
Scrandle round 1 of 10: two plates side by side, a breaded cutlet with sweet potato and a seared steak, with the question of which the channel rated higher

Two plates from the channel. Pick the one it rated higher.

View project →

Scranbot

The Discord bot behind Scrandle. It posts a daily food photo matchup in a friends' channel, keeps votes private until the round closes, reveals the result, and posts weekly standings with rank changes.

Cloudflare WorkersD1R2DiscordTypeScript
ScranbotBOT09/28/2026 9:00 AM

Today's matchup

Bot card with two numbered food photos side by side, a Detroit-style pizza and fried chicken with fries, each with its name underneath and the matchup number in the corner
12
ScranbotBOT09/29/2026 9:00 AM
Result card: the same two photos with vote shares of 67 and 33 percent, vote counts, and each cook's name, with the winner outlined in green and the loser dimmed
ScranbotBOT09/30/2026 9:00 AM

Rank the plates

Ranking card with five numbered food photos in a grid under the header Rank the plates
12345
ScranbotBOT10/01/2026 9:00 AM
The five photos in finishing order, from 1st to 5th, each with its rating change and the number of ballots in the corner
ScranbotBOT10/04/2026 6:00 PM
Chef standings card: a ranked table with places gained or lost, a NEW tag, the rating, and the rating change for each cook

Yut Hut

A Discord bot that turns workout check-ins into Old School RuneScape progress for a friend group. Each check-in is a Slayer session run on the game's real XP table and drop tables, and the results come back as OSRS-style cards.

  • Two a week. The first two check-ins count in full, then half, then a fifth. A rest day is written down and never punished.
  • The bot asks. Every morning it posts one question with a Yes and a No, and edits the roll call into the post as people answer.
  • Numbers from the wiki. Monsters, Slayer masters, drop rates and gear come from the OSRS Wiki. Only the session length is tuned.
  • Something to chase. Clue caskets, a pick of three spoils, gear drops, an Achievement Diary, a quest and a group boss each week.
Cloudflare WorkersD1R2DiscordNext.jsTypeScript
Read the rules →
Yut HutBOT10/04/2026 8:00 AM

Act 1 · Week 3 · Day 17 in Lumbridge

Did you work out in the last 24 hours?

Yesterday: Bramble (verified by Odo), Odo, Tamsin. 3 of 6.

Week so far: 4 in form, 1 with one to go.

Quest: Rune Mysteries, supplies 2/3.

🌿 Bryophyta ██████░░░░░░ 46%. Every check-in takes a swing.

🎁 Today's spoils: Magpie impling jar (rare) is on the table for every full-value check-in.

✅ Bramble, Odo · 😴 Marlowe · 3 still to answer

💪 Yes😴 No, rest dayJoin the campaign📋 My to-do
Yut HutBOT10/04/2026 8:12 AM

Bramble checked in (2nd this week, full value). ⚔️ 23 hill giants slain (23/40 on task). Strength 54! Slayer 58!

Old School RuneScape style progress card for a check-in: loot icons, XP gained in seven skills, two level-ups and the current Slayer task
Yut HutBOT10/04/2026 8:13 AM

🎁 Bramble opened a magpie impling jar (rare): 2 diamonds, 1 dragonstone, 5 gold rings, 8,200 coins, 3 ruby rings, 4 emeralds. 62.4k gp.

Card for a magpie impling jar opened from a check-in spoils pick, with a rare blue frame and the gems, rings and coins inside
Yut HutBOT10/04/2026 5:40 PM

Odo checked in (1st this week, full value). 📜 Odo opened a hard casket: Robin hood hat!

Check-in card showing a clue casket, an antique lamp, a Robin hood hat unique and 21.3k coins alongside the session's drops and XP
Yut HutBOT10/04/2026 5:41 PM

Slayer 60!

RuneScape level-up scroll reading Congratulations, Bramble! Your Slayer level is now 60.
Yut HutBOT10/04/2026 6:02 PM
Stats sheet in the RuneScape skills-tab style for Bramble: nine skill levels with progress bars, total level 483, combat 78, Dragon tier frame, form dots and clue progress
Yut HutBOT10/04/2026 6:03 PM

✨ Bramble's gear

Gear card for Bramble showing ten worn slots from a Dragon mace to a Kurask head, 21 of 89 pieces collected, chasing an Abyssal whip
Yut HutBOT10/05/2026 8:00 AM
Week 14 standings table for six players, ranked by combat level with armour tier, form weeks and units

Magic: The Gathering

Next.jsReactVercel

Tools for Commander players and deck builders

MTG Commander Scorekeeper

Touch-friendly scorekeeper for Commander. Four-player quadrant layout with life, poison, and commander damage tracking.

View project →

Magic Tutor Helper

Import a decklist from Archidekt and filter it by mana cost and card type, with Scryfall card images.

View project →

MTG Token Helper

Import a deck and it finds every token the deck can make. Track them on the battlefield with tap/untap, counters, and buffs.

View project →
Tutor Helper

Tutor Helper

FloatWise

Float trip planner. Hourly forecast tables for multiple locations with the live Yellowstone River flow, and a map for pinning put-ins, take-outs, and swim spots.

Next.jsLeafletOpen-MeteoUSGS
FloatWise forecast table with hourly temperature, wind, and precipitation for eight Yellowstone River towns, plus the live river flow
View project →

Dota 2 Randomizer

Spin two wheels to get a random hero and a random item to build. Canvas-animated wheels fed by live OpenDota data, with sound and confetti.

Next.jsCanvasOpenDota
Dota 2 Randomizer showing the hero and item wheels with Phantom Lancer and Urn of Shadows selected
View project →

IRLScape

Old School RuneScape streaming overlay. Game UI on a live camera feed with Twitch chat integration and Joycon controls.

IRLScape YouTube video thumbnail
Watch on YouTube

OSRS Progress Generator

API for generating progress report images for Old School RuneScape players. Collection log items, OSRS Wiki integration.

OSRS ProgressBOT01/08/2025 9:14 PM
OSRS progress report
OSRS ProgressBOT10/14/2025 11:11 PM
OSRS collection log
Ben AdamsGitHub