DEV Community

Devanshu Biswas
Devanshu Biswas

Posted on

I Built Frogger in 120 Lines of Vanilla JavaScript

Frogger looks like a different beast from a side-scroller — roads, rivers, hopping, riding logs. But under the hood it's one of the cleanest little game-design lessons there is: lanes of moving rectangles, and one rule per terrain. Let me build it from scratch in vanilla JavaScript.

This is Day 8 of GameFromZero, where I rebuild a classic game every day.

Hopping, not gliding

Unlike Flappy Bird's smooth physics, Frogger moves in discrete hops. Each arrow press changes the frog's row (up/down) or shifts it one cell left/right. Snapping to a grid is exactly what gives Frogger its timing-puzzle feel — you commit to a square and live with it.

if (key === "ArrowUp")   frog.row++;
if (key === "ArrowLeft") frog.x -= CELL;
Enter fullscreen mode Exit fullscreen mode

Lanes that scroll and wrap

Each road or river row is a "lane" with its own direction and speed. Every frame the obstacles slide along; when one exits one side it reappears on the other. That endless wrap is what makes a few rectangles feel like continuous traffic.

for (const o of lane.items) {
  o.x += lane.speed;
  if (o.x > W) o.x = -o.w;   // wrap around
}
Enter fullscreen mode Exit fullscreen mode

Two terrains, two opposite rules

This is the heart of Frogger, and it's beautifully symmetric:

The road kills on contact. On a road row, the frog dies if its box overlaps any car's box — the same axis-aligned overlap check from every collision-based game.

if (onRoad && cars.some(car => overlap(frog, car))) die();
Enter fullscreen mode Exit fullscreen mode

The river is inverted. Here, open water kills and a log saves you. So you must be standing on a log — and while you are, the log carries you sideways at its speed. Drift off the screen edge and you drown.

const log = logs.find(l => overlap(frog, l));
if (onRiver) log ? (frog.x += log.speed) : die();
Enter fullscreen mode Exit fullscreen mode

Same overlap test, opposite consequence. That single inversion is what makes the river feel so different from the road.

Reaching the top

When the frog reaches the top grass row, you score and it respawns at the bottom to do it again. Add a few lives and you've got the full game loop:

if (frog.row === TOP) { score++; resetFrog(); }
Enter fullscreen mode Exit fullscreen mode

What you actually learn

Frogger teaches a pattern you'll reuse constantly: independent lanes of recycled objects, each with its own behaviour, and per-terrain rules for the player. That structure scales up to endless runners, tower-defense paths, traffic sims — anything with "stuff moving across the screen in tracks."

And the deeper lesson: a game's feel often comes from one clever rule (here, "the river's logic is flipped"), not from piles of code. Frogger is maybe 120 lines, and most of it is drawing rectangles.

👉 Play it (arrow keys — click the board first): https://dev48v.infy.uk/game/day8-frogger.html

🌐 All games: https://dev48v.infy.uk/gamefromzero.php

Tomorrow: Space Invaders.

Top comments (0)