Life Grid
Conway's Game of Life runs on a seeded grid, newborn cells flashing in the accent and dying cells shrinking away
$ pnpm dlx shadcn@latest add @remocn/life-gridUsage
LifeGrid plays Conway's Game of Life. A seeded first generation fills a
density share of the cells, and every next generation follows the standard
rules: a live cell with two or three live neighbors survives, and an empty
cell with exactly three is born. The board wraps at the edges, so patterns
leave one side and come back on the other, and the border never runs dry.
The step between generations is animated. A newborn cell pops in as an
accent tile with a small overshoot, then a tile in color grows from its
center and covers it. A dying cell shrinks to nothing in the first 60% of the
step. Surviving cells hold still. A faint lattice marks the empty cells.
import { LifeGrid } from "@/components/remocn/life-grid";
export const Simulation = () => <LifeGrid />;The component fills its parent and paints its own background. cols sets
the number of columns, the row count follows the composition aspect ratio,
and the square board is centered. Generations are computed once per seed,
grid size and density and cached for the render, so every frame is
deterministic and cheap after the first.
Timing
At 30 fps, speed={1} and framesPerGeneration={5}:
| Frames | Motion |
|---|---|
| 0–5 | The seeded first generation holds still |
| 5 | Generation 1 begins: newborns pop in as accent tiles, dying cells start to shrink |
| 5–8 | Dying cells shrink away |
| 7–10 | The core of each newborn grows over its accent tile |
| every 5 frames | The next generation starts |
The simulation runs for as long as the composition: it precomputes
durationInFrames × speed / framesPerGeneration generations. It has no loop
point. Over a long run the board can settle into still lifes and blinkers;
try another seed or a higher density if a seed calms down too early.
Variations
Fewer cols gives big, readable cells; more gives a fine texture.
framesPerGeneration slows the simulation for a calmer bed; at 1 the board
churns every frame. showGrid={false} removes the lattice, and gap={0}
merges neighboring cells into solid shapes.
<LifeGrid
cols={24}
density={0.3}
framesPerGeneration={8}
gap={0.08}
showGrid={false}
background="#f6f5f1"
color="#171717"
accent="#2f6bff"
/>Props10
| Prop | Type | Default |
|---|---|---|
| cols | number48 Columns, rounded, minimum 4; rows follow the frame aspect ratio | |
| density | number0.24 Share of cells alive in the seeded first generation, 0 to 1 | |
| framesPerGeneration | number5 Frames each generation is held, minimum 1 | |
| gap | number0.16 Gap between tiles as a fraction of the cell | |
| showGrid | booleantrue Draws the faint lattice of empty cells | |
| seed | number7 Seeds the first generation | |
| background | string"#111111" Background fill | |
| color | string"#FFFFFF" Living cells and the lattice | |
| accent | string"#E5322D" Flash color of newborn cells | |
| speed | number1 Playback multiplier; 0 holds the first generation | |
- colsnumber
Columns, rounded, minimum 4; rows follow the frame aspect ratio
Default
48 - densitynumber
Share of cells alive in the seeded first generation, 0 to 1
Default
0.24 - framesPerGenerationnumber
Frames each generation is held, minimum 1
Default
5 - gapnumber
Gap between tiles as a fraction of the cell
Default
0.16 - showGridboolean
Draws the faint lattice of empty cells
Default
true - seednumber
Seeds the first generation
Default
7 - backgroundstring
Background fill
Default
"#111111" - colorstring
Living cells and the lattice
Default
"#FFFFFF" - accentstring
Flash color of newborn cells
Default
"#E5322D" - speednumber
Playback multiplier; 0 holds the first generation
Default
1