How ujjwalvivek/loom works
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.go Engine · mario/main.go Mario demo · mario-term/main.go Mario term demo · world.go ECS
Components 19
Core runtime
Engine subsystems and shared primitives
- Engine · Startup, shutdown, frame loop, and scene/context coordination
engine/engine.go - ECS · Entity-component world, archetypes, queries, systems, and commands
ecs/world.go - Physics · AABB collision, spatial grid, and swept movement solver
physics/physics.go - Audio · Procedural synthesis, sequencing, and PCM streaming control
audio/audio.go - Perf · Frame-time and GC observability overlays
perf/perf.go - Math · Vector, rectangle, color, and noise primitives shared across subsystems
math/vec2.go - World · Entity storage and world mutation boundary
ecs/world.go - Queries · Read and iterate over archetype-matched components
ecs/query.go - Systems · System interfaces and scheduling hooks
ecs/system.go - Solver · Main physics integration and collision resolution path
physics/physics.go - Synth · Procedural waveform and note generation
audio/synth.go - Sequencer · Event and note scheduling for music playback
audio/sequencer.go
Frontends
Rendering and input backends
- Input · Keyboard and mouse state plus engine-level actions
input/input.go - Renderer · Batching renderer with camera, shaders, textures, and post-processing
renderer/renderer.go - Terminal renderer · Character-grid rendering backend with platform-specific input support
termrenderer/terminal.go - Batching · Sprite and shape batching to minimize draw overhead
renderer/batch.go - Camera · World-to-screen framing and viewport control
renderer/camera.go
Examples
Runnable Mario demos
- Mario demo · OpenGL/GLFW example showing how engine systems compose into a game
examples/mario/main.go - Mario term demo · Text-mode example using the terminal renderer backend
examples/mario-term/main.go
Connections 30
- 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