Skip to content

Chapter 57 — Composition Guide

AI RPG Engine ships 10 starter worlds. They are examples, not templates. Each one demonstrates how to combine engine modules into a game with its own combat identity, resource economy, and narrative pressure.

This chapter shows you how to build your own game by composing the same pieces the starters use.


Every game built on the engine has the same structure:

stat mapping → combat stack → modules → content → Engine constructor

You define stats, configure combat, pick the modules you need, create your content (entities, zones, dialogue), and wire it all into new Engine(). That’s the whole pattern.

The starters add demo glue on top — scripted event listeners for item gifts, audio cues, and fallout hooks. Those are polish, not architecture.


Every game needs a stat mapping — three stat roles that drive every combat formula:

RoleWhat It DrivesExample Names
AttackDamage, guard breakthroughvigor, might, brawn, chrome, grit, fitness
PrecisionHit chance, disengage, guard counterinstinct, agility, cunning, reflex, perception, wits
ResolveGuard absorption, brace resistance, moralewill, composure, sea-legs, command, presence, nerve

The golden rule: three distinct stats, never collapse attack = resolve. If your attack and resolve map to the same stat, guard breakthrough becomes trivial and combat loses its tension.

const statMapping = { attack: 'might', precision: 'agility', resolve: 'will' };

You can define stats beyond these three — exploration stats, social stats, crafting stats. The mapping only governs combat formulas.


buildCombatStack is the recommended entry point. It generates formulas, wraps them with engagement and resource modifiers, sets up review tracing, and returns a module array.

Minimal combat (no resources, no engagement roles)

Section titled “Minimal combat (no resources, no engagement roles)”
import { buildCombatStack } from '@ai-rpg-engine/modules';
const combat = buildCombatStack({
statMapping: { attack: 'might', precision: 'agility', resolve: 'will' },
playerId: 'hero',
});
const combat = buildCombatStack({
statMapping: { attack: 'might', precision: 'agility', resolve: 'will' },
playerId: 'hero',
resourceProfile: {
packId: 'my-game',
gains: [
{ trigger: 'attack-hit', resourceId: 'momentum', amount: 2 },
],
spends: [
{ action: 'attack', resourceId: 'momentum', amount: 5, effects: { damageBonus: 2 } },
],
drains: [],
aiModifiers: [],
},
});
const combat = buildCombatStack({
statMapping: { attack: 'might', precision: 'agility', resolve: 'will' },
playerId: 'hero',
engagement: {
backlineTags: ['ranged', 'caster'],
protectorTags: ['bodyguard'],
},
biasTags: ['undead', 'beast'],
});

See Build a Combat Pack for deep combat authoring.


Pick the modules your game needs:

import { Engine } from '@ai-rpg-engine/core';
import { traversalCore, statusCore, buildCombatStack, createDialogueCore, /* ... */ } from '@ai-rpg-engine/modules';
const combat = buildCombatStack({
statMapping: { attack: 'might', precision: 'agility', resolve: 'will' },
playerId: 'hero',
resourceProfile: myResourceProfile,
cognition: { decay: { baseRate: 0.02 } },
});
const engine = new Engine({
manifest: { id: 'my-game', title: 'My Game', version: '1.0.0' },
seed: 42,
modules: [
traversalCore,
statusCore,
...combat.modules,
createDialogueCore(myDialogues),
// ... add what you need
],
});
If your game has…You need
Rooms to move betweentraversalCore
CombatbuildCombatStack
NPC dialoguecreateDialogueCore
NPC beliefs and memorybuildCombatStack({ cognition: {...} })
Items and equipmentcreateInventoryCore
FactionscreateFactionCognition
Character abilitiescreateAbilityCore + createAbilityEffects
Boss encounterscreateBossPhaseListener

A zone connects to others through neighbors (zone ids), and entities locate themselves with zoneId — a zone does not carry an entity roster. Combatants must share a zoneId and carry a stamina resource, or combat-core rejects the attack (“target not in same zone” / “not enough stamina”). blueprintId is required on every entity.

