@eternaxcode/agentia-engine
v1.1.0
Published
Lightweight, AI-Native 2D Game Engine for TypeScript/Next.js
Maintainers
Readme
Agentia Engine
A lightweight, AI-native 2D game engine built with TypeScript. Zero runtime dependencies. Pure HTML5 Canvas rendering with a strict Entity-Component-System architecture.
Designed to be data-driven so AI agents can generate game content — scenes, animations, UI — dynamically.
Features
- Entity-Component-System — strict separation of data (components) and logic (systems)
- Hierarchical Transforms — scene graph with parent/child relationships and Matrix2D
- Physics — rigid body dynamics, AABB/Circle/Polygon collision, spatial grid broadphase, raycasting
- Camera — follow, zoom, shake, fade/flash, parallax layers, viewport culling
- Particles — emitter-based system with emit zones, lifetime/scale/alpha curves, gravity
- Tilemap — Tiled JSON loader, animated tiles, collision grid, object layers
- Scene Manager — scene stack, transitions (fade/slide), parallel scenes, data passing
- Sprite Sheets — frame-based animation with auto-grid detection and background removal
- Floating Text — rising/fading text labels for damage numbers, notifications
- Tweens & Effects — 10+ easing functions, pre-built effects (fadeIn, shake, popIn)
- State Machine — generic FSM with context, auto-transitions, state history
- Audio — Web Audio API wrapper for SFX and music with volume/mute control
- Input — keyboard, mouse, touch, gamepad with deadzone and action mapping
- Asset Manager — unified loader for sprites, SVG, audio with progress tracking
- AI CLI —
npx agentia init claude|geminibootstraps AI context files - Zero Dependencies — pure TypeScript + browser APIs, no runtime packages
Installation
npm install @eternaxcode/agentia-engineQuick Start
import {
Engine, CanvasRenderer, RenderSystem,
Transform, Sprite, HierarchySystem
} from '@eternaxcode/agentia-engine';
// Setup
const engine = new Engine();
const renderer = new CanvasRenderer('game-canvas');
engine.addSystem(new HierarchySystem());
engine.addSystem(new RenderSystem(renderer));
// Create a sprite entity
const em = engine.getEntityManager();
const player = em.createEntity();
em.addComponent(player, new Transform(100, 200));
em.addComponent(player, new Sprite('/assets/player.png', 32, 32));
// Run
engine.start();
// Cleanup (important in React)
// engine.stop();Core Architecture
ECS Pattern
Entity (ID) + Components (data) → Systems (logic)- Entities are numeric IDs (starting from 1)
- Components are plain data classes — no logic
- Systems process entities each frame via
update(delta, entityManager)
System Layers
Systems execute in layer order. Each layer can be independently paused:
| Layer | Value | Purpose |
|-------|-------|---------|
| BACKGROUND | 0 | Parallax, environment |
| GAME | 100 | Core gameplay (default) |
| GUI | 200 | HUD, status bars |
| OVERLAY | 300 | Dialogs, menus |
Game Loop Order
Each frame:
EventBus.processQueue()— flush deferred eventsCommandBuffer.processAll()— execute queued commands- Systems update — sorted by layer, then insertion order
Systems Reference
Physics
import {
PhysicsSystem, CollisionSystem,
RigidBody, Collider, BodyType,
createAABBShape, createCircleShape
} from '@eternaxcode/agentia-engine';
engine.addSystem(new PhysicsSystem({ gravity: { x: 0, y: 980 } }));
engine.addSystem(new CollisionSystem());
const entity = em.createEntity();
em.addComponent(entity, new Transform(100, 100));
em.addComponent(entity, new RigidBody(BodyType.DYNAMIC));
em.addComponent(entity, new Collider(createAABBShape(16, 16)));Camera
import {
CameraSystem, CameraRenderSystem,
CameraComponent, screenToWorld, shake
} from '@eternaxcode/agentia-engine';
const camera = em.createEntity();
const cam = new CameraComponent();
cam.followTarget = playerEntity;
cam.followSmoothing = 5;
cam.zoomLevel = 2;
em.addComponent(camera, cam);
em.addComponent(camera, new Transform());
engine.addSystem(new CameraSystem());
engine.addSystem(new CameraRenderSystem(renderer));
// Shake effect
shake(cam, 10, 8);Particles
import {
ParticleSystem, ParticleEmitter
} from '@eternaxcode/agentia-engine';
engine.addSystem(new ParticleSystem(renderer));
const emitter = em.createEntity();
em.addComponent(emitter, new Transform(200, 200));
em.addComponent(emitter, new ParticleEmitter({
rate: 50,
lifetime: { min: 0.5, max: 1.5 },
speed: { min: 50, max: 150 },
angle: { min: 0, max: 360 },
startScale: 1, endScale: 0,
startAlpha: 1, endAlpha: 0,
startColor: { r: 255, g: 100, b: 0 },
endColor: { r: 255, g: 255, b: 0 },
gravity: { x: 0, y: 200 },
}));Sprite Sheet Animation
import {
SpriteSheet, SpriteSheetSystem, SpriteLoader
} from '@eternaxcode/agentia-engine';
engine.addSystem(new SpriteSheetSystem());
// Load sprite sheet
const info = await SpriteLoader.load('/assets/character.png', {
forceGrid: { cols: 4, rows: 2 },
removeBackground: true,
});
// Create animated entity
const entity = em.createEntity();
em.addComponent(entity, new Transform(100, 100));
em.addComponent(entity, new Sprite(info.image.src, 32, 32));
em.addComponent(entity, SpriteSheet.fromLoaderInfo(info, 0.15));Floating Text
import {
FloatingText, FloatingTextSystem
} from '@eternaxcode/agentia-engine';
engine.addSystem(new FloatingTextSystem(renderer));
// Spawn damage number
const text = em.createEntity();
em.addComponent(text, new Transform(x, y));
em.addComponent(text, new FloatingText(
'-42', // text
'#ff0000', // color
1.0, // lifetime (seconds)
16, // font size
));
// Automatically rises and fades out, then self-destructsTilemap (Tiled)
import {
TilemapLoader, TilemapSystem, Tilemap,
worldToTile, isSolid, getObjectsByType
} from '@eternaxcode/agentia-engine';
const mapData = await TilemapLoader.load('/maps/level1.json');
const map = em.createEntity();
em.addComponent(map, mapData);
engine.addSystem(new TilemapSystem(renderer));
// Collision queries
const solid = isSolid(mapData, worldX, worldY);
const spawns = getObjectsByType(mapData, 'spawn_point');Scene Manager
import { Scene, SceneManager } from '@eternaxcode/agentia-engine';
class MenuScene extends Scene {
constructor() { super('menu'); }
create() {
// Setup menu entities
}
update(delta: number) {
// Menu logic
}
}
class GameScene extends Scene {
constructor() { super('game'); }
init(data?: Record<string, unknown>) {
// Receive data from previous scene
}
create() { /* ... */ }
}
const sm = new SceneManager(engine);
sm.register(new MenuScene());
sm.register(new GameScene());
sm.activate('menu');
// Switch with transition
sm.switchTo('game', { level: 1 }, {
type: 'fade', duration: 500
});Timer & Tween
import { TimerSystem, TweenSystem, Easing, Effects } from '@eternaxcode/agentia-engine';
const timer = new TimerSystem();
timer.setTimeout(() => spawnEnemy(), 2000);
timer.setInterval(() => heal(5), 1000);
const tween = new TweenSystem();
tween.create({
from: 0, to: 1, duration: 500,
easing: Easing.easeOutBounce,
onUpdate: (v) => { sprite.alpha = v; },
});
// Pre-built effects
Effects.fadeIn(tween, (v) => { el.style.opacity = String(v); });
Effects.shake(tween, (x) => { el.style.left = x + 'px'; }, 10, 300);
Effects.popIn(tween, (v) => { el.style.transform = `scale(${v})`; });State Machine
import { StateMachine } from '@eternaxcode/agentia-engine';
interface Ctx { score: number; lives: number; }
const fsm = new StateMachine<Ctx>();
fsm.addStates({
menu: {
onEnter: () => showMenu(),
},
playing: {
onEnter: (ctx) => { ctx.score = 0; },
onUpdate: (delta, ctx) => updateGame(delta, ctx),
onExit: (ctx) => saveScore(ctx.score),
},
gameOver: {
onEnter: (ctx) => showGameOver(ctx.score),
},
});
fsm.start('menu', { score: 0, lives: 3 });
fsm.transition('playing');
fsm.update(delta);EventBus & CommandBuffer
import { Engine } from '@eternaxcode/agentia-engine';
const engine = new Engine();
// EventBus — pub/sub
engine.eventBus.on('player:hit', (data) => {
console.log('damage:', data.amount);
});
engine.eventBus.emit('player:hit', { amount: 25 });
// Deferred events (processed next frame)
engine.eventBus.queue('score:update', { delta: 100 });
// CommandBuffer — command pattern with priority
const buffer = engine.getCommandBuffer();
buffer.registerHandler('attack', (commands, ctx) => {
for (const cmd of commands) {
dealDamage(cmd.payload.target, cmd.payload.damage);
}
});
buffer.push('attack', { target: enemy, damage: 10 }, 1);Input
import {
InputSystem, GamepadSystem, InputActionMap
} from '@eternaxcode/agentia-engine';
// Keyboard + Mouse + Touch
const input = new InputSystem(canvas);
engine.addSystem(input);
engine.eventBus.on('input:keydown', (e) => { /* ... */ });
engine.eventBus.on('input:mousedown', (e) => { /* ... */ });
// Gamepad
engine.addSystem(new GamepadSystem());
engine.eventBus.on('gamepad:buttondown', (e) => { /* ... */ });
// Action mapping
const actions = new InputActionMap();
actions.addBinding('jump', { type: 'keyboard', key: 'Space' });
actions.addBinding('jump', { type: 'gamepad_button', button: 0 });
if (actions.isActive('jump')) { /* ... */ }Audio
import { AudioSystem } from '@eternaxcode/agentia-engine';
const audio = new AudioSystem();
audio.init(); // Must call after user interaction
await audio.load('jump', '/sounds/jump.mp3');
await audio.load('bgm', '/sounds/music.mp3');
audio.play('jump', { volume: 0.5 });
audio.playMusic('bgm', { volume: 0.3 });
audio.setMasterVolume(0.8);
audio.mute();Debug
import { DebugRenderer } from '@eternaxcode/agentia-engine';
// Shows FPS, entity count, collider outlines
engine.addSystem(new DebugRenderer(renderer));AI CLI
Bootstrap AI coding assistants with engine context:
npx agentia init claude # Generates CLAUDE.md
npx agentia init gemini # Generates .gemini fileReact / Next.js Integration
import { useEffect, useRef } from 'react';
import { Engine, CanvasRenderer, RenderSystem } from '@eternaxcode/agentia-engine';
export default function Game() {
const canvasRef = useRef<HTMLCanvasElement>(null);
useEffect(() => {
const canvas = canvasRef.current!;
const engine = new Engine();
const renderer = new CanvasRenderer(canvas);
engine.addSystem(new RenderSystem(renderer));
engine.start();
return () => engine.stop(); // Prevent memory leaks
}, []);
return <canvas ref={canvasRef} width={800} height={600} />;
}Build Outputs
| File | Format | Purpose |
|------|--------|---------|
| dist/agentia-engine.js | ES Module | import usage |
| dist/agentia-engine.umd.cjs | UMD/CJS | require usage |
| dist/index.d.ts | TypeScript | Type declarations |
| dist/index.cjs | CLI | npx agentia init |
License
MIT
