@ujjwalvivek/tinyts
    Preparing search index...

    @ujjwalvivek/tinyts

    TinyTS

    API Quick Reference Examples Browser Engine API NPM

    A tiny, fast, TypeScript-first 2D web game engine.

    ~88 KB minified, ~27 KB gzip - zero runtime dependencies. Lightweight. Performant. Reliable.

    Load the pre-bundled global build directly via a <script> tag. All engine exports are automatically mapped to the browser's global namespace:

    <!DOCTYPE html>
    <html lang="en">
    <head>
    ...
    </head>
    <body>
    <script src="dist/tinyts.js"></script>
    <script>
    const pos = vec2(100, 100);

    engineStart({
    size: { width: 480, height: 270 },
    pixelated: true,

    update(dt) {
    if (keyDown("KeyD")) pos.x += 120 * dt;
    if (keyDown("KeyA")) pos.x -= 120 * dt;
    },

    render() {
    clear(Color.fromHSL(235, 0.45, 0.05));
    drawRect(pos, vec2(16, 16), "#e94560");
    drawText("USE A/D TO MOVE", vec2(240, 30), {
    color: "#fff",
    align: "center",
    size: 16,
    });
    },
    });
    </script>
    </body>
    </html>

    Install via npm and import components into your build system:

    import { engineStart, vec2, clear, drawRect, Color } from "@ujjwalvivek/tinyts";

    engineStart({
    size: { width: 640, height: 360 },
    render() {
    clear("#08080f");
    drawRect(vec2(320, 180), vec2(32, 32), "#f0c040");
    },
    });

    Follow these steps to scaffold a project from scratch:

    1. Initialize your project:

      npm create vite@latest my-tinyts-game -- --template vanilla-ts
      cd my-tinyts-game
      npm install @ujjwalvivek/tinyts
    2. Configure your files:

      Update src/main.ts with this setup template:

      import { engineStart, vec2, clear, drawRect, keyDown } from "@ujjwalvivek/tinyts";

      const pos = vec2(100, 100);

      const engine = engineStart({
      size: { width: 480, height: 270 },
      pixelated: true,
      update(dt) {
      // Input tracking
      if (keyDown("KeyD") || keyDown("ArrowRight")) pos.x += 120 * dt;
      if (keyDown("KeyA") || keyDown("ArrowLeft")) pos.x -= 120 * dt;
      },
      render() {
      clear("#11111b"); // Clear background
      drawRect(pos, vec2(16, 16), "#89b4fa"); // Draw player
      },
      });

      // Mount engine canvas to index.html container
      const container = document.querySelector("#app");
      if (container) {
      container.appendChild(engine.canvasManager.canvas);
      if (engine.overlayCanvas) {
      container.appendChild(engine.overlayCanvas);
      }
      }

      Update index.html:

      <!DOCTYPE html>
      <html lang="en">
      <head>
      <meta charset="UTF-8" />
      <title>My TinyTS Game</title>
      <style>
      body {
      margin: 0;
      padding: 0;
      background: #1e1e2e;
      display: flex;
      align-items: center;
      justify-content: center;
      width: 100vw;
      height: 100vh;
      overflow: hidden;
      }
      #app {
      position: relative;
      width: 100%;
      height: 100%;
      }
      #app canvas {
      position: absolute;
      left: 50%;
      top: 50%;
      transform: translate(-50%, -50%);
      max-width: 95%;
      max-height: 95%;
      aspect-ratio: 16/9;
      }
      </style>
      </head>
      <body>
      <div id="app"></div>
      <script type="module" src="/src/main.ts"></script>
      </body>
      </html>
    3. Run the development server:

      npm run dev
      
    Category Description
    Overall Architecture Singleton-free, instance-bound, clean module boundaries
    Game Loop Fixed-timestep with accumulator, alpha interpolation, frame clamping
    Rendering Unified interface, optional WebGPU, WebGL2 batcher, Canvas2D fallback
    Input Bitmask state tracking, action mapping, gamepad, touch, keyboard and mouse
    Audio Full ADSR synth, voice stealing, groups, spatial audio, sequencer
    Physics Swept AABB, tilemap collision, spatial grid, verlet
    ECS View caching, component pooling, hierarchy, serialization, event hooks
    Particles Object pooling, emitter lifecycle, shapes, additive blending, prewarm
    API Ergonomics Dead-simple global helpers plus full OOP access for power users

    TinyTS implements a highly disciplined engine design thats fun to work with:

    • Zero memory leaks on restart - engineStop() truly dismantles everything.
    • Embeddable - can run inside an iframe or component without polluting the host page.
    • Quad batching - 8192-quad batch buffer with pre-built index buffer
    • High-Performance WebGPU backend - opt in with webgpu: true; utilizes instanced rendering and a texture atlas. Falls back through WebGL2/Canvas2D when unavailable
    • State-cached uniforms - texture, shape, and shape params are tracked to avoid redundant GL calls
    • GPU-batched lines - drawLine() renders through the WebGL2 batcher as transformed quads
    • Canvas2D overlay - text and debug overlays use a synchronized Canvas2D layer
    • Sprite batching - rotated/flipped sprites are pre-transformed on CPU and batched, avoiding per-sprite draw calls
    • Renderer stats - getRendererStats() and the debug overlay expose draw calls, batch flushes, switches, quads, and overlay calls
    • Default font - ships and loads the MIT-licensed TinyTS font from dist/font/tinyTS.woff2
    • View caching with reactive updateEntityInCaches on add/remove
    • Component pooling via obtain() with init()/reset() hooks
    • Entity free list for ID recycling
    • Serialization via registerComponentType / serialize / deserialize
    • Event hooks via onAdded / onRemoved with unsubscribe handles
    • Voice pool with configurable max voices and voice stealing (oldest non-looping first)
    • Audio groups (sfx, music, ambient) with per-group volume
    • Spatial audio via playSoundAt with distance falloff and stereo panning
    • Sequencer for pattern-based music with MIDI-to-frequency conversion
    • Clip caching and AudioClip abstraction
    # Ensure Node.js is installed

    # Clone the repository
    git clone https://github.com/ujjwalvivek/tinyts.git
    cd tinyts
    npm install # Install package dependencies
    npm run check # Typecheck, run ES module / CJS builds, and execute tests
    npm run docs # Generate the API Documentation site locally
    npm run serve # Start a local HTTP utility server to test examples
    Scenario Reliable?
    Drop a <script> tag, call engineStart(), draw stuff ✅ Yes
    Use as ES module with bundler ✅ Yes
    Pixel art games with integer scaling ✅ Yes
    Smooth HD games with fractional scaling ✅ Yes
    Start/stop/restart engine multiple times ✅ Yes, zero leaks
    Mobile browser with touch ✅ Yes, on-screen touch controls work
    Gamepad support ✅ Yes, with deadzone
    WebGPU/WebGL2 not available ✅ Yes, auto-falls back to Canvas2D
    Mix Canvas2D calls with engine rendering ✅ Yes, getContext() exposes the raw context
    Platform Support
    Chrome / Edge (desktop) ✅ Full WebGL2 + Canvas2D
    Firefox (desktop) ✅ Full WebGL2 + Canvas2D
    Safari 15+ (desktop) ✅ WebGL2 + Canvas2D
    Chrome / Firefox (Android) ✅ WebGL2 + Canvas2D + Touch
    Safari (iOS 15+) ✅ WebGL2 + Canvas2D + Touch
    Older browsers without WebGL2 ✅ Canvas2D fallback
    Node.js (SSR / testing) ✅ Headless (math, ECS, physics work; rendering needs DOM)
    Optimization Present?
    WebGL2 quad batching (single draw call per texture + shape)
    High-Performance WebGPU backend (instanced rendering + texture atlas)
    Pre-allocated batch Float32Array (no per-frame alloc)
    Pre-built static index buffer
    GPU-batched lines
    Texture caching
    State-cached uniforms (avoid redundant GL calls)
    Renderer instrumentation counters
    Object pooling (particles, ECS components)
    SDF shapes (no per-circle geometry)
    imageSmoothingEnabled = false for pixel art
    Framerate-independent damping (Math.pow(damp, dt * 60))
    Spatial grid for broad-phase collision

    MIT License.

    TinyTS - Designed with zero bloat, maximum performance, and straightforward readability.