DEV Community

Cover image for I Built a Retro JavaScript Game About Pair Programming With a Brilliant Asshole
John Munn
John Munn

Posted on

I Built a Retro JavaScript Game About Pair Programming With a Brilliant Asshole

Most coding games test syntax, algorithms, or puzzle solving.

I wanted to build a game about the part of software work that is harder to model: what happens when the code is fine, but the room is not.

So I built Pair Programming with an Asshole, a retro browser game where you work through JavaScript tickets while pairing with Chuck, a brilliant coworker who is technically useful and socially corrosive.

The result sits somewhere between:

  • a coding game
  • a workplace simulator
  • a small emotional horror story for developers who have absolutely worked with this guy before

Honestly, this has been one of the most enjoyable strange little systems projects I’ve touched in a while.

You can play the current prototype here: https://pair-programming-with-an-asshole.johnmunn.tech/

one of the most enjoyable strange little systems projects I’ve touched in a while.


The premise

The entire game loop is built around a simple idea:

bad engineering decisions are often social before they are technical

Each run puts you through five JavaScript tickets.

Every scenario starts the same way:

  1. a stylized Jira ticket appears
  2. Chuck comments before you can touch the code
  3. you drop into a retro pixel IDE
  4. you write the JavaScript fix
  5. Chuck interrupts while you work
  6. visible tests pass
  7. hidden tests reveal production reality
  8. you get a debrief on both the code and the human dynamics

The fun part is that the game isn’t only asking:

“does the code work?”

It’s asking:

what kind of engineering decisions do you make under pressure?

Ticket Screen


Why Chuck had to be a system

Chuck started as a joke.

Everyone who has worked in software long enough has met some version of him:

  • fast
  • sharp
  • often right
  • exhausting
  • dismissive
  • weirdly territorial about obvious bugs
  • suddenly collaborative when leadership joins the call

The shift for me was realizing Chuck could not live as just dialogue pasted beside an editor.

He had to behave like a system pressure.

Something the player had to reason around, not just read.

So his interruptions are tied to what the player is actually doing.

If the player adds a null guard:

if (!user) return "Guest";
Enter fullscreen mode Exit fullscreen mode

Chuck might immediately jump in with:

“You really think the API is sending ghosts today?”

If the player skips the guard:

return user.name;
Enter fullscreen mode Exit fullscreen mode

Chuck approves:

“Exactly. Keep it simple.”

That tension is the whole game.

The player has to decide whether to:

  • ignore him
  • joke back
  • follow his advice
  • push back directly

Sometimes Chuck is wrong.

Sometimes Chuck is rude and still technically right.

That distinction is where the game gets interesting.


Visible tests vs hidden tests

This became the mechanic that made the whole thing click for me.

The game uses visible tests and hidden tests.

The visible tests teach the happy path.

The hidden tests represent what production actually does to your assumptions.

So a player might see this pass:

renderGreeting({ name: "John" })
Enter fullscreen mode Exit fullscreen mode

…and feel good.

Then the hidden test hits:

renderGreeting(null)
Enter fullscreen mode Exit fullscreen mode

And suddenly the real lesson lands.

The failure is not just:

null crash

The real lesson is:

why did Chuck’s certainty make you stop validating the edge case?

That gap between “passed locally” and “safe in production” maps almost perfectly to the real world.

Chuck Image


Building the prototype

The first version started as one giant file.

That worked for about fifteen minutes.

Once Chuck became more reactive and the scenarios needed authored pacing, it got messy fast, so I split it into modules:

src/game.js
src/data.js
src/evaluator.js
src/dom.js
src/editor-ui.js
src/utils.js
Enter fullscreen mode Exit fullscreen mode

That gave the game a much cleaner shape:

  • scenario data drives tickets
  • evaluator handles visible + hidden tests
  • interruption rules live with the scenario content
  • UI flow is isolated from state transitions
  • Chuck can react through authored triggers instead of hardcoded timing

One of the more useful additions here was building a proper test harness around the game loop itself.

I wanted to be able to verify full progression through all five scenarios, visible and hidden test behavior, interruption rule matching, and the forced Chuck takeover states.

That ended up mattering more than I expected because the strangest bugs were almost never syntax bugs. They were flow bugs.

A good example is the evaluator pressure point:

const outcome = evaluateScenario({
  code: playerCode,
  visibleTests,
  hiddenTests,
  socialState: chuckState
})
Enter fullscreen mode Exit fullscreen mode

Once the game moved beyond a single scenario, validating state transitions became just as important as validating the JavaScript fixes themselves.

That was the point where it stopped feeling like a funny bit and started feeling like an actual systems design problem with narrative weight.


The interesting bugs weren’t code bugs

This was the part I did not fully expect going in.

The hardest bugs were not JavaScript bugs.

They were design bugs.

Things like:

  • hidden tests that felt unfair
  • Chuck interrupting too predictably
  • UI copy over-explaining the joke
  • debrief screens that felt too robotic
  • interruptions that felt scripted instead of reactive
  • pacing issues where the tension peaked too early

Those problems ended up being far more interesting than simply wiring the evaluator.

It turned into a really interesting exercise in:

how do you make social pressure feel fair?

That question is much more game design than frontend engineering, which made it a blast.


Why this project was worth building

What keeps pulling me back to the project is that it is modeling something very real:

engineering judgment is not only about writing code
it is also about handling pressure, ego, certainty, and hierarchy

We talk a lot about pair programming as if it’s automatically collaborative.

Sometimes it is.
Sometimes it’s adversarial.
Sometimes the hardest bug in the room is not in the code editor.

It’s sitting beside you.

That felt like something worth turning into a playable system instead of just another article thought experiment.


What’s next

The current version is a fully playable prototype, but there’s still a lot I want to improve:

  • richer evaluator semantics
  • better hidden-test fairness
  • stronger pacing variance for Chuck
  • more expressive portrait states
  • more authored debrief outcomes
  • additional coworker archetypes
  • more “Chuck was technically right” moments

I especially want to keep pushing the line between:

coding correctness
and
emotional realism

because that is where the idea starts to say something beyond the joke.


Try it / read the code

If you want to try the prototype or dig through the implementation, both are live:

I would especially love feedback on:

  • fairness
  • difficulty
  • whether Chuck feels believable
  • whether the hidden tests feel earned
  • whether the social pressure actually changes how you code

Because if people play this and immediately say:

“I know this exact coworker.”

then I think the idea is doing what it is supposed to do.

Top comments (0)