Skip to content

Latest commit

 

History

History
413 lines (280 loc) · 12.9 KB

File metadata and controls

413 lines (280 loc) · 12.9 KB

Systems

Game systems are optional modules that extend the simulation with additional behaviours. Each system implements the GameSystem interface and receives a SystemContext on every engine tick, giving it access to all agent runtime states, the global simulation state, and the event bus.

Without any systems, the simulation still renders agents and plays their animations based on the status values you emit from your adapter. Systems layer on top to add economics, morale, weather, awards ceremonies, and more.

Enabling systems

Pass an array of instantiated system objects in config.systems:

import { EconomySystem, TimeSystem, ReputationSystem } from 'pixel-ops/systems';

const config = {
  agents: [...],
  systems: [
    new EconomySystem(),
    new TimeSystem(),
    new ReputationSystem(),
  ],
};

Systems execute in priority order on each game tick. Lower priority numbers run first.

GameSystem interface

If you want to create a custom system, implement this interface:

interface GameSystem {
  name: string;
  priority: number;
  update(delta: number, context: SystemContext): void;
  onEvent?(eventType: string, payload: unknown): void;
}

interface SystemContext {
  agents: Map<string, AgentRuntimeState>;
  state: GlobalSimState;
  eventBus: GameEventBusType;
}
Field Type Description
name string Identifier used in logs
priority number Execution order; lower runs first
update function Called every game tick with elapsed milliseconds
onEvent function Optional — receives events from the internal event bus

SystemContext

Field Description
agents Map of agent ID to AgentRuntimeState. Mutate needs, moods, and stats here.
state Global simulation state: reputation, economy, time, season, policies, room prestige
eventBus Emit and subscribe to internal game events

Available systems

EconomySystem

Priority: 55

Tracks compute credits as an in-simulation currency. Agents earn credits on task completion and spend them on upkeep per tick. Error recovery costs additional credits.

Events emitted:

  • credits-earned{ amount: number, agentId: string, reason: string }
  • credits-spent{ amount: number, reason: string }
  • budget-warning{ credits: number } — fired when credits drop below 50

HUD wired to: BudgetBar component (top right area of canvas)

Usage: Useful when you want to model agent costs visually — e.g., token spend per LLM call, compute cost per inference job.

import { EconomySystem } from 'pixel-ops/systems';

new EconomySystem()

You can also drive the economy directly from your adapter:

this.emit('economy:transaction', { amount: 100, type: 'income', reason: 'API call' });

WeatherSystem

Priority: 3

Cycles the ambient weather between clear, cloudy, rain, snow, and storm. Weather transitions are weighted by the current season. Intervals range from 5 to 15 real minutes, shortened at higher time speeds.

Depends on: TimeSystem (for the current season)

Events emitted:

  • weather-changed{ type: WeatherType, intensity: number, previous: WeatherType, season: string }

Usage: Purely cosmetic in v0.1.0. Can be used with a custom system that changes agent morale based on weather events.

import { WeatherSystem, TimeSystem } from 'pixel-ops/systems';

systems: [new TimeSystem(), new WeatherSystem()]

ResearchSystem

Priority: 60

Running research agents accumulate research points each tick, with diminishing returns for multiple simultaneous researchers. Points are awarded to the first incomplete research topic in a fixed queue.

Built-in research topics:

Topic ID Name Points required Unlocks
adv-monitoring Advanced Monitoring 100 Heatmap overlays
agent-training Agent Training 150 Training room
infra-v2 Infrastructure v2 200 Server upgrade room
social-intel Social Intelligence 120 Enhanced relationships
stats-suite Statistics Suite 80 Statistics room

Events emitted:

  • research-progress{ topicId, topicName, progress, required, delta }
  • research-completed{ topicId, topicName, unlocks, category }

Usage: Assign agents the research sprite and set their status to working when they are actively running.

import { ResearchSystem } from 'pixel-ops/systems';

new ResearchSystem()

NeedsSystem

Priority: 10

Tracks three needs for each agent on a 0–1 scale. Needs influence the MoodSystem and can trigger automatic room changes.

Need Depletes when Restores when
energy Agent is running Agent is idle or disabled
morale Agent fails or errors Agent succeeds, is idle
focus Agent changes status Agent is running or idle

Events emitted:

  • agent-tired{ agentId, energy } — when energy drops below the rest threshold
  • agent-rested{ agentId, energy } — when energy recovers above 70%
  • agent-morale-changed{ agentId, morale, delta }

Usage: Pair with MoodSystem to show visible mood icons. Pair with a custom system to automatically route tired agents to the break room.

import { NeedsSystem, MoodSystem } from 'pixel-ops/systems';

systems: [new NeedsSystem(), new MoodSystem()]

MoodSystem

Priority: 20

Derives visible mood icons from each agent's needs, status, and recent history. Up to two icons are shown per agent at a time. Icons are re-evaluated every 500ms.

Mood icons and their conditions:

Icon Condition
exhausted Energy < 15%
frustrated Morale < 30%
on-fire Success streak >= threshold
tired Energy < 30% while running
celebrating Recently went idle after a success streak
processing Running with energy > 50%
thinking Focus < 30% while running
on-break Idle with energy < 60%
confident Morale > 90%
anxious Morale between 30% and 40%
cold Idle for a long time

Depends on: NeedsSystem

Events emitted:

  • mood-changed{ agentId, moods: MoodIcon[] }

ReputationSystem

Priority: 30

Adjusts the campus reputation score (0–1000) based on task completions, failures, and agent crashes. Uses quadratic dampening so score changes become harder near the extremes.

Score tiers:

Score Tier
800–1000 Legendary
600–799 Excellent
400–599 Good
200–399 Struggling
0–199 Critical

