Chapter 58 — Create Your Own Starter
Create Your Own Starter
Section titled “Create Your Own Starter”The fastest path to a new game: scaffold from the CLI.
Quick Start
Section titled “Quick Start”ai-rpg-engine create-starter my-gameThis generates packages/starter-my-game/ with:
buildCombatStackas the default combat composition- A marked starter-owned systems section for your custom modules
- A pressure example (
createTensionPressure) to build from - A smoke test that validates the scaffold boots
Then:
cd packages/starter-my-gamenpm installnpx tsc --noEmitnpx vitest runOptions
Section titled “Options”ai-rpg-engine create-starter my-game --out=./somewhere-elseai-rpg-engine create-starter my-game --force # overwrite existingManual Template Route
Section titled “Manual Template Route”If you prefer to work without the CLI, the template is published on npm as an artifact to copy from (not a runtime dependency):
npm pack @ai-rpg-engine/starter-templatetar -xzf ai-rpg-engine-starter-template-*.tgzmv package packages/starter-mygamerm ai-rpg-engine-starter-template-*.tgzOr inside the monorepo:
cp -r templates/starter packages/starter-mygameWhat You Own vs What the Stack Owns
Section titled “What You Own vs What the Stack Owns”| Layer | Owner | You Touch? |
|---|---|---|
| Combat formulas (hit/damage/dodge) | buildCombatStack | No |
| Cognition, engagement, tactics | buildCombatStack | No |
| Recovery, intent, narration | buildCombatStack | No |
| Stat mapping | You | Config only |
| Resource profile | You | Config only |
| Traversal + zones | You | Yes |
| Entities + content | You | Yes |
| Custom modules | You | Yes |
| Ruleset definition | You | Yes |
The Four Files You Edit
Section titled “The Four Files You Edit”1. src/ruleset.ts — Declarative contract
Section titled “1. src/ruleset.ts — Declarative contract”Define your stats, resources, verbs, and formulas. The three combat stats must map to attack, precision, and resolve via buildCombatStack’s statMapping.
stats: [ { id: 'brawn', name: 'Brawn', min: 1, max: 20, default: 5 }, // → attack { id: 'reflex', name: 'Reflex', min: 1, max: 20, default: 5 }, // → precision { id: 'nerve', name: 'Nerve', min: 1, max: 20, default: 5 }, // → resolve],Add your starter-specific resource — this is what makes your game feel different:
resources: [ { id: 'hp', name: 'HP', min: 0, max: 100, default: 25 }, { id: 'guts', name: 'Guts', min: 0, max: 50, default: 10 }, // your pressure lever],2. src/content.ts — Entities and world
Section titled “2. src/content.ts — Entities and world”Define your manifest, player, enemies, NPCs, and zones. Zones need id, roomId, name, tags, and neighbors.
3. src/setup.ts — Composition root
Section titled “3. src/setup.ts — Composition root”This is where the composition contract lives:
const combat = buildCombatStack({ statMapping: { attack: 'brawn', precision: 'reflex', resolve: 'nerve' }, playerId: 'player', recovery: { safeZoneTags: ['safe'] },});
const engine = new Engine({ modules: [ traversalCore, statusCore, ...combat.modules, // ← the full combat stack (9 modules) // YOUR MODULES HERE createMyCustomPressure(), ],});4. src/starter.test.ts — Smoke test
Section titled “4. src/starter.test.ts — Smoke test”At minimum, verify:
- Ruleset validates against schema
createGame()boots without throwing- Your custom resource exists on the player
Writing a Custom Module
Section titled “Writing a Custom Module”import type { EngineModule, ResolvedEvent, WorldState } from '@ai-rpg-engine/core';
function createMyPressure(): EngineModule { return { id: 'my-pressure', version: '1.0.0', register(ctx) { ctx.events.on('combat.round.end', (event: ResolvedEvent, world: WorldState) => { const p = world.entities['player']; if (p) { p.resources.guts = Math.max(0, (p.resources.guts ?? 0) - 3); } }); }, };}Optional: Resource Profile
Section titled “Optional: Resource Profile”If your combat costs resources (stamina for attacks, mana for abilities), configure resourceProfile:
buildCombatStack({ statMapping: { attack: 'brawn', precision: 'reflex', resolve: 'nerve' }, resourceProfile: { spends: [ { verbId: 'attack', costStat: 'stamina', amount: 2 }, { verbId: 'use-ability', costStat: 'mana', amount: 5 }, ], },});Optional: Cognition Config
Section titled “Optional: Cognition Config”Control AI belief decay and morale:
buildCombatStack({ // ... cognition: { decay: { baseRate: 0.03, pruneThreshold: 0.1 }, moraleFleeThresholds: { low: 20, critical: 10 }, }, // cognition: false, // ← to exclude AI cognition entirely});Checklist
Section titled “Checklist”- Three stats mapped to
attack/precision/resolve - At least one starter-specific resource
-
buildCombatStackwithstatMapping(no custom formulas needed) - At least one custom module demonstrating your game’s pressure
-
createGame()boots and tests pass -
package.jsonname follows@ai-rpg-engine/starter-*convention