Design a Living-City NPC Platform

Design a scalable NPC simulation with tiered updates and persistent state.

Introduction

30 Second Summary

A busy open-world city feels alive when people keep reacting beyond the player's immediate view. Giving every resident equal attention can exhaust the tiny slice of time available for each moment on screen.

In this project, you will design a fictional living-city NPC simulation platform in draw.io. Your architecture will keep nearby NPC behavior responsive while bounding distant simulation work inside a fixed budget.

What You'll Build

Your finished diagram lets you trace a street crime from the player through nearby witnesses, distant districts, persistent NPC history, overload controls, and recovery.

By the end of this project, you'll have:

  • A visible capacity estimation that traces one update across 10,000 NPCs. The displayed 500 ms cost visibly overwhelms the 8 ms simulation budget.
  • A relevance-based city model where spatial partitioning assigns NPCs to High, Medium, or Low simulation level of detail. The displayed 7.2 ms total fits inside the budget.
  • A street-crime walkthrough that shows immediate local reactions, delayed distant effects, persistent state, and safe event replay during promotion.
  • Secret Mission: Adapt the platform to a citywide hurricane using 100 cell-level updates while keeping the 8 ms NPC-simulation budget intact.

Are there any prerequisites?

You should be familiar with system-design fundamentals such as components, data flows, latency, throughput, and bottlenecks. You only need a Mac with browser access because no additional software or accounts are required.

Before We Start

This project commits you to a fictional living-city NPC simulation platform while leaving Rockstar's undisclosed implementation outside the scope. The architecture must preserve a responsive, believable player-visible city within an 8 ms NPC-simulation budget inside each 16.67 ms frame window.

Set Up the Design Canvas and Budget

Your architecture needs a measurable ceiling before any component can earn a place on the canvas. Without a defined workload or resource limit, later claims about scalability have nothing concrete to defend.

The draw.io web editor gives you an editable canvas for the design. You will pin the workload assumptions beside the fixed simulation budget before drawing any architecture flows.

In this step, get ready to:
  • Create a blank diagram with the title Living-City NPC Platform.
  • Add a Design Target panel containing the population, spatial, frame, and simulation-budget assumptions.
  • Add a Cost Model panel before saving the editable diagram locally.
Create the blank design canvas

A blank canvas keeps the exercise focused on your reasoning. The only elements added here are the title and budget assumptions.

  • Visit the official draw.io web editor in your browser.
  • Choose your local device as the storage location if draw.io asks where to store the diagram.
  • Select Create New Diagram if the start screen is shown.
  • Enter Living-City NPC Platform in the filename field.
  • Select Blank Diagram in the template library.
  • Select Create to enter the editor.

You will see an empty gridded canvas with shape libraries beside it.

  • Double-click an empty area near the top of the canvas.
  • Select the text-only shape from the shape picker.
  • Type Living-City NPC Platform as the diagram title.
  • Press Enter to save the title text.

Good start. Your canvas now has a clear identity without any architecture flow boxes competing for attention.

Blank canvas not opening?

  • Reload the editor if the template library remains blank.
  • Allow the site to store or download a local file if your browser requests permission.

If the editor still does not open, help me troubleshoot access to the draw.io web editor.

Add the Design Target panel

Capacity estimation turns a design goal into a workload you can test. A frame budget defines the time available before simulation work starts harming responsiveness.

  • Drag a Rectangle from the General shape library onto the left side of the canvas.
  • Resize the rectangle to leave room for six lines of text.
  • Double-click the rectangle to edit its label.
  • Replace the label with Design Target 10,000 persistent NPCs 100 spatial cells 60 FPS target 1000 / 60 = 16.67 ms total frame window 8 ms NPC-simulation budget.
  • Press Enter to save the panel label.

You will see one panel that makes the scale and timing constraints visible at a glance.

How does the budget fit together?

  • The 10,000 persistent NPCs value defines the total population whose state must survive over time.
  • The 100 spatial cells value divides the city into bounded regions for later relevance decisions.
  • The 60 FPS target produces a total frame window of 16.67 ms.
  • The 8 ms NPC-simulation budget reserves only part of that frame window for NPC work.
Add the cost model and save

