Chunk System
The chunk system procedurally generates the forest trail that players navigate. Chunks stream ahead of the player and despawn behind them.
Pipeline Overview
Server Startup
→ Load start chunk (ChunkPrefab_Start)
→ Prewarm 3 chunks ahead
→ Sync game seed to clients
Heartbeat (0.25s)
→ Update safe zone players
→ Ensure chunks ahead for all players
→ Check run completion
→ Process pending chunk queue (one per tick)
→ Process pending unload queue (one per tick)
Key Files
| File | Purpose |
|---|---|
chunk-service.ts | Main orchestrator — heartbeat, safe zones, run completion |
chunk-lifecycle-manager.ts | Per-chunk spawn / unload queue, ground-grid upkeep |
run-director.ts | Source of truth for the run plan — owns PacingManager + FeedbackState, handles devtools replans |
chunk-generator.ts | Template cloning, positioning, overlap detection |
chunk-prepper.ts | Creates Start/End parts from baseplate attachments |
utils/pacing-manager.ts | Difficulty cycle, safe zone markers, enemy scaling (pure calculator) |
utils/chunk-planner.ts | DFS with chronological backtracking — pre-validates the entire run's chunk layout |
utils/planner/plan-chase-section.ts | River / minecart atomic sections + river realignment |
utils/planner/plan-fork-section.ts | Split-and-merge branch sections with interleaved DFS |
danger-zone-manager.ts | Ring zones around baseplates for enemy spawning |
baseplate-manager.ts | Octree-based spatial indexing of chunk positions |
director/feedback-state.ts | Phase 8 accumulator — rolling signal vector from gameplay events |
director/feedback-policies.ts | Pressure adjusters consuming FeedbackSignal (flag-gated) |
RunDirector
RunDirector (formerly RunPlanManager) is the single handle ChunkService uses for all run-level state. It owns:
- The pre-validated placement plan (
PlacementInstruction[]) produced byChunkPlanner.planRun. - A composed
PacingManager— pacing queries likegetPacingForChunk(idx),getMaxTrailMarker()are exposed as director delegates. - The
FeedbackStateaccumulator (Phase 8) — tracks deaths, clears, and streaks to feed the pressure policies. - Preset / fork-section / chase-section configuration from devtools.
- Seed-retry logic for
ensurePlanBuiltand the devtoolsplanWithSeed/replanFutureChunkspaths.
Callers consume it through ChunkService — never instantiate a separate PacingManager outside the director unless you're in a pure-function context (tests, planner sub-modules).
Chunk Planner
ChunkPlanner.planRun is the main DFS loop. Chase and fork sections were extracted into utils/planner/:
plan-chase-section.ts— atomic multi-chunk sections (River, minecart). Handles river-specific steering: straight-first on entry, cardinal realignment over the last few chunks.plan-fork-section.ts— split-and-merge branches. Interleaves A / B placements (A₀, B₀, A₁, B₁, …) with its own backtracking stack, then runscomputeMergeChunksto reconverge.planner/build-candidates.ts,overlap-checks.ts,simulate-placement.ts,screening.ts,bush-validation.ts— shared helpers.
Chunk Creation Flow
- Plan lookup —
runDirector.getRunPlan()returns the pre-validatedPlacementInstructionfor the next chunk index. - Template Selection —
getChunkForPacing()resolves the instruction againstReplicatedStorage.Prefabs.Cyclable. - Preparation —
prepareChunk()creates Start/End parts from baseplate attachments. - Positioning — End-to-end alignment using Start/End attachment CFrames (planner already validated this works).
- Registration — Tagged
Gameplay_Chunk, baseplate registered in octree. - Danger Zones — Deferred ring creation around the baseplate.
Pacing System
The game cycles through phases, with safe zones at fixed trail markers:
Calm (2 chunks) → Tense (2 chunks) → Challenge (2 chunks) → repeat
Safe Zones at markers: 10, 30, 70
Trail Markers
- ~1 marker per 2 chunks:
trailMarker = floor(chunkIndex / 2) + 1 - Physical wooden posts placed by
GameplayChunkcomponent - Max trail marker: 30 (MVP) — chunks stop generating after this
Difficulty Scaling
- Multiplier:
1.0 + (trailMarker × 0.05), capped at 3.0 - Affects enemy density and aggression per phase
Chunk Unloading
When enabled, chunks 3+ behind the furthest-back player are queued for unloading:
- Path nodes re-parented to
UnloadedPathNodesfolder (keeps refs valid) - Danger zones removed
- Chunk model destroyed
- Echo boundary updated for late joiners
Safe Zones
Safe zone detection uses a dual approach:
- Registered parts — Tagged
SafeZoneparts checked viaPointToObjectSpace - Pacing-based — Chunks with
isSafeZonepacing flag
Safe zone effects (0.25s tick):
- Health regen: 10 HP/sec (2.5 per tick)
- Insanity decay (client-side)
- Enemy exclusion
Server Verification
Client detects safe zone entry via ZonePlus, fires remote. Server verifies with retry logic (3 attempts, 0.15s apart) to account for network latency.
Run Completion
When a player reaches the final safe zone (marker 30):
checkRunCompletion()detects player on SafeZone chunk at max markerrunCompleteCallbackfires- Player teleported to lobby