Skip to content

Latest commit

 

History

1,072 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ExoJS

Latest npm CI Coverage License

A TypeScript-first 2D engine for games and interactive apps. Explicit scene graph, WebGPU/WebGL2 rendering, native physics, spatial audio, and a strict type system — measured and verified, not just claimed.

Guide · API Reference · Playground · Benchmarks

The ExoJS companion, a small waving robot

Pre-1.0. The public API is under active design — minor versions may include breaking changes. Pin exact versions in downstream projects. 1.0.0 marks the first stable API contract.

Packages

Package Description
@codexo/exojs Core runtime — scene graph, rendering, audio, UI, serialization
@codexo/exojs-physics Native 2D physics — shapes, constraints, TGS-Soft solver
@codexo/exojs-particles GPU-driven particles (WebGPU compute) with CPU fallback
@codexo/exojs-tilemap Format-independent tilemap runtime and object layers
@codexo/exojs-tiled Tiled JSON adapter and scene-graph conversion
@codexo/exojs-tilemap-physics Static physics colliders from tilemap collision geometry
@codexo/exojs-aseprite Aseprite adapter — sprite sheets, tags, frame direction/repeat, slices
@codexo/exojs-ldtk LDtk adapter — multi-world levels, entities, structured field values
@codexo/exojs-lighting Forward, normal-mapped 2D point lighting inside the sprite batch
@codexo/exojs-pathfinding A* with jump-point search over weighted grids and waypoint graphs
@codexo/exojs-audio-fx Audio effects — biquad filters, analyser, beat detection, worklets
@codexo/exojs-react React bindings — run an ExoJS Application inside React components

Features

Rendering

  • WebGPU-first with automatic WebGL2 fallback; force either backend with one option
  • Drawables: Sprite, AnimatedSprite, NineSliceSprite, RepeatingSprite, Graphics, Text (SDF), BitmapText, Video
  • Rendering composition: RenderTexture, RenderPipeline, filter chains, visual masks, cache-as-bitmap
  • Immediate-mode rendering: one-off drawGeometry and instanced RenderBatch collapsing to a single draw call
  • Linear and radial gradients, pixel snapping, view/camera helpers (follow, shake, zoom, bounds clamp)
  • Custom sprite materials (SpriteMaterial) with your own GLSL/WGSL fragment stage, plus built-in DropShadowFilter, DisplacementFilter, colour matrix and blur filters
  • @codexo/exojs-lighting: normal-mapped point lights shaded in the sprite fragment stage — no extra pass, no extra draw call
  • Render stats with GPU memory accounting (gpuMemoryBytes, texture/buffer upload bytes)

Text

  • SDF text with Unicode-safe layout (Intl.Segmenter graphemes, bidi runs, soft wrapping) and browser-native shaping for complex scripts
  • Multi-stop gradients with an angle, oblique/small-caps variants, underline and strikethrough, maxLines with a configurable ellipsis, textTransform, tabSize
  • BitmapText for prebuilt atlases; both text kinds batch with sprites

Scene & UI

  • Application, Scene, SceneDirector — one active scene with change/restore/preload/unload navigation, pause/resume, and fade, slide, or cross-fade transitions (or your own SceneTransition)
  • scene.ui — screen-fixed widget layer with Label, Panel, Button, ProgressBar, Stack, ScrollContainer, Tooltip, and anchoring
  • Keyboard focus through app.interactionfocus, blur, focusNext/focusPrevious Tab traversal, and scoped focus traps for modals
  • Exact picking: rotated nodes hit-test as oriented boxes, or set a local hitArea (Circle, Ellipse, Polygon, Rectangle) for round buttons and irregular shapes
  • app.jobs — a frame-budgeted JobScheduler that runs generator jobs a slice per frame, so world generation or batch pathfinding never blocks a frame and never needs an async update
  • Write your own SceneTransition against the same conformance harness the built-in fade, slide and cross-fade use

Physics (@codexo/exojs-physics)

  • Circles, boxes, capsules, and convex polygons; static, kinematic, and dynamic bodies
  • SAP broadphase, manifold narrow-phase, warm-started TGS-Soft solver (sub-stepped, stable to 20+ box stacks)
  • Contact graph, collision events, spatial queries; allocation-free per step (V8-sampler verified)
  • Sleeping islands, contact modifiers, joints; measured against matter.js, planck.js and Rapier in packages/exojs-bench
  • Scene-graph binding and a /debug draw subpath

Pathfinding (@codexo/exojs-pathfinding)

  • One search core — A* with jump-point pruning — over weighted grids (top-down worlds) and waypoint graphs (platformers, abstract graphs)
  • Deterministic and allocation-free per query; plain logic with no scene node, renderer or registration step

Audio

  • Voice capability matrix across Sound, AudioStream, and AudioGenerator
  • Spatial panning, audio sprites, frequency and waveform analysis, BiquadEffect filters
  • @codexo/exojs-audio-fx: AudioAnalyser, BeatDetector, worklets, and DSP helpers

Assets & Storage

  • Typed Loader with a declarative asset catalog (Assets.from, Asset.type, defineAsset) and a de-duplicating LoadingQueue
  • Binary asset containers (loader.loadContainer) for bundled distribution
  • Key-value persistence: WebStorageStore (localStorage/sessionStorage), IndexedDbKeyValueStore (structured-clone, binary-safe), MemoryStore (tests/ephemeral)