A unit cost turns the population count into an estimated frame cost. The baseline assumes that one full-fidelity NPC update consumes 0.05 ms.

  • Drag another Rectangle from the General shape library beneath the Design Target panel.
  • Resize the rectangle to fit two lines of text.
  • Double-click the second rectangle to edit its label.
  • Replace the label with Cost Model 0.05 ms per full-fidelity NPC update.
  • Press Enter to save the panel label.

The canvas now shows both sides of the capacity argument. One panel defines the ceiling while the other defines the cost of each unit of work.

  • Open the File menu.
  • Select Save As.
  • Enter Living-City NPC Platform.drawio as the filename.
  • Keep .drawio as the file format.
  • Choose a local folder on your Mac where you can find the file again.
  • Confirm the save in the file picker.

Why save as a draw.io file?

The recommended .drawio format preserves the diagram data. You can reopen the file to move shapes or extend the architecture later.

Cannot find the saved file?

  • Repeat the save if the browser did not confirm that a file was created.
  • Choose a familiar local folder when the file picker opens again.
  • Confirm that the filename ends with .drawio.

If the save still fails, help me troubleshoot saving a local draw.io file.

Before you reopen the file, do you expect both panels to survive the round trip as editable shapes? Make your prediction now.

  • Open a new browser tab.
  • Visit the draw.io web editor.
  • Drag Living-City NPC Platform.drawio from Finder onto the drawing canvas.

What should I see?

Your saved diagram opens as an editable canvas.

  • The title reads Living-City NPC Platform.
  • The Design Target panel shows 10,000 persistent NPCs.
  • The Design Target panel shows 100 spatial cells.
  • The Design Target panel shows a 60 FPS target.
  • The Design Target panel shows 1000 / 60 = 16.67 ms total frame window.
  • The Design Target panel shows an 8 ms NPC-simulation budget.
  • The Cost Model panel shows 0.05 ms per full-fidelity NPC update.

✔️ My diagram matches

That is the foundation in place. Your editable diagram now exposes the workload and budget that every later architecture choice must respect.

ⓧ I'd like to double check

The target artifact is a saved editable draw.io diagram titled Living-City NPC Platform.

  • Confirm that the local file is named Living-City NPC Platform.drawio.
  • Confirm that the Design Target panel contains 10,000 persistent NPCs.
  • Confirm that the Design Target panel contains 100 spatial cells.
  • Confirm that the Design Target panel contains a 60 FPS target.
  • Confirm that the Design Target panel contains 1000 / 60 = 16.67 ms total frame window.
  • Confirm that the Design Target panel contains an 8 ms NPC-simulation budget.
  • Confirm that the Cost Model panel contains 0.05 ms per full-fidelity NPC update.
  • Confirm that no architecture flow boxes have been added.

Your assumptions are now visible and defensible. Next, you will use the cost model to test whether full-fidelity simulation can stay inside the budget.

Prove Full-Fidelity Simulation Fails

The saved Living-City NPC Platform.drawio file already makes the workload visible. It also shows the timing limits.

This step tests the simplest possible design. You will measure that design against the fixed budget before using the result as evidence in your scalability argument.

In this step, get ready to:
  • Draw one baseline path for all 10,000 NPCs.
  • Calculate its per-frame cost against both timing limits.
  • Explain why the baseline collapses under load.
Draw the full-fidelity baseline

Full-fidelity simulation gives every NPC its most detailed update on every frame. Behavior work, navigation work, and animation work all run for each NPC.

  • Drag four rectangle shapes into the open area beneath the existing panels.
  • Arrange the four rectangles in one horizontal row.

You should now see a clear path with space for four stages.

  • Label the first box Frame Update Loop.
  • Label the second box All NPCs.

The first half of the flow now shows where each frame begins and who receives its work.

  • Label the third box Behavior, Navigation, Animation.
  • Label the fourth box World State.

The second half now shows the detailed simulation work and its destination.

  • Draw a right-pointing connector from Frame Update Loop to All NPCs.
  • Draw a right-pointing connector from All NPCs to Behavior, Navigation, Animation.

You can now follow the update into the NPC group and through its detailed simulation work.

  • Draw a right-pointing connector from Behavior, Navigation, Animation to World State.
  • Place the label 10,000 full-fidelity updates every frame beneath the All NPCs box.

The completed path sends every frame through the entire NPC population. No stage reduces the amount of detailed work.

Why model uniform updates?

This baseline ties the workload to the total NPC population. Every additional NPC adds another full update to each frame.

The diagram gives the existing 8 ms budget a concrete design to challenge.

