benadams.

These are some of
 the things I've built

(that weren't my job)

Experience my portfolio

Walk through every project in a 3D museum.

About 18 MB download

Prefer the boring version? Keep scrolling
Six otters paddling a raft through white water between two boulders, with a merit badge and a near-miss card on screen

A full raft squeezing past a rock in a sunny rapid, close enough to count as a near-miss.

In development

Middle Fork Rafting Simulator

A co-op rafting game where everyone paddles the same raft.

A multiplayer rafting game I'm making in Godot. You and your friends play river otters in oversized helmets, paddling one raft down a procedurally generated Idaho canyon to deliver cargo to the take-out. The water physics are based on real rivers.

  • Jobs. Pick a cargo like a wedding cake, a beehive or a piano and get it to the take-out flag. Hit something too hard and you lose a tier of the cake.
  • Join by code. Friends can join with a three-word code or a link, even after the trip has started. If the host leaves, the trip keeps going.
  • Real rapids. Each canyon is generated from a seed. Rocks can pin the raft, holes can trap it, and waves can launch it.
  • Rescues. Use throw bags and ropes to pull swimmers back in or haul the raft off a rock. If someone gets stranded, a bird carries them back to the raft.
Godot 4GDScriptMultiplayerHost-authoritative netcodeProcedural generation
Game page →itch.io page

Testing on Android

Oathkeep

A guild chat app with a co-op idle ARPG built around a daily check-in.

Once a day the app asks everyone in the guild whether they kept their oath. You decide what your oath is, like a run, a lift or twenty minutes of practice, and it's on the honor system. Checking in powers up your hero, the guild's hearth and that week's raid. Fights play out while you're away, and you can watch the replay when you come back.

  • Builds. Put any support gem on any skill it fits, pick from a constellation of over a hundred stars with keystones that change the rules, and respec for free. Builds can get pretty broken. Court of Bones never attacks, and its minions do five times the damage of a basic build in the same gear.
  • Fight breakdowns. After each fight you get the time, DPS and damage taken, plus a breakdown of where the damage came from, your biggest hit and your best second. Fights are seeded, so a guildmate can replay yours exactly.
  • Endgame. The Unlit Hall is the twelfth and final zone. After that, the Unlit Depths keep going one level at a time, with a boss every ten levels. Gear stops improving, but the difficulty keeps going up.
  • Rest days are fine. Your power is based on the last two weeks, not your total playtime. Taking a day off doesn't cost you or the guild anything.
Godot 4.7GDScriptAndroidCloudflare WorkersAsync co-op
A swarm of skeleton minions surrounds the Unlit Hall's boss on a purple stone arena, huge damage numbers bursting over them, until the Victory card appears.

A Court of Bones skeleton army fighting the final zone's boss.

A pixel-art town square with an observatory, bell tower, war room, dormitory and road gate around a campfire, and an I kept my oath seal at the bottom.

Each feature is a building you walk to. Tap the seal at the bottom to check in for the day.

Prognosticator

Command Center

The home screen links to all the tools: Now Playing, Effect Picks, the Disperser, Lights, Gear Setup, Scene Controls, and your playlists and tags. When you import a Spotify playlist, it downloads each track from YouTube and gets the 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

Prognosticator also sends its beat grid and DMX output to a visualizer I built in Godot, so the same light cues play in a virtual venue.

Red lasers and moving-head beams sweeping across a night plaza, with giant wheel and tower megastructures against a blue dusk.

The biggest outdoor area with the whole rig in red, and the giant structures on the horizon.

Warehouse

A procedurally generated club, lit only by DMX values. The same rigs, actions and Effect Picks cards that run the real lights also run its 104 virtual fixtures. Each load builds a new layout: concrete rooms, blacklight hallways with graffiti, and outdoor plazas up to 200 meters across with huge wheels, towers and arches on the horizon. A virtual camera cuts between wide, drone, jib and crowd shots 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 running toward a bank of coins used as blinders, under star-shaped pars and a laser.

Super Mario 64

The warehouse's DMX lights reskinned for Super Mario 64: the pars are Power Stars, the moving heads are cannons, the lasers are Amps, and the lava is eight pars. The open-source decomp port runs as a library inside Godot, and Godot renders each frame. All 45 areas have their own lighting setup and DJ Peach on the decks. An autopilot plays Mario in time with the music while the camera cuts between nine angles. Bring your own ROM.

Godot 4GDScriptGDExtensionCDMXBeat sync
Luigi Raceway at night, white spotlights sweeping down from a truss onto the track, a kart ahead.

CPU drivers racing through Luigi Raceway, Toad's Turnpike and Bowser's Castle at night, with the lights running live.

Mario Kart 64

Mario Kart 64 running under the same 104-light rig as the warehouse, so the lights, rigs and Effect Picks cards that run the club also run the racetrack. The decomp's PC port is built as a library that Godot steps one frame at a time and renders. All 20 courses (16 race tracks and 4 battle arenas) have their own lighting setup. When nobody's playing, CPU drivers race while the camera cuts between 12 angles on the downbeat, and up to four people can grab a controller and play split screen. 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

A job queue for all the Godot runs on my PC.

The warehouse, the two Nintendo scenes, the rafting game and Oathkeep all run their tests and captures on one PC, from a couple dozen worktrees at once. When two test suites started at the same time, they slowed each other down enough to fail timing-sensitive tests, and those failures looked just like real bugs. testq is a small daemon that hands out the machine's CPU and GPU slots, and each run script checks with it before launching Godot.

  • Separate from the projects. A capture in the DJ app and a physics test in the rafting game don't know about each other, so the queue lives in its own repo outside both.
  • Shortest first. It estimates each job's length from its past runs, so a 20-second test doesn't get stuck behind two 11-minute suites. Jobs that have been waiting a long time move to the front.
  • Hung runs get killed. If Godot stalls or runs past its time limit, testq kills it and frees the slot. If a client crashes, testq takes its slots back in about five seconds.
  • Status page. A web page and a tray icon show what's running, what's queued and roughly when it'll start. Finished runs are saved in SQLite, which makes flaky tests easy to find.
PythonSQLiteNodeBashPowerShellGodot
Source on GitHub →

Scrandle

A weekly game made from my friends' dinner photos. You get ten pairs of plates and pick the one the group rated higher, then see the ratings and who cooked each one.

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 Discord. Pick the one people rated higher.

View project →

Scranbot

The Discord bot behind Scrandle. Every day it posts a food photo matchup in our group's channel, keeps the votes hidden until voting closes, and then posts the result. Once a week it posts 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 for my friends that turns workout check-ins into Old School RuneScape progress. Each check-in counts as a Slayer session using the game's real XP and drop tables, and the bot posts the results as OSRS-style cards.

  • Two a week. Your first two check-ins each week count in full. After that they count for half, then a fifth. Rest days get logged and don't cost you anything.
  • Morning check-in. Each morning the bot posts a yes-or-no question and updates the post as people answer.
  • Real game data. Monsters, Slayer masters, drop rates and gear all come from the OSRS Wiki. The only number I tuned is how long a session lasts.
  • Goals. Clue caskets, a choice of three rewards, 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