A basketball game in one file
Full-court 5v5 with quarters, a 24-second clock, inbounds, fouls and free throws. A career you play through a season and a playoff bracket. A park you walk around as your own player.
Runs in the browser. Nothing to install, nothing to sign up for.
What you can play
Six ways in
Full court 5v5
Four quarters, a 24-second clock, inbounds, fouls and free throws. Thirty clubs across two conferences, each with its own colours and a change strip so two teams never share a court in similar kit.
MyCareer
Build a player — name, position, height, number, look, archetype — then pick a club and play a twelve-game season, a top-eight conference bracket and a Finals. Games grade your box score and pay XP against your archetype's ceilings. Seasons roll over and the history stacks up.
MyPark
A walkable outdoor lobby you enter as your career player. Six half courts around a plaza, team pads behind each midcourt line, live chat. Fill every pad and the game tips off where it stands, with everyone else free to watch from the sideline.
Streetball
1v1 to 21 on a half court, loser's ball. 3v3 with a 14-second clock and a clear past the arc after every stop.
Multiplayer
Peer-to-peer over WebRTC with a join code. No server holds the game — one player hosts it and the others predict locally against host-authoritative snapshots.
A first game that teaches
There is no tutorial to sit through. Your first career game is a real game against the CPU, and it slows down to teach each control at the moment you need it. The empty gym is still there when you just want to shoot. The full guide covers everything else.
How it's built
One file, no assets
The whole game is a single HTML document — markup, styles and JavaScript in one file, opened directly or served as a static page. There is no build step, no bundler and no asset pipeline, because there are no assets. Every court line, jersey number, crowd member, backboard and sound effect is generated in code while the page loads.
Physics run on a fixed 120 Hz timestep decoupled from rendering, with the drawn frame interpolated between simulation ticks, so the game behaves identically whether your screen runs at 60 Hz or 144. Gameplay randomness goes through a seeded generator, which is what makes a match reproducible and the test suite possible.
Three.js, pinned to one version and fetched from a CDN, is the only dependency the game needs to run. A regression suite drives the simulation headlessly — checking that shooting percentages stay in a believable band, that nobody heaves from the far end of the floor, that a career survives a reload, and that the frame budget holds — and runs on every push.
A look around
Menu and park
Controls
Keyboard, remappable in settings
| Move | WASD |
| Sprint | Shift |
| Shoot or dunk — hold, then release | Space |
| Pass | E |
| Pump fake | R |
| Dribble moves | ←↑→↓ |
| Jump or contest, on defence | Space |
| Steal | E |
| Switch defender | Tab |
| Pause | Esc |
Hold shoot to start the meter and let go in the green. Sprint at the rim and shoot to dunk. Flick a dribble move toward the basket to spin past, away from it to fade back, or across to cross over — time one while the defender is mirroring you and they hit the floor. A keyboard is required; there is no touch control yet.
About
Who makes this
Hardwood Legends is a personal project by theloyaltrojan, written to see how much of a sports game fits inside a single HTML file with nothing loaded from disk. It is free to play, open source under the MIT licence, and has no accounts, no logins and no paid anything — the coins in it are earned by playing and only buy cosmetics.
The code is on GitHub, along with a changelog covering what changed and why. Bugs, ideas and pull requests are welcome as issues on that repository, which is also the best way to get in touch.