Enemy System
Enemies are managed through the ECS (see ECS System) with spawning orchestrated by EnemyService.
Enemy Types
Hostile Entities
| Entity | Damage | Speed | Behavior |
|---|---|---|---|
| FlowerTrap | 20 | 10 | Weeping Angel — can't move while observed |
| PathMonster | Instant kill | 36 | Charges down path, must hide to survive |
| TreeBranchSnatcher | 20 | 40 | Drop attack from above |
| RootSnare | 20 + 3s immobilize | 0 | Ground trap |
| GigglingBush | Kill (50% chance) | 0 | 50/50 lethal/harmless |
| Watcher | Instant kill | 6 | Boss — hunts off-path players |
Neutral Entities
- NeutralFlowerTrap — Same appearance as hostile, never attacks
- NeutralRootSnare — Visible roots, safe to step over
- LostQuirkymal — Downed character to rescue (30s timer)
- MimicEntity — Appears as Lost Quirkymal, attacks rescuers
Spawning
Enemy placement is pre-computed for the whole run by planEnemies (pressure-based) and materialized per chunk by EnemySlotGenerator. See Enemy Spawning Pipeline for the full flow: planner → policy-filter → slot generator → dispatch.
Quick summary:
// Once per run (RunDirector.buildRunPlan)
const enemyRunPlan = planEnemies(seed, ENEMY_BALANCE, pacingManager, chaseSections);
// Per chunk
const slots = generateEnemySlots(geometry, plannedPlacements, rng);
for (const slot of slots) dispatchEnemySpawn(slot);
Per-enemy tuning (pressure, minTrail, maxPerRun, cooldownMarkers, compatibility) lives in apps/enemies/server/balance/enemy-balance.ts.
Petal Palette
FlowerTrap colors are generated per session using petal-colors.ts. Both hostile and neutral traps share the same color pool — players can't distinguish by color alone.
Enemy Registry
enemy-registry.ts defines detection ranges and behaviors:
FlowerTrap: { triggerRadius: 16, chaseRadius: 50, attackRange: 5 }
PathMonster: { triggerRadius: 40, speed: 36 }
Watcher: { triggerRadius: 60, speed: 6 }
RootSnare: { triggerRadius: 3, speed: 0 } // trap
PathMonster Sweep
PathMonsters follow the global path node array:
- Pick direction (forward or backward)
- Sweep through nodes at 36 studs/sec
- Kill any unhiding player within 8 studs
- Despawn at +2 chunks from player
Watcher Boss
- Spawns when player is off-path for 30+ seconds
- Follows path nodes toward player
- Direct pursuit when close
- Cannot enter safe zones
- Debug logs gated behind
WatcherLogsflag