Architecture

This document describes LifeGrid’s internal architecture and module relationships.


High-Level Overview

┌──────────────────────────────────────────────────┐
│                  Entry Points                    │
│  main.py (GUI)   cli.py (CLI)   api/app.py (API) │
└──────┬──────────────┬──────────────┬─────────────┘
       │              │              │
       ▼              ▼              ▼
┌──────────────────────────────────────────────────┐
│               Core Engine Layer                  │
│  Simulator  ←→  SimulatorConfig                  │
│      │                                           │
│      ├── UndoManager      (state history)        │
│      ├── BoundaryMode     (wrap/fixed/reflect)   │
│      └── CellularAutomaton (abstract base)       │
└──────────────────────────────────────────────────┘
       │
       ▼
┌──────────────────────────────────────────────────┐
│             Automata Implementations             │
│  ConwayGameOfLife  │  HighLife  │  Wireworld     │
│  BriansBrain       │  LangtonsAnt │ Generations  │
│  ImmigrationGame   │  RainbowGame │ HexagonalGoL │
│  LifeLikeAutomaton (custom B/S rules)            │
└──────────────────────────────────────────────────┘
       │
       ▼
┌──────────────────────────────────────────────────┐
│              Support Modules                     │
│  ExportManager    │  PatternManager              │
│  PluginManager    │  ConfigManager (AppConfig)   │
│  ThemeManager     │  StatisticsCollector          │
│  EnhancedStatistics │ PatternAnalyzer            │
│  RLEParser/Encoder  │ CellAgeTracker             │
│  HeatmapGenerator   │ SymmetryAnalyzer           │
│  RuleDiscovery      │ GPUSimulator               │
└──────────────────────────────────────────────────┘

Module Breakdown

Entry Points

Module

Purpose

src/main.py

Launches the Tkinter GUI via AutomatonApp

src/cli.py

Headless CLI with argparse. Creates a Simulator, runs N steps, exports results.

src/api/app.py

FastAPI server with REST endpoints and WebSocket streams

Core (src/core/)

Module

Key Classes

Responsibility

simulator.py

Simulator

Orchestrates automaton stepping, undo/redo, metrics, callbacks

config.py

SimulatorConfig

Dataclass holding grid size, speed, mode, rule sets, feature flags

undo_manager.py

UndoManager

Bounded stack of grid snapshots (default 100)

boundary.py

BoundaryMode, convolve_with_boundary(), roll_with_boundary()

Edge-handling strategies

utils.py

Utility functions

Shared helpers

The Simulator owns a CellularAutomaton instance and an UndoManager. On each step() call it:

  1. Pushes the current grid to the undo stack.

  2. Calls automaton.step().

  3. Records metrics (generation, population, density).

  4. Fires the on-step callback.

Automata (src/automata/)

All automata inherit from CellularAutomaton (defined in base.py) which provides:

  • step() — advance one generation

  • get_grid() -> np.ndarray — return the current grid

  • set_cell(x, y, value) — set a cell value

  • reset() — clear the grid

  • boundary: str — edge mode ("wrap" | "fixed" | "reflect"), default "wrap"

All convolution-based automata use core.boundary.convolve_with_boundary() (wrapping scipy) instead of calling scipy.signal.convolve2d directly. This routes every neighbour count through the correct boundary handler.

LifeLikeAutomaton additionally caches the Moore-neighbourhood kernel as a class-level constant (_KERNEL) to avoid re-allocation on every step.

LangtonsAnt exposes get_population_grid() which returns the raw cell grid without the ant-marker overlay (used for population statistics).

LifeLikeAutomaton accepts arbitrary B/S rules via parse_bs(), making it the backbone of custom-rule support and the Rule Explorer.

GUI (src/gui/)

Module

Purpose

app.py

AutomatonApp — main window, menus, toolbar, event loop. Owns AutoSaveManager (started on init, stopped on close).

rendering.py

Canvas drawing: cells, grid lines, overlays. Uses a PIL/Pillow fast-path (_draw_pil_fast) when Pillow is installed and grid lines are hidden — a single PhotoImage replace instead of per-cell create_rectangle calls.

ui.py

UI builder: creates widgets, binds callbacks

config.py

GUI constants: MODE_FACTORIES, MODE_PATTERNS, colors

state.py

SimulationState — mutable runtime state (grid, speed, history deques). export_metrics_csv() dynamically discovers all metric keys; _calculate_complexity() is vectorised with numpy.lib.stride_tricks.sliding_window_view; seen_hashes is capped at 2 000 entries with LRU-style eviction.

tools.py

ToolManager — pencil/eraser/stamp/selection, brush settings. Drag gestures push exactly one undo checkpoint regardless of stroke length.

new_features.py

GenerationTimeline, PopulationGraph, BreakpointManager, RuleExplorer, CommandPalette, ThemeEditorDialog, PatternShapeSearch

