Wikipedia’s shoot ’em up page still starts with Spacewar! (1962) and then credits Taito’s Space Invaders (1978) with locking the genre template: multiple enemies that fire back, extra lives, a climbing high score. Asteroids (1979) added 360-degree movement. Robotron: 2084 (1982) split move and fire onto two sticks. What did not stay still is the search query. People who type how to make a shooter game in 2026 often mean three different games: a 3D first-person shooter, a bullet-hell specialist title, or a top-down arcade arena you can finish in a weekend. This guide is the third. In a browser that means WizardGenie for the loop, Quick Sprites for the walk sheets and explosions, Sorceress AI Image Gen for the arena, SFX Gen for shots and hits, and Music Gen for a combat bed. This is the honest end-to-end for how to make a shooter game in 2026, in a browser, in a weekend.
What how to make a shooter game actually means in 2026
The query “how to make a shooter game” hides three intents. Some searchers want a first-person shooter: pointer lock, a 3D camera, hitscan or projectile weapons. That is a different weekend and a different article — start with Aim How to Make a First Person Shooter Game (Browser 2026) and stay in Three.js. A second intent is a bullet hell beginner project: curtain-fire patterns, a tiny hitbox, memorized routes. Wikipedia groups that as a mid-1990s offshoot of scrolling shooters, not as a first build. The third intent, and the one this shooter game tutorial targets, is a single-player top down shooter: an arena viewed from above, WASD to move, mouse to aim, a bullet pool, three enemy types, five waves, a score, and a Play Again card. That is a weekend javascript shooter. It demos the whole Sorceress toolset. It is the format most first-time arcade shooter tutorial readers actually want.
The presentation contract is small and strict. A title screen shows the game name, a Play button, and a mute toggle. The play screen is a square arena, a player sprite, incoming enemies, a HUD with HP, current wave, and score. Mouse aim is independent of facing so the ship or soldier can strafe while firing, the browser version of a twin stick shooter. Wikipedia’s twin-stick shooter page names Robotron: 2084 as the arcade template and notes that keyboard and mouse may replace either stick. A results card shows wave reached, kill count, and Play Again. A first browser shooter that ships that loop honestly will teach you more than a half-built campaign with twelve unfinished maps.
The shooter loop in one minute (move, aim, fire, spawn, score)
Five moving parts and nothing else, in parallel every frame. First, move — read a Set of currently held keys, add a unit vector, scale by speed and dt so 144 Hz monitors do not make the player twice as fast. Second, aim — pointer position minus player position, normalize, that is the fire heading. Third, fire — if the pointer button is down and cooldown is zero, spawn a bullet from a pool with that heading, then reset cooldown. Fourth, spawn — when the live enemy count hits zero, increment the wave index and drop the next row from the table. Fifth, score — on overlap, subtract HP, play a hit sting, and if HP is zero return the enemy to the pool and add its score. That is a top down shooter. Everything else — a boss on wave five, a weapon pickup, a dash — is polish.
Drive the tick with requestAnimationFrame, not setInterval. MDN marks rAF Baseline widely available since July 2015 and warns you to use the callback timestamp so the sim stays frame-rate independent. Keep movement keys in a Set updated from KeyboardEvent keydown and keyup (also Baseline since July 2015). Read event.code (KeyW, KeyA) rather than event.key so a Dvorak layout does not remap strafe. Never use the obsolete keypress event. Autosave mute, best wave, and high score to localStorage. Keep the core loop tight, ship one full wave end-to-end, and only then layer polish. A first browser shooter that ships three honest enemy types and a fair cooldown will outplay an arena with forty undrawn guns.
Pick your engine for how to make a shooter game: vanilla Canvas, Phaser 4, or WizardGenie
Three good browser targets in 2026, each with a different trade-off. Vanilla JavaScript with Canvas is the honest default and the pick this guide recommends for a first build. A top down shooter is a background blit, a player sprite, a bullet pool, and circle overlap checks. Total code footprint for a working browser shooter is under 600 lines and ships as a static HTML file. No engine to install, no build step, deploys to GitHub Pages, Netlify, or Vercel with a drag-and-drop. This is the stack most javascript shooter and arcade shooter tutorial pages should have started with. The vector cousin of this loop — wrap-around rocks instead of waves — is covered in Blast How to Make Asteroids (Browser Vector Loop 2026).
Phaser v4.2.1 “Giedi” (released 9 July 2026, verified 2026-08-18 on the official stable download page) becomes the right pick if you want Arcade Physics bodies, group overlap callbacks, particle explosions, or a Scene lifecycle that maps onto title-arena-results. Phaser’s Arcade Sprite is a sprite plus an AABB or circle body; once the body exists you set velocity and listen for overlap instead of writing the pool math by hand. For a first twin stick shooter browser build, Phaser is optional weight — use it when motion and particles are the product, not when the product is a fair wave table and a correct cooldown. Searchers who land here for a phaser shooter usually want those overlap callbacks; give them a hand-rolled pool first, then offer Phaser as the upgrade path.
WizardGenie is not a separate rendering engine — it scaffolds whichever of the two you pick, from a single natural-language prompt. WizardGenie is the Sorceress game-native coding agent. It ships as both a desktop app (Windows installer with auto-update, available to Early Access supporters and above) and a no-install web build at the same URL. Its coding-model lineup covers Claude Opus 4.7, Claude Sonnet 4.6, GPT-5.5, Gemini 3.1 Pro, DeepSeek V4 Pro, Kimi K2.5, Grok 4.2, and MiniMax M2.7 (verified 2026-08-18 in src/app/_home-v2/_data/tools.ts). For a shooter, any frontier model scaffolds the wave table and bullet pool in one prompt. If you want to run cheap, pair a frontier planner (Claude Opus 4.7 or GPT-5.5) with a budget executor (DeepSeek V4 Pro or Kimi K2.5) and let the executor do the typing — the Dual-agent planner-and-executor pattern is why WizardGenie exists, and it lands most projects at roughly one-fifth the single-frontier cost. Never put Opus, GPT-5.5, Gemini 3.1 Pro, or Sonnet on the typing side.
Step 1 — scaffold player, bullets, and enemy spawn tables
Nothing else in the pipeline matters if every wave dumps the same three grunts in a line. Ship JSON, not a hardcoded array in the tick file. Each enemy needs an id, display name, HP, speed, score value, and a count per wave. Each bullet type needs speed, radius, cooldown, and damage. The player needs max HP, move speed, and a fire cooldown. Waves should escalate count and mix, not invent a new enemy every row. A dash or a second weapon is a later pickup, not a first-weekend feature.
{
"player": { "hp": 5, "speed": 220, "fireCooldownMs": 140, "bulletSpeed": 520 },
"enemies": {
"grunt": { "hp": 2, "speed": 70, "score": 50, "radius": 14 },
"runner": { "hp": 1, "speed": 160, "score": 80, "radius": 12 },
"turret": { "hp": 4, "speed": 0, "score": 120, "radius": 16 }
},
"waves": [
{ "grunt": 4, "runner": 0, "turret": 0 },
{ "grunt": 5, "runner": 2, "turret": 0 },
{ "grunt": 4, "runner": 3, "turret": 1 },
{ "grunt": 6, "runner": 4, "turret": 2 },
{ "grunt": 8, "runner": 6, "turret": 3 }
]
}
Implement spawn as a pure function: read waves[waveIndex], clone that many of each type at positions around the arena rim (never on top of the player), and return the live list. Turrets stay put and fire on their own cooldown; grunts walk at the player; runners strafe. Persist the table separately from session state so a later “night arena” pack can swap rows without touching the tick. That is the whole twin stick shooter browser upgrade path too: a second table is a second mode, not a fork.
Before you draw a single bullet pixel, unit-test the spawner: wave 1 never includes a turret, wave 3 actually includes one, a grunt spawned inside the player radius is rejected and retried, and a dead enemy returned to the pool does not keep firing. Those four asserts catch the bugs that make an arena demo embarrassing — a wave that never ends, a turret that spawns on the player, and a corpse that still shoots.