When structure grants legitimacy and fear silences the majority, who holds power — and for how long?
Inspired by Conway's Game of Life — where simple rules on a grid produce complex emergent behavior , Algorithm of Revolution replaces abstract birth/death mechanics with the real dynamics of power: suppression, coordination, fear, legitimacy, and radicalization.
Every revolution begins with the same asymmetry. A small group holds power — not because they are many, but because they are organized. Their legitimacy is structural: it exists as long as the structure holds. A much larger group lives under that structure — dispersed, uncoordinated, afraid. Their power is latent. It only becomes real when they find each other.
Where Conway asked "what emerges from simple rules of life and death?", this simulation asks "what emerges from the rules of power and resistance?" The grid is the same. The cells are the same. But the rules encode something different: the geometry of oppression and the arithmetic of collective action.
This simulation models that tension.
RED cells represent centralized power. A single RED cell is fragile — it decays and dies without support. But nine RED cells arranged in a 3x3 cluster become legitimate. They can suppress adjacent opposition, expand aggressively, and rebuild when damaged. Their power is architectural. Break the structure, and the power evaporates.
This mirrors how authoritarian systems maintain control: not through popularity, but through institutional cohesion. A regime doesn't need the people's love — it needs its internal structure intact.
WHITE cells represent distributed, popular power. They vastly outnumber RED. But a single WHITE cell can do nothing alone. To eliminate even one RED cell, WHITE needs neighbors — and those neighbors need supporters nearby, and those supporters need to overcome their fear. The closer you are to concentrated power, the harder it is to act.
This is the coordination problem at the heart of every collective action dilemma. Everyone wants change, but no one wants to move first.
Fear is not abstract here — it's geometric. Every WHITE cell scans a radius around itself and counts how many RED cells it sees. The more RED in range, the more allies WHITE needs before it can act. Concentrated power doesn't just suppress; it radiates suppression. A single fortress of RED can paralyze an entire neighborhood of WHITE — not by touching them, but by being visible.
When power suppresses dissent, it doesn't always succeed in killing it. In this simulation, every WHITE cell that is eliminated spawns up to eight new cells in its wake — some WHITE, some NEUTRAL. Suppression breeds opposition. The harder RED pushes, the more enemies it creates. This is the regime's dilemma: every act of force is also an act of recruitment for the other side.
Not everyone picks a side. NEUTRAL cells are born from violence but choose their allegiance based on their surroundings. Surrounded by RED? They assimilate. Surrounded by WHITE? They radicalize. They are the silent majority that tips the balance — and their conversion is what makes the simulation's outcome genuinely unpredictable.
Revolutions don't happen in vacuums — they happen when people are desperate. A global stress variable rises with conflict intensity. High stress makes WHITE coordination easier (desperate people take more risks) and makes RED suppression faster (paranoid regimes react instantly). Stress is the accelerant that turns a slow burn into a wildfire.
Structure, time, and legitimacy decide outcomes — not raw numbers or force alone.
A well-organized minority can hold power indefinitely against a disorganized majority. But structure is brittle. One crack, one moment of coordinated pressure, and the whole thing can cascade into collapse. The simulation doesn't enforce who wins. It lets the dynamics play out and asks you to watch what emerges.
| Mechanic | Description |
|---|---|
| Legitimacy | Requires a 3x3 cluster (9 cells). Isolated RED decays and self-destructs after legitimacy_timeout steps |
| Suppression | Legitimate RED moves onto adjacent WHITE, eliminating them instantly. Costs 10 energy |
| Movement | Aggressive expansion toward WHITE. Tramples opponents. Gap-closing and rescue modes |
| Rebuilding | 3+ connected RED generate new RED cells to repair structure |
| Collapse | Surrounded by 6+ WHITE, the cluster scatters |
| Fragmentation | Very large clusters (20+) become internally unstable |
| Mechanic | Description |
|---|---|
| Attack | Needs 3+ adjacent WHITE AND enough supporters within coordination_radius |
| Fear penalty | required = base_attack_count + clamp(red_in_radius - fear_threshold, 0, max_fear) |
| Movement | Scans radius 32 for RED targets. Anti-stagnation forces repositioning after 5 idle steps |
| Momentum | Success +5, failure -5. High momentum enables better coordination |
| Radicalization | When eliminated, spawns up to 8 new cells (WHITE or NEUTRAL) |
| Mechanic | Description |
|---|---|
| Spawn | 30% chance when WHITE is eliminated (instead of full radicalization) |
| Assimilation | 3+ RED neighbors → converts to RED |
| Radicalization | 3+ WHITE neighbors → converts to WHITE |
| Legitimacy block | Conversion to WHITE is blocked near high-legitimacy RED |
Each simulation step applies rules in this exact sequence:
- Copy current state to next buffer
- WHITE movement — seek RED targets, anti-stagnation
- Legitimacy timers — cluster-based reset, isolated decay, self-destruct
- RED cluster movement — attack, gap-close, rescue, trample (costs energy)
- WHITE coordinated attacks — fear factor + stress modifier + buildup delay
- Structural collapse — surrounded clusters scatter
- RED reforming — broken clusters merge toward nearest ally
- RED counter-attack — small clusters fight back (1 cell = 1 kill)
- Radicalization — eliminated WHITE spawns new cells
- RED rebuilding — threshold-based spawn for damaged clusters
- Neutral conversion — neighbor-based assimilation
- Global metrics — update tension and stress
- Commit — swap buffers, update population counts
The simulation engine has been fully ported from the original Go prototype to TypeScript. This is the current, actively maintained version. It runs entirely in a Web Worker — no backend needed. Pure static site.
Prerequisites: Node.js 20+
cd app
# Install dependencies
npm install
# Development server (hot reload)
npm run dev
# Production build
npm run build
# Preview production build
npm run preview- Simulation engine runs in a Web Worker — keeps the UI thread free
- Grid data uses Structure of Arrays with TypedArrays for performance on large grids
- Snapshots transferred via
postMessagewith TransferableUint8Array— zero-copy - Canvas rendering uses
ImageDatapixel manipulation with blur/glow post-processing - Dark/light theme with CSS variables and
localStoragepersistence
- React 19 + TypeScript 5.9
- Vite 7
- No UI libraries — pure CSS with glass morphism, Inter + JetBrains Mono fonts
The original prototype was built in Go 1.22 with terminal-based visualization. It is no longer under active development but remains in the repository as a reference implementation.
See doc/GO_PROTOTYPE.md for full documentation on running and configuring the Go version.
# Quick start
go run ./cmd/simulator
# Build and run
make build && ./simulatorcd app
npm run build
GOOGLE_APPLICATION_CREDENTIALS=./firebase-service-account.json firebase deploy --only hostingThe firebase-service-account.json file is gitignored. Deployment only works from machines that have this credential file.
All parameters can be set via config.yaml (Go) or the in-app configuration panel (Web).
| Parameter | Type | Default | Description |
|---|---|---|---|
world_size |
int | 256 | Grid dimensions (NxN) |
fear_radius |
int | 5 | How far RED radiates fear |
fear_threshold |
int | 3 | RED count before fear kicks in |
max_fear |
int | 5 | Maximum coordination penalty from fear |
legitimacy_timeout |
int | 10 | Steps before isolated RED self-destructs |
legitimacy_threshold |
int | 50 | Steps for legitimacy accumulation |
red_cluster_size |
int | 9 | Cells in a legitimate cluster (3x3) |
red_rebuild_threshold |
int | 3 | Connected RED needed to trigger rebuild |
red_rebuild_spawn_count |
int | 5 | New RED spawned during rebuild |
red_spawn_rate |
float | 0.5 | Probability of RED generation |
energy_cost |
int | 10 | Energy cost per RED action |
base_white_attack_count |
int | 3 | Base WHITE needed to eliminate 1 RED |
white_collapse_threshold |
int | 6 | WHITE needed to collapse a RED cluster |
white_spawn_count |
int | 8 | Cells spawned when WHITE is eliminated |
coordination_radius |
int | 8 | Radius for WHITE supporter counting |
momentum_decay |
int | 5 | Momentum loss on failed WHITE attack |
initial_white_count |
int | 16 | Starting WHITE cells |
initial_red_cluster_count |
int | 1 | Starting RED clusters |
neutral_spawn_chance |
float | 0.3 | Chance eliminated WHITE becomes NEUTRAL |
stress_impact |
float | 0.1 | How much stress affects mechanics |
terminal_g/
├── doc/ # Documentation
├── cmd/simulator/ # Go prototype entry point
├── pkg/
│ ├── cell/ # Cell state definitions
│ ├── config/ # Configuration (YAML/JSON)
│ ├── world/ # Grid, double-buffer, neighbors
│ ├── rules/ # 12-step rule engine (~1450 lines)
│ ├── simulator/ # Step orchestration, win detection
│ ├── display/ # Terminal rendering, statistics
│ └── server/ # WebSocket server for web mode
├── web/ # Vanilla JS frontend (for Go backend, prototype)
├── app/ # React/TypeScript app (current version)
│ ├── src/
│ │ ├── simulation/ # Engine port (types, world, rules, worker)
│ │ ├── components/ # React UI (landing, config, sim panels)
│ │ ├── hooks/ # useSimulationWorker, useTheme
│ │ ├── worker/ # Worker message protocol
│ │ └── styles/ # CSS (tokens, components, layouts)
│ ├── firebase.json # Hosting configuration
│ └── package.json
├── config.yaml # Simulation parameters
├── Makefile
└── RULES.md # Detailed rule documentation
MIT
