Phoenix Panels and the Swarm: Building a Living NPC Simulator

Introduction

In Phoenix we set out to build perpetual panels — panels that don’t just open, display data, and close, but stay alive as dynamic, self-refreshing windows of the swarm.

This vision materialized with the NPC Simulator panel, a cockpit-style control board wired into an autonomous swarm agent. It demonstrated how Phoenix panels can stream live state, accept control commands, and provide immediate, sensory feedback.

Perpetual Panels in Phoenix

Most GUIs render state once, then rely on manual refresh. Phoenix panels work differently:

  • Session-aware – Each panel binds to a unique session_id, scoping all inbound/outbound events.

  • Event-driven – Panels subscribe to bus channels like:

inbound.verified.npc_simulator.gameboard.response.{session_id}

  • Self-refreshing – Each incoming payload triggers redraws.

  • FIFO frame buffering – Updates are queued and drained safely in the Qt main loop, preventing crashes during resize.

The NPC Gameboard exemplifies this: it’s not a static grid, it’s a perpetual viewport into a live simulation stream.

The npc_simulator Agent

At the heart sits the npc_simulator agent, a swarm-aware Phoenix agent built on BootAgent.

Core roles

  • Scouts: wander randomly, spot the player, broadcast sightings.

  • Hunters: converge on last seen player.

  • Followers: cluster behind hunters.

Key mechanics

  • Streams:
    Each session starts a dedicated thread via cmd_start_npc_stream.
    The agent runs a _stream_loop, updating NPC state and broadcasting frames.

  • Sessions:
    Each stream is scoped to a session_id. If the session expires (flag check), it cleans itself up.

  • Broadcast frames:
    Each loop emits an encrypted, signed payload including:

{
  "session_id": "...",
  "player_pos": [x, y],
  "npc_list": [...],
  "last_seen_player": [lx, ly],
  "timestamp": 12345678
}
  • Control commands:
    NPC state can be influenced live via cmd_control_npcs.
    Actions like hunt, scatter, ping, shield, lock temporarily alter swarm behavior.

Swarm Behaviors

We extended control beyond “move NPCs” into emergent swarm modes:

  • Hunt → hunters aggressively converge on player’s position.

  • Scatter → swarm jitters chaotically, breaking formation.

  • Ping → scouts extend vision radius for 2 ticks, scanning further.

  • Shield → hunters are repelled from player, forming a bubble.

  • Lock → the entire swarm freezes for 5 ticks.

Each mode is managed via simple tick counters (scatter_ticks, ping_ticks, etc.) decremented in the main loop.
This made behaviors temporary, tactical, and visually distinct.

The Gameboard Panel

The Gameboard is a PyQt panel showing the swarm as a 20×20 grid:

  • Player → green @

  • Hunters → red o

  • Scouts → yellow o

  • Followers → cyan o

  • Last seen player → red X

  • Overlaps → numeric markers (“2”, “3”, …)

Key innovations

  • Safe streaming updates – _handle_gameboard_response enqueues frames in a deque, _drain_frame_queue flushes only the latest frame.

  • Thread-safe UI – Grid updates are always scheduled onto Qt’s main thread with QMetaObject.invokeMethod.

  • Resize resilience – Updates are skipped during resize, preventing crashes.

  • Perpetual state – The panel remembers last_player_pos, last_seen_player, and last_npc_list across redraws.

Control bar

The panel provides buttons bound to commands:

  • Start / Stop stream

  • Hunt / Scatter

  • Ping / Shield / Lock

Stability Fixes

We faced and solved several hard problems along the way:

  1. Qt crash during resize → Solved by deferring updates with FIFO + disabling updates mid-resize.

  2. NPC overlap spam → Prevented stack collisions at move time, replaced with numeric counters.

  3. Non-GUI thread updates → Routed all updates through queued slots on the GUI thread.

  4. NoneType errors → Guarded last_seen_player unpacking.

These fixes hardened the system into a cockpit that can run indefinitely without crash.

Lessons Learned

  • Perpetual panels in Phoenix allow long-lived, stream-driven views.

  • Swarm agents can simulate emergent behaviors with simple tick counters and shared state.

  • Event buses with session scoping keep simulations isolated and clean.

  • Feedback matters — visuals + logs + audio together make control feel meaningful.

  • Sometimes the right solution really is “more cowbell.”

Conclusion

What began as a technical test — “can we display NPCs on a grid?” — evolved into a fully interactive swarm control cockpit.

  • A Phoenix panel perpetually alive, streaming frames, and taking orders.

  • An npc_simulator agent managing swarm roles with simple but emergent behaviors.

  • A stable, extensible architecture that could scale to more panels, more agents, and richer behaviors.

The NPC panel is more than a demo — it’s proof that Phoenix panels can serve as perpetual living windows into the swarm, combining security, session isolation, and a touch of flair.

Resources

GitHub: https://github.com/matrixswarm/matrixos

GitHub: https://github.com/matrixswarm/phoenix

Docs: https://matrixswarm.com

Discord: https://discord.gg/CyngHqDmku

Python: pip install matrixswarm

Codex: /agents/gatekeeper

X/Twitter: @matrixswarm

💬 Join the Hive:
Join the Swarm: https://discord.gg/CyngHqDmku
Report bugs, fork the swarm, or log your own Codex banner.

Similar Posts