Getting Two People on One Keyboard
I spent about three weeks last year building a two-player version of the Chrome Dino game for a weekend hackathon. We wanted both players to use the same keyboard — one with W and Space, the other with Up and Enter. The concept sounds simple, but the collision detection and input handling get messy fast if you don't plan for it from the start. Here's what I learned doing it the hard way, so you don't have to.
How the Dino Game 2 Player actually works under the hood
The original Chrome t-Rex game is just a single canvas element with a game loop running at roughly 60 frames per second. You add a second player by creating a second set of coordinates and rendering a second sprite. The main complexity isn't the graphics — it's keeping the game loop synchronized while two separate inputs affect the same obstacles. Both players share the same ground, same cactus array, and same score calculation unless you're doing a competitive variant where each player has their own score. In my build, I kept it cooperative — both jump, both die, same run. The input handler maps keypresses to each player independently: document.addEventListener('keydown', (e) => { if (e.key === 'w' || e.key === ' ') player1.jump(); if (e.key === 'ArrowUp' || e.key === 'Enter') player2.jump(); });
That's the entire input layer. The game loop itself doesn't change. You just update two x/y position pairs per frame instead of one. The tricky part is the collision check. With one player, you iterate through obstacles once and check overlap against a single hitbox. With two players, you run the same loop twice — once per player hitbox. It's negligible CPU cost unless you start adding flying pterodactyls and double the obstacle count.
Get the Full Details

Download and setup
There are a few open-source implementations floating around on GitHub. The one I ended up using was built by a developer called felixhummel, and it's the most complete version I found — proper sprite rendering, sound off by default, and no bloat. The repo is at github.com/felixhummel/dinosaur-game but search for "dino game two player" to find the forked variants since the original doesn't include multiplayer. To get it running locally, clone the repo, open the HTML file in any modern browser, and you're playing within about 30 seconds. No build step, no dependencies. It's a single self-contained file for the most part. Some forks use separate JavaScript modules, in which case you'll need a local server. I use Python's built-in one: python3 -m http.server 8080
Then open localhost:8080 in your browser. That's it.
A problem I ran into and how I fixed it
About halfway through testing, I noticed that when both players pressed their jump keys within the same frame — or within 16 milliseconds, which is one frame at 60fps — the game would sometimes skip the second player's jump entirely. The keydown event would fire, but the game state wouldn't update because the first player's jump animation locked the update cycle for that frame. The root cause was that I was using a single requestAnimationFrame callback and checking jump state at the top of the loop. If player 1's jump triggered first, it set a flag that prevented player 2's input from registering until the flag cleared. The fix was straightforward but easy to miss: I moved the input reading outside the animation loop entirely. The event listener sets a buffer — a simple array of pending inputs — and the game loop drains that buffer at the start of each frame before doing any updates. Both players' inputs get processed every frame regardless of animation state.

Code change was about four lines. I stopped using boolean flags for jump state and switched to a timestamped input queue. That way if two keys press in the same frame, both get registered and applied in order.
Things nobody tells you about this kind of project
First, the ground texture scrolling is going to look weird if the two players move at different speeds. In the base game the ground is a static repeating texture, but if you add a speed differential — say player 1 dies slower than player 2 — the visual sync breaks. Fix it by making the ground scroll based on the faster player's velocity, or just lock both players to the same speed. Locking them is what most people do and what I ended up doing too. Second, and this is the part that catches people out: spacebar and arrow-up will both trigger jumps if you're not careful. Some people play with arrow keys, some with space. On a shared keyboard, both keys will fire the same handler unless you explicitly gate them per player. I spent an afternoon debugging why player 2 kept jumping when player 1 pressed space, only to realize both keys were hitting the same conditional. Third, the game gets exponentially harder when you account for human reaction variance. Two players means two reaction times, and the one who's slower determines the effective difficulty. I actually made a version where the slower player's score counted double, which somehow made it more fun and less frustrating. The alternative — where one player's death ends the run for both — feels punitive rather than challenging.
Where this approach breaks down
The two-player local co-op model only works well with two people. Three or more and you're out of keys on a standard keyboard unless you bring in controllers or gamepads via the Web Gamepad API. Even then, browser support is inconsistent — Safari on macOS doesn't expose gamepads the same way Chrome does, and I've seen reports of Firefox handling them differently too. Another limitation is screen real estate. At the default resolution, two dinosaur sprites side by side look cramped and the hitboxes overlap visually even when they don't collide. I solved this by increasing the canvas width from 600px to 800px and spacing the players apart horizontally. It's a minor visual tweak but it matters a lot for readability during fast gameplay. Finally, if you're planning to host this publicly, be aware that some ad networks and website builders strip out canvas-based games or block them entirely. I learned this the hard way when a friend tried to embed the game on a WordPress page and the canvas was invisible. The solution is to serve it as a standalone HTML file rather than embedding it in a CMS.

Quick reference for the core files
If you're cloning a fork and want to modify it, these are the files that matter: dino.js — main game loop, physics, and collision detection. This is where you'll adjust player count, speed, and gravity constants. input.js — key mapping. Edit this if you want to change controls or add a third player.
render.js — sprite drawing. Each player gets its own render call, usually something like renderPlayer(player1, ctx) and renderPlayer(player2, ctx). obstacles.js — cactus and bird generation. This file doesn't change for two-player mode unless you want different obstacle patterns per player. Most of the work in porting single-player to two-player happens in dino.js and input.js. The other files are largely untouched.
Bottom line
Dino Game 2 Player is a straightforward project if you treat it as an extension of the original rather than a fundamentally different game. The architecture is already there — you're just duplicating state and wiring up a second input channel. The gotchas are real but small: input buffering, sprite positioning, and the occasional browser quirk with gamepad support. Build it, test it with a friend, and you'll have a working version in an afternoon.