Events emitted:

  • reputation-changed{ reputation, delta, reason, agentId? }
  • reputation-milestone{ reputation, tier } — fired when the tier changes

HUD wired to: ReputationHUD component (top left of canvas)

You can also drive reputation from your adapter:

this.emit('reputation:change', { delta: 25, reason: 'Deployment succeeded' });

TimeSystem

Priority: 2

Advances a simulation clock where 1 real minute equals 1 game hour at 1x speed. Tracks the time of day (0–24), day count, and season. The TimeControls HUD lets users pause or accelerate time (1x, 2x, 4x).

Season cycle: Each season lasts a configurable number of game days. Seasons advance: spring → summer → autumn → winter → spring.

Events emitted:

  • time-of-day-changed{ timeOfDay, dayCount } — once per game hour
  • season-changed{ season }

HUD wired to: TimeControls component (top centre of canvas)


IdleBehaviorSystem

Priority: 25

Plays short sprite animation micro-behaviours when an agent is idle. Each agent type has a curated set of behaviours (e.g., workers stretch and sip coffee, orchestrators pace and point, researchers flip pages).

Behaviours fire at random intervals between idle periods. Custom agent types without a defined behaviour set fall back to a generic stretch and look-around animation.

Events emitted:

  • idle-behavior-started{ agentId, behavior: string }
  • idle-behavior-ended{ agentId }

PrestigeSystem

Priority: 35

Evaluates room prestige scores based on placed furniture. Furniture is classified into four tiers — functional, comfort, decoration, and premium — and the sum determines a room's prestige value. Prestige is re-evaluated every 5 seconds.

Events emitted:

  • room-prestige-changed{ roomId, prestige: number }

Usage: Use the furniture editor to place higher-quality items in a room to raise its prestige. Custom systems can respond to prestige changes to boost morale or reputation.


EventSystem

Priority: 45

Generates random simulation events that require player decisions. Events have deadlines; ignoring them results in a reputation penalty.

Event types:

Type Trigger Description
rush-job Random chance per tick A client demands urgent delivery. Accept for quick reputation, or decline.
bug-epidemic 3+ agent errors within 60 seconds Rapid agent crashes detected. Declare code freeze or quarantine affected agents.
vip-audit Every N game hours Senior stakeholder visits. Prepare a showcase or let them wander.
infra-failure Very rare random chance Critical infrastructure offline. Emergency patch or controlled shutdown.

Events emitted:

  • simulation-event-created{ event: SimulationEvent }
  • simulation-event-resolved{ event, delta, reason, reputation }

HUD wired to: FaxMachine component (bottom right of canvas)


RelationshipSystem

Priority: 50

Tracks sentiment between agent pairs, updated every 10 seconds. Sentiment is a value between -1 (negative) and +1 (positive), updated by four rules:

  1. Orchestrators appreciate high-success-rate workers
  2. Workers are neutral or negative towards peers with unbalanced (very heavy) workloads
  3. Agents running simultaneously develop proximity rapport
  4. Shared failures build empathy

Relationships are ephemeral — they reset when the component unmounts.

Query methods available on the system instance:

const relSys = new RelationshipSystem();
relSys.getRelationship('agent-a', 'agent-b');  // AgentRelationship | null
relSys.getTopRelationships('agent-a', 5);       // AgentRelationship[]

AwardsSystem

Priority: 60

Tracks per-agent performance across weekly game time periods and awards trophies at week end. Four award categories:

Category Trophy name Criteria
productivity Top Producer Most task successes this week
reliability Flawless Record Zero failures, most total runs
speed Speed Demon Best success rate (min 3 runs)
endurance Iron Agent Most total runs this week

Events emitted:

  • award-granted{ trophy: Trophy }
  • ceremony-started{ trophies: Trophy[], week: number }

HUD wired to: AwardsModal component — displayed when a ceremony is triggered

Depends on: TimeSystem (for game day count)


SoundSystem

Priority: 99

Plays short audio tones using the browser's Web Audio API. No external audio files — all sounds are synthesised from oscillators. Runs last in the pipeline (priority 99) so it reacts to events from all other systems.

Audio events:

Event Sound
reputation-changed Short 880 Hz sine beep
emergency-started Two-tone sawtooth alarm
award-granted Three-note ascending fanfare
ceremony-started Four-note C-E-G-C fanfare

Audio is rate-limited to one sound per 200ms to prevent overlap. All errors are swallowed silently — audio is non-fatal.

Control methods:

const soundSys = new SoundSystem();
soundSys.setMuted(true);    // silence all sounds
soundSys.setVolume(0.5);    // 0–1

Creating a custom system

import type { GameSystem, SystemContext } from 'pixel-ops';

export class AlertOnErrorSystem implements GameSystem {
  name = 'AlertOnErrorSystem';
  priority = 40;

  private prevStatus = new Map<string, string>();

  update(_delta: number, ctx: SystemContext): void {
    for (const [id, agent] of ctx.agents) {
      const prev = this.prevStatus.get(id);
      if (prev && prev !== 'error' && agent.status === 'error') {
        ctx.eventBus.emit('notification-added', {
          notification: {
            id: `alert-${id}-${Date.now()}`,
            priority: 'critical',
            message: `Agent ${id} entered error state`,
            agentId: id,
            createdAt: Date.now(),
            expiresAt: Date.now() + 30_000,
            read: false,
          },
        });
      }
      this.prevStatus.set(id, agent.status);
    }
  }

  onEvent(eventType: string, payload: unknown): void {
    // Optionally react to events from other systems or the adapter
  }
}

Register it alongside built-in systems:

import { AlertOnErrorSystem } from './AlertOnErrorSystem';

config.systems = [
  new ReputationSystem(),
  new AlertOnErrorSystem(),
]