Hardwood Legends

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.

A 5v5 possession in Hardwood Legends: a made jumper, the crowd in the stands behind, player name tags over the court.
5v5, second quarter. The scorebug, crowd, ribbon boards and every jersey are drawn from code.

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.

Source1 file · about 520 KB
Build stepnone
Asset files0
DependenciesThree.js r128
Simulation120 Hz fixed
Render target60 FPS
MultiplayerWebRTC, host-authoritative
Tests25, in CI
LicenceMIT

A look around

Menu and park

Controls

Keyboard, remappable in settings

MoveWASD
SprintShift
Shoot or dunk — hold, then releaseSpace
PassE
Pump fakeR
Dribble moves←↑→↓
Jump or contest, on defenceSpace
StealE
Switch defenderTab
PauseEsc

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.