# ujjwalvivek/loom architecture

> Architecture diagram of the GitHub repository ujjwalvivek/loom, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-06-22). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/ujjwalvivek/loom
- Repository: https://github.com/ujjwalvivek/loom

## Overview

1. **What this repo is**
   - Loom Engine is a Go-based 2D game engine split into small packages for rendering, physics, audio, input, ECS, performance telemetry, and a terminal renderer.
   - The repo contains the engine itself plus two example games: a graphical Mario demo and a terminal-based Mario demo.

2. **Main application entry points**
   - `examples/mario` is the OpenGL/GLFW version.
   - `examples/mario-term` is the text-mode version built on the terminal renderer.
   - Both examples are the best places to understand how the engine packages are composed into a runnable game.

3. **Core orchestration lives in `engine/`**
   - `engine/engine.go`, `loop.go`, `context.go`, `config.go`, and `scene.go` hold the runtime shell around the game.
   - This layer owns startup/shutdown, frame stepping, shared runtime configuration, and the context object passed to systems.
   - The README indicates the engine is designed around concurrent subsystems, so this package is the coordination boundary rather than a game-logic layer.

4. **ECS is the game-state backbone**
   - `ecs/` provides archetypes, queries, systems, commands, and world management.
   - The ECS is used to organize gameplay entities like player, level objects, positions, and physics components.
   - The README notes concurrent write safety is still a concern, so ECS is the main shared state model and also a boundary where parallelism must be controlled.

5. **Input flows in from GLFW**
   - `input/` wraps keyboard and mouse handling, exposing both current-state polling and discrete actions.
   - Input is a front-end boundary: it converts window-system events into engine-level actions that can be consumed by gameplay, physics, or UI code.
   - The repo does not show a gamepad implementation yet, and the README calls that out as future work.

6. **Physics is its own simulation subsystem**
   - `physics/` contains AABB collision, a spatial grid, and the main physics integrator.
   - The README describes it as a swept-collision, multi-pass sliding solver, optimized for platformer movement.
   - Architecturally, physics is treated as a separate simulation worker that receives commands/input and produces state snapshots for rendering.

7. **Rendering is OpenGL-based and batching-oriented**
   - `renderer/` implements the graphical front end: batching, camera, post-processing hooks, shader and texture management.
   - It targets OpenGL 3.3 and is built around batching sprites/shapes to reduce draw overhead.
   - The renderer consumes the latest simulation state and draws on the main OS thread alongside the GLFW window context.

8. **Audio is procedural and streamed separately**
   - `audio/` contains a synth, sequencer, and high-level audio control.
   - The README says it uses Oto v3 underneath for streaming PCM audio.
   - Audio is intentionally decoupled from rendering and physics: gameplay emits events, and the audio thread turns them into sound effects or sequenced music.

9. **Performance telemetry is a first-class subsystem**
   - `perf/` contains overlays and GC-related instrumentation.
   - The README emphasizes live GC tuning and frame-time visualization, so this package is not just debugging glue; it is part of the engine’s runtime observability.
   - It connects to the engine loop to show frame timing, GC pauses, and tuning effects in real time.

10. **Terminal rendering is a parallel frontend**
   - `termrenderer/` is a separate rendering backend that rasterizes shapes and sprites into a character grid.
   - It has platform-specific input support for Unix and Windows, indicating it can run without the OpenGL/GLFW stack.
   - This package lets the same kind of game logic drive a non-graphical output path.

11. **Shared math utilities**
   - `math/` provides vector, rectangle, and color types plus noise generation.
   - These types are the common geometry and visual primitives used across physics, rendering, and content generation.

12. **Example game structure**
   - The Mario examples are decomposed into `art.go`, `audio.go`, `entities.go`, `level.go`, and `main.go`.
   - That layout shows how the engine expects a game to be built: content/assets, entity setup, level logic, and startup wiring are kept separate from the engine core.

13. **Testing and release shape**
   - There are focused tests in `audio/`, `ecs/`, and `physics/`, which suggests those packages are the most behavior-critical subsystems.
   - GitHub Actions workflows for release and deploy indicate the repo ships packaged binaries, likely especially for the example games.

14. **High-level data flow**
   - Input enters through GLFW or terminal input wrappers.
   - The engine loop dispatches that input into ECS/game systems and physics.
   - Physics emits updated world snapshots.
   - Renderer or termrenderer consumes the latest snapshot to draw a frame.
   - Audio receives event commands and streams sound independently.
   - Perf overlays observe the loop and GC behavior rather than participating in gameplay state.

Main entry points: [`engine/engine.go`](https://github.com/ujjwalvivek/loom/blob/main/engine/engine.go) (Engine), [`examples/mario/main.go`](https://github.com/ujjwalvivek/loom/blob/main/examples/mario/main.go) (Mario demo), [`examples/mario-term/main.go`](https://github.com/ujjwalvivek/loom/blob/main/examples/mario-term/main.go) (Mario term demo), [`ecs/world.go`](https://github.com/ujjwalvivek/loom/blob/main/ecs/world.go) (ECS)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_core["Core runtime"]
  node_engine["Engine<br/>runtime shell<br/>[engine.go]"]
  node_ecs["ECS<br/>state model<br/>[world.go]"]
  node_physics["Physics<br/>simulation<br/>[physics.go]"]
  node_audio["Audio<br/>streaming synth<br/>[audio.go]"]
  node_perf["Perf<br/>telemetry<br/>[perf.go]"]
  node_math["Math<br/>geometry types<br/>[vec2.go]"]
  node_ecs_world["World<br/>ecs storage<br/>[world.go]"]
  node_ecs_queries["Queries<br/>ecs access<br/>[query.go]"]
  node_ecs_systems["Systems<br/>ecs execution<br/>[system.go]"]
  node_physics_solver["Solver<br/>collision stepper<br/>[physics.go]"]
  node_audio_synth["Synth<br/>sound generation<br/>[synth.go]"]
  node_audio_seq["Sequencer<br/>music timing<br/>[sequencer.go]"]
end

subgraph group_frontends["Frontends"]
  node_input["Input<br/>event bridge<br/>[input.go]"]
  node_renderer["Renderer<br/>OpenGL frontend<br/>[renderer.go]"]
  node_termrenderer["Terminal renderer<br/>text frontend<br/>[terminal.go]"]
  node_renderer_batch["Batching<br/>draw pipeline<br/>[batch.go]"]
  node_renderer_camera["Camera<br/>view transform<br/>[camera.go]"]
end

subgraph group_examples["Examples"]
  node_mario["Mario demo<br/>graphical game<br/>[main.go]"]
  node_mario_term["Mario term demo<br/>terminal game<br/>[main.go]"]
end

node_engine -->|"reads input"| node_input
node_engine -->|"updates state"| node_ecs
node_engine -->|"steps sim"| node_physics
node_engine -->|"presents frame"| node_renderer
node_engine -->|"presents frame"| node_termrenderer
node_engine -->|"triggers audio"| node_audio
node_engine -->|"reports timing"| node_perf
node_ecs -->|"stores entities"| node_ecs_world
node_ecs -->|"reads components"| node_ecs_queries
node_ecs -->|"runs systems"| node_ecs_systems
node_physics -->|"solves collisions"| node_physics_solver
node_physics -->|"uses geometry"| node_math
node_renderer -->|"batches draws"| node_renderer_batch
node_renderer -->|"projects view"| node_renderer_camera
node_renderer -->|"uses primitives"| node_math
node_audio -->|"generates sound"| node_audio_synth
node_audio -->|"schedules notes"| node_audio_seq
node_audio -.->|"uses primitives"| node_math
node_mario -->|"boots through"| node_engine
node_mario -->|"uses graphics"| node_renderer
node_mario -->|"handles controls"| node_input
node_mario -->|"plays sound"| node_audio
node_mario -->|"builds world"| node_ecs
node_mario -->|"uses collision"| node_physics
node_mario_term -->|"boots through"| node_engine
node_mario_term -->|"uses terminal"| node_termrenderer
node_mario_term -->|"handles controls"| node_input
node_mario_term -->|"plays sound"| node_audio
node_mario_term -->|"builds world"| node_ecs
node_mario_term -->|"uses collision"| node_physics

click node_engine "https://github.com/ujjwalvivek/loom/blob/main/engine/engine.go"
click node_ecs "https://github.com/ujjwalvivek/loom/blob/main/ecs/world.go"
click node_physics "https://github.com/ujjwalvivek/loom/blob/main/physics/physics.go"
click node_audio "https://github.com/ujjwalvivek/loom/blob/main/audio/audio.go"
click node_perf "https://github.com/ujjwalvivek/loom/blob/main/perf/perf.go"
click node_math "https://github.com/ujjwalvivek/loom/blob/main/math/vec2.go"
click node_input "https://github.com/ujjwalvivek/loom/blob/main/input/input.go"
click node_renderer "https://github.com/ujjwalvivek/loom/blob/main/renderer/renderer.go"
click node_termrenderer "https://github.com/ujjwalvivek/loom/blob/main/termrenderer/terminal.go"
click node_mario "https://github.com/ujjwalvivek/loom/blob/main/examples/mario/main.go"
click node_mario_term "https://github.com/ujjwalvivek/loom/blob/main/examples/mario-term/main.go"
click node_ecs_world "https://github.com/ujjwalvivek/loom/blob/main/ecs/world.go"
click node_ecs_queries "https://github.com/ujjwalvivek/loom/blob/main/ecs/query.go"
click node_ecs_systems "https://github.com/ujjwalvivek/loom/blob/main/ecs/system.go"
click node_physics_solver "https://github.com/ujjwalvivek/loom/blob/main/physics/physics.go"
click node_renderer_batch "https://github.com/ujjwalvivek/loom/blob/main/renderer/batch.go"
click node_renderer_camera "https://github.com/ujjwalvivek/loom/blob/main/renderer/camera.go"
click node_audio_synth "https://github.com/ujjwalvivek/loom/blob/main/audio/synth.go"
click node_audio_seq "https://github.com/ujjwalvivek/loom/blob/main/audio/sequencer.go"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_engine,node_ecs,node_physics,node_audio,node_perf,node_math,node_ecs_world,node_ecs_queries,node_ecs_systems,node_physics_solver,node_audio_synth,node_audio_seq toneBlue
class node_input,node_renderer,node_termrenderer,node_renderer_batch,node_renderer_camera toneAmber
class node_mario,node_mario_term toneMint
```

## Components

### Core runtime

Engine subsystems and shared primitives

- [Engine](https://github.com/ujjwalvivek/loom/blob/main/engine/engine.go): runtime shell · Startup, shutdown, frame loop, and scene/context coordination · `engine/engine.go`
- [ECS](https://github.com/ujjwalvivek/loom/blob/main/ecs/world.go): state model · Entity-component world, archetypes, queries, systems, and commands · `ecs/world.go`
- [Physics](https://github.com/ujjwalvivek/loom/blob/main/physics/physics.go): simulation · AABB collision, spatial grid, and swept movement solver · `physics/physics.go`
- [Audio](https://github.com/ujjwalvivek/loom/blob/main/audio/audio.go): streaming synth · Procedural synthesis, sequencing, and PCM streaming control · `audio/audio.go`
- [Perf](https://github.com/ujjwalvivek/loom/blob/main/perf/perf.go): telemetry · Frame-time and GC observability overlays · `perf/perf.go`
- [Math](https://github.com/ujjwalvivek/loom/blob/main/math/vec2.go): geometry types · Vector, rectangle, color, and noise primitives shared across subsystems · `math/vec2.go`
- [World](https://github.com/ujjwalvivek/loom/blob/main/ecs/world.go): ecs storage · Entity storage and world mutation boundary · `ecs/world.go`
- [Queries](https://github.com/ujjwalvivek/loom/blob/main/ecs/query.go): ecs access · Read and iterate over archetype-matched components · `ecs/query.go`
- [Systems](https://github.com/ujjwalvivek/loom/blob/main/ecs/system.go): ecs execution · System interfaces and scheduling hooks · `ecs/system.go`
- [Solver](https://github.com/ujjwalvivek/loom/blob/main/physics/physics.go): collision stepper · Main physics integration and collision resolution path · `physics/physics.go`
- [Synth](https://github.com/ujjwalvivek/loom/blob/main/audio/synth.go): sound generation · Procedural waveform and note generation · `audio/synth.go`
- [Sequencer](https://github.com/ujjwalvivek/loom/blob/main/audio/sequencer.go): music timing · Event and note scheduling for music playback · `audio/sequencer.go`

### Frontends

Rendering and input backends

- [Input](https://github.com/ujjwalvivek/loom/blob/main/input/input.go): event bridge · Keyboard and mouse state plus engine-level actions · `input/input.go`
- [Renderer](https://github.com/ujjwalvivek/loom/blob/main/renderer/renderer.go): OpenGL frontend · Batching renderer with camera, shaders, textures, and post-processing · `renderer/renderer.go`
- [Terminal renderer](https://github.com/ujjwalvivek/loom/blob/main/termrenderer/terminal.go): text frontend · Character-grid rendering backend with platform-specific input support · `termrenderer/terminal.go`
- [Batching](https://github.com/ujjwalvivek/loom/blob/main/renderer/batch.go): draw pipeline · Sprite and shape batching to minimize draw overhead · `renderer/batch.go`
- [Camera](https://github.com/ujjwalvivek/loom/blob/main/renderer/camera.go): view transform · World-to-screen framing and viewport control · `renderer/camera.go`

### Examples

Runnable Mario demos

- [Mario demo](https://github.com/ujjwalvivek/loom/blob/main/examples/mario/main.go): graphical game · OpenGL/GLFW example showing how engine systems compose into a game · `examples/mario/main.go`
- [Mario term demo](https://github.com/ujjwalvivek/loom/blob/main/examples/mario-term/main.go): terminal game · Text-mode example using the terminal renderer backend · `examples/mario-term/main.go`

## Connections

- Engine → Input: reads input · Engine loop consumes front-end actions and device state
- Engine → ECS: updates state · Engine coordinates world updates through ECS
- Engine → Physics: steps sim · Engine advances physics as part of frame execution
- Engine → Renderer: presents frame · Engine hands the latest snapshot to the graphical frontend
- Engine → Terminal renderer: presents frame · Engine can also drive the terminal rendering path
- Engine → Audio: triggers audio · Engine forwards gameplay events into audio playback
- Engine → Perf: reports timing · Loop timing and GC data feed observability overlays
- ECS → World: stores entities · World is the core mutable state container
- ECS → Queries: reads components · Queries expose archetype-matched access
- ECS → Systems: runs systems · Systems operate over world state each frame
- Physics → Solver: solves collisions · Main simulation path resolves movement and contacts
- Physics → Math: uses geometry · Physics depends on shared vector and rectangle types
- Renderer → Batching: batches draws · Renderer groups primitives before issuing GPU work
- Renderer → Camera: projects view · Camera shapes the visible world region
- Renderer → Math: uses primitives · Rendering shares colors, vectors, and rectangles
- Audio → Synth: generates sound · Synth produces procedural audio signals
- Audio → Sequencer: schedules notes · Sequencer coordinates musical timing and events
- Audio → Math: uses primitives · Audio shares common numeric and signal-related helpers
- Mario demo → Engine: boots through · Graphical example wires game content into the engine runtime
- Mario demo → Renderer: uses graphics · Example targets the OpenGL renderer backend
- Mario demo → Input: handles controls · Player control flows through engine input wrappers
- Mario demo → Audio: plays sound · Example emits gameplay audio events
- Mario demo → ECS: builds world · Game entities and level logic live on ECS state
- Mario demo → Physics: uses collision · Platformer movement depends on the physics subsystem
- Mario term demo → Engine: boots through · Terminal example wires game content into the engine runtime
- Mario term demo → Terminal renderer: uses terminal · Example targets the text-mode backend
- Mario term demo → Input: handles controls · Terminal input is adapted into engine actions
- Mario term demo → Audio: plays sound · Example emits gameplay audio events
- Mario term demo → ECS: builds world · Game entities and level logic live on ECS state
- Mario term demo → Physics: uses collision · Platformer movement depends on the physics subsystem