Calculate the overload

Capacity estimation translates the architecture into a number that can be compared with a budget. The existing panels provide the two inputs.

Before you calculate it, do you expect this baseline to fit inside the 8 ms NPC-simulation budget?

  • Calculate the per-frame cost by multiplying 10,000 by 0.05 ms.

You should get 500 ms per frame.

  • Calculate the budget multiple by dividing 500 ms by 8 ms.

You should get 62.5× the NPC-simulation budget.

  • Compare 500 ms with the 16.67 ms total frame window.

The baseline exceeds the entire frame window. NPC simulation alone would consume far more time than the complete frame can allow.

  • Add a rectangular capacity callout beside the All NPCs box.
  • Enter 10,000 × 0.05 ms = 500 ms per frame as the first line.

The raw capacity cost now sits beside the component that creates it.

  • Add 62.5× the 8 ms NPC budget as the second line.
  • Add Above the 16.67 ms total frame window as the third line.

The callout now compares the baseline with both timing limits.

  • Set the capacity callout border to red.
  • Set the capacity callout fill to a light red shade.

The capacity result should now stand out as an overload warning.

  • Set every baseline box border to red.
  • Set every baseline box fill to a light red shade.

The four stages should now read as one overloaded path.

  • Set all three connector lines to red.

You should now see a continuous red flow from the frame update loop to world state.

Numbers do not match?

  • Check that the population input is 10,000.
  • Check that one full-fidelity update costs 0.05 ms.
  • Divide the calculated 500 ms cost by the 8 ms budget.

Help me verify the baseline capacity calculation.

Explain the failure

A failure analysis connects the scaling variable to the system bottleneck. Here, total NPC population drives a CPU bottleneck.

Distant NPC updates consume the same budget as nearby updates. That unnecessary work causes frame-time collapse.

  • Add a callout shape beside the red baseline flow.
  • Set its title to Failure Analysis.

The new panel now has a clear purpose beside the overloaded design.

  • Add Scaling variable: Total NPC population.
  • Add Bottleneck: CPU simulation work.

The first two entries connect population growth directly to CPU demand.

  • Add Unnecessary work: Distant NPC updates.
  • Add Outcome: Frame-time collapse.

The panel now identifies the wasted work and the effect the player experiences.

  • Position the Failure Analysis callout beside the overloaded path.
  • Save the current diagram to Living-City NPC Platform.drawio using the save control in the editor toolbar.

That is the baseline proven. Your saved diagram now turns an abstract scalability concern into a visible budget failure.

Before you trace the finished path, do you expect any stage to reduce the number of NPC updates?

  • Trace the red flow from Frame Update Loop through All NPCs to Behavior, Navigation, Animation to World State.
  • Confirm that the All NPCs group is labeled 10,000 full-fidelity updates every frame.
  • Confirm that the red capacity callout reads 10,000 × 0.05 ms = 500 ms per frame.
  • Confirm that the callout identifies the result as 62.5× the 8 ms NPC budget.
  • Confirm that the callout says Above the 16.67 ms total frame window.

You should see every frame update pass through all 10,000 NPCs. The red capacity callout proves that 500 ms is 62.5× the NPC-simulation budget.

The same callout shows that the baseline also exceeds the 16.67 ms total frame window.

  • Confirm that Failure Analysis names total NPC population as the scaling variable.
  • Confirm that it names CPU simulation work as the bottleneck.
  • Confirm that it identifies distant NPC updates as unnecessary work.
  • Confirm that it names frame-time collapse as the outcome.

Your final diagram should make the cause of failure clear without extra explanation. Population-wide full-fidelity work breaks both timing limits.

✔️ Awesome, I've got everything!

Your baseline failure analysis is complete. Keep the saved Living-City NPC Platform.drawio file open for the next step.

ⓧ I'd like to double check the full diagram

Compare your saved diagram with this cumulative checkpoint.

  • Confirm that the diagram title remains Living-City NPC Platform.
  • Confirm that the Design Target panel still shows 10,000 persistent NPCs, 100 spatial cells, a 60 FPS target, a 1000 / 60 = 16.67 ms total frame window, plus an 8 ms NPC-simulation budget.
  • Confirm that the Cost Model panel still shows 0.05 ms per full-fidelity NPC update.
  • Confirm that the red baseline flows from Frame Update Loop to All NPCs to Behavior, Navigation, Animation to World State.
  • Confirm that the All NPCs label reads 10,000 full-fidelity updates every frame.
  • Confirm that the red capacity callout shows 10,000 × 0.05 ms = 500 ms per frame, 62.5× the 8 ms NPC budget, plus Above the 16.67 ms total frame window.
  • Confirm that Failure Analysis identifies total NPC population, CPU simulation work, unnecessary distant work, plus frame-time collapse.