Serialization

  • Scene.serialize / deserialize captures scene structure — nodes, drawables, UI, tilemap
  • SerializationRegistry and Prefab for templates; pairs with any KeyValueStore for save-slot persistence

Architecture

  • noUncheckedIndexedAccess + exactOptionalPropertyTypes across the full codebase — zero as any, zero ts-ignore
  • Ordered SystemRegistry (app.systems, scene.systems) with deterministic tick bands
  • Deterministic disposal via Destroyable / DisposalScope; all managers are app-owned, not process singletons

Getting Started

Scaffold a new project with one command:

npm create exo-app@latest my-game

Or pick a template explicitly:

npm create exo-app@latest my-game -- --template minimal
npm create exo-app@latest my-game -- --template game-starter
npm create exo-app@latest my-game -- --template audio-reactive

Then:

cd my-game
npm install
npm run dev

Installation

npm install @codexo/exojs

ExoJS ships as ESM — use import syntax with a modern bundler or runtime. A prebuilt IIFE bundle (dist/exo.iife.js, global Exo) is included for CDN and script-tag usage. Optional packages install independently — add only what your project needs:

npm install @codexo/exojs-physics
npm install @codexo/exojs-particles
npm install @codexo/exojs-tilemap @codexo/exojs-tiled @codexo/exojs-tilemap-physics
npm install @codexo/exojs-aseprite @codexo/exojs-ldtk
npm install @codexo/exojs-lighting @codexo/exojs-pathfinding
npm install @codexo/exojs-audio-fx
npm install @codexo/exojs-react

Quickstart

import { Application, Color, Graphics, type RenderingContext, Scene, type Seconds } from '@codexo/exojs';

class HelloScene extends Scene {
  private readonly box = new Graphics();

  override init(): void {
    this.box.fillColor = Color.white;
    this.box.drawRectangle(-32, -32, 64, 64);
    this.box.setPosition(this.app.width / 2, this.app.height / 2);
    this.addChild(this.box);
  }

  override update(delta: Seconds): void {
    this.box.rotate(delta * 45);
  }

  override draw(context: RenderingContext): void {
    context.render(this.root);
  }
}

const app = new Application({
  scenes: { HelloScene },
  canvas: { width: 800, height: 600, mount: document.body },
  clearColor: Color.black,
});

await app.start(HelloScene);

See the Guide for physics, audio, UI, and more, or browse the live examples.

Roadmap

Directional work toward the 1.0.0 API freeze. Priorities may shift — nothing here is a release commitment.

  • Backend selection by class (backends: [WebGl2Backend]) and compile-time defines for single-backend builds
  • Typed shader uniform blocks shared between GLSL and WGSL
  • @codexo/exojs-cliexo serve, exo create, exo doctor, asset packing
  • Rich text with style spans and inline icons
  • Worker-backed jobs on the same Job handle as app.jobs
  • Post-processing passes (bloom, tone mapping, grading) on RenderPipeline
  • Platform adapters for Worker and headless runtimes
  • Final pre-1.0 API audit and stabilization pass

Benchmarks

ExoJS is measured against Pixi, Phaser and Excalibur for rendering, and against matter.js, planck and Rapier for physics, on one reference machine per release. On the current reference run:

  • Level with Pixi on plain sprite scaling, and 2x or better ahead of it on WebGPU filter chains.
  • About 7x behind Pixi on masked clipping — the widest rendering loss on that machine.
  • In physics, ahead of the pure-JS peers on a 1000-body box stack (roughly 3x over matter.js, 17x over planck) and behind Rapier's Rust/WASM solver on five of six scenes.

The full matrix, the mechanism behind each row, the rows that were left out and the steps to reproduce all of it are on the benchmarks page.

WebGPU and WebGL2

Application auto-selects the best available backend. Force one when needed:

new Application({ backend: { type: 'webgpu' } });
new Application({ backend: { type: 'webgl2' } });
new Application({ backend: { type: 'auto' } }); // default

Development

Prerequisites: Node 24 (.nvmrc; devEngines in package.json refuses any other major) and pnpm (packageManager pins the version; with Corepack enabled, or any installed pnpm 10+, it switches itself).

pnpm bootstrap:dev   # dependencies, git hooks, every build, the bench competitors, a Chromium
pnpm doctor          # what is missing, and the command that fixes it

pnpm bootstrap alone is what CI runs: dependencies and the build tooling, nothing else. It installs with scripts disabled, so whether a clone ends up with git hooks depends on whether pnpm ran an install of its own first - and it builds nothing. pnpm doctor reports the actual state either way.

pnpm typecheck
pnpm lint
pnpm test
pnpm build:all       # core plus every extension package
pnpm verify:package
pnpm clean:artifacts # what a local test, benchmark or release run left behind

Package-internal imports use Node package.json#imports subpath imports: ./X for the same directory, #dir/X for any other path in the same package, and the public bare specifier (@codexo/exojs) across packages. See CONTRIBUTING.md for the full import policy, per-package commands, and the shared @codexo/exojs-config tooling. Building the library requires TypeScript 6.

This repository uses pnpm workspaces (site/ is a workspace package). Use root-level commands as the source of truth — avoid running pnpm install inside site/ directly:

pnpm bootstrap
pnpm site:build
pnpm site:build:api

Links

About

Modern multimedia framework with a focus on performance and extensibility

Topics

Resources

Contributing

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages