← Back to Blog

Building Glyph Lock: A Pattern-Deduction Game as an npm Package

Play Glyph Lock →
Share

Why I Built Glyph Lock

Most pattern games show you the pattern and ask you to remember it. Glyph Lock reverses this: it shows you partial evidence and asks you to deduce the underlying rule. You see some cells filled in with colors, and you need to figure out what pattern governs the entire grid, then fill in the missing cells.

This creates a fundamentally different kind of challenge. Memory games test recall. Glyph Lock tests reasoning. The same pattern algorithm can feel completely different depending on which cells are revealed and which are hidden.

Pattern System Architecture

The core of Glyph Lock is its pattern system. Eight base pattern algorithms generate color grids: alternating rows, alternating columns, checkerboard, diagonal stripes, concentric rings, quadrants, border fill, and spiral. Each algorithm takes a grid size and a color palette, then assigns a color to every cell according to its rule.

typescript
const checkerboard: PatternFn = (row, col, _size, colors) => { return colors[(row + col) % colors.length]; }; const diagonalStripes: PatternFn = (row, col, _size, colors) => { return colors[(row + col) % colors.length]; }; const concentricRings: PatternFn = (row, col, size, colors) => { const center = (size - 1) / 2; const ring = Math.round(Math.max(Math.abs(row - center), Math.abs(col - center))); return colors[ring % colors.length]; };

The real power comes from composition. At higher levels, two patterns are combined: for example, checkerboard plus concentric rings. The combination function takes two patterns and a blend mode, producing grids that require recognizing multiple overlapping rules.

Grid Generation and Hiding

Grid generation works in two phases. First, the full grid is generated from a selected pattern. Then cells are hidden based on the current level's hide percentage. Level 1 hides 30% of cells. By level 10, 70% are hidden.

The hiding algorithm is not purely random. It ensures that enough of each color remains visible for deduction to be possible. If a color only appears in three cells and all three are hidden, the pattern becomes undeducible. The algorithm tracks color coverage and biases hiding toward over-represented colors.

Difficulty Progression

Difficulty scales along four axes: grid size increases from 4x4 to 8x8, the number of colors increases from 2 to 4, the hide percentage increases, and the timer decreases. Early levels use simple patterns like alternating rows with 2 colors. Later levels combine two patterns with 4 colors on an 8x8 grid with 70% hidden and a 15-second timer.

The level selection algorithm picks patterns appropriate for the current difficulty tier. Simple patterns appear in early levels. Combined patterns appear only after level 5, when players have seen individual patterns enough to recognize them in combination.

Input and Color Picking

The color picker shows the available colors for the current level. Tap a color to select it, then tap empty cells to fill them. This two-step interaction works well on both mobile and desktop. Cells can be overwritten before submission, so mistakes are easily corrected.

Validation runs on submit: every hidden cell is checked against the full pattern grid. If all cells match, you advance. If any cell is wrong, you lose a life. Three lives total, no partial credit. This makes submission feel weighty, you want to be sure before committing.

State Management

Game state is managed through pure functions. createInitialState generates a fresh game. fillCell updates a single cell's color. submitGrid validates and transitions to the next level or deducts a life. tick decreases the timer. Every state transition is a pure function that returns a new state object.

This architecture made testing straightforward: 50 tests cover all 8 pattern algorithms, grid generation, hiding logic, validation, state transitions, and edge cases like submitting with unfilled cells or running out of timer.

Lessons Learned

The hardest part was calibrating difficulty. The jump from single patterns to combined patterns is steep. Players who breeze through levels 1-5 often hit a wall at level 6 when combinations appear. Adding a brief flash animation that highlights the correct answer when you lose a life helps players learn faster without making the game easier.

Pattern games need variety to stay interesting. Eight base patterns with composition give dozens of possible grids. But even that can feel repetitive. The randomized hiding ensures that even if you see the same pattern twice, the deduction challenge is different each time.

Get more posts like this

I write about system design, backend engineering, and building npm packages from scratch. Follow along on Substack for new posts.

Subscribe on Substack →