Your baseline now proves why population-wide simulation fails. Next, you will bound that work around what the player can actually observe.

Build Spatial Tiers and a Bounded Scheduler

The failed baseline in your draw.io diagram now proves that 500 ms of work cannot fit inside the 8 ms NPC budget. Its cost follows all 10,000 NPCs.

This step makes cost follow spatial relevance. A bounded scheduler gives the most frequent updates to the NPCs that matter near the player.

In this step, get ready to:
  • Build the active simulation path through four bounded-work components.
  • Divide the NPC population into High, Medium, and Low simulation tiers.
  • Prove that the average workload fits inside the 8 ms NPC-simulation budget.
Build the relevance path

A Spatial Cell Index applies spatial partitioning to the 100 cells already listed in your Design Target. The relevance path uses those cells to direct bounded work toward the player.

Why spatial tiers?

Uniform full-fidelity updates make per-frame work grow with the total NPC population. Spatial tiers make work grow with the smaller set of relevant NPCs.

The scheduler admits that work within a fixed budget. Distant NPCs receive less frequent updates.

  • Drag a rectangle from the left shape palette into an empty area below the failed red baseline.
  • Label the rectangle Spatial Cell Index.
  • Place a second rectangle to the right of the Spatial Cell Index.
  • Label the second rectangle Player Relevance Tracker.

You should now see the first two components of the target path in a separate area from the failed baseline.

  • Draw a connector from Spatial Cell Index to Player Relevance Tracker.
  • Place a third rectangle to the right of the Player Relevance Tracker.
  • Label the third rectangle Tier Manager.
  • Draw a connector from Player Relevance Tracker to Tier Manager.

The target path can now classify relevant NPCs before assigning simulation work.

  • Place a fourth rectangle to the right of the Tier Manager.
  • Label the fourth rectangle Budgeted Simulation Scheduler.
  • Draw a connector from Tier Manager to Budgeted Simulation Scheduler.

You now have a complete active path from spatial lookup to budgeted execution.

  • Place a small input box above the Player Relevance Tracker.
  • Label the first input box player location.
  • Draw a connector from player location to Player Relevance Tracker.
  • Place a second input box beside the first input box.
  • Label the second input box mission-critical flags.
  • Draw a connector from mission-critical flags to Player Relevance Tracker.

The tracker now receives both sources of relevance. Its output carries those decisions into the Tier Manager.

Are the connectors floating?

Attach each connector endpoint directly to its component. A line that moves independently from a box is not attached.

Help me fix the connectors in my draw.io target architecture.

Add the simulation tiers

Simulation level of detail assigns different update frequencies according to relevance. High-tier NPCs receive immediate work while distant NPCs receive cheaper periodic work.

Keeping three lanes aligned can be fiddly on a busy canvas. Place them in a vertical stack beside the Budgeted Simulation Scheduler.

  • Drag a wide rectangle to the right of the Budgeted Simulation Scheduler.
  • Label the first lane High = 100 NPCs at 0.05 ms every frame.
  • Place a second wide rectangle below the High lane.
  • Label the second lane Medium = 900 NPCs at 0.01 ms every 10 frames.

The first two lanes now distinguish player-visible work from less frequent background work.

  • Place a third wide rectangle below the Medium lane.
  • Label the third lane Low = 9,000 NPCs at 0.002 ms every 60 frames plus event-triggered work.
  • Draw a connector from Budgeted Simulation Scheduler to the High lane.
  • Draw a connector from Budgeted Simulation Scheduler to the Medium lane.
  • Draw a connector from Budgeted Simulation Scheduler to the Low lane.

Your scheduler now distributes work across all three tiers. Each lane makes its population size visible beside its update frequency.

Are the tier labels hard to read?

Widen each lane until its full population and timing label is visible. Keep the High lane above Medium.

Help me arrange readable simulation-tier lanes in draw.io.

Prove the scheduler fits the budget