enhanced_features.py

Additional feature widgets

enhanced_rendering.py

Enhanced rendering utilities

icon_factory.py

Procedural icon generation

layouts.py

Layout management helpers

modern_ui.py

Modern UI components (styled buttons, frames)

ui_polish.py

Visual refinements

The GUI uses Tkinter’s grid geometry manager throughout. The main layout is:

root
└── content_frame (grid)
    ├── toolbar (row 0, sticky EW)
    ├── sidebar (row 1, column 0)
    ├── canvas  (row 1, column 1)
    ├── timeline (row 2, columnspan 2)
    ├── graph   (row 3, columnspan 2)
    └── statusbar (row 4, columnspan 2)

API (src/api/)

Module

Purpose

app.py

FastAPI application with session CRUD, stepping, state retrieval, pattern loading, WebSocket streaming

collab.py

CollaborativeSession — multi-client shared grid with asyncio lock

Sessions are stored in a module-level dict keyed by UUID. The collaborative endpoint creates sessions on demand.

Advanced Analytics (src/advanced/)

Module

Key Classes

Purpose

statistics.py

StatisticsCollector, StatisticsExporter

Per-generation metrics collection via .collect(step, grid), CSV/plot export

enhanced_statistics.py

EnhancedStatistics

Entropy, complexity, fractal dimension, connected components, cluster stats, symmetry, centre of mass, radial distribution (static-method API)

pattern_analysis.py

PatternAnalyzer

Bounding box, period detection, displacement detection

pattern_manager.py

PatternManager, PatternEntry

Favourites/history backed by JSON, tag-based search, similarity matching. Add patterns with add_favorite(PatternEntry.from_grid(...)).

rle_format.py

RLEParser, RLEEncoder

Run-Length Encoded I/O. RLEParser.parse(rle_string) returns (grid: np.ndarray, metadata: dict).

rule_discovery.py

RuleDiscovery

Vectorised observe_transition(before, after) using np.roll stacking — no Python nested loop over cells. Infers B/S rules from transitions.

cell_tracker.py

CellAgeTracker(width, height), CellHistoryTracker

Track cell age, birth/death history

visualization.py

HeatmapGenerator, SymmetryAnalyzer

Activity/age heatmaps, symmetry detection and scoring

Performance (src/performance/)

Module

Key Classes

Purpose

gpu.py

GPUSimulator, xp backend

CuPy-accelerated Life-like simulation with NumPy fallback

benchmarking.py

Benchmarking utilities

Performance measurement and reporting

Plugin System (src/plugin_system.py)

PluginManager scans a directory for .py files, imports them, finds AutomatonPlugin subclasses, and registers them. Plugins are discovered at GUI startup from the plugins/ directory.

Export & Persistence (src/export_manager.py, src/autosave_manager.py)

ExportManager handles all output formats (PNG, GIF, MP4, WebM, JSON). It accumulates frames for animation export and supports 4 colour themes (light, dark, blue, warm).

Key method signatures:

em.export_png(grid, filepath, cell_size=8)      # grid is first arg
em.export_gif(filepath, cell_size=8, duration=100)
em.export_json(filepath, grid, metadata=None)
em.export_video(filepath, cell_size=8, fps=10, codec="mp4")

AutoSaveManager runs a background thread that calls a user-supplied callback and writes the return value as JSON to a configurable directory. It is started with am.start() and stopped cleanly with am.stop().

# Default: saves to ./autosave/ every 300 seconds, keeps 5 backups
am = AutoSaveManager(save_dir="autosave", interval=300, max_backups=5)
am.set_save_callback(lambda: {"generation": sim.generation, "grid": sim.get_grid().tolist()})
am.start()

Configuration

Module

Class

Storage

src/core/config.py

SimulatorConfig

In-memory dataclass

src/config_manager.py

AppConfig

Persisted to settings.json


Data Flow

GUI Simulation Loop

User clicks Start
    → AutomatonApp sets running = True
    → Tkinter after() callback fires every (101 - speed) ms
        → Simulator.step()
            → UndoManager.push_state(grid)
            → CellularAutomaton.step()  ← uses convolve_with_boundary()
            → Metrics recorded
            → on_step callback fires
        → Canvas re-rendered (PIL fast-path if Pillow available + grid lines off)
        → Timeline updated
        → PopulationGraph updated
        → Breakpoints checked
        → AutoSaveManager fires on its own background thread (every 60s)

CLI Pipeline

argparse → build SimulatorConfig → Simulator.initialize()
    → loop N steps, collecting frames
    → ExportManager.export_*(frames, output_path)

API Request Flow

HTTP POST /session → create Simulator → store in sessions dict → return UUID
HTTP POST /session/{id}/step → lookup Simulator → step() → return generation
WS /session/{id}/stream → lookup Simulator → loop: step + send JSON state
WS /collab/{id} → lookup or create CollaborativeSession → broadcast mutations