engine.store.addZone({ id: 'cave', roomId: 'cave', name: 'Goblin Cave', tags: ['dark'], neighbors: ['clearing'] });
engine.store.addEntity({ id: 'hero', blueprintId: 'hero', type: 'player', name: 'Fighter', tags: ['human'], stats: { might: 6, agility: 5, will: 4 }, resources: { hp: 25, maxHp: 25, stamina: 5 }, zoneId: 'cave', inventory: [], equipment: {}, statuses: [] });
engine.store.addEntity({ id: 'goblin', blueprintId: 'goblin', type: 'enemy', name: 'Cave Goblin', tags: ['beast'], stats: { might: 3, agility: 6, will: 2 }, resources: { hp: 12, maxHp: 12, stamina: 5 }, zoneId: 'cave', statuses: [] });
engine.store.state.playerId = 'hero';
// setPlayerLocation keeps state.locationId and the player's zoneId in sync.
engine.store.setPlayerLocation('cave');

buildCombatStack() is infrastructure. Starters are fantasy. The boundary is clear:

ConcernHow
Formula generationstatMapping → hit/damage/guard/dodge/brace formulas
Formula wrappingengagement modifiers, resource effects, review tracing
Cognitionbelief decay, morale tracking, flee thresholds
Engagementbackline/protector/chokepoint zone states
Resourcesgain/spend/drain triggers, AI resource-aware scoring
IntentAI verb selection, pack biases, dimension awareness
Recoverysafe-zone healing, morale reset
State narrationcombat state change narration
Tacticsbrace stabilize, guard counter, tactical hooks
ConcernExamples
Resource identityinfection, composure, bloodlust, crowd-favor, power, dust
Resource economywhat gains/spends/drains mean thematically
Environment hazardsroaming-dead, dark-alley, scorching-sand, dust-storm
Faction cognitionpack behavior, group morale, cohesion
Presentation rulesspirit perception, suspect paranoia, noir framing
AbilitiesDeductive Strike, War Cry, Field Triage
AI modifiershigh-infection aggression, low-composure flee
Boss definitionsphase tags, threshold logic
Progression treesXP rewards, unlock paths
Defeat falloutwhat happens when entities die
// Custom decay (most starters)
buildCombatStack({ cognition: { decay: { baseRate: 0.02, instabilityFactor: 0.5 } } })
// Exclude cognition (caller provides their own)
buildCombatStack({ cognition: false })
// Default cognition (omit the key)
buildCombatStack({ statMapping, playerId })

Do not add a separate createCognitionCore() to your module list if you are using buildCombatStack(). The stack handles it.


All 10 starters use buildCombatStack(). This matrix shows how each genre maps to stack config:

StarterGenre PressureStack Config UsedStarter-Owned Systems
FantasySimple baselinestatMapping, biasTags, recovery, cognitionUndead faction, unstable-floor hazard, boss phases
Weird WestDual-resource frontierstatMapping, resourceProfile, biasTags, cognitionDust/resolve resources, spirit-drain hazard, spirit perception
GladiatorPerformance economystatMapping, resourceProfile, biasTags, cognitionCrowd-favor/fatigue, scorching-sand, trap-pit, 3-phase boss
VampireOpposing dual resourcesstatMapping, resourceProfile, biasTags, engagement, recovery, cognitionBloodlust/humanity tension, blood-scent, consecrated-ground
ZombieSurvival/attritionstatMapping, resourceProfile, biasTags, recovery, cognitionInfection-as-resource, roaming-dead, infection-risk, safe-zone recovery
ColonyParty/settlementstatMapping, resourceProfile, biasTags, engagement, recovery, cognitionPower/morale economy, ally-defeated penalty, resonance-field
DetectiveSocial-combatstatMapping, resourceProfile, biasTags, cognitionComposure drains, dark-alley, suspect paranoia, no safe haven
CyberpunkTech/networkstatMapping, resourceProfile, biasTags, engagement, cognitionBandwidth economy, exposed-wiring, ICE security framing
PirateCrew moralestatMapping, resourceProfile, biasTags, recovery, cognitionMorale drives everything, storm-surge, drowning-pressure
RoninDiscipline/duelstatMapping, resourceProfile, biasTags, engagement, recovery, cognitionKi/honor, poison-residue, shadow-watch, dual-faction

Key insight: No starter required formulaOverrides or custom combat state definitions. The standard buildCombatFormulas() output plus resourceProfile.spends[].resistState covered all 10 genres.


StarterBest Pattern to Borrow
FantasySimplest combat wiring — no resources, no engagement roles
Weird WestbuildCombatStack usage, dual resource profile
CyberpunkSquad engagement with backline/protector tags
DetectiveDefensive resource spending
PirateCrew morale as shared group resource
ZombieConsequence-only resource (infection)
VampireOpposing dual resources (bloodlust vs humanity)
GladiatorPerformance economy, 3-phase boss
RoninMultiple protector roles, dual-layer resources