Tiering only solves the baseline failure when the average cost stays bounded. The final panel turns each tier frequency into an average per-frame contribution.

  • Drag a panel rectangle into the open space near the scheduler.
  • Label the panel Average Per-Frame Cost.

The cost panel now has a visible home beside the architecture it evaluates.

  • Add High: 100 × 0.05 = 5.0 ms to the cost panel.
  • Add Medium: 900 × 0.01 / 10 = 0.9 ms below the High calculation.

The Medium row divides its periodic work across 10 frames. This converts its update schedule into an average per-frame cost.

  • Add Low: 9,000 × 0.002 / 60 = 0.3 ms below the Medium calculation.
  • Add Spatial plus scheduling overhead = 1.0 ms below the Low calculation.

The panel now accounts for all three tiers plus the machinery that finds relevant NPCs and schedules their work.

  • Calculate the total from the four cost entries.

Your total is 7.2 ms. This leaves 0.8 ms of room inside the NPC-simulation budget.

  • Add Total: 5.0 + 0.9 + 0.3 + 1.0 = 7.2 ms to the bottom of the panel.
  • Add 7.2 ms is within the 8 ms NPC-simulation budget below the total.

That closes the budget gap. Your target architecture now replaces population-wide ticking with bounded relevance work.

  • Save the existing Living-City NPC Platform.drawio file using the same save action from earlier.

Before you do the final check, do you expect every target-path component to remain inside the 8 ms NPC budget?

  • Trace the target path from the Spatial Cell Index through the scheduler.
  • Sum every row in the Average Per-Frame Cost panel.

You should read 5.0 + 0.9 + 0.3 + 1.0 = 7.2 ms. That total fits inside the 8 ms NPC-simulation budget.

Your city simulation now spends work according to relevance while staying inside its fixed budget. Next, you can preserve distant consequences when NPCs leave active cells.

Add Events and Persistent NPC State

Your simulation tiers now keep average work at 7.2 ms within the 8 ms NPC budget. Player relevance now controls how much simulation work each NPC receives.

Unloaded NPCs still need their history to survive. Concurrent interactions also need clear ownership to prevent contradictory outcomes.

This step adds an event-driven architecture for work that matters. Persistent state carries each NPC across unloading and promotion.

In this step, get ready to:
  • Connect event routing to per-cell queues.
  • Preserve NPC history through unloading.
  • Trace a street crime through consistency-safe promotion.
Add the event and state backbone

An event path sends new work to an affected cell. A state store preserves the history needed when an NPC returns.

  • In the draw.io canvas from earlier, create a component labeled World Event Router above the Budgeted Simulation Scheduler.
  • Create a component labeled per-cell Event Queue beside the World Event Router.

You should now see a short event intake path beside the active simulation path.

  • Create a component labeled NPC State Store below the Budgeted Simulation Scheduler.
  • Create a component labeled Interaction Reservation beside the scheduler.

The diagram now separates transient runtime work from durable NPC history.

  • Connect the World Event Router to the per-cell Event Queue.
  • Connect the Budgeted Simulation Scheduler to the NPC State Store.

You should now see events entering through a queue while runtime updates leave through the state path.

  • Label the state-store connector Runtime updates: versioned NPC snapshots + event identifiers.
  • Connect the Interaction Reservation to the Budgeted Simulation Scheduler.

Your scheduler now has a route for durable writes. It also has a reservation boundary for exclusive interactions.

Why events need persistent state

  • The World Event Router turns one published event into targeted cell work.
  • The per-cell Event Queue holds work until that cell can process it.
  • The NPC State Store preserves an NPC after its runtime instance disappears.
  • Event identifiers let replay logic recognize work that has already been applied.

Does the event path look ambiguous?

  • Move the event components away from the red baseline so their connectors remain distinct.
  • Keep the arrow direction moving from the router toward the queue.
  • Keep the state-write arrow moving from the scheduler toward the store.

Use this if you want help checking the layout: Help me verify the event-routing and persistent-state paths in my living-city architecture diagram.

Trace one street-crime event

A street crime shows how one event can produce different amounts of work across the three tiers. Each reaction keeps the same cause while matching the NPC's current relevance.

  • Place a source node labeled Street Crime Event beside the World Event Router.
  • Connect the Street Crime Event to the router.

You should now see one source event entering the routing path.

  • Label the source connector Publish crime once.
  • Label the router-to-queue connector Route to affected cell.

The event now has one publication point. The affected cell receives the routed work.

  • Draw a branch from the per-cell Event Queue to the High-tier lane with the label Immediate High-tier witness reaction.
  • Draw a branch from the queue to the Medium-tier lane with the label Scheduled Medium-tier reaction.

High-tier witnesses now react within the visible scene. Medium-tier NPCs receive scheduled work.

  • Draw a branch from the queue to the Low-tier lane with the label Compact district alert for Low-tier NPCs.
  • Save your updated Living-City NPC Platform.drawio file using the save method from earlier.

You should now see one crime branch into immediate work, scheduled work, or a compact district-level update.

What does this flow prove?

Publishing once creates one source event. The router chooses the affected cell before tier-specific reactions begin.

High-tier NPCs receive immediate detail. Low-tier NPCs retain enough information to catch up when they become relevant.

Define consistency and test promotion

Clear consistency boundaries decide which state must agree immediately. An authoritative cell owner prevents two runtime instances from committing conflicting outcomes.

  • Create a panel labeled Consistency Boundaries beside the state path.
  • Add Active combat, mission state, and interaction reservations use one authoritative cell owner. to the panel.

The panel now identifies the state that requires immediate authority.

  • Add Distant ambient schedules may converge later. to the panel.
  • Add Promotion replays events newer than the stored snapshot before visibility. to the panel.

Your consistency policy now gives strict ownership to visible interactions. Distant ambient state gets time to catch up before promotion.

  • Add a lifecycle node labeled Active NPC runtime near the NPC State Store.
  • Extend the lifecycle to a node labeled Runtime instance unloaded.

The lifecycle now shows the transient runtime instance disappearing when the NPC leaves the active cell.

  • Draw a persistence branch labeled Versioned snapshot persists.
  • Draw a second persistence branch labeled Pending event persists.

Both pieces of durable history now survive after the runtime instance is removed.

  • Extend the unload path to a node labeled Promotion.
  • Extend the promotion path to Replay events newer than stored snapshot.

The return path now starts from the stored version before applying later events.

  • Extend the replay path to One current NPC version.
  • Extend the current-version path to Visible.

The NPC now becomes visible only after its current version has been reconstructed.

  • Connect Versioned snapshot persists to Replay events newer than stored snapshot.
  • Connect Pending event persists to the same replay node.

The replay node now receives both the stored base version and the pending work.

  • Add the annotation Event identifiers prevent duplicate replay. beside the replay path.
  • Save your updated Living-City NPC Platform.drawio file using the save method from earlier.

Before you trace the lifecycle, which parts do you expect to remain after the runtime instance is unloaded?

  • Trace one NPC from Active NPC runtime to Runtime instance unloaded.
  • Follow the durable branches to the stored snapshot and pending event.
  • Continue through promotion until the NPC reaches Visible.

You should see the runtime instance disappear while its snapshot and pending event remain. Promotion reconstructs one current version without applying the event twice.

That is the hardest state transition captured. Your city can unload an NPC without erasing its history.

Does promotion create duplicate state?

  • Check that both durable branches survive outside the unloaded runtime instance.
  • Check that replay happens before the NPC reaches Visible.
  • Check that the event-identifier annotation sits beside the replay path.

Use this if the reconstruction path still feels unclear: Help me debug the NPC unload and promotion lifecycle in my architecture diagram.

Use this final comparison to confirm that every event and persistence requirement appears in the diagram.

✔️ My event and state flow is complete

Your diagram is ready when you can trace the street crime through each tier and return one unloaded NPC to visibility.

ⓧ I'd like to double-check the diagram

  • Confirm that the World Event Router routes events to the affected per-cell Event Queue.
  • Confirm that runtime updates write versioned NPC snapshots and event identifiers to the NPC State Store.
  • Confirm that the street-crime flow publishes once before branching into High-tier, Medium-tier, and Low-tier reactions.
  • Confirm that the Consistency Boundaries panel defines one authoritative cell owner for active interactions.
  • Confirm that the unloaded runtime instance disappears while its versioned snapshot and pending event persist.
  • Confirm that promotion replays newer events before producing one visible NPC version without a duplicate event.

Your city can now preserve causality beyond the active simulation area. Next, you will pressure-test these paths against queue growth, promotion spikes, and state-store failure.

Define Overload and Recovery Controls

Your draw.io architecture now preserves NPC history after runtime instances unload. It also prevents concurrent interactions from producing contradictory state.

