webdevpuneet.com

Lights Out Puzzle Game — Free HTML CSS JS Snippet

Lights Out Puzzle Game · Games · Plain HTML, CSS & JS · Live preview

CategoryGames

For supporters

Source Code

Want the source code?

Play the game for free. Become a WebDevPuneet supporter to unlock the complete HTML, CSS and JavaScript source code, the exports (HTML, React, Vue, Angular, Tailwind) and Fork.

Play freeSource code: Patreon

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

applyToggle() implements the classic plus-shaped neighbor toggle rule with edge bounds checking
Puzzles are generated by replaying random toggles from the solved state, guaranteeing solvability with no solver needed
Reset puzzle replays the exact same seed sequence; New puzzle generates a fresh random seed
Live move counter and a best-moves-to-solve record tracked for the session
Win detection via a single board.every() check — no partial-credit state
Grid is built once and updated by toggling CSS classes, not full DOM re-renders
Glowing lit-tile styling with inset box-shadow and CSS transitions for tactile feedback
Configurable SIZE constant scales the grid and all logic to any board dimension

About this UI Snippet

Lights Out Puzzle Game — 5x5 Toggle Grid with Guaranteed-Solvable Generation

Screenshot of the Lights Out Puzzle Game snippet rendered live

Lights Out is a classic electronic puzzle from the 1990s: a grid of lights where clicking one tile toggles it and its orthogonal neighbors, and the goal is to turn every light off. It is a pure logic puzzle rooted in linear algebra over GF(2) — every toggle is its own inverse, which makes it possible to generate a puzzle that is provably solvable without running any solver at all. This snippet implements a complete playable 5x5 board in vanilla JavaScript: click handling, the plus-shaped toggle rule, guaranteed-solvable puzzle generation, a move counter, and a best-score tracker.

The plus-shaped toggle rule

applyToggle(r, c) flips the clicked cell and its four orthogonal neighbors (up, down, left, right — never diagonals), skipping any neighbor that falls outside the SIZE x SIZE grid. This five-cell "plus" pattern is the entire rule set of the game. Every other mechanic — solvability, the win condition, puzzle generation — follows directly from how this one function behaves.

Why random toggles from the solved state always produce a solvable puzzle

Because every toggle operation is its own inverse (applying the same toggle twice returns a cell to its original state) and toggles commute with each other, any sequence of toggles applied to the solved, all-off board can be undone by applying the exact same sequence of toggles again, in any order. generatePuzzle() exploits this directly: it starts from an all-off board, records a random sequence of cell coordinates in seed, and applies each one silently. The resulting scrambled board is guaranteed solvable — no backtracking solver or brute-force search is needed to prove it, because the seed sequence itself is a valid solution.

Reset versus New Puzzle

The two action buttons expose this property directly. "Reset puzzle" replays the same seed array from a cleared board, restoring the identical starting position without re-randomizing it — useful if you want to retry a specific puzzle after a failed attempt. "New puzzle" calls generatePuzzle() again, producing a fresh random seed and therefore a fresh solvable puzzle.

Move counting and win detection

Every click that isn't ignored (input is locked once won is true) increments moves and re-renders the grid. checkWin() runs after every move and simply checks whether every entry in the board array is false — Lights Out has no partial-credit state, only fully off or not yet solved. When the board clears, the game locks input, shows the final move count, and updates best if this run beat the previous record for the session.

Rendering as toggled CSS classes, not redrawn DOM

buildGrid() creates the 25 button elements once, and every subsequent update only toggles the .on class via render() — the DOM nodes themselves are never rebuilt during play. This keeps the click handler wiring stable and avoids the flicker or lost focus state that full re-renders can introduce in a rapid-click puzzle game.

Step by step

How to Use

  1. 1
    Click any lit tileClicking a tile calls applyToggle(r, c), which flips that cell and its up/down/left/right neighbors — never diagonals.
  2. 2
    Watch the move counterEvery accepted click increments the moves stat shown in the header, live.
  3. 3
    Turn every light off to wincheckWin() runs after each move and checks board.every(v => v === false). Clearing the board locks the grid and shows your final move count.
  4. 4
    Reset to retry the same puzzleClick "Reset puzzle" to replay the same random seed array from a cleared board — useful for re-attempting a puzzle you scrambled up.
  5. 5
    Generate a new puzzleClick "New puzzle" to call generatePuzzle() again, which applies a fresh set of random toggles from the solved state.
  6. 6
    Tune the grid sizeChange the SIZE constant in the JS panel to build a 3x3, 4x4, or larger board — the toggle and win logic scale automatically.

Real-world uses

Common Use Cases

Brain-training and puzzle game collections
A self-contained logic puzzle that fits alongside other grid-based games like the sliding puzzle game or minesweeper in a games hub.
Teaching linear algebra over GF(2)
Lights Out is a textbook example of a system of equations over the field with two elements. Use this snippet as a concrete, interactive demo before introducing the underlying matrix theory.
Loading-screen or empty-state distraction
Drop the puzzle into an idle moment in a product — a waiting room, an empty dashboard state, or a loading screen — as a lightweight, dependency-free timekiller.
Reference implementation of state-toggle generation
The seed-and-replay generation technique (apply random moves from a known-solved state to guarantee solvability) generalizes to any puzzle built on invertible, commutative operations.
Neon-tile visual style reference
The glowing yellow lit-tile treatment with inset shadows is directly reusable for any toggle-grid or status-light dashboard visualization.

Got questions?

Frequently Asked Questions

applyToggle(r, c) flips the clicked cell and its up, down, left, and right neighbors (never diagonals), skipping any neighbor that falls outside the grid boundary. This five-cell plus pattern is the entire rule set of the game.

Every toggle in Lights Out is its own inverse and toggles commute, so any sequence of random toggles applied to the all-off solved board can always be undone by applying that exact same sequence again. generatePuzzle() records the random sequence it applies as seed, which doubles as a guaranteed valid solution.

Reset puzzle replays the stored seed array from a cleared board, restoring the exact same starting position. New Puzzle calls generatePuzzle() again to produce a brand-new random seed and a different scrambled board.

Yes. Change the SIZE constant in the JS panel. The board array, toggle logic, win check, and CSS grid-template-columns all reference SIZE, so a 3x3, 4x4, or 7x7 board works without further changes.

No, best is held in a plain JavaScript variable for the current session only. To persist it across visits, read and write the value to localStorage inside startPuzzle() and checkWin().

Yes, but this snippet does not compute it — it only verifies the seed sequence itself is a valid solution. Finding the minimum-move solution requires solving the underlying linear system over GF(2), which is a good extension exercise but outside the scope of the base game.