How I Built a Full 11v11 Football Game in Vanilla JavaScript — With Man-Marking AI
There are 22 players on the pitch, one ball, and a single <canvas>. Every one of those players has to decide — every single frame — whether to chase, hold shape, mark an opponent, or drop back. Doing this at 60fps in plain JavaScript taught me more about game AI than any tutorial ever did.
This is the story of Limn League 2027 — a full 11v11 football game that runs in any browser. No downloads. No frameworks. No build tools. Just the browser's animation loop, a 2D canvas, and a lot of math.
It runs on Limn Engine, a custom canvas game engine I wrote in vanilla JavaScript. Everything you're about to read is built from primitives: components, vectors, and state machines.
Let me walk you through how it works.
The Core Problem: 22 Players, Zero Scripts
Most browser football games cheat. They teleport the ball, script the animations, and fake the AI with pre-recorded paths. I wanted something that felt like football — where the players on your team actually support you when you attack and actually track back when you lose the ball.
That means every outfield player needs to answer three questions on every frame:
- What is my role right now? (attacker, defender, chaser, marker)
- Where should I be? (a target position, not the ball)
- What is everyone else doing? (because 10 other players are asking the same questions)
Answer all three every frame for 22 players, and you have football. Get it wrong, and you get the classic "everyone chases the ball in a mob" problem.
Man-Marking AI: The Hardest Part
The biggest technical challenge was defensive positioning. Early versions had defenders run directly at the ball carrier — which looks like football for about five seconds, then falls apart the moment you pass.
The fix was a proper man-marking system. Here's the idea:
- Every defender on the AI team gets assigned one specific attacker to mark
- The assignment refreshes every 0.4 seconds (any faster and it flickers; any slower and they react late)
- Markers stand goal-side of their target — between the attacker and their own goal — at a distance scaled by difficulty
- The closest defender breaks off to press the ball, and on hard difficulties a second defender doubles up
The whole defensive shape is computed as distances from a role anchor, not from the ball. This is the key insight: players move toward a position that shifts based on game state, not toward the ball. That's what gives you the illusion of a real team holding its shape.
Every defender knows their job. They don't all converge on the ball. They cover the space, they track the runners, and they let the closest one press. That's how real football works, and that's how the AI plays.
Difficulty That Actually Scales
Most games fake difficulty by giving AI players more speed or faster reactions. I wanted a proper skill curve — where a 1★ team plays like a Sunday league side and a 10★ team feels like playing against a human pro.
So every AI team's behaviour is driven by a skill profile with multiple independent parameters. Rather than a single "difficulty" number, each team gets its own combination of traits that scale from 1 star to 10:
- Chase speed — how aggressively they close down the ball carrier
- Marking tightness — how close they stand to their mark
- Mark refresh rate — how quickly they reassign marks when you pass
- Pass accuracy — how much angle noise is added to their passes
- Shot accuracy — how much angle noise is added to their shots
- Shooting range — how far from goal they're willing to try
- Error rate — how often they fumble a loose ball
- Double-team flag — whether they send a second defender at you
- Goal-side marking flag — whether they mark from the goal side or just track
At 1★, defenders mark loosely, miss easy chances, and pass into traffic. At 10★, they press instantly, thread through-balls, and double-team your ball carrier. Same code path, different numbers.
The error rate was the most satisfying parameter to tune. At 1★, an AI player has a meaningful chance of fumbling a loose ball — which feels chaotic and fun. At 10★, that chance is almost zero — which feels surgical.
The Career: 12 Divisions, 96 Teams
The game isn't just one match — it's a full career mode. You start in the Street Division and work your way up through 11 more tiers to the Immortal League.
Street → Amateur → Semi-Pro → Championship → Premier → Continental → Limn Elite → Galactic → World Class → Legendary → Mythic → Immortal
Each division has eight rival clubs with star ratings matching the tier. Every season is seven matches. Finish first — and only first — to promote. Anything else, and you replay the same division with a fresh draw.
The AI opponents you don't play each round still simulate their own matches, so the league table keeps moving. Your promotion depends on how you perform relative to everyone else, not just on your own results.
Five Cup Tiers and a Championship Grind
Beyond the career league, there are two other competition tracks:
- The Cup — five tiers (Bronze → Silver → Gold → Platinum → Diamond). Each cup is a group stage plus knockout rounds. Only the champion unlocks the next tier.
- Championship Mode — pick any of the 96 clubs and play 30 matches with them. Complete it for the biggest coin payout in the game.
All three tracks run in parallel. You can be mid-career, mid-cup, and mid-championship at the same time — which gives players something to do no matter what mood they're in.
Controls That Work on Touch and Keyboard
Most browser games pick a platform and half-ass the other. I wanted Limn League 2027 to feel native on both.
On mobile:
- A real analog stick in the bottom-left corner. Drag it anywhere within its zone and the knob follows your finger. Move the stick gently to jog, push it hard to sprint, drag it diagonally to move diagonally.
- A / B / C action buttons in the bottom-right. A passes, B shoots or slide-tackles, C sprints.
- The game detects your device and pre-zooms to 50% so the pitch fits your screen.
On desktop:
- WASD or arrow keys to move.
- F passes, Space shoots or tackles, Shift sprints.
- Full-screen pitch, mouse-driven menus.
A subtle detail that mattered: shot aiming uses the analog stick. Push the stick toward the top-left corner, and your shot goes toward the top-left corner. Nothing auto-aims at the goal — you aim, you shoot.
Squads That Actually Upgrade
You earn coins every match, and those coins buy four permanent upgrades:
- Speed — applies to your entire team, not just your controlled player
- Shooting — powers up shots and improves your teammates' passing
- Stamina — your sprint lasts longer, drains slower
- Defense — you're harder to tackle, and your ball shield lasts longer after winning possession
Upgrades aren't cosmetic. If you max Speed, your whole team moves visibly faster. If you max Defense, you can hold the ball under pressure for noticeably longer. Every coin spent is felt on the pitch.
Costs scale steeply — the first upgrade costs a few hundred coins, the last costs tens of thousands. Maxing everything takes a long time. But the milestones along the way feel meaningful.
The Little Details
Some smaller features that make the game feel finished:
- Player collision — no more ghosting through each other. Every player physically separates from the others.
- Ball shield mechanic — after winning the ball, you can't be tackled for a fraction of a second. Prevents the tackle ping-pong you see in some arcade football games.
- Slide tackle cooldown — miss a slide, and you're out of the play for a moment. Encourages clean defending.
- 3-2-1-GO countdown before every kickoff and after every goal.
- Particle celebrations — bursts of colour from the goal mouth.
- Camera shake — subtle, on goals and big hits.
- Match analysis after every game — possession, shots, passes, tackles, and coins earned.
What I Learned
A few takeaways from building this:
1. AI isn't about smart decisions. It's about consistent decisions.
The hardest part of the AI wasn't making defenders clever — it was making them predictable enough to feel real. A defender who always stands goal-side is more convincing than one who occasionally does something brilliant.
2. Frame-rate independence is non-negotiable.
Every movement in Limn League 2027 is scaled by time delta. If I hadn't done this from day one, the game would run at wildly different speeds on a phone vs a desktop. Retrofitting it is painful. Do it upfront.
3. Difficulty is not a single number.
If you want a game that's genuinely easy at the bottom and genuinely brutal at the top, you need multiple independent levers. Speed alone is boring. Combining speed, marking tightness, error rate, and shot accuracy creates a real skill curve.
4. Mobile browsers will fight you.
Touch events, viewport quirks, and the fact that a single tap can fire both a touch event and a synthetic mouse event 300ms later — I spent more time debugging mobile input than any other single feature. If you're building for mobile, expect it.
Play It Now
Limn League 2027 is free, runs in any modern browser, and saves everything locally — no signup, no server required once it loads.
Whether you're building a Street Division club into an Immortal League powerhouse, hunting your first Bronze Cup trophy, or just settling in for a thirty-match grind — it's a full football game in your browser.
No downloads. No signup. Just football.
If you build something on top of it, fork it, or have feedback, let me know in the comments. I read every one.
Built with vanilla JavaScript on the Limn Engine — a custom canvas game engine. No React, no Vue, no bundler. Just a canvas and a lot of animation frames.





Top comments (0)