A design that fits during normal traffic can still fail during promotion spikes. Growing event queues can exhaust the scheduler.

An outage in the NPC State Store can also interrupt recovery. This step makes the platform's response to overload explicit.

In this step, get ready to:
  • Feed overload signals into a Budget Monitor.
  • Order the work that the platform sheds under pressure.
  • Defend the numbered street-crime walkthrough under overload and recovery.
Add budget monitoring and alerts

A Budget Monitor converts runtime signals into an early warning for overload. Its alerts apply backpressure where new work enters the simulation.

  • Add a rectangle labeled Budget Monitor beside the Budgeted Simulation Scheduler.
  • Add six input rows inside the monitor labeled tier counts, scheduler time, promotion rate, event-queue depth, oldest-event age, and state-store latency.
  • Inspect the monitor at your current zoom level.

You should see all six signals inside one readable monitoring component.

  • Draw an inbound connector from the monitored architecture to the Budget Monitor.
  • Label the processing path leaving the per-cell Event Queue as event processor.
  • Locate the inbound metrics connector beside the newly labeled processing path.

The monitor should now have a clear source for its measurements. The queue-processing path should also have an explicit alert destination.

  • Draw an alert connector from the Budget Monitor to the Budgeted Simulation Scheduler.
  • Draw a second alert connector from the Budget Monitor to the event processor.
  • Trace both outbound alert connectors from the monitor.

You should reach the scheduler on one path. You should reach the event processor on the other path.

Can't fit the monitor clearly?

Place the monitor beside the scheduler instead of inside the main simulation flow. Use short connector labels so the six measurements remain readable.

Ask for help reorganizing the monitor without hiding existing components.

Order graceful degradation

Graceful degradation is an ordered plan for spending less compute when demand exceeds capacity. The safest order removes invisible ambient work first.

Recovery comes last because snapshots preserve a stable starting point. Event identifiers reveal which deferred updates still need replay.

  • Add a tall panel labeled Graceful Degradation near the Budget Monitor.
  • Enter these first three rungs as separate lines: 1. Defer Low-tier ambient work, 2. Coalesce duplicate district events, 3. Reduce Medium-tier frequency.
  • Read the top half of the ladder from top to bottom.

You should see low-value background work shed before the platform changes player-visible behavior.

  • Enter these final three rungs as separate lines: 4. Cap noncritical promotions, 5. Preserve player-visible and mission-critical work, 6. Recover deferred state from snapshots and event identifiers.
  • Read the complete ladder from rung 1 through rung 6.

The final order should reduce background demand first. It should protect critical work before replaying deferred state.

Why does this order matter?

The first four rungs reduce demand before overload reaches player-visible work.

The fifth rung protects the interactions that sustain the living-city illusion.

The final rung restores deferred state from durable snapshots. Event identifiers prevent duplicate processing during replay.

Number and defend the street-crime walkthrough

A numbered walkthrough turns the architecture into a causal story. A reviewer can follow one crime from publication through unload and reconstruction.

Numbering map

  • Use 1 for crime-event creation.
  • Use 2 for routing to the affected cell.
  • Use 3 for the immediate High-tier witness reaction.
  • Use 4 for Medium-tier reaction scheduling.
  • Use 5 for the Low-tier district alert.
  • Use 6 for NPC demotion and runtime unloading.
  • Use 7 for the persisted snapshot and pending event.
  • Use 8 for re-promotion and current-state reconstruction.
  • Add numbered badges from 1 through 8 beside the existing street-crime stages using the numbering map.
  • Trace the numbered arrows from event creation to re-promotion.

You should reach the reconstructed NPC after passing through its persisted snapshot. The pending event should be applied once.

The walkthrough proves the runtime path. A Design Defense panel makes each trade-off visible during a review.

  • Add a panel titled Design Defense beside the numbered walkthrough.
  • Add the answer Why not full fidelity? 10,000 updates cost 500 ms per frame against an 8 ms budget. CPU simulation becomes the bottleneck..
  • Read the panel heading and its first answer.

The first answer should connect the failed baseline directly to its capacity limit and CPU bottleneck.

  • Add the answer What enforces 8 ms? Budgeted Simulation Scheduler..
  • Add the answer Where is backpressure applied? Event Queue and promotion scheduling..
  • Read the first three answers from top to bottom.

