JSPM

@eternaxcode/agentia-engine

1.1.0
  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 4
  • Score
    100M100P100Q43215F
  • License MIT

Lightweight, AI-Native 2D Game Engine for TypeScript/Next.js

Package Exports

  • @eternaxcode/agentia-engine

Readme

Agentia Engine

npm version License: MIT TypeScript

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 CLInpx agentia init claude|gemini bootstraps AI context files
  • Zero Dependencies — pure TypeScript + browser APIs, no runtime packages

Installation

npm install @eternaxcode/agentia-engine

Quick 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:

  1. EventBus.processQueue() — flush deferred events
  2. CommandBuffer.processAll() — execute queued commands
  3. 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-destructs

Tilemap (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 file

React / 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