A TypeScript-first
2D runtime for
arcade games

ExoJS gives you scenes, sprites, graphics, input, audio, effects, assets, and rendering primitives — without turning your project into a full game-engine workflow.

npm install @codexo/exojs
Or download the latest releaseFull ZIP, no build step
game.tsscenelighting
import { Application, Color, Scene, Sprite } from '@codexo/exojs';
import { Lighting, LitMaterial, Normals, PointLight } from '@codexo/exojs-lighting';

const lighting = new Lighting();
const lights = Array.from({ length: 24 }, (_, i) => {
  const color = Color.fromCss(`hsl(${i * 15} 80% 60%)`);
  return new PointLight({ radius: 190, color });
});

class LitScene extends Scene {
  async load(loader) {
    const stone = await loader.load('stone.png');
    const normalMap = await loader.load('stone-normal.png');
    const material = new LitMaterial({ lighting, normals: Normals.map(normalMap) });

    for (let i = 0; i < 112; i++) {
      const tile = new Sprite(stone);
      tile.setPosition((i % 14) * 96, Math.floor(i / 14) * 96);
      tile.material = material;
      this.root.addChild(tile);
    }
  }

  init() {
    this.systems.add(lighting);
    lights.forEach(light => lighting.add(light));
  }

  update() {
    const t = this.app.activeSeconds;
    lights.forEach((light, i) => {
      const angle = t * (0.25 + i * 0.08) + i;
      light.setPosition(640 + Math.cos(angle) * 420, 360 + Math.sin(angle * 1.37) * 260);
    });
  }

  draw(context) {
    context.render(this.root);
  }
}

new Application({ canvas: { width: 1280, height: 720 } }).start(new LitScene());
Live — rendering in your browser

Many Lights

Not a video or a GIF — this is the engine running in the page. Hit play, then open it in the Playground and edit it live.

Preview is paused until you click Play.

SCN

Scenes & lifecycle

Compose scenes from sprites, graphics, and text. Lifecycle hooks make state predictable.

INP

Unified input

Keyboard, pointer, and gamepad behind one action mapping API.

AUD

Spatial audio

Buses, effects, and listener-source positioning built on Web Audio.

FX

Filters & particles

Post-processing, bloom, blur, particles — composable and GPU-accelerated.

Measured against Pixi, Phaser, Excalibur, matter.js, planck and Rapier on one reference machine — roughly 2x ahead of Pixi on WebGPU filter chains, and about 7x behind it on masked clipping, both published with the counters behind them.

See the benchmarks

Live examples.

Open any of these in the Playground. The code and preview stay in sync with the running example.

examples / 67 chapters / 150 demos

Install once, use anywhere.

ExoJS ships as plain ES modules. Drop it into Vite, esbuild, or whatever you already use.

Open Getting Started
npm install @codexo/exojs
import { Application, Scene } from '@codexo/exojs';

class HelloScene extends Scene {
  draw(context) {
    context.render(this.root);
  }
}

const app = new Application({ canvas: { width: 800, height: 600 } });
app.start(new HelloScene());