The panel should identify the scheduler as the budget enforcer. It should place pressure controls at both admission boundaries.

  • Add the answer Which state is authoritative? One active cell owns combat, mission state, and reservations..
  • Add the answer Queue or state-store outage: degrade queued work. Replay snapshots plus event identifiers after recovery..
  • Read all five Design Defense answers.

The final two answers should define ownership during normal operation. They should also explain replay after an outage.

  • Save the updated Living-City NPC Platform.drawio file by pressing Cmd+Shift+S.

Before you trace the completed design, which control do you expect to activate first during a promotion spike?

  • Follow the numbered street-crime path from 1 through 8.
  • Point to the red baseline capacity callout to explain why full fidelity fails.
  • Point to the Budget Monitor to identify the signals that expose overload.
  • Point to the Budgeted Simulation Scheduler to explain enforcement of the 8 ms budget.
  • Point to the Event Queue to show where event backpressure is applied.
  • Point to the Consistency Boundaries panel to identify authoritative state.
  • Point to the Graceful Degradation ladder to explain which work is sacrificed first.
  • Point to the Design Defense panel to explain outage recovery.

You should trace the crime from one published event to a reconstructed NPC without duplicate processing.

Your monitor should show all six overload signals. Your defense panel should answer every required review question.

That is a strong finish. Your architecture now shows how the city protects the player experience under overload.

Secret mission

Survive a Citywide Hurricane

A hurricane creates demand across every district at once. Extend your architecture so one durable event drains through 100 cell summaries in five frames while the player cell stays first and the 8 ms NPC-simulation budget remains fixed.

Clean Up Your Resources

Clean Up Your Resources

Choose whether to keep the architecture available, save it for later, or delete it from your Mac. The local file has no ongoing cost.

Resources you used:

  • One saved draw.io architecture file: Living-City NPC Platform.drawio, stored locally on your Mac.

Keep everything running

No action is needed. Choose this if you plan to keep refining the architecture or use it during a system-design discussion.

  • Leave the existing draw.io tab open while you continue refining the architecture.
  • Keep Living-City NPC Platform.drawio on your Mac so you can reopen the editable design later.
  • Use the saved diagram to revisit the baseline failure proof, tiered scheduler, street-crime walkthrough, or hurricane pressure test.
  • Keep the file for as long as you need because it has no ongoing cost.

Pause - I'll come back to this later

Save the latest version before closing the editing session. The local file preserves every component, connector, calculation, and defense note.

  • Return to the draw.io editor from earlier.
  • Save your latest changes by pressing Cmd+Shift+S.
  • Close the browser tab.
  • Reopen Living-City NPC Platform.drawio from Finder when you are ready to continue.

Your complete architecture returns with the baseline, simulation tiers, persistent state, degradation plan, and hurricane extension ready to edit.

Delete - I don't want to use this again

Remove the local project file if you want to start fresh. Deleting it becomes permanent when you empty your Mac's Bin.

That final action is meant to be irreversible. Your browser and the draw.io editor remain untouched.

  • Close the draw.io browser tab.
  • Search for Living-City NPC Platform.drawio in Finder.
  • Move Living-City NPC Platform.drawio to your Mac's Bin.
  • Empty your Mac's Bin.
  • Search for Living-City NPC Platform.drawio in Finder again.

That completes the cleanup. Finder should return no matching file.

There are no cloud or paid resources to remove.

Nice Work!

Nice Work!

You did it! Your saved Living-City NPC Platform.drawio file now presents a defensible living-city architecture in draw.io. You can trace how the platform bounds simulation work while preserving a persistent world for the player.

What you learned:

  • Used capacity estimation to prove that 10,000 full-fidelity NPC updates would consume 500 ms per frame. You compared that load with the 8 ms frame budget to expose the CPU bottleneck.
  • Designed a scalable replacement using spatial partitioning, player relevance, and simulation level of detail. Your budgeted scheduler keeps the average NPC workload at 7.2 ms.
  • Preserved city history through event-driven architecture, persistence, and explicit consistency boundaries. You defended the street-crime flow with monitoring, backpressure, graceful degradation, and replay-based recovery.
  • Secret Mission: Pressure-tested the platform against a citywide hurricane using 100 cell-level updates. You prioritized player-visible work while draining the full fan-out in 5 frames without increasing the 8 ms NPC-simulation budget.

Ready to quiz yourself?