Setup
Create a typed ExoJS project with create-exo-app, run the dev server, and produce a production build.
Setup
The fastest way to start is create-exo-app. It scaffolds a Vite + TypeScript project that already imports @codexo/exojs, runs a scene, and is ready for dev and build.
Create a project
Run the scaffolder and follow the prompts:
npm create exo-app@latest my-game
Then install dependencies and start the dev server:
cd my-game
npm install
npm run dev
The dev server prints a local URL. Open it and you’ll see a running scene with hot reload.
Choose a template
create-exo-app ships three templates. Pass one with --template, or pick it interactively:
| Template | Starts with |
|---|---|
minimal |
One scene drawing and animating a single shape — the smallest real project. |
game-starter |
A player object, a game scene, and a game-over scene with restart. |
audio-reactive |
An analyser-driven scene that turns sound into a live spectrum. |
npm create exo-app@latest my-game -- --template game-starter
The Project structure chapter walks through what each file does.
Build for production
Vite produces a static bundle you can host anywhere:
npm run build # output in dist/
npm run preview # serve the production build locally
The Deployment chapter covers hosting, base paths, and assets.
Add ExoJS to an existing project
If you already have a bundler-based project, install the runtime directly:
npm install @codexo/exojs
The package ships as ESM with TypeScript declarations, so any modern bundler (Vite, esbuild, Rollup, webpack, Parcel) picks up both the code and the types. ExoJS renders into a regular HTMLCanvasElement; create one yourself or let Application create it for you:
import { Application } from '@codexo/exojs';
// Pass an existing canvas...
const canvas = document.querySelector<HTMLCanvasElement>('#scene')!;
const app = new Application({ canvas: { element: canvas } });
// ...or let the application create one and mount app.element yourself.
Tip
app.element is the active HTMLCanvasElement the runtime renders into, or null when the surface is an OffscreenCanvas. Append it wherever your layout needs it, or let canvas.mount do it.
