I pushed a game to GitHub today. Not a tech demo. Not a prototype. A real, finished, playable game with ten rounds, a boss, original music, and a winning state. I have been building websites since I was 12 years old. I am 43. This is the first game I have ever shipped.

TERMINAL 21 boot splash screen showing the retro CRT terminal aesthetic with green phosphor text and amber accents

The boot screen. This is where it starts. Ten rounds. One Commander AI. No save states.

The code is at github.com/mikjgens/terminal21 and you can play it right now at mikeljorgensen.com/projects/terminal21/. Full walkthrough is built into the game. Best played on a full-screen desktop browser. The whole thing is vanilla HTML, CSS, and JavaScript. Zero dependencies. Open index.html and it runs.

KEY TAKEAWAYS
  • terminal21 fuses rock-paper-scissors with pachinko, slot machines, and blackjack. Ten escalating rounds. Each round has a farming phase and a blackjack phase. The Commander AI cheats more every round.
  • Zero dependencies, pure vanilla HTML/CSS/JS. The whole game is one HTML file, one CSS file, and 16 JavaScript files. No npm, no build tools, no frameworks. You can read every line.
  • Original big band music soundtrack. Eight MP3 tracks composed and produced by me using Suno. Win tracks, lose tracks, atmosphere, credits. Embedded below.
  • Inspired by Inscryption. That game made me believe a card-game hybrid could carry real atmosphere. This is my version of that idea through a CRT terminal lens.
  • Vibe coding made it possible. Claude handled the parts I always got stuck on. I handled the design, the music, the aesthetic, and the direction. That partnership is the only reason this exists.

The Thing That Stopped Me for 30 Years

I wanted to go to DigiPen back when it was only in Canada. I was a kid who loved games and wanted to make them. But every time I opened a game dev tutorial, I hit the same wall. The learning curve was vertical. Engines required C++. Frameworks changed every six months. By the time you learned one toolchain, the industry had moved on.

So I stayed in my lane. Websites. PHP, HTML, CSS, some JavaScript. That was my world. I could build anything in a browser as long as it was a page. But a game? With state machines and game loops and collision detection and AI? That was a different species of problem. I told myself I would get to it someday. Someday never came.

Meanwhile I watched indie game dev explode. Game Maker, Unity, Unreal, Godot. Titles and tools everywhere. And I still could not ship a single game. Not because the tools were bad. Because the distance between opening a tutorial and having a fun thing running was still too far for someone with a full-time business and a family. The activation energy was too high.

What Changed

Vibe coding, right? Everyone is talking about it. But for me it was not about generating code I could not write. It was about removing the friction of getting stuck.

I have written JavaScript for 20 years. I know how the DOM works. I know event loops and closures and async patterns. But I do not know how to write a game loop that runs at 60fps. I do not know how to do collision detection on a 15 by 12 grid of descending invaders. I do not know how to build a blackjack engine with proper card dealing and hand evaluation and split logic. I know websites. Games are a different muscle.

With Claude, I did not need to learn Unreal. I did not need to read a 400-page book on C#. I described the game in plain English, iterated on the design, and Claude generated the scaffolding. I read every line. I modified every system. But I did not have to start from absolute zero on a codebase I had no intuition for.

The pachinko reward board is a good example of the partnership in practice. I described the mechanic in plain English: a token drops through a pegboard, deflects off pegs, and lands in a slot with a reward. I explained the physics in terms of what I wanted the player to feel: gravity that felt weighty, peg spacing that created suspense, slot widths that made rare drops exciting. Claude generated the collision math and DOM rendering. I then rewrote the gravity constant and adjusted the peg spacing because the first version came down too fast. I changed the slot reward distribution because the middle slots were too generous. I described the feeling I wanted. Claude generated the working version. I tuned it until it felt right. That loop was the entire project. Neither of us could have produced the game alone.

That is the real unlock. Not "AI writes the whole game." AI closes the gap between what you know and what you need to know to ship something real. If you already understand systems, architecture, and user experience, you can direct the output. You are the designer. The AI is the typist who never gets tired.

What Terminal21 Actually Is

Ten rounds. Two phases per round. One Commander AI with 250 HP. You have 100 HP. Round 10 is sudden death: all-in, one hand, no safety nets.

Farming Phase

The round starts with a protocol ante. You pick a flight protocol through a slot-machine reel reveal. Rock, paper, scissors logic determines advantage. Then your auto-piloted ship drops into a 15 by 12 invader formation. The ship fires automatically. You steer left and right, chasing kill combos.

Slot reel protocol reveal showing three reels spinning with amber CRT text and the player selecting a flight path

The protocol ante. Three reels spin, you pick a flight path. Rock-paper-scissors determines advantage before combat starts.

Hit the lucky lane for 3x jackpots. Chain combos to multiply your score. When the formation is cleared, you get a pachinko-style reward selector. A token drops through a pegboard and lands in a slot. Hack cards, HP restoration, score multipliers. The pachinko board changes every round.

Invader formation combat with auto-firing ship, combo chain counter, parallax starfield, and pixel-art planet in the background

Farming phase combat. Auto-piloted ship, descending invader grid, combo chains. Parallax starfield and per-round pixel-art planets in the background.

Blackjack Phase

You sit at the card table. Standard 21 rules. The Commander AI deals and plays against you. But the Commander cheats. Every round the odds climb. The card counting gets more aggressive. The reveals get more painful.

Blackjack table with player hand, Commander AI hand, hack card inventory slots, and the Commander's snark feed

The blackjack table. Hack cards on the left, Commander AI's snark feed on the right. Every round the cheating gets worse.

This is where the hack card economy matters. You collected hack cards during the farming phase. Each card does something: reveal the Commander's hand, swap a card, peek at the deck, force a redraw. But hack cards have a corruption risk. Use too many and you damage your own hand. Burn a card to heal HP instead. A desperate play that trades advantage for survival.

Four-slot inventory. Every decision is a resource tradeoff. Do you spend the reveal card now to win this hand, or save it for round 7 when the Commander is dealing from a stacked deck?

Round 10 total lockdown screen with HP towers, card shuffle glitch, and no safety nets

Round 10. All-in. One hand. The screen locks down. No safety nets.

Round Progression and Difficulty Arc

The difficulty climb is intentional. Each round cluster teaches a new skill and then tests it under pressure.

Rounds Phase What You Learn Commander Behavior
1-2 Onboarding Slot reels, invader combat, blackjack rules Plays straight 21. Teaches basic strategy.
3-4 Economy Hack card management, HP as a resource Tighter draws. Starts to punish small mistakes.
5-6 Pressure When to spend hack cards, when to hoard Knows your hand. Forces resource decisions.
7-8 Scramble Survival under stacked conditions Deck manipulation. Every hand is a fight.
9 Brink Managing corruption risk under duress Draws exactly what it needs. Overwhelming.
10 Sudden Death All or nothing. No safety nets. Perfect hand. You must out-cheat the cheater.

By the time you reach round 10, the Commander is drawing from a stacked deck. Your only hope is the hack cards you hoarded across the previous nine rounds and the decisions you made about when to spend them.

The Code

Sixteen JavaScript files. One CSS file at 109KB (it is doing a lot of CRT work). One HTML file. Here is the architecture:

Layer Files What it does
Data config.js, cards.js, patterns.js, commander.js Game configuration, card definitions, invader formation patterns, Commander AI personality + scaling difficulty
Systems audio.js, particles.js, starfield.js, snark.js Web Audio API synthesis, particle effects, 2-layer parallax starfield, Commander AI live commentary feed
Engines invaders.js, blackjack.js Invader formation combat engine, blackjack card game engine with proper dealing and hand evaluation
UI ui.js, fsm.js All DOM rendering, state machine driving SPLASH, RPS, FARM, REWARD, BLACKJACK, OUTCOME, TILT, VICTORY
Controllers gameLoop.js, economy.js, commander.js Main 60fps game loop, hack card economy manager, Commander AI decision engine
Main main.js Wire everything together. One entry point.

No framework. No build step. The script tags load in dependency order. main.js is the last thing that fires. Everything communicates through a shared state object and the finite state machine in fsm.js.

The architecture decision was deliberate. I considered React for component isolation and Phaser for the game renderer. I rejected both for the same reason: every framework adds an abstraction layer between the code and what the browser actually does. For a game running at 60fps with real-time input handling and DOM rendering, that overhead matters. The shared state object in gameLoop.js holds the entire game state as a plain JavaScript object. The FSM in fsm.js transitions between game states. No virtual DOM. No reconciliation. No build step. Just direct DOM manipulation inside a requestAnimationFrame loop. The result is a game that runs at a locked 60fps on a 2015 MacBook Pro and can be read and understood by anyone who opens the repo.

The CSS is doing heavy lifting. CRT scanlines overlay, curvature vignette, phosphor-bleed text shadow, rivet greebles, panel wear effects. The amber phosphor aesthetic (#ffb000 on #1a1100) across every screen. Two-layer parallax starfield with CSS-animated star drift. Per-round pixel-art planets drawn entirely in CSS. Round 9 has storm sparks. Round 10 has death clouds with red-tinted particles.

Victory screen with post-run stat dump showing rounds completed, hack cards used, and Commander AI defeated

Victory. The post-run stat dump. Rounds completed, cards used, combos chained. The Commander is down.

The Music

I made eight tracks for this game. Big band, swing, casino floor energy. I used my music background and Suno to produce them. Credits, busts, wins, atmosphere. Each one is tied to a game state.

Here are a few tracks from the game. They play during different moments. The credits theme opens the game. The bust tracks play when the Commander beats you. The house-always-wins theme kicks in when the odds stack against you.

// CREDITS THEME

// BUST V1

// HOUSE ALWAYS WINS V1

// SHE BUSTED V1

What Inscryption Taught Me

I need to name the elephant in the room. Inscryption from Daniel Mullins Games is one of the best games I have ever played. It is a card game that is not really a card game. It is a horror game that is not really a horror game. It is a puzzle box that keeps unfolding. That game made me believe you could fuse genres into something that felt completely new.

terminal21 is not Inscryption. It is not trying to be. But Inscryption showed me that a game does not need to fit a genre. You can take roguelike structure, card game mechanics, and arcade action and weld them together with a strong aesthetic. That is what I tried to do here. The CRT terminal is the aesthetic glue. The amber phosphor, the scanlines, the rivets, the boot sequences. Everything happens inside a fake terminal. The Commander AI talks to you through it. The slot reels are terminal output. The hack cards are files in a directory. The aesthetic is not decoration. It is the container that makes the fusion work.

What I Learned Shipping This

I could work on this game forever. There are a dozen features I would add. More hack cards. More invader patterns. A second Commander phase. Leaderboards. Replayability unlocks. But I stopped because shipping is a skill and I wanted to practice it.

Here is what I actually learned:

The blocking layer for most people is not skill. It is the distance between the idea and the first playable thing. Before vibe coding, that distance was weeks of boilerplate. Now it is hours of conversation with a model that generates scaffolding you can actually use.

Vanilla is a feature. The shared state object and FSM pattern replaced what would have been a React app with Redux. The direct DOM manipulation inside a requestAnimationFrame loop replaced what would have been a Phaser or PixiJS render pipeline. Every framework I did not use is a dependency I will never have to update. The game runs at 60fps on old hardware. The code is readable. I made the right call.

Music makes the game. I have been a musician longer than I have been a developer. Writing the soundtrack in Suno and mixing big band swing into a CRT terminal game was the most fun part of the project. The bust tracks hit harder because they sound like a 1940s casino band falling apart.

The difference between wanting to make a game and having made one is just one week of focused work with the right partner. Claude was the partner. I was the director. That partnership is the only reason terminal21 exists.

The repo is at github.com/mikjgens/terminal21. The live game is at mikeljorgensen.com/projects/terminal21/. If you play it and beat the Commander, I want to hear about it. If you find something broken, open an issue. If you are someone who always wanted to make a game but never did, steal this energy and go make yours.

The thing that stopped me for 30 years was not ability. It was the belief that I needed to be a game developer to make a game. I did not. I just needed to be someone who could direct the work. That is a different bar. And it is one a lot more people can clear.