# IStalk — Complete Unity Editor Setup Guide

> **Current State:** 69 C# scripts written, FishNet v4 + Synapse installed, DOTween installed, URP configured. **Nothing exists in the Unity Editor yet** — no prefabs, no scenes, no ScriptableObject assets, no materials, no physics layers. This guide takes you from zero to playable greybox.

---

## What You Have vs What You Need

```
HAVE (code-only)                    NEED (Unity Editor work)
─────────────────                   ────────────────────────
69 .cs scripts                      2 Scenes (Lobby + Game)
Assembly definitions                Physics layers configured
Folder structure                    Prefabs (15+)
FishNet v4 + Synapse transport      ScriptableObject assets (15+)
URP pipeline settings               Materials (greybox)
DOTween                             NetworkManager setup
                                    Canvas prefabs (3 HUDs)
                                    Input System bindings
                                    Room prefabs (5)
                                    Build Settings configured
```

---

## Master Flowchart

```mermaid
graph TD
    A[Phase 1: Project Settings] --> B[Phase 2: Scenes]
    B --> C[Phase 3: ScriptableObject Assets]
    C --> D[Phase 4: Materials & Greybox Meshes]
    D --> E[Phase 5: Room Prefabs]
    E --> F[Phase 6: Player Prefabs]
    F --> G[Phase 7: Prop & Item Prefabs]
    G --> H[Phase 8: UI Canvases]
    H --> I[Phase 9: NetworkManager & Boot]
    I --> J[Phase 10: Scene Assembly]
    J --> K[Phase 11: Build & Test Locally]
    K --> L[Phase 12: Relay Server Test]

    style A fill:#ff6b6b,color:#fff
    style B fill:#ff6b6b,color:#fff
    style C fill:#ffa06b,color:#fff
    style D fill:#ffa06b,color:#fff
    style E fill:#ffd06b,color:#000
    style F fill:#ffd06b,color:#000
    style G fill:#6bff8f,color:#000
    style H fill:#6bff8f,color:#000
    style I fill:#6bb5ff,color:#fff
    style J fill:#6bb5ff,color:#fff
    style K fill:#c46bff,color:#fff
    style L fill:#c46bff,color:#fff
```

---

## Phase 1: Project Settings (15 min)

These are one-time settings that MUST be configured before anything else compiles or runs.

### 1.1 Physics Layers

`Edit → Project Settings → Tags and Layers → Layers`

| Layer # | Name | Purpose |
|---------|------|---------|
| 6 | `Wall` | Room geometry walls, ceilings, floors |
| 7 | `Prop` | Moveable/static props (crates, barrels) |
| 8 | `Runner` | Runner player colliders |
| 9 | `Eye` | Eye-related colliders (if needed) |
| 10 | `SmokeVolume` | Smoke bomb effect volumes |
| 11 | `Interactable` | WorldItems, Altars, Shrines |
| 12 | `Trap` | Trap trigger volumes |

### 1.2 Physics Collision Matrix

`Edit → Project Settings → Physics → Layer Collision Matrix`

Disable unnecessary collisions:
- Runner ↔ Runner: **OFF** (runners dont collide with each other)
- Eye ↔ everything: **OFF** (Eye has no physical presence)
- Trap ↔ Wall: **OFF**
- Trap ↔ Prop: **OFF**
- SmokeVolume ↔ everything except Runner: **OFF**

### 1.3 Tags

`Edit → Project Settings → Tags and Layers → Tags`

Add these tags:
- `Runner`
- `Eye`
- `WorldItem`
- `Altar`
- `Shrine`
- `Connector`
- `SpawnSlot`

### 1.4 Input System

`Edit → Project Settings → Player → Active Input Handling` → set to **"Both"** (Input System Package + legacy Input class)

> We use `Input.GetKey` in scripts for simplicity in prototype. If Input System package isn't imported yet, go to Package Manager and install "Input System".

### 1.5 TextMeshPro

If you haven't already: `Window → TextMeshPro → Import TMP Essential Resources`

### 1.6 Quality Settings

`Edit → Project Settings → Quality`
- Set default to "Medium"
- Ensure URP asset `PC_RPAsset` is assigned in each quality tier

---

## Phase 2: Create Scenes (10 min)

### 2.1 Create LobbyScene

1. `File → New Scene → Basic (URP)`
2. Save as `Assets/Scenes/LobbyScene.unity`
3. Delete default objects (leave only Main Camera + Directional Light)
4. This will be assembled later in Phase 10

### 2.2 Create GameScene

1. `File → New Scene → Basic (URP)`
2. Save as `Assets/Scenes/GameScene.unity`
3. Delete default objects (leave only Directional Light — camera comes from player prefab)

### 2.3 Build Settings

`File → Build Settings`
1. Add `Assets/Scenes/LobbyScene.unity` (index 0)
2. Add `Assets/Scenes/GameScene.unity` (index 1)
3. Remove `SampleScene` if present
4. Platform: PC, Mac & Linux Standalone

### 2.4 Delete SampleScene

Delete `Assets/Scenes/SampleScene.unity` — we don't need it.

---

## Phase 3: Create ScriptableObject Assets (20 min)

All data assets live in `Assets/Resources/Items/` subfolders so `Resources.LoadAll<T>()` finds them at runtime.

### 3.1 GlobalRules_SO

1. Right-click `Assets/Resources/` → `Create → ScriptableObject` → find `GlobalRules_SO`
   - If it doesn't appear, the `[CreateAssetMenu]` attribute should be on the class. Check that `GlobalRules_SO.cs` has:
     ```
     [CreateAssetMenu(menuName = "IStalk/GlobalRules", fileName = "GlobalRules")]
     ```
2. Save as `Assets/Resources/GlobalRules.asset`
3. Fill in default values (the script has defaults, but verify in Inspector):

| Field | Value | Notes |
|-------|-------|-------|
| baseRunSpeed | 6 | |
| sprintMultiplier | 1.6 | |
| matchTimeLimit | 300 | 5 minutes |
| gracePeriodDuration | 30 | |
| losTicksPerSecond | 30 | |
| losMaxDistance | 100 | |
| maxShrinesPerMap | 3 | |
| extractionThreshold | 20 | loot value needed to win |

### 3.2 Loot Item SOs (5 items)

Create in `Assets/Resources/Items/Loot/`:

| Asset Name | itemId | weight | lootValue | spawnWeight |
|-----------|--------|--------|-----------|-------------|
| `Loot_Coin.asset` | coin | 1 | 1 | 40 |
| `Loot_Gem.asset` | gem | 2 | 3 | 25 |
| `Loot_Idol.asset` | idol | 3 | 5 | 15 |
| `Loot_Crown.asset` | crown | 5 | 8 | 10 |
| `Loot_Relic.asset` | relic | 7 | 12 | 5 |

For each: Right-click → `Create → IStalk/ItemData` → fill fields. Leave `icon` and `worldMesh` null for now (greybox).

### 3.3 Shrine Item SOs (3 items)

Create in `Assets/Resources/Items/Shrine/`:

| Asset Name | itemId | itemType | lootCost | effectDuration | cooldown | isConsumedOnUse |
|-----------|--------|----------|----------|----------------|----------|-----------------|
| `Shrine_Mirror.asset` | mirror | Mirror | 5 | 8 | 20 | false |
| `Shrine_Decoy.asset` | decoy | Decoy | 3 | 10 | 15 | false |
| `Shrine_GrapplingHook.asset` | grapple | GrapplingHook | 8 | 0 | 0 | true |

### 3.4 Trap Data SOs (3 traps)

Create in `Assets/Resources/Items/Traps/`:

| Asset Name | trapId | trapType | dreadCost | effectRadius | duration |
|-----------|--------|----------|-----------|--------------|----------|
| `Trap_SlowField.asset` | slowfield | SlowField | 20 | 5 | 15 |
| `Trap_NoiseTrip.asset` | noisetrip | NoiseTrip | 10 | 2 | 999 |
| `Trap_PathBlocker.asset` | pathblocker | PathBlocker | 30 | 3 | 20 |

### 3.5 Room Node SOs (5 rooms)

Create in `Assets/Resources/Items/Rooms/`:

| Asset Name | roomId | dimensions | connectors |
|-----------|--------|------------|------------|
| `Room_Small_A.asset` | small_a | 10x10 | 2 connectors |
| `Room_Small_B.asset` | small_b | 10x10 | 3 connectors |
| `Room_Medium_A.asset` | medium_a | 15x15 | 3 connectors |
| `Room_Medium_B.asset` | medium_b | 15x12 | 4 connectors |
| `Room_Large_A.asset` | large_a | 20x20 | 4 connectors |

> Leave `roomPrefab` reference null for now — you'll assign it after creating room prefabs in Phase 5.

---

## Phase 4: Greybox Materials & Meshes (15 min)

Create `Assets/Materials/` folder.

### 4.1 Materials

Create these URP Lit materials:

| Material | Color (hex) | Purpose |
|----------|-------------|---------|
| `Mat_Floor.mat` | #4A4A4A | Room floors |
| `Mat_Wall.mat` | #6B6B6B | Room walls |
| `Mat_Ceiling.mat` | #3D3D3D | Room ceilings |
| `Mat_Runner.mat` | #2196F3 | Runner capsule |
| `Mat_WorldItem.mat` | #FFD700 | Gold items on ground |
| `Mat_Altar.mat` | #9C27B0 | Purple altar |
| `Mat_Shrine.mat` | #00BCD4 | Cyan shrine |
| `Mat_Trap_Slow.mat` | #FF5722 | Red trap zone (semi-transparent, alpha 0.3) |
| `Mat_Trap_Blocker.mat` | #FF9800 | Orange barrier |
| `Mat_Connector.mat` | #2E2E2E | Door frame/corridor |
| `Mat_Prop.mat` | #795548 | Brown props |

For semi-transparent materials: Set Surface Type → Transparent, set alpha in base color.

### 4.2 Quick Mesh Note

We'll use Unity primitives (Cube, Cylinder, Sphere, Capsule) for all greyboxing. No external meshes needed.

---

## Phase 5: Room Prefabs (30 min)

This is the biggest Editor task. Each room is a prefab with greybox geometry.

### Room Prefab Structure

```
Room_Small_A (Empty GameObject)
├── Floor (Cube, scaled to 10x0.1x10, layer: Wall)
├── Walls (Empty)
│   ├── Wall_North (Cube, 10x3x0.3, layer: Wall)
│   ├── Wall_South (Cube, 10x3x0.3, layer: Wall)
│   ├── Wall_East (Cube, 0.3x3x10, layer: Wall)
│   └── Wall_West (Cube, 0.3x3x10, layer: Wall)
├── Ceiling (Cube, scaled to 10x0.1x10, y=3, layer: Wall)
├── Connectors (Empty)
│   ├── Connector_North (Empty + ConnectorMarker.cs)
│   └── Connector_East (Empty + ConnectorMarker.cs)
├── SpawnSlots (Empty)
│   ├── LootSlot_1 (Empty + SpawnSlot.cs, type=Loot)
│   ├── LootSlot_2 (Empty + SpawnSlot.cs, type=Loot)
│   ├── RunnerSpawn_1 (Empty + SpawnSlot.cs, type=Runner)
│   └── PropSlot_1 (Empty + SpawnSlot.cs, type=Prop)
├── RoomBounds (Empty + RoomBounds.cs + BoxCollider trigger)
└── Light (Point Light, warm white, range 12)
```

### Step-by-step for ONE room (repeat for all 5):

1. **Create empty GameObject**, name it `Room_Small_A`
2. **Floor**: Create → 3D Object → Cube. Parent it under `Room_Small_A`. Scale (10, 0.1, 10). Position (0, 0, 0). Apply `Mat_Floor`. Set layer to `Wall`.
3. **Walls**: Create child empty "Walls". Under it, create 4 cubes:
   - North: Scale (10, 3, 0.3), Position (0, 1.5, 5)
   - South: Scale (10, 3, 0.3), Position (0, 1.5, -5)
   - East: Scale (0.3, 3, 10), Position (5, 1.5, 0)
   - West: Scale (0.3, 3, 10), Position (-5, 1.5, 0)
   - All use `Mat_Wall`, layer `Wall`
4. **Cut holes for connectors**: For each connector direction, either delete that wall section or scale it to leave a 3-unit gap in the center. The gap = the connector opening.
5. **Ceiling**: Cube, Scale (10, 0.1, 10), Position (0, 3, 0), `Mat_Ceiling`, layer `Wall`
6. **Connectors**: Empty children at the gap positions. Add `ConnectorMarker.cs` component. Position at the center of each wall opening, facing outward.
7. **SpawnSlots**: Empty children at floor positions. Add `SpawnSlot.cs` component. Set `slotType` in inspector (Loot, Runner, Prop, Altar, Shrine).
8. **RoomBounds**: Empty child, add `RoomBounds.cs`. Add BoxCollider (trigger), size matches room interior (9.5, 3, 9.5).
9. **Light**: Add a Point Light child. Color warm white, Range 12, Intensity 2.
10. **Save as Prefab**: Drag into `Assets/Prefabs/Rooms/`
11. **Assign to SO**: Open `Room_Small_A.asset`, drag the prefab into `roomPrefab` field.

### Room Variations Cheat Sheet

| Room | Size | Connectors | Special Slots |
|------|------|------------|---------------|
| Small_A | 10x10 | N, E | 2 Loot, 1 Runner |
| Small_B | 10x10 | N, E, S | 2 Loot, 1 Prop |
| Medium_A | 15x15 | N, E, W | 3 Loot, 1 Altar, 1 Runner |
| Medium_B | 15x12 | N, E, S, W | 3 Loot, 1 Shrine, 2 Prop |
| Large_A | 20x20 | N, E, S, W | 4 Loot, 1 Altar, 1 Shrine, 1 Runner, 2 Prop |

> **Tip**: Build `Small_A` completely, then duplicate and modify for other rooms. It's faster.

---

## Phase 6: Player Prefabs (25 min)

### 6.1 Runner Prefab

```
Runner (Empty)
├── Components on Root:
│   ├── NetworkObject
│   ├── NetworkTransform (for non-predicted visual sync to observers)
│   ├── RunnerController.cs
│   ├── RunnerLook.cs
│   ├── RunnerStamina.cs
│   ├── RunnerHealth.cs
│   ├── PlayerInventory.cs
│   ├── WeightComponent.cs
│   ├── RunnerInteraction.cs
│   ├── NoiseEmitter.cs
│   ├── ShrineItemEffect.cs
│   ├── RunnerAnimator.cs
│   ├── RunnerFootsteps.cs
│   ├── RunnerVisibility.cs
│   ├── CharacterController (Height 1.8, Radius 0.3, Center 0,0.9,0)
│   ├── CapsuleCollider (isTrigger=false, same dims, layer: Runner)
│   └── AudioSource (spatial blend 1.0)
├── Body (Capsule mesh, scale 0.6x0.9x0.6, Mat_Runner)
│   └── [This is the 3rd-person visual other players see]
├── FPSArms (Empty, position 0,1.5,0.3)
│   └── [Future: FPS arm mesh. For now, empty placeholder]
├── CameraHolder (Empty, position 0,1.6,0)
│   └── PlayerCamera (Camera component)
│       ├── Tag: MainCamera
│       ├── Clear Flags: Solid Color (dark grey)
│       └── Audio Listener
└── GroundCheck (Empty, position 0,0.05,0, used for grounded raycast)
```

**Steps:**
1. Create Empty → name "Runner"
2. Add `NetworkObject` component (from FishNet)
3. Add `CharacterController`: Height 1.8, Radius 0.3, Center (0, 0.9, 0)
4. Add all Runner scripts listed above
5. Create child Capsule → name "Body" → scale 0.6, 0.9, 0.6 → position (0, 0.9, 0) → apply `Mat_Runner` → remove its default CapsuleCollider (we use the CharacterController)
6. Create child Empty "CameraHolder" → position (0, 1.6, 0) → child Camera "PlayerCamera" → Tag MainCamera
7. Set root GameObject layer to `Runner`
8. Drag into `Assets/Prefabs/Player/Runner.prefab`

### 6.2 Eye Prefab

```
Eye (Empty)
├── Components on Root:
│   ├── NetworkObject
│   ├── EyeCameraController.cs
│   ├── EyeLaserController.cs
│   ├── EyeScanAbility.cs
│   ├── EyeTrapPlacer.cs
│   ├── DreadEconomy.cs
│   ├── EyeIncarnationController.cs
│   └── AudioSource
├── EyeCamera (Camera component)
│   ├── Projection: Orthographic
│   ├── Size: 20 (default zoom)
│   ├── Rotation: (90, 0, 0) — looking straight down
│   ├── Position: (0, 50, 0) — elevated
│   ├── Audio Listener
│   └── Tag: MainCamera
└── LaserOrigin (Empty, for raycast origin reference)
```

**Steps:**
1. Create Empty → name "Eye"
2. Add `NetworkObject`
3. Add Eye scripts listed above
4. Create child Camera "EyeCamera" → Orthographic, Size 20, Rotation (90,0,0), Position (0,50,0)
5. Drag into `Assets/Prefabs/Player/Eye.prefab`

---

## Phase 7: Prop & Item Prefabs (20 min)

### 7.1 WorldItem Prefab

```
WorldItem (Empty)
├── NetworkObject
├── WorldItem.cs
├── SphereCollider (trigger, radius 0.5, layer: Interactable)
├── Visual (Sphere mesh, scale 0.4, Mat_WorldItem)
└── PointLight (range 2, intensity 0.5, color gold — subtle glow)
```

Save as `Assets/Prefabs/Props/WorldItem.prefab`

### 7.2 Extraction Altar Prefab

```
Altar (Empty)
├── NetworkObject
├── Altar.cs (ExtractionAltar script)
├── BoxCollider (trigger, size 2x2x2, layer: Interactable)
├── Visual (Cylinder mesh, scale 1.5x0.5x1.5, Mat_Altar)
├── Pedestal (Cylinder, scale 0.8x1x0.8, stacked on top)
└── PointLight (range 4, purple, intensity 1)
```

Save as `Assets/Prefabs/Props/Altar.prefab`

### 7.3 Shrine Prefab

```
Shrine (Empty)
├── NetworkObject
├── Shrine.cs (ShrineInteractable)
├── BoxCollider (trigger, size 2x2x2, layer: Interactable)
├── Visual (Cube mesh, scale 1x1.5x1, Mat_Shrine)
├── DisplayOrb (Sphere, scale 0.3, positioned on top — represents item)
└── PointLight (range 3, cyan, intensity 1)
```

Save as `Assets/Prefabs/Props/Shrine.prefab`

### 7.4 Trap Prefabs (3)

**SlowField:**
```
SlowField (Empty)
├── NetworkObject
├── TrapInstance.cs (or SlowFieldTrap.cs)
├── SphereCollider (trigger, radius from TrapData_SO, layer: Trap)
└── Visual (Sphere, Mat_Trap_Slow, semi-transparent, scale matches radius)
```

**NoiseTrip:**
```
NoiseTrip (Empty)
├── NetworkObject
├── TrapInstance.cs
├── BoxCollider (trigger, thin: 3x2x0.1, layer: Trap)
└── [No visual mesh — invisible to runners. Eye sees via HUD overlay]
```

**PathBlocker:**
```
PathBlocker (Empty)
├── NetworkObject
├── TrapInstance.cs
├── BoxCollider (NOT trigger — physical blocker, size 3x3x0.5, layer: Wall)
└── Visual (Cube, scale 3x3x0.5, Mat_Trap_Blocker)
```

Save all three in `Assets/Prefabs/Props/`

### 7.5 DynamicProp Prefab

```
DynamicProp (Empty)
├── NetworkObject
├── NetworkTransform
├── DynamicProp.cs
├── IncarnationProp.cs
├── Rigidbody (kinematic by default, non-kinematic when possessed)
├── BoxCollider (size varies, layer: Prop)
└── Visual (Cube, scale 1x1x1, Mat_Prop)
```

Save as `Assets/Prefabs/Props/DynamicProp.prefab`

---

## Phase 8: UI Canvas Prefabs (25 min)

### 8.1 Runner HUD

Create: `Assets/Prefabs/UI/RunnerHUD.prefab`

```
RunnerHUD (Canvas, Screen Space - Overlay)
├── CanvasScaler (Scale With Screen Size, 1920x1080 reference)
├── Top Panel
│   ├── TimerText (TMP, center-top, "05:00")
│   └── ExtractionBar (Image fill, left-right, shows progress)
├── Bottom-Left Panel
│   ├── StaminaBar (Image fill, green-to-red gradient)
│   ├── HealthBar (Image fill, red)
│   └── WeightIndicator (TMP, "LIGHT / MEDIUM / HEAVY")
├── Bottom-Right Panel
│   ├── InventorySlots (6x Image placeholders, horizontal)
│   └── ShrineItemSlot (Image + cooldown ring overlay + "Q" text)
├── Center
│   └── Crosshair (Image, small dot)
└── InteractionPrompt (TMP, "Press F to pick up", hidden by default)
```

Add `RunnerHUD.cs` component to the root Canvas. Wire TMP/Image references in Inspector.

### 8.2 Eye HUD

Create: `Assets/Prefabs/UI/EyeHUD.prefab`

```
EyeHUD (Canvas, Screen Space - Overlay)
├── CanvasScaler (Scale With Screen Size, 1920x1080)
├── Top Panel
│   ├── TimerText (TMP, "05:00")
│   ├── VisibilityCount (TMP, "Runners: 2/4 visible")
│   └── SealedRoomCount (TMP, "Sealed: 0", hidden until overtime)
├── Left Panel
│   └── DreadBar (Image fill, vertical, purple gradient)
├── Bottom Panel
│   ├── AbilitySlot_Laser (Image + cooldown ring + cost text + "LMB")
│   ├── AbilitySlot_Scan (Image + cooldown ring + cost text + "SPACE")
│   └── TrapSelector (3 icons with cost + hotkeys "1" "2" "3")
├── Minimap Panel (RawImage, top-right corner, for RenderTexture)
└── GraceIndicator (TMP, "GRACE PERIOD - 0:30", yellow, hidden after grace)
```

Add `EyeHUD.cs` component. Wire references.

### 8.3 Lobby UI

Create: `Assets/Prefabs/UI/LobbyCanvas.prefab`

```
LobbyCanvas (Canvas, Screen Space - Overlay)
├── CanvasScaler (Scale With Screen Size, 1920x1080)
├── Title (TMP, "ISTALK", large, center-top)
├── MainPanel (center)
│   ├── CreateRoomBtn (Button + TMP "Create Room")
│   ├── RoomCodeInput (TMP InputField, placeholder "Enter Code")
│   ├── JoinRoomBtn (Button + TMP "Join Room")
│   ├── RoomCodeDisplay (TMP, hidden until room created, shows "CODE: ABCD")
│   ├── PlayerList (Vertical Layout Group + TMP entries)
│   └── StartGameBtn (Button + TMP "Start Game", hidden until host + 2 players)
├── StatusText (TMP, bottom, "Connecting..." / "Connected" / errors)
└── NetworkStatusUI.cs (shows ping/connection state)
```

Add `LobbyUI.cs` component. Wire button references.

### 8.4 Results Screen

Create: `Assets/Prefabs/UI/ResultsScreen.prefab`

```
ResultsScreen (Canvas, Screen Space - Overlay)
├── Panel (Image, dark overlay, covers screen, starts INACTIVE)
│   ├── TitleText (TMP, "VICTORY" / "ESCAPED!")
│   ├── SubtitleText (TMP, flavor text)
│   ├── StatsText (TMP, match stats)
│   ├── ReturnToLobbyBtn (Button)
│   └── QuitBtn (Button)
└── ResultsScreen.cs
```

---

## Phase 9: NetworkManager & GameBoot (15 min)

### 9.1 Create NetworkManager Prefab

1. Create Empty in scene → name "NetworkManager"
2. Add component: `NetworkManager` (FishNet)
3. Add component: `RelayTransport.cs` (your custom transport)
4. In NetworkManager Inspector:
   - Transport → drag RelayTransport component
   - Logging → set to Development for now
5. **DO NOT add Synapse/Tugboat** — we use our custom RelayTransport
6. Save as prefab: `Assets/Prefabs/NetworkManager.prefab`

### 9.2 Create GameBoot Prefab

```
GameBoot (Empty, DontDestroyOnLoad)
├── GameBoot.cs
├── AudioManager.cs
├── ItemDatabase.cs (singleton, loads all SOs in Awake)
└── [Reference to GlobalRules_SO asset in inspector]
```

1. Create Empty → name "GameBoot"
2. Add `GameBoot.cs`, `AudioManager.cs`, `ItemDatabase.cs`
3. In `GameBoot.cs` inspector: assign `GlobalRules.asset` reference
4. Save as prefab (it'll be placed in LobbyScene)

### 9.3 Prefab Registration

**CRITICAL FishNet Step:**

1. Select `Assets/DefaultPrefabObjects.asset` (FishNet auto-creates this)
2. OR go to `NetworkManager` → Prefab Objects → Default Prefab Objects
3. Open the Prefab Objects inspector
4. Add ALL networked prefabs to the list:
   - Runner.prefab
   - Eye.prefab
   - WorldItem.prefab
   - Altar.prefab
   - Shrine.prefab
   - SlowField.prefab
   - NoiseTrip.prefab
   - PathBlocker.prefab
   - DynamicProp.prefab

> **If you skip this, FishNet cannot spawn any networked objects and you'll get errors.**

---

## Phase 10: Scene Assembly (20 min)

### 10.1 LobbyScene Setup

Open `Assets/Scenes/LobbyScene.unity`:

1. Place `GameBoot` prefab in scene (it persists via DontDestroyOnLoad)
2. Place `NetworkManager` prefab in scene
3. Place `LobbyCanvas` prefab in scene
4. Add `LobbyManager.cs` to an empty GameObject "LobbyManager"
5. Wire references in LobbyManager inspector:
   - NetworkManager reference
   - LobbyUI reference
6. Set Camera background to dark color
7. Add some ambient lighting

### 10.2 GameScene Setup

Open `Assets/Scenes/GameScene.unity`:

1. Place `GameManager` empty GameObject:
   - Add `GameManager.cs`
   - Add `ExtractionManager.cs`
   - Add `LootSpawner.cs`
   - Add `PlayerSpawner.cs`
   - Set `PlayerSpawner` references: Runner prefab, Eye prefab
2. Place `MapGenerator` empty GameObject:
   - Add `MapGenerator.cs`
   - Set room prefab array (drag all 5 room prefabs)
   - Set shrine prefab reference
3. Place `LoSManager` empty GameObject:
   - Add `NetworkObject`
   - Add `LoSManager.cs`
   - Set `_wallLayer` to Layer 6 (Wall)
   - Set `_runnerLayer` to Layer 8 (Runner)
4. Place `RunnerHUD` prefab (starts disabled, enabled by Runner on spawn)
5. Place `EyeHUD` prefab (starts disabled, enabled by Eye on spawn)
6. Place `ResultsScreen` prefab
7. Add Directional Light (slightly angled for shadow)

### 10.3 Wire Inspector References

This is the tedious but critical step. For each script with `[SerializeField]` fields, you must drag the correct references:

**GameManager:**
- `_mapGenerator` → MapGenerator object
- `_lootSpawner` → LootSpawner (on same object or child)
- `_extractionManager` → ExtractionManager (same object)

**PlayerSpawner:**
- `_runnerPrefab` → Runner.prefab
- `_eyePrefab` → Eye.prefab

**LootSpawner:**
- `_worldItemPrefab` → WorldItem.prefab

**EyeTrapPlacer (on Eye prefab):**
- Trap prefab references (slow, noise, blocker)

---

## Phase 11: Build & Local Test (15 min)

### 11.1 Verify Compilation

1. Open Unity Console (`Window → General → Console`)
2. Clear all
3. If any errors: fix them before proceeding
4. Common issues:
   - Missing `using` statements
   - Missing assembly references in `.asmdef`
   - `[SerializeField]` fields showing as null (that's fine, just means you need to wire them)

### 11.2 Test Solo (Editor)

1. Open LobbyScene
2. Press Play
3. Expected: GameBoot initializes, ItemDatabase loads SOs, LobbyUI appears
4. Click "Create Room" — should attempt relay connection
5. If relay server is down: test will fail at connection, but UI should work

### 11.3 Test 2-Player (ParrelSync or 2 editors)

Option A — **ParrelSync** (recommended):
1. Install ParrelSync from Package Manager (git URL: `https://github.com/VeriorPies/ParrelSync.git`)
2. Open clone project
3. Run original as Host (Create Room)
4. Run clone as Client (Join Room)

Option B — **Build + Editor**:
1. `File → Build and Run` (makes a standalone build)
2. Keep Editor in Play mode
3. One creates room, other joins with code

### 11.4 What to Look For

| Checkpoint | Expected Result |
|-----------|-----------------|
| Both players in lobby | Player count shows 2 |
| Start Game clicked | Both load GameScene |
| Map generates | Rooms appear (greybox cubes) |
| Runner spawns | FPS view, can look around and move |
| Eye spawns | Top-down view, can pan |
| WorldItems visible | Gold spheres on floor |
| Pickup works | Walk over item, press F, item disappears, inventory updates |
| Laser fires | Eye clicks, telegraph line appears, then beam |
| Timer counts down | Both see timer ticking |

---

## Phase 12: Relay Server Test (10 min)

### 12.1 Verify Relay is Running

```bash
curl -s https://istalk-relay.caprover.al-arcade.com/health
```

Should return a response (or check CapRover dashboard).

### 12.2 Set Relay URL in RelayTransport

In the `RelayTransport.cs` inspector (on NetworkManager prefab):
- Set `_relayUrl` to `wss://istalk-relay.caprover.al-arcade.com`

### 12.3 Test Over Internet

1. Build the game
2. Send build to a friend (or use a second machine)
3. One creates room, shares code
4. Other joins with code
5. Play a full match

---

## Dependency Graph (What Blocks What)

```mermaid
graph LR
    PL[Physics Layers] --> RP[Room Prefabs]
    PL --> PP[Player Prefabs]
    
    SO[ScriptableObject Assets] --> RP
    SO --> ItemPrefabs[Item/Trap Prefabs]
    
    MAT[Materials] --> RP
    MAT --> PP
    MAT --> ItemPrefabs
    
    RP --> GS[GameScene Assembly]
    PP --> GS
    ItemPrefabs --> GS
    UI[UI Canvases] --> GS
    
    NM[NetworkManager] --> LS[LobbyScene Assembly]
    UI --> LS
    
    LS --> LocalTest[Local Test]
    GS --> LocalTest
    
    LocalTest --> RelayTest[Relay Test]
    
    style PL fill:#ff6b6b,color:#fff
    style SO fill:#ffa06b,color:#fff
    style MAT fill:#ffa06b,color:#fff
    style RP fill:#ffd06b,color:#000
    style PP fill:#ffd06b,color:#000
    style ItemPrefabs fill:#6bff8f,color:#000
    style UI fill:#6bff8f,color:#000
    style NM fill:#6bb5ff,color:#fff
    style GS fill:#6bb5ff,color:#fff
    style LS fill:#6bb5ff,color:#fff
    style LocalTest fill:#c46bff,color:#fff
    style RelayTest fill:#c46bff,color:#fff
```

---

## Time Estimates

| Phase | Task | Time |
|-------|------|------|
| 1 | Project Settings | 15 min |
| 2 | Scenes + Build Settings | 10 min |
| 3 | ScriptableObject Assets | 20 min |
| 4 | Materials | 15 min |
| 5 | Room Prefabs (5) | 30 min |
| 6 | Player Prefabs (2) | 25 min |
| 7 | Prop/Item Prefabs (7) | 20 min |
| 8 | UI Canvases (4) | 25 min |
| 9 | NetworkManager + Boot | 15 min |
| 10 | Scene Assembly + Wiring | 20 min |
| 11 | Build + Local Test | 15 min |
| 12 | Relay Server Test | 10 min |
| **TOTAL** | | **~3.5 hours** |

---

## Common Pitfalls

| Pitfall | How to Avoid |
|---------|-------------|
| Forgot to register prefabs in FishNet DefaultPrefabObjects | Phase 9.3 — add ALL networked prefabs |
| NetworkObject missing on spawned prefab | Every prefab that's Spawn()'d needs `NetworkObject` |
| Camera conflict (two cameras active) | Runner disables camera if `!IsOwner`. Eye same. |
| Physics layer not set → LoS raycasts dont hit walls | Verify all wall geometry is on Layer 6 |
| ScriptableObjects not in Resources/ folder | `Resources.LoadAll` only finds assets in Resources/ |
| Missing inspector references → NullReferenceException | Phase 10.3 — wire every `[SerializeField]` |
| CharacterController + NetworkTransform conflict | Runner uses prediction (`[Replicate]`/`[Reconcile]`), not NetworkTransform for movement |
| Relay URL not set | Phase 12.2 — set WSS URL in RelayTransport |
| Build Settings scenes not ordered | LobbyScene must be index 0 |
| TextMeshPro resources not imported | Phase 1.5 — import TMP essentials |

---

## After Greybox Works — Next Steps

Once you have a working greybox game:

1. **Replace greybox meshes** with real 3D models (runner character, room assets, items)
2. **Add particle effects** (laser beam, pickup sparkle, trap zones)
3. **Add sound effects** (footsteps, laser, UI clicks, ambient)
4. **Add post-processing** (volume profiles per match state)
5. **Polish UI** (proper layouts, animations, icons)
6. **Playtest and tune** GlobalRules_SO values
7. **Add more rooms** (10-15 for variety)
8. **Add more items** (expand loot/shrine/trap pools)

---

## Quick Reference: All Prefabs Needed

| # | Prefab | Path | NetworkObject? |
|---|--------|------|----------------|
| 1 | Runner | Prefabs/Player/ | YES |
| 2 | Eye | Prefabs/Player/ | YES |
| 3 | WorldItem | Prefabs/Props/ | YES |
| 4 | Altar | Prefabs/Props/ | YES |
| 5 | Shrine | Prefabs/Props/ | YES |
| 6 | SlowField | Prefabs/Props/ | YES |
| 7 | NoiseTrip | Prefabs/Props/ | YES |
| 8 | PathBlocker | Prefabs/Props/ | YES |
| 9 | DynamicProp | Prefabs/Props/ | YES |
| 10 | NetworkManager | Prefabs/ | NO (manages others) |
| 11 | GameBoot | Prefabs/ | NO (singleton) |
| 12 | RunnerHUD | Prefabs/UI/ | NO (local UI) |
| 13 | EyeHUD | Prefabs/UI/ | NO (local UI) |
| 14 | LobbyCanvas | Prefabs/UI/ | NO (local UI) |
| 15 | ResultsScreen | Prefabs/UI/ | NO (local UI) |
| 16-20 | Room_* (5) | Prefabs/Rooms/ | NO (spawned by MapGen as children) |

---

## Quick Reference: All ScriptableObject Assets Needed

| # | Asset | Path | Type |
|---|-------|------|------|
| 1 | GlobalRules | Resources/ | GlobalRules_SO |
| 2-6 | Loot_Coin/Gem/Idol/Crown/Relic | Resources/Items/Loot/ | ItemData_SO |
| 7-9 | Shrine_Mirror/Decoy/GrapplingHook | Resources/Items/Shrine/ | ShrineItemData_SO |
| 10-12 | Trap_SlowField/NoiseTrip/PathBlocker | Resources/Items/Traps/ | TrapData_SO |
| 13-17 | Room_Small_A/B, Medium_A/B, Large_A | Resources/Items/Rooms/ | RoomNode_SO |

---

## Editor Tools & Map Generation Workflow

You have a full suite of custom editor tools already coded. Here's how to use them — they're the backbone of the room/map workflow.

### Custom Menu Items (`IStalk` menu in Unity)

These are all accessible from the top menu bar after scripts compile:

| Menu Path | What It Does |
|-----------|--------------|
| `IStalk > Map Generation Tester` | Opens MapGenTestWindow — test generation without play mode |
| `IStalk > Room Validator` | Opens RoomValidator — batch-validate all room prefabs vs their SOs |
| `IStalk > Create > Room Prefab Setup` | Scaffolds a full room hierarchy (RoomBounds + 2 connectors + 1 slot) in scene |
| `IStalk > Create > Loot Item SO` | Creates a new ItemData_SO asset at the correct path |
| `IStalk > Create > Shrine Item SO` | Creates a new ShrineItemData_SO asset |
| `IStalk > Create > Trap SO` | Creates a new TrapData_SO asset |
| `IStalk > Create > Room Node SO` | Creates a new RoomNode_SO asset |
| `IStalk > Create > Global Rules SO` | Creates GlobalRules_SO (warns if one already exists) |
| `IStalk > Quick Setup > Create All Resource Folders` | One-click creates the entire folder hierarchy |
| `IStalk > Quick Setup > Setup Physics Layers` | Shows dialog with required layer assignments |

### Quickstart: Use `IStalk > Quick Setup > Create All Resource Folders` FIRST

This creates:
```
Assets/Resources/Items/Loot/
Assets/Resources/Items/Shrine/
Assets/Resources/Items/Traps/
Assets/Resources/Items/Rooms/
Assets/Prefabs/Player/
Assets/Prefabs/Props/
Assets/Prefabs/UI/
Assets/Prefabs/Rooms/
Assets/Scenes/
```

---

### Map Generation Tester Window

**Open**: `IStalk > Map Generation Tester`

This editor window lets you test procedural map generation without entering play mode:

```
┌─────────────────────────────────────────┐
│  Map Generation Tester                  │
│─────────────────────────────────────────│
│  Seed: [42]           [Randomize Seed]  │
│                                         │
│  [Generate Single Map (Preview)]        │
│                                         │
│  ── Stress Test ──                      │
│  Iterations: ======[100]============    │
│  [Run 100 Generations]                  │
│                                         │
│  ── Results ──                          │
│  Seed: 42                               │
│  Rooms placed: 9                        │
│  Altars: 2                              │
│  Loot slots: 14                         │
│  Time: 3ms                              │
│  Bounds: (center(12,0,8), size(48,3,40))│
│  Room breakdown:                        │
│    Corridor: 3                          │
│    SmallRoom: 4                         │
│    LargeRoom: 2                         │
└─────────────────────────────────────────┘
```

**How to use:**
1. Create your GlobalRules_SO first (sets room count ranges, cell sizes, etc.)
2. Create at least 3 RoomNode_SO assets with prefabs assigned
3. Open the tester window
4. Set a seed (or randomize) → click "Generate Single Map (Preview)"
5. Check the output: room counts, altar positions, loot slot distribution
6. **Stress Test**: Run 100-1000 iterations to check for failures, timing, and room range consistency

**What it validates:**
- Map always generates within `minRoomsPerMap`–`maxRoomsPerMap` range
- All rooms are connected (no orphaned rooms after ValidateConnectivity)
- Altars respect `altarMinDistanceFromSpawn`
- Generation time stays under budget (target: <10ms per generation)

---

### Room Validator Window

**Open**: `IStalk > Room Validator`

Batch-validates ALL room prefabs against their RoomNode_SO definitions:

```
┌─────────────────────────────────────────┐
│  Room Validator                         │
│─────────────────────────────────────────│
│  [Validate All Rooms] [Validate Selected]│
│                                         │
│  ┌─ Results ──────────────────────────┐ │
│  │ ⛔ [Room_Small_A] Room ID is empty │ │
│  │ ⛔ [Room_Med_B] Prefab has no      │ │
│  │    ConnectorMarker components      │ │
│  │ ⚠️ [Room_Large_A] Loot slots      │ │
│  │    mismatch: prefab=3, SO=4       │ │
│  │ ℹ️ [Room_Small_B] PASS — all OK   │ │
│  └────────────────────────────────────┘ │
└─────────────────────────────────────────┘
```

**What it checks per room:**
- `roomId` is not empty (ERROR)
- `roomPrefab` is assigned (ERROR)
- Prefab has at least one `ConnectorMarker` component (ERROR)
- Prefab has a `RoomBounds` component (WARNING if missing)
- `RoomBounds.gridSize` matches `RoomNode_SO.gridSize` (WARNING if mismatch)
- Every direction declared in SO has a matching ConnectorMarker in prefab (ERROR)
- Every ConnectorMarker in prefab has a matching SO declaration (WARNING)
- Loot slot count in prefab matches `lootSpawnSlots` in SO (WARNING)

**Workflow**: After building a room prefab, run the validator to catch mismatches before you try to generate maps with it.

---

### RoomNode_SO Custom Inspector

When you select any `RoomNode_SO` asset, the inspector shows extra tools:

**"Auto-Populate from Prefab" Button:**
- Reads all `ConnectorMarker` components → fills `openConnections` list
- Reads `RoomBounds` component → fills `gridSize`
- Counts `SpawnSlot` components by type → fills `lootSpawnSlots`, `incarnationPropSlots`
- Checks for slot types → sets `isValidRunnerSpawn`, `isValidAltarLocation`, `canContainShrine`

**This is the fastest workflow:**
1. `IStalk > Create > Room Prefab Setup` → scaffolds hierarchy in scene
2. Build your room geometry as children (cubes for walls/floor)
3. Add more `ConnectorMarker` and `SpawnSlot` components where needed
4. Drag to `Assets/Prefabs/Rooms/` to save as prefab
5. `IStalk > Create > Room Node SO` → creates the SO asset
6. Drag your prefab into the SO's `roomPrefab` field
7. Click **"Auto-Populate from Prefab"** → all fields auto-filled
8. Tweak `spawnWeight`, `category`, `maxPerMap` manually

**"Validate Room" Button:**
- Runs the same checks as RoomValidator but for the single selected asset
- Shows inline errors/warnings directly in the inspector

---

### GlobalRules_SO Custom Inspector

The GlobalRules inspector shows a **Balance Preview** panel with computed values:

```
── Balance Preview ──

Weight Tiers:
  Naked: 0.0–5.0kg → 100% speed
  Light: 5.0–12.0kg → 90% speed
  Moderate: 12.0–20.0kg → 75% speed
  Heavy: 20.0–30.0kg → 55% speed
  Overloaded: 30.0kg+ → 35% speed

Movement at Base Speed:
  Walk: 5.5 m/s
  Sprint: 8.8 m/s
  Slide: 12.0 m/s
  Overloaded Walk: 1.9 m/s

Extraction Economy:
  Threshold: 20 loot value
  Min loot in map: ~60 value
  Channel time (empty): 3.0s
  Channel time (20kg): 5.4s

Map Generation:
  Rooms: 8–12
  Floors: 1–2
  Altars: 2–3
  Map area (max): ~1920m²

Match Timing:
  Grace: 30s
  Hunt: 5.0 min
  Total max: 5.5 min
```

This lets you instantly see the impact of tuning values without entering play mode.

---

### ItemData_SO Custom Inspector

Shows per-item computed values:
- Icon thumbnail preview (if `icon` sprite assigned)
- **Weight Tier (alone)** — what tier this single item puts you in
- **Speed Multiplier (alone)** — how much speed you lose carrying just this item
- **Value/Weight Ratio** — efficiency metric for item balance (higher = more rewarding to carry)
- **"Generate ID from Name"** button — auto-fills `itemId` from asset name
- Validation warnings: empty ID, missing world prefab, zero value/weight

---

### TrapData_SO & ShrineItemData_SO Custom Inspectors

**Trap inspector shows:**
- Cost/Duration ratio (dread per second of effect)
- Area coverage (π × radius² in m²)
- Trigger-to-arm delay
- "Generate ID from Name" button
- Validation: empty ID, missing prefab, zero cost

**Shrine item inspector shows:**
- Net weight change (positive or negative)
- Cost/Effect ratio (loot cost per second of effect)
- Uptime percentage (effect / (effect + cooldown))
- "Generate ID from Name" button
- Validation: empty ID

---

### Room Prefab Helper Components (Scene Gizmos)

These MonoBehaviours are placed on room prefab children and draw colored gizmos in the Scene view:

#### ConnectorMarker
- **Color-coded by direction:** Red=Left, Blue=Right, Green=Up, Yellow=Down
- Draws a wireframe rectangle showing the connector opening size
- Draws an arrow pointing in the connection direction
- Set `connectorWidth` (0.5–3m) and `connectorHeight` (2–4m) to match your wall gaps

#### RoomBounds
- Draws a **cyan wireframe cube** showing the room's grid footprint
- Draws a subtle **grid overlay** on the floor (one line per cell)
- `gridSize` field must match the RoomNode_SO's `gridSize`
- Used by MapGenerator to know how many grid cells a room occupies

#### SpawnSlot
- Draws a **color-coded wireframe sphere** at each slot position:
  - Gold = Loot Item
  - Magenta = Shrine
  - Grey = Static Prop
  - Cyan = Dynamic Prop
  - Purple = Incarnation Prop
  - Green = Runner Spawn
  - Orange = Altar Location
- Shows a label above with slot type + spawn probability
- `radius` controls gizmo size (visual only — not gameplay relevant)
- `spawnProbability` (0–1) tells MapGenerator the chance of actually spawning content here

---

### MapGenerator Code Architecture

Understanding how `MapGenerator.cs` works helps you author rooms that generate well:

```mermaid
graph TD
    A[Generate called] --> B[Load all RoomNode_SO from ItemDatabase]
    B --> C[Categorize: Start / Corridor / Small / Large]
    C --> D[Place Starting Room at origin 0,0]
    D --> E{Rooms < target?}
    E -->|Yes| F[Pick candidate by category + weight]
    F --> G[Find open connectors on placed rooms]
    G --> H{Candidate fits at any open connector?}
    H -->|Yes| I[Place room, mark cells occupied]
    H -->|No| E
    I --> E
    E -->|No / max attempts| J[ValidateConnectivity — BFS prune orphans]
    J --> K[PopulateContent — assign altars, loot, shrines]
    K --> L[SpawnRoomPrefabs — server instantiates NetworkObjects]

    style D fill:#6bff8f,color:#000
    style J fill:#ff6b6b,color:#fff
    style L fill:#6bb5ff,color:#fff
```

**Key rules for room authorship:**
1. Every room MUST have at least 1 connector (otherwise it can never be placed)
2. Connector directions must be complementary — a room with `Right` can attach to a room with `Left`
3. `spawnWeight` controls how often a room appears (higher = more common)
4. `maxPerMap` of 0 means unlimited; set to 1 for unique/special rooms
5. `corridorRatioMin` in GlobalRules ensures maps have enough corridors to not feel cramped
6. Rooms that fail connectivity BFS get pruned — so isolated rooms never appear in final map

**Room category distribution logic:**
- If corridor ratio is below `corridorRatioMin` → forced to pick a corridor
- 15% chance to pick a large room (capped by `maxLargeRooms`)
- Otherwise picks from small rooms (most common)
- All pools use weighted random selection (`spawnWeight`)

---

### Complete Room Building Workflow (with Tools)

```mermaid
graph LR
    A[IStalk > Create > Room Prefab Setup] --> B[Edit geometry in Scene]
    B --> C[Add ConnectorMarkers at openings]
    C --> D[Add SpawnSlots at positions]
    D --> E[Save to Assets/Prefabs/Rooms/]
    E --> F[IStalk > Create > Room Node SO]
    F --> G[Drag prefab → roomPrefab field]
    G --> H[Click 'Auto-Populate from Prefab']
    H --> I[Set category + spawnWeight + maxPerMap]
    I --> J[IStalk > Room Validator — validate]
    J --> K[IStalk > Map Gen Tester — test generation]

    style A fill:#6bff8f,color:#000
    style H fill:#ffd06b,color:#000
    style J fill:#ff6b6b,color:#fff
    style K fill:#6bb5ff,color:#fff
```

**Step-by-step (10 min per room after first one):**

1. **Scaffold**: `IStalk > Create > Room Prefab Setup`
   - Creates: Root + RoomBounds + 2 ConnectorMarkers + 1 SpawnSlot (Loot)
   - A dialog explains next steps

2. **Build Geometry**: Add cubes for floor/walls/ceiling as children
   - All geometry on Layer `Wall`
   - Cut holes in walls where connectors are positioned
   - Apply greybox materials

3. **Position Connectors**: Move ConnectorMarker objects to wall openings
   - Set `connectionDirection` to match the direction the opening faces OUT
   - Left connector → placed at the left wall opening, direction = Left
   - Adjust `connectorWidth`/`connectorHeight` to match opening size

4. **Place SpawnSlots**: Add empty GameObjects + SpawnSlot component
   - Position at floor level where items/props should appear
   - Set `slotType` for each (Loot, Shrine, PropDynamic, PropIncarnation, RunnerSpawn, AltarLocation)
   - Set `spawnProbability` (usually 0.8–1.0 for loot, 1.0 for altars/shrines)

5. **Save Prefab**: Drag root into `Assets/Prefabs/Rooms/`

6. **Create SO**: `IStalk > Create > Room Node SO`
   - Drag prefab into `roomPrefab` field
   - Click **"Auto-Populate from Prefab"** — fills connections, grid size, slot counts
   - Set `roomId` (e.g. "small_a"), `displayName`, `category`, `spawnWeight`

7. **Validate**: `IStalk > Room Validator` → "Validate All Rooms"
   - Fix any errors (missing connectors, ID, etc.)

8. **Test Generation**: `IStalk > Map Generation Tester`
   - Run 100 iterations stress test
   - Check: 0 failures, room counts in expected range, <10ms average

---

### Debugging Map Generation Issues

| Problem | Cause | Fix |
|---------|-------|-----|
| "Rooms placed: 1" (only starting room) | No compatible connectors between rooms | Ensure rooms have opposing directions (Left↔Right, Up↔Down) |
| Failures in stress test | Null SO fields or missing prefab references | Run Room Validator, fix all errors |
| Altars: 0 | No room has `isValidAltarLocation = true` or distance rule too strict | Add AltarLocation SpawnSlot to at least 2 rooms |
| Rooms always the same | `maxPerMap` too low or only 1 room per category | Add more room variants, increase `maxPerMap` |
| Map too linear | Only Left/Right connections | Add rooms with 3-4 connections (especially Up/Down for branching) |
| Large rooms never appear | `spawnWeight` too low or pool empty | Check `largeRooms` category has assets, weight > 0 |
| "GlobalRules_SO not found" error | No GlobalRules asset in Resources/ | `IStalk > Create > Global Rules SO`, save to `Assets/Resources/` |

---

---

# Part 2: Full-Featured Greybox Demo Setup

> **Goal:** Take the working greybox from Part 1 and wire up EVERY gameplay system so you have a complete demo showcasing all mechanics — incarnation, shrine purchases, all 6 shrine items, overtime sealing, parkour, noise/dread loop, revive, and spectator camera. This is the "vertical slice" that proves the game works end-to-end.

---

## Greybox Demo Feature Checklist

```mermaid
graph TD
    subgraph "RUNNER EXPERIENCE"
        R1[FPS Movement + Parkour]
        R2[Pickup Loot → Weight Slows You]
        R3[Deposit at Altar → Extraction Progress]
        R4[Buy Shrine Items → Use Abilities]
        R5[Take Damage → Get Downed → Get Revived]
        R6[Noise Actions Feed Eye Dread]
    end

    subgraph "EYE EXPERIENCE"
        E1[Top-Down Camera + Pan/Zoom]
        E2[LoS System → See Runners Through Geometry]
        E3[Laser → Telegraph → Fire → Damage + Item Drop]
        E4[Place Traps → SlowField / NoiseTrip / PathBlocker]
        E5[Incarnate Props → Move Them → Spook Runners]
        E6[Scan Ability → Reveal All Runners]
        E7[Dread Economy → Abilities Cost Resources]
    end

    subgraph "MATCH FLOW"
        M1[Lobby → Room Code → Join]
        M2[Grace Period → No Eye Abilities]
        M3[Main Phase → Full Gameplay]
        M4[Timer Expires → Overtime]
        M5[Overtime → Rooms Seal Progressively]
        M6[Win Condition: Extract OR Time Runs Out]
        M7[Results Screen → Stats → Return to Lobby]
    end

    R1 --> R6
    R2 --> R3
    E7 --> E3
    E7 --> E4
    E7 --> E5
    M3 --> M4
    M4 --> M5
```

---

## Phase 13: Complete Inspector Wiring Reference (30 min)

This is the exhaustive list of EVERY `[SerializeField]` field on EVERY script that needs a reference dragged in the inspector. Do this methodically — one prefab at a time.

### 13.1 Runner Prefab — Full Wiring

Open `Assets/Prefabs/Player/Runner.prefab`:

| Component | Field | Drag This |
|-----------|-------|-----------|
| RunnerController | (auto-gets CharacterController) | — |
| RunnerLook | `_camera` | CameraHolder/PlayerCamera (Transform) |
| RunnerStamina | — | (reads GlobalRules_SO.Instance at runtime) |
| RunnerHealth | — | (auto, reads GlobalRules_SO) |
| PlayerInventory | — | (SyncList, no inspector refs) |
| WeightComponent | — | (auto, reads GlobalRules_SO) |
| RunnerInteraction | `_interactLayer` | Layer mask: Interactable (11) |
| RunnerInteraction | `_interactRange` | 2.5 |
| NoiseEmitter | — | (auto) |
| ShrineItemEffect | — | (auto, reads ItemDatabase.Instance) |
| RunnerAnimator | `_animator` | Body child's Animator (add Animator component to Body) |
| RunnerFootsteps | `_audioSource` | AudioSource on root |
| RunnerVisibility | `_bodyRenderer` | Body child's MeshRenderer |
| CharacterController | Height: 1.8, Radius: 0.3 | Center: (0, 0.9, 0) |

**Camera Setup:**
- PlayerCamera → Field of View: **90**
- PlayerCamera → Near Clip: **0.1**
- PlayerCamera → Far Clip: **200**
- PlayerCamera → Clear Flags: Solid Color → dark grey (#1A1A1A)

### 13.2 Eye Prefab — Full Wiring

Open `Assets/Prefabs/Player/Eye.prefab`:

| Component | Field | Drag This |
|-----------|-------|-----------|
| EyeCameraController | `_camera` | EyeCamera (Camera component) |
| EyeCameraController | `_panSpeed` | 15 |
| EyeCameraController | `_zoomSpeed` | 5 |
| EyeCameraController | `_minZoom` | 8 |
| EyeCameraController | `_maxZoom` | 40 |
| EyeLaserController | `_laserOrigin` | LaserOrigin (Transform) |
| EyeLaserController | `_wallLayer` | Layer mask: Wall (6) |
| EyeLaserController | `_runnerLayer` | Layer mask: Runner (8) |
| EyeTrapPlacer | `_slowFieldPrefab` | SlowField.prefab |
| EyeTrapPlacer | `_noiseTripPrefab` | NoiseTrip.prefab |
| EyeTrapPlacer | `_pathBlockerPrefab` | PathBlocker.prefab |
| EyeTrapPlacer | `_placementLayer` | Layer mask: Wall (floor detection) |
| EyeIncarnationController | `_propLayer` | Layer mask: Prop (7) |
| EyeIncarnationController | `_maxIncarnateRange` | 50 |
| DreadEconomy | — | (reads GlobalRules_SO.Instance) |
| EyeScanAbility | `_scanCost` | 25 |
| EyeScanAbility | `_scanDuration` | 3 |
| EyeScanAbility | `_scanCooldown` | 15 |

### 13.3 WorldItem Prefab — Full Wiring

| Component | Field | Drag This |
|-----------|-------|-----------|
| WorldItem | `_renderer` | Visual child's MeshRenderer |
| WorldItem | `_collider` | SphereCollider on root |
| WorldItem | `_bobHeight` | 0.3 |
| WorldItem | `_rotateSpeed` | 45 |

### 13.4 Altar Prefab — Full Wiring

| Component | Field | Drag This |
|-----------|-------|-----------|
| Altar | `_channelDuration` | 3.0 |
| Altar | `_interactCollider` | BoxCollider (trigger) |
| Altar | `_glowRenderer` | Pedestal child's MeshRenderer |

### 13.5 Shrine Prefab — Full Wiring

| Component | Field | Drag This |
|-----------|-------|-----------|
| Shrine | `_interactCollider` | BoxCollider (trigger) |
| Shrine | `_displayRenderer` | DisplayOrb child's MeshRenderer |

### 13.6 Trap Prefabs — Full Wiring

**SlowField:**
| Component | Field | Drag This |
|-----------|-------|-----------|
| TrapInstance | `_trapData` | Trap_SlowField.asset |
| TrapInstance | `_collider` | SphereCollider (trigger) |
| TrapInstance | `_renderer` | Visual sphere's MeshRenderer |

**NoiseTrip:**
| Component | Field | Drag This |
|-----------|-------|-----------|
| TrapInstance | `_trapData` | Trap_NoiseTrip.asset |
| TrapInstance | `_collider` | BoxCollider (trigger) |
| TrapInstance | `_renderer` | null (invisible) |

**PathBlocker:**
| Component | Field | Drag This |
|-----------|-------|-----------|
| TrapInstance | `_trapData` | Trap_PathBlocker.asset |
| TrapInstance | `_collider` | BoxCollider (NOT trigger) |
| TrapInstance | `_renderer` | Visual cube's MeshRenderer |

### 13.7 DynamicProp Prefab — Full Wiring

| Component | Field | Drag This |
|-----------|-------|-----------|
| PropBase (inherited) | `_renderer` | Visual cube's MeshRenderer |
| PropBase (inherited) | `_collider` | BoxCollider |
| IncarnationProp | `_incarnationDreadCost` | 20 |
| IncarnationProp | `_moveDreadCostPerSecond` | 5 |
| IncarnationProp | `_moveSpeed` | 3 |
| IncarnationProp | `_incarnateSound` | null (no audio yet) |
| DynamicProp | `_noiseRadius` | 5 |
| Rigidbody | Is Kinematic | true (until possessed) |
| Rigidbody | Use Gravity | true |

---

## Phase 14: GameScene Complete Assembly (25 min)

### 14.1 Full GameScene Hierarchy

```
GameScene
├── --- MANAGERS ---
├── GameManager
│   ├── GameManager.cs
│   ├── ExtractionManager.cs
│   ├── LootSpawner.cs
│   └── PlayerSpawner.cs
├── MapGenerator
│   └── MapGenerator.cs
├── LoSManager
│   ├── NetworkObject
│   └── LoSManager.cs
├── OvertimeManager
│   └── OvertimeManager.cs (or on GameManager)
│
├── --- LIGHTING ---
├── Directional Light (Rotation: 50, -30, 0)
│   └── Color: warm white, Intensity: 1.2
│
├── --- UI ---
├── RunnerHUD (prefab instance, starts DISABLED)
├── EyeHUD (prefab instance, starts DISABLED)
├── ResultsScreen (prefab instance, panel starts inactive)
├── PauseMenu (prefab instance, starts DISABLED)
├── LoadingScreen (Canvas, Image full-screen black, starts ACTIVE, fades out)
│
├── --- ENVIRONMENT ---
├── FloorPlane (fallback floor, Cube 200x0.1x200, y=-0.5, layer: Wall, Mat_Floor)
│   └── [Prevents falling into void if MapGen hasn't finished]
└── KillZone (BoxCollider trigger at y=-50, kills/respawns runners who fall)
```

### 14.2 GameManager Inspector Setup

| Field | Value |
|-------|-------|
| `_mapGenerator` | MapGenerator object |
| `_lootSpawner` | LootSpawner (same GO or child) |
| `_extractionManager` | ExtractionManager (same GO) |
| `_playerSpawner` | PlayerSpawner (same GO) |
| `_runnerHUD` | RunnerHUD canvas (disabled) |
| `_eyeHUD` | EyeHUD canvas (disabled) |
| `_resultsScreen` | ResultsScreen object |
| `_overtimeManager` | OvertimeManager object |

### 14.3 MapGenerator Inspector Setup

| Field | Value |
|-------|-------|
| `_roomPrefabs` | Array[5]: all Room_*.prefab |
| `_shrinePrefab` | Shrine.prefab |
| `_altarPrefab` | Altar.prefab (if spawned by MapGen) |
| `_dynamicPropPrefab` | DynamicProp.prefab |
| `_minRooms` | 8 |
| `_maxRooms` | 12 |
| `_seed` | 0 (random) |

### 14.4 PlayerSpawner Inspector Setup

| Field | Value |
|-------|-------|
| `_runnerPrefab` | Runner.prefab |
| `_eyePrefab` | Eye.prefab |

### 14.5 LootSpawner Inspector Setup

| Field | Value |
|-------|-------|
| `_worldItemPrefab` | WorldItem.prefab |

---

## Phase 15: Incarnation Demo Setup (10 min)

The incarnation system needs props to possess. Here's how to set up a demo-ready room with possessable objects.

### 15.1 Create Multiple DynamicProp Variants

Duplicate `DynamicProp.prefab` to create visual variety (all share the same scripts):

| Variant | Visual | Scale | Placement |
|---------|--------|-------|-----------|
| `Prop_Crate.prefab` | Cube | 1x1x1 | Floor, against walls |
| `Prop_Barrel.prefab` | Cylinder | 0.6x1x0.6 | Corners, clusters |
| `Prop_Table.prefab` | Cube | 2x0.8x1 | Center of rooms |
| `Prop_Chair.prefab` | Cube | 0.5x0.8x0.5 | Near tables |

For each:
1. Duplicate DynamicProp.prefab
2. Change Visual child mesh scale/shape
3. Apply `Mat_Prop` (brown)
4. Keep all scripts identical (PropBase + DynamicProp + IncarnationProp)
5. Register each in `DefaultPrefabObjects.asset` (FishNet prefab list)

### 15.2 Room Prefab Prop Placement

In each room prefab, add 2-4 DynamicProp instances at `PropSlot` positions:

```
Room_Medium_A (existing prefab)
├── ... existing children ...
├── SpawnSlots
│   ├── PropSlot_1 (position 3, 0.5, 2) → place Prop_Crate here at runtime
│   ├── PropSlot_2 (position -2, 0.5, -3) → place Prop_Barrel here
│   └── PropSlot_3 (position 0, 0.4, 4) → place Prop_Table here
```

> **Option A (static):** Place DynamicProp prefab instances directly in the room prefab. They'll spawn with the room.
> **Option B (dynamic):** MapGenerator reads PropSlot SpawnSlots and spawns random prop variants at those positions (more variety, requires code in PopulateContent).

For the demo, **Option A is faster** — just drag props into room prefabs and save.

### 15.3 Incarnation Flow Verification Checklist

| Step | Expected |
|------|----------|
| Eye presses Q on a prop | Prop glows (emission shader) |
| Eye uses WASD | Prop moves on ground plane for all clients |
| Dread bar drains | 5/second while moving |
| Dread hits 0 | Prop auto-releases, glow stops |
| Eye presses Q or Escape | Manual release |
| Runner near moving prop | Noise triggers (future: audio feedback) |

---

## Phase 16: Shrine Purchase Demo Setup (10 min)

### 16.1 Shrine Item Configuration

Ensure all 3 shrine items have correct values in their SOs:

**Shrine_Mirror.asset:**
```
itemId: mirror
itemType: Mirror
lootCost: 5          ← runner needs 5 loot-weight of items to buy
effectDuration: 8    ← 8 seconds invisible
cooldown: 20         ← 20 seconds between uses
isConsumedOnUse: false
effectRadius: 0      ← not used
effectIntensity: 0   ← not used
```

**Shrine_Decoy.asset:**
```
itemId: decoy
itemType: Decoy
lootCost: 3
effectDuration: 10   ← 10 seconds decoy lasts
cooldown: 15
isConsumedOnUse: false
effectRadius: 0
effectIntensity: 0
```

**Shrine_GrapplingHook.asset:**
```
itemId: grapple
itemType: GrapplingHook
lootCost: 8          ← expensive, one-time use
effectDuration: 0
cooldown: 0
isConsumedOnUse: true ← consumed after one use
effectRadius: 0
effectIntensity: 0
```

### 16.2 Shrine Purchase Flow

```mermaid
sequenceDiagram
    participant R as Runner
    participant S as Shrine
    participant SIE as ShrineItemEffect
    participant LoS as LoSManager

    R->>S: Press F near Shrine
    Note over R: ShrineUI panel opens (client-side)
    R->>S: Click Purchase (ServerRpc)
    S->>S: Validate: runner.TotalLootValue >= item.lootCost?
    S->>R: Deduct loot items from PlayerInventory
    S->>SIE: ApplyEffect(shrineItemData)
    Note over SIE: _activeItemId set, synced to client
    Note over R: HUD shows shrine item icon + "Q"
    R->>SIE: Press Q (ServerRpc ActivateItem)
    SIE->>LoS: Mirror → SetRunnerInvisible(8s)
    Note over LoS: Runner removed from visible list for 8s
```

### 16.3 Demo Test Steps

1. Runner picks up 5+ weight of loot
2. Runner approaches Shrine → sees "Press F"
3. Press F → ShrineUI opens showing Mirror (cost: 5)
4. Purchase → loot deducted, item icon appears on HUD
5. Press Q → Runner goes invisible to Eye for 8 seconds
6. Eye's minimap/LoS no longer shows that runner
7. After 8s → runner reappears
8. 20s cooldown before Q works again

---

## Phase 17: Overtime & Room Sealing Demo (10 min)

### 17.1 GlobalRules_SO Values for Demo

Set these for faster demo testing (not final balance):

| Field | Demo Value | Production Value |
|-------|-----------|------------------|
| matchTimeLimit | 120 | 300 |
| gracePeriodDuration | 10 | 30 |
| overtimeDuration | 60 | 90 |
| overtimeSealInterval | 15 | 20 |
| extractionThreshold | 10 | 20 |

### 17.2 Room Sealing Visual

When `OvertimeManager` seals a room, it needs to instantiate a barrier at each connector of that room. Add to Room prefabs:

**In each Room prefab, add a `RoomSeal` setup:**

Each connector already has a `ConnectorMarker.cs`. The `OvertimeManager` will:
1. Pick the room furthest from the altar
2. For each connector in that room: spawn a PathBlocker-style barrier at the connector position
3. The barrier uses `Mat_Trap_Blocker` (orange) so players see it clearly
4. Seal barrier is NOT a trap — it's permanent (no duration timer)

### 17.3 Overtime Flow

```mermaid
sequenceDiagram
    participant GM as GameManager
    participant OT as OvertimeManager
    participant Map as MapGenerator
    participant All as All Clients

    GM->>GM: Timer hits 0
    GM->>GM: State → Overtime
    GM->>OT: ActivateOvertime()
    Note over All: HUD flashes "OVERTIME!" in red
    loop Every overtimeSealInterval seconds
        OT->>Map: GetFurthestUnsealedRoom()
        Map-->>OT: Room reference
        OT->>OT: SealRoom(room) — spawn barriers at connectors
        OT->>All: ObserversRpc → update minimap, show seal VFX
        OT->>GM: SealedRoomCount++
    end
    Note over GM: If all rooms sealed OR overtime timer expires → EyeWins
```

---

## Phase 18: Parkour Level Design for Demo (15 min)

Parkour needs level geometry to test against. Add these to your room prefabs:

### 18.1 Vault Obstacles (waist height)

In 2-3 rooms, add low obstacles:

```
VaultObstacle (Cube)
├── Scale: (2, 0.9, 0.5)    ← waist-height, thin
├── Position: center of room or blocking a path
├── Layer: Wall
├── Material: Mat_Wall (slightly different shade for visibility)
└── [No script needed — CharacterController detects height via raycast]
```

### 18.2 Mantle Ledges (head height)

In 1-2 rooms, add taller climbable surfaces:

```
MantleLedge (Cube)
├── Scale: (3, 1.8, 3)      ← head-height platform
├── Position: corner of room, creates elevated area
├── Layer: Wall
├── Children:
│   └── TopSurface (Cube, scale 3x0.1x3, on top) ← walkable surface
└── [Runner can mantle up to stand on top]
```

### 18.3 Slide Gaps (low clearance)

In 1-2 rooms, add low-clearance passages:

```
SlideGap (Empty)
├── TopBar (Cube, scale 3x0.1x0.5, position y=1.0) ← blocks standing runner
├── SideL (Cube, scale 0.1x1x0.5)
├── SideR (Cube, scale 0.1x1x0.5)
└── [Gap is only 1m tall — must slide to pass through]
    [All on layer: Wall]
```

### 18.4 Wall-Run Surfaces

Wall-run works on ANY wall that's:
- Vertical (90 degrees)
- Continuous for at least 3 meters
- On layer `Wall`

Your existing room walls already satisfy this. For better demo, add some interior walls:

```
WallRunWall (Cube)
├── Scale: (0.3, 3, 8)     ← tall, long wall in middle of large room
├── Position: creates a corridor within the room
├── Layer: Wall
└── [Runner sprints alongside, jumps, wall-runs]
```

### 18.5 Parkour Room Layout Example (Large_A)

```
┌──────────────────────────────────────┐
│                                      │
│  ┌──────┐         ┌───────────┐     │
│  │MANTLE│         │ WALL-RUN  │     │
│  │LEDGE │         │   WALL    │     │
│  │      │         │           │     │
│  └──────┘         └───────────┘     │
│                                      │
│     ╔═══╗                            │
│     ║LOW║ ← Slide gap               │
│     ╚═══╝                            │
│                                      │
│  ▬▬▬▬▬▬▬▬ ← Vault obstacle          │
│                                      │
│            [ALTAR]                   │
│                                      │
└──────────────────────────────────────┘
```

---

## Phase 19: Noise → Dread Feedback Loop Demo (10 min)

### 19.1 Verify NoiseEmitter Triggers

The noise system creates the core asymmetry feedback. Ensure these actions emit noise:

| Runner Action | Noise? | Dread Generated |
|--------------|--------|-----------------|
| Walk | NO | 0 |
| Sprint | YES | dreadPerNoise per tick |
| Jump | YES (on land) | dreadPerNoise × 2 |
| Pickup item | YES | dreadPerNoise |
| Drop item | YES | dreadPerNoise |
| Channel at altar | YES (continuous) | dreadPerNoise per second |
| Slide | NO | 0 |
| Wall-run | NO | 0 |
| Crouch-walk | NO | 0 |

### 19.2 GlobalRules_SO Noise Values

| Field | Value | Purpose |
|-------|-------|---------|
| dreadRegenRate | 2.0 | Passive Dread regen per second |
| dreadMax | 100 | Dread pool cap |
| dreadPerNoise | 3.0 | Dread gained per noise event |
| sprintNoiseInterval | 0.5 | Seconds between sprint noise ticks |
| sprintNoiseRadius | 8.0 | How far sprint noise carries |
| laserDreadCost | 30 | Cost to fire laser |

### 19.3 Feedback Visualization (Eye Side)

On the EyeHUD, the Dread bar should:
- Glow/pulse when receiving noise bonus (DOTween punch scale)
- Show "+3" floating text on each noise event (optional polish)
- Smoothly fill (not instant jump)

On the EyeHUD minimap:
- Brief ping dot at noise source location (fades over 1s)
- Helps Eye know WHERE runners are making noise (even if not LoS-visible)

---

## Phase 20: Revive System Demo Setup (10 min)

### 20.1 How Revive Works

```mermaid
sequenceDiagram
    participant Eye as Eye
    participant R1 as Runner A
    participant R2 as Runner B (Alive)

    Eye->>R1: Laser hit → RunnerHealth.TakeDamage()
    Note over R1: HP reaches 0 → _isDown = true
    Note over R1: Drops ALL inventory items
    Note over R1: Movement frozen, body goes prone/ragdoll
    R2->>R2: Approaches downed R1 (within interact range)
    Note over R2: Prompt: "Hold F to Revive"
    R2->>R1: Hold F for reviveDuration seconds (ServerRpc)
    Note over R2: Channel bar shows progress
    R1->>R1: RunnerHealth.Revive(reviveHpAmount)
    Note over R1: _isDown = false, can move again
    Note over R1: Revived with partial HP (not full)
```

### 20.2 Revive Setup in Inspector

On the `RunnerRevive.cs` component (Runner prefab):

| Field | Value |
|-------|-------|
| `_reviveDuration` | 4.0 (seconds holding F) |
| `_reviveHpAmount` | 50 (revived at half HP) |
| `_reviveRange` | 2.5 (must be close to downed runner) |

### 20.3 Downed State Visual

When `RunnerHealth._isDown` syncs to true on clients:
- Body capsule rotates to lay flat (Quaternion.Euler(90, 0, 0))
- Material color shifts to darker shade (MaterialPropertyBlock)
- Pulse effect on body (DOTween scale ping-pong, subtle)
- Runner's camera detaches and looks at their body from slightly above (spectator-lite)

### 20.4 Demo Test: Damage → Down → Revive

1. Eye fires laser at Runner A (carrying items)
2. Runner A takes damage → HP reaches 0
3. Runner A drops all items → falls prone → cannot move
4. Runner B approaches → "Hold F to Revive" prompt
5. Runner B holds F for 4 seconds → channel completes
6. Runner A stands up with 50 HP → can move again
7. Dropped items still on ground — Runner A can re-pickup

---

## Phase 21: Spectator Camera (5 min)

### 21.1 When Spectator Activates

`SpectatorCamera.cs` activates when:
- Runner is downed AND no other runners are alive to revive them
- All runners are downed → game over (EyeWins) but short spectator period first
- Post-death: downed runner can cycle through other runners' cameras

### 21.2 Spectator Prefab Setup

The `SpectatorCamera.cs` is already on the Runner prefab (or spawned when downed). Its setup:

| Field | Value |
|-------|-------|
| `_orbitDistance` | 5 |
| `_orbitSpeed` | 60 (degrees/sec) |
| `_cycleKey` | Mouse1 or Tab |

### 21.3 Behavior

- Camera orbits around the downed runner's body
- Press Tab: cycle to spectate another living runner
- If all runners downed: 3-second freeze, then Results Screen

---

## Phase 22: Audio Placeholders for Demo (10 min)

Even without final audio, placeholder sounds make the demo feel alive. Create simple clips using Unity's built-in AudioClip.Create() or import free sounds.

### 22.1 Critical Audio (import ANY placeholder .wav/.ogg)

Create `Assets/Audio/` folder with subfolders:

```
Assets/Audio/
├── SFX/
│   ├── laser_fire.ogg         ← any zap/beam sound
│   ├── laser_telegraph.ogg    ← warning hum/charge
│   ├── item_pickup.ogg        ← coin clink
│   ├── item_drop.ogg          ← thud
│   ├── damage_hit.ogg         ← impact
│   ├── trap_trigger.ogg       ← alarm buzz
│   ├── channel_loop.ogg       ← humming (looping)
│   ├── scan_pulse.ogg         ← sonar ping
│   ├── incarnate_start.ogg    ← whoosh/possession
│   └── ui_click.ogg           ← button press
├── Music/
│   ├── lobby_ambient.ogg      ← chill loop
│   └── match_tension.ogg      ← subtle tension loop
└── Footsteps/
    ├── step_stone_01.ogg
    ├── step_stone_02.ogg
    ├── step_stone_03.ogg
    └── step_stone_04.ogg
```

> **Free sources:** freesound.org, kenney.nl/assets (CC0), mixkit.co

### 22.2 Wire Audio References

| Prefab | Field | Clip |
|--------|-------|------|
| Eye → EyeLaserController | `_fireSound` | laser_fire.ogg |
| Eye → EyeLaserController | `_telegraphSound` | laser_telegraph.ogg |
| Eye → EyeScanAbility | `_scanSound` | scan_pulse.ogg |
| Eye → EyeIncarnationController | — | (IncarnationProp handles) |
| DynamicProp → IncarnationProp | `_incarnateSound` | incarnate_start.ogg |
| Runner → RunnerFootsteps | `_stepClips` | Array: step_stone_01-04 |
| Runner → RunnerInteraction | `_pickupSound` | item_pickup.ogg |

---

## Phase 23: Full Demo Playtest Checklist (Final Verification)

Run through this ENTIRE checklist with 2+ players before calling the demo "done":

### Runner Side

| # | Test | Pass? |
|---|------|-------|
| 1 | WASD movement smooth, no stutter | ☐ |
| 2 | Mouse look smooth, no drift | ☐ |
| 3 | Sprint works (Shift), stamina drains visibly | ☐ |
| 4 | Jump works (Space), correct height | ☐ |
| 5 | Slide works (Ctrl while sprinting), fits under low gaps | ☐ |
| 6 | Wall-run works (jump near wall while sprinting) | ☐ |
| 7 | Vault triggers on waist-height obstacles | ☐ |
| 8 | Dash works (mid-air direction burst) | ☐ |
| 9 | Walk near WorldItem → "Press F" prompt appears | ☐ |
| 10 | Press F → item disappears, inventory slot fills | ☐ |
| 11 | Weight indicator changes (Light → Medium → Heavy) | ☐ |
| 12 | Movement visibly slower when Heavy/Overloaded | ☐ |
| 13 | Walk to Altar → "Hold F to Deposit" prompt | ☐ |
| 14 | Hold F → channel bar fills → loot deposited | ☐ |
| 15 | Extraction bar on HUD increases | ☐ |
| 16 | Walk to Shrine → "Press F" → Shrine UI opens | ☐ |
| 17 | Purchase item → loot deducted, item icon appears on HUD | ☐ |
| 18 | Press Q → shrine item activates (Mirror: go invisible) | ☐ |
| 19 | Cooldown ring fills after use, blocks re-use until done | ☐ |
| 20 | Take laser hit → screen flash, HP bar drops | ☐ |
| 21 | HP at 0 → fall prone, drop all items, cannot move | ☐ |
| 22 | Other runner revives you → stand up with 50 HP | ☐ |
| 23 | Timer visible, counts down correctly | ☐ |
| 24 | Extraction threshold reached → "ESCAPED!" results screen | ☐ |

### Eye Side

| # | Test | Pass? |
|---|------|-------|
| 25 | Top-down camera, WASD pans smoothly | ☐ |
| 26 | Scroll wheel zooms in/out | ☐ |
| 27 | Camera stays within map bounds | ☐ |
| 28 | Runners appear as blips when in LoS (no wall between) | ☐ |
| 29 | Runners disappear from view behind walls | ☐ |
| 30 | Dread bar fills passively + bonus on runner noise | ☐ |
| 31 | Left-click → laser telegraph line appears (all see) | ☐ |
| 32 | Laser fires after charge → hits runner → damage applied | ☐ |
| 33 | Hit runner drops an item (visible WorldItem spawns) | ☐ |
| 34 | Laser blocked by walls (raycast stops) | ☐ |
| 35 | Cooldown prevents laser spam | ☐ |
| 36 | Press 1/2/3 → select trap type | ☐ |
| 37 | Right-click → place trap at position (costs Dread) | ☐ |
| 38 | SlowField: runner entering slows down | ☐ |
| 39 | NoiseTrip: runner crossing triggers alarm + Dread bonus | ☐ |
| 40 | PathBlocker: physical wall blocks runner path | ☐ |
| 41 | Space → scan pulse → all runners revealed briefly | ☐ |
| 42 | Q on prop → incarnate → WASD moves prop → Dread drains | ☐ |
| 43 | Q/Escape → release possession | ☐ |
| 44 | Cannot use abilities during grace period | ☐ |

### Match Flow

| # | Test | Pass? |
|---|------|-------|
| 45 | Lobby: Create room → get code | ☐ |
| 46 | Lobby: Join with code → player count updates | ☐ |
| 47 | Start Game → all load GameScene together | ☐ |
| 48 | Grace period: timer shows, Eye abilities blocked | ☐ |
| 49 | Grace ends → normal play begins | ☐ |
| 50 | Timer reaches 0 → "OVERTIME" message | ☐ |
| 51 | Rooms seal every N seconds (orange barriers appear) | ☐ |
| 52 | Overtime timer expires → Eye wins | ☐ |
| 53 | Results screen shows stats, buttons work | ☐ |
| 54 | Return to Lobby → back in lobby, can play again | ☐ |
| 55 | Player disconnect → game handles gracefully (no crash) | ☐ |

---

## Phase 24: Demo Build & Distribution (10 min)

### 24.1 Build Settings

`File → Build Settings`:
- Architecture: x86_64
- Compression: LZ4HC
- Development Build: OFF (for final demo)
- IL2CPP: recommended for performance (but Mono is faster to build for testing)

### 24.2 Player Settings

`Edit → Project Settings → Player`:
- Product Name: **IStalk**
- Company Name: your name
- Default Screen Width: 1920
- Default Screen Height: 1080
- Fullscreen Mode: Fullscreen Window
- Run In Background: **ON** (required for multiplayer — game must tick when alt-tabbed)
- Resolution Dialog: Disabled

### 24.3 Build & Share

1. `File → Build and Run` → pick output folder
2. Output: `IStalk.exe` + `IStalk_Data/` folder
3. Zip the entire build folder
4. Share with testers
5. Everyone connects to same relay server with room codes

---

## Time Estimate: Part 2 Total

| Phase | Task | Time |
|-------|------|------|
| 13 | Complete Inspector Wiring | 30 min |
| 14 | GameScene Full Assembly | 25 min |
| 15 | Incarnation Demo | 10 min |
| 16 | Shrine Purchase Demo | 10 min |
| 17 | Overtime & Sealing | 10 min |
| 18 | Parkour Level Design | 15 min |
| 19 | Noise→Dread Loop | 10 min |
| 20 | Revive System | 10 min |
| 21 | Spectator Camera | 5 min |
| 22 | Audio Placeholders | 10 min |
| 23 | Full Playtest Checklist | 20 min |
| 24 | Build & Distribute | 10 min |
| **TOTAL Part 2** | | **~2.5 hours** |

---

## Grand Total: Zero to Playable Demo

| Part | Work | Time |
|------|------|------|
| Part 1 | Basic greybox (compiles, connects, spawns) | ~3.5 hours |
| Part 2 | Full-featured demo (all mechanics working) | ~2.5 hours |
| **GRAND TOTAL** | | **~6 hours** |

---

## After Demo: Polish Priorities

```mermaid
graph TD
    DEMO[Working Greybox Demo] --> ART[Replace Greybox Art]
    DEMO --> AUDIO[Real Sound Design]
    DEMO --> VFX[Particle Effects]
    DEMO --> UI_POLISH[UI Art + Animations]
    DEMO --> BALANCE[Tune GlobalRules_SO]
    DEMO --> MORE_CONTENT[More Rooms/Items/Traps]

    ART --> ALPHA[Alpha Build]
    AUDIO --> ALPHA
    VFX --> ALPHA
    UI_POLISH --> ALPHA
    BALANCE --> ALPHA
    MORE_CONTENT --> ALPHA

    ALPHA --> PLAYTEST[Playtesting]
    PLAYTEST --> BETA[Beta]
    BETA --> STEAM[Steam Release]

    style DEMO fill:#6bff8f,color:#000
    style ALPHA fill:#ffd06b,color:#000
    style BETA fill:#6bb5ff,color:#fff
    style STEAM fill:#c46bff,color:#fff
```
