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"
/>| Prop | Type | Default | Description |
|---|---|---|---|
cols | number | 48 | Columns, rounded, minimum 4; rows follow the frame aspect ratio |
density | number | 0.24 | Share of cells alive in the seeded first generation, 0 to 1 |
framesPerGeneration | number | 5 | Frames each generation is held, minimum 1 |
gap | number | 0.16 | Gap between tiles as a fraction of the cell |
showGrid | boolean | true | Draws the faint lattice of empty cells |
seed | number | 7 | 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 | number | 1 | Playback multiplier; 0 holds the first generation |