How ujjwalvivek/tinyts works
1. Repo shape
- This is a TypeScript-first 2D web game engine named TinyTS.
- The repo is split into the reusable engine library under src/, a separate sample app under game/, and many browser demos under examples/.
- The README positions the library as embeddable, zero-runtime-dependency, and usable both as a bundled npm package and via a global browser build.
2. Primary runtime flow
- The main entrypoint is the engine bootstrap API exposed from src/index.ts, centered around engineStart().
- An app passes in update/render callbacks plus configuration such as size, pixel scaling, and backend preferences.
- The engine then owns the game loop, calls user update logic on a timestep, and delegates drawing to the active renderer.
- Shutdown/restart is a first-class concern; the README emphasizes engineStop() fully dismantles internal state.
3. Core engine layer
- src/core/ holds the foundation used by all subsystems: engine.ts, scene.ts, ecs.ts, timer.ts, input.ts, canvas.ts, assets.ts, math.ts, easing.ts, and textInput.ts.
- This is where scheduling, scene management, entity/component lifecycle, input state tracking, and asset loading are coordinated.
- Tests in src/core/test/ suggest these modules are designed to be reusable and headless-testable, not just browser-bound.
4. Scene and application orchestration
- Scene management is explicit via src/core/scene.ts and src/scenes/ in the game example.
- The engine likely swaps or stacks scenes to separate gameplay, menus, or loading states.
- The sample game in game/src/scenes/game.ts and game/src/ui/screens.ts shows how the engine is used as a host for game-specific state flow.
5. Rendering subsystem
- Rendering is modular under src/render/, with shared interfaces in renderer2d.ts and concrete backends in rendererCanvas2d.ts, rendererWebGL2.ts, and rendererWebGPU.ts.
- camera.ts, spriteAnimation.ts, font.ts, embeddedFont.ts, procedural.ts, and color.ts indicate a layered rendering pipeline that supports sprites, text, shapes, camera transforms, and procedural drawing.
- The README says the engine auto-falls back from WebGPU to WebGL2 to Canvas2D, so backend selection is a major architectural boundary.
6. Canvas and overlay composition
- The engine uses a canvas-centric output model, with a primary render canvas plus an optional overlay canvas.
- The overlay layer is used for text and debug UI, and the README notes it is synchronized with the main renderer.
- This means the final frame is composed from at least two coordinated surfaces: game rendering and UI/debug overlay.
7. Input and text entry
- src/core/input.ts and src/core/textInput.ts cover keyboard, mouse, touch, and gamepad-style interaction.
- Input appears to be stateful and frame-updated rather than event-only, which fits the engine’s fixed-timestep loop.
- The examples/input-tester and examples/text-input demos likely exist to validate these device and text paths.
8. Audio subsystem
- src/audio/audio.ts is the main audio runtime, with tests under src/audio/test/.
- The README describes synthesized audio, voice pooling/stealing, grouped volumes, spatial audio, clip caching, and a sequencer.
- This subsystem is separate from rendering and likely consumes engine timing to schedule notes, envelopes, and playback updates.
9. Physics and world simulation
- src/physics/ contains collision and simulation helpers: aabb.ts, tilemap.ts, tilemapHelpers.ts, spatialGrid.ts, verlet.ts, and noise.ts.
- The README calls out swept AABB, tilemap collision, spatial broad-phase, and verlet integration, so physics is a distinct subsystem with both geometry and world-generation utilities.
- Tests around tilemaps, verlet, and noise indicate these modules are used as standalone building blocks, not only by the main engine loop.
10. ECS and object lifecycle
- ECS is part of core rather than a plugin, with view caching, component pooling, entity ID recycling, serialization, and add/remove hooks described in the README.
- This suggests gameplay systems can be built around pooled components and cached entity views for performance.
- The architecture likely favors data-oriented, frame-updated systems instead of class-heavy object graphs.
11. FX, plugins, and extension points
- src/fx/particles.ts provides particle system support.
- src/plugins/ contains higher-level presets and integrations such as asset helpers, audio presets, particle presets, and a debug overlay plugin.
- These look like optional composition layers that sit on top of the core engine and renderer rather than being required for basic usage.
12. Game/content example package
- game/ is a separate Vite-powered package with its own package.json, tsconfig.json, and src/ tree.
- It includes world/atlas.ts, world/palette.ts, world/renderer.ts, game/textures.ts, game/interactables.ts, and UI/scenes code, which implies a real gameplay showcase built on top of the library.
- This package demonstrates how the engine is consumed as an application, not just as a library.
13. Examples and documentation as architectural proof
- examples/ contains many self-contained browser demos for mechanics and subsystems: platformer, roguelike, particle lab, sound lab, sequencer lab, framebuffer, tilemap patterns, etc.
- These demos are static HTML entrypoints, which shows the engine can be embedded directly without a heavy app framework.
- README.md, REFERENCE.md, TUTORIAL.md, and RELEASE-NOTES.md form the documentation surface around the codebase.
14. Build, test, and release boundaries
- Root-level package.json, tsconfig.json, and typedoc.json support library packaging and docs generation.
- The repo includes CI and release workflows in .github/workflows/ci.yml and release.yml, plus tests spread across src/**/test.
- scripts/embed-font.ts and src/render/embeddedFont.ts show that font assets are part of the build pipeline, not just runtime files.
Main entry points: engine.ts Loop · debugOverlayPlugin.ts Plugins · index.ts Engine API · rendererCanvas2d.ts Backends
Components 22
TinyTS
Library, demos, and sample app
- Engine API · Main entrypoint that starts and stops the engine loop
src/index.ts
Core runtime
Engine loop, scenes, input, ECS, timing, and shared utilities
- Loop · Owns fixed-timestep update, shutdown, restart, and orchestration
src/core/engine.ts - Scenes · Scene switching and application flow coordination
src/core/scene.ts - ECS · Entity/component lifecycle, pooling, view caching, and hooks
src/core/ecs.ts - Input · Keyboard, mouse, touch, and gamepad-style state tracking
src/core/input.ts - Text entry · Text composition and committed text handling
src/core/textInput.ts - Assets · Loading and caching of runtime resources
src/core/assets.ts - Timer · Timing and tick coordination for the game loop
src/core/timer.ts - Canvas · Primary canvas and overlay surface coordination
src/core/canvas.ts
Rendering
Backend selection and 2D drawing pipeline
- 2D API · Shared renderer contract for 2D backends
src/render/renderer2d.ts - Backends · Canvas2D, WebGL2, and WebGPU rendering implementations
src/render/rendererCanvas2d.ts - Render utils · Camera, color, fonts, sprites, and procedural drawing helpers
src/render/camera.ts
Audio
Synthesis, voices, sequencing, and playback
- Audio engine · Playback, voice pooling, spatial audio, and sequencing
src/audio/audio.ts
Physics
Collision, grids, tilemaps, verlet, and noise
- Physics core · Swept AABB, tilemaps, broad-phase grids, verlet, and noise
src/physics/aabb.ts
Extensions
Plugins and visual effects built on top of core
Sample game
Standalone Vite application using the engine
- Game app · Standalone app entrypoint and package boundary
game/src/main.ts - Game scene · Sample gameplay scene and state progression
game/src/scenes/game.ts - World layer · Atlas, palette, renderer, textures, and interactables for the demo game
game/src/world/renderer.ts
Examples
Browser demos for subsystems and gameplay patterns
- Demos · Self-contained examples for mechanics, rendering, input, audio, and physics
examples/index.html
Docs & build
Documentation, scripts, CI, and packaging
- Docs · README, reference, tutorial, and release notes
README.md - Build & CI · Packaging, typedoc, font embedding, and GitHub workflows
package.json
Connections 25
- Engine API → Loop: starts · Bootstrap API creates and manages the runtime
- Loop → Scenes: drives · Loop advances the active scene graph
- Loop → ECS: updates · Runtime coordinates entity/component lifecycle
- Loop → Input: polls · Frame updates read device state
- Loop → Text entry: routes · Text entry is integrated with input handling
- Loop → Timer: ticks · Fixed timestep and scheduling are driven by timer state
- Loop → Canvas: renders to · Engine owns the main and overlay canvas surfaces
- Loop → 2D API: selects · Engine chooses a renderer contract
- 2D API → Backends: implemented by · Backend-specific rendering implementations satisfy the interface
- Backends → Render utils: uses · Backends rely on camera, font, color, and drawing helpers
- Loop → Assets: loads · Asset lifecycle is coordinated by the engine
- Loop → Audio engine: plays · Audio runtime is updated alongside the main loop
- Loop → Physics core: simulates · Gameplay systems can use physics helpers during updates
- Loop → Particles: emits · Visual effects plug into the runtime and renderer
- Plugins → Assets: extends · Asset helper plugin builds on core loading
- Plugins → Audio engine: extends · Audio presets build on the audio runtime
- Plugins → Particles: extends · Particle presets wrap the particles system
- Plugins → Backends: adds overlay · Debug overlay integrates with rendering surfaces
- Game app → Engine API: uses · Sample app boots through the engine API
- Game app → Game scene: hosts · Application entry delegates to the game scene flow
- Game scene → World layer: uses · Gameplay scene builds on world and rendering assets
- Demos → Engine API: demonstrates · Demos show direct embedding of the engine in HTML pages
- Docs → Engine API: describes · Documentation explains the public bootstrap and runtime model
- Build & CI → Docs: supports · Tooling generates docs and release artifacts
- Build & CI → Render utils: embeds font · Build script feeds embedded font assets to rendering