DEV Community

Sorceress for Sorceress

Posted on Originally published at sorceress.games

How to Make a Snake Game in the Browser (Grid Loop, 2026)

Originally published on the Sorceress blog.

TL;DR: a fixed-tick grid, a growing body, food on empty cells, death on wall or self-collision. Under ~350 lines of vanilla JS.

Scope it first

"Snake" covers three builds: a Python turtle classroom demo, a multiplayer .io arena (weeks of backend), or a single-player browser snake — fixed grid, fixed tick, arrow/WASD turns, respawning food, growth on eat, death on wall or self. The last is the weekend build.

The grid loop in one minute

  1. Input — read arrow/WASD presses into a one-slot nextDirection buffer; reject reverses.
  2. Tick — every N ms, take direction from the buffer, compute the next head cell, advance.
  3. Eat — if the next cell holds food, push a new head without dropping the tail, then respawn food on a random empty cell. Otherwise push head and shift tail.
  4. Collide — if the next cell is out of bounds or in the body, stop and show Game Over.
  5. Score — increment on eat; optionally shrink tickMs every few points so tension ramps.

Portals, wrap-around walls and power-ups are polish added after one apple feels fair.

Two details that bite beginners

  • One-slot direction buffer. Writing direction on keydown lets a fast double-tap reverse the snake into itself. Queue one turn per tick, validated against the current direction.
  • Food respawn. Pick from the set of empty cells, not a random cell retried until free — the retry loop degenerates as the board fills.

Picking an engine

  • Vanilla JS + canvas — the default. Fill rects per segment, fixed tick, paint with requestAnimationFrame.
  • DOM grid with CSS cells — accessible labels per tile; heavy at larger boards.
  • Phaser 4 — Scene lifecycle and tweens; you still write the tick and reverse-guard.

Full guide: sorceress.games

Top comments (1)

Collapse
 
marcusykim profile image
Marcus Kim

The one-slot nextDirection buffer is the small detail that keeps fast double-taps from turning a fair game into a mysterious self-collision. Building food placement from the set of empty cells is similarly important once the board gets crowded, where retrying random coordinates can become unpredictable. One edge case worth defining explicitly is whether the next head may enter the current tail cell when the snake is not eating: allowing it requires collision detection to account for the tail moving on that tick, but it also keeps tight endgame paths fair.