# IStalk — Complete Unity Editor Setup Guide

> **Current State:** 80+ C# scripts written (including Eye Types, Wearables, Co-op, Extraction Room systems), 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)
─────────────────                   ────────────────────────
80+ .cs scripts                     2 Scenes (Lobby + Game)
Assembly definitions                Physics layers configured
Folder structure                    Prefabs (18+)
FishNet v4 + Synapse transport      ScriptableObject assets (30)
URP pipeline settings               Materials (greybox)
DOTween                             NetworkManager setup
Custom editor inspectors            Canvas prefabs (4 HUDs)
Eye Type system (3 types)           Input System bindings
Wearable system (6 abilities)       Room prefabs (5)
Co-op mechanics                     Extraction Room prefab
Extraction Room system              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 Eye Type SOs (3 types)

Create in `Assets/Resources/EyeTypes/` (use `IStalk > Create > Eye Type SO`):

| Asset Name | typeId | displayName | Abilities | hasEyelids |
|-----------|--------|-------------|-----------|------------|
| `EyeType_Watcher.asset` | watcher | Watcher | Scan, Incarnation | No |
| `EyeType_Predator.asset` | predator | Predator | Laser, Incarnation | Yes |
| `EyeType_Trapper.asset` | trapper | Trapper | Traps, Scan, Incarnation | No |

**Stat multipliers (fill in Inspector):**

| Type | laserCdMult | laserRadMult | scanCdMult | scanRadMult | trapCostMult | trapMaxBonus |
|------|------------|-------------|-----------|-----------|------------|------------|
| Watcher | 1.0 | 1.0 | 0.6 | 1.3 | 1.0 | 0 |
| Predator | 0.5 | 1.4 | 1.0 | 1.0 | 1.0 | 0 |
| Trapper | 1.0 | 1.0 | 1.0 | 1.0 | 0.6 | 3 |

> **Tip:** Select any EyeType_SO and use the "Preset: Watcher/Predator/Trapper" buttons in the inspector to auto-fill these values.

### 3.6 Wearable SOs (6 wearables)

Create in `Assets/Resources/Items/Wearables/` (use `IStalk > Create > Wearable SO`):

| Asset Name | wearableId | abilityType | isPassive | cooldown | lootCost |
|-----------|-----------|-------------|-----------|----------|----------|
| `Wearable_Dash.asset` | bracelet_dash | Dash | false | 3 | 4 |
| `Wearable_WallRun.asset` | boots_wallrun | WallRun | true | 0 | 5 |
| `Wearable_AirDash.asset` | wings_airdash | AirDash | false | 5 | 6 |
| `Wearable_Slide.asset` | kneepads_slide | Slide | true | 0 | 3 |
| `Wearable_Vault.asset` | gloves_vault | Vault | true | 0 | 3 |
| `Wearable_Grapple.asset` | hook_grapple | Grapple | false | 8 | 8 |

All wearables: `throwRange = 8`, `worldPrefab = null` (for greybox, assign later)

### 3.7 New Shrine Item SOs (4 co-op items)

Add to `Assets/Resources/Items/Shrine/`:

| Asset Name | itemId | itemType | lootCost | effectDuration | cooldown | isConsumedOnUse |
|-----------|--------|----------|----------|----------------|----------|-----------------|
| `Shrine_FlashOrb.asset` | flash_orb | FlashOrb | 6 | 0 | 0 | true |
| `Shrine_LinkedSprint.asset` | linked_sprint_totem | LinkedSprintTotem | 4 | 15 | 30 | false |
| `Shrine_SilenceShroud.asset` | silence_shroud | SilenceShroud | 5 | 20 | 25 | false |
| `Shrine_VitalityLink.asset` | vitality_link | VitalityLink | 7 | 12 | 35 | false |

### 3.8 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
│   ├── RunnerWearableManager.cs      ← NEW: manages 2 wearable slots
│   ├── RunnerCoopActions.cs          ← NEW: ledge boost (F) + bag throw (G)
│   ├── RunnerBuffSystem.cs           ← NEW: proximity buffs (linked sprint, etc.)
│   ├── 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
│   ├── EyeTypeController.cs          ← NEW: master controller, reads EyeType_SO
│   ├── EyeCameraController.cs
│   ├── EyeLaserController.cs
│   ├── EyeScanAbility.cs
│   ├── EyeTrapPlacer.cs
│   ├── DreadEconomy.cs
│   ├── EyeIncarnationController.cs
│   ├── EyeEyelidController.cs        ← NEW: right-click toggle, fullscreen black overlay
│   ├── EyeFlashReceiver.cs           ← NEW: receives flash, checks eyelid state
│   └── 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 (including 3 new ones)
4. Create child Camera "EyeCamera" → Orthographic, Size 20, Rotation (90,0,0), Position (0,50,0)
5. Drag into `Assets/Prefabs/Player/Eye.prefab`

> **EyeTypeController** dynamically enables/disables Laser/Scan/Traps/Incarnation/Eyelid scripts at spawn based on which EyeType_SO asset is selected. The Eye player picks their type in lobby.

---

## 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`

### 7.6 Extraction Room Prefab (NEW)

Use `IStalk > Create > Extraction Room Prefab Setup` or build manually:

```
ExtractionRoom (Empty)
├── NetworkObject
├── ExtractionRoom.cs
├── AntiAfkRitual.cs
├── BoxCollider (trigger, size 15x4x15, center 0,2,0)
├── Floor (Cube, 15x0.1x15, layer: Wall, Mat_Floor)
├── Walls (4x Cube walls with NO connector openings — 1 entrance only)
├── IncarnationProps (6-8 DynamicProp instances scattered inside)
│   ├── Prop_Crate_1
│   ├── Prop_Barrel_1
│   ├── Prop_Table_1
│   ├── Prop_Chair_1
│   ├── Prop_Crate_2
│   └── Prop_Barrel_2
└── Entrance (single gap in one wall, 3m wide)
```

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

> **Important:** The room must be dense with incarnation props (Eye can possess them during the 30s extraction). Only ONE entrance so runners can be trapped.

### 7.7 Wearable World Pickup Prefab (NEW)

```
WearablePickup (Empty)
├── NetworkObject
├── WorldWearable.cs (or reuse WorldItem pattern)
├── SphereCollider (trigger, radius 0.5, layer: Interactable)
├── Visual (Cube mesh, scale 0.3x0.3x0.3, Mat_Shrine — cyan tint)
└── PointLight (range 1.5, intensity 0.4, cyan)
```

Save as `Assets/Prefabs/Props/WearablePickup.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)
│   └── ExtractionRoomTimer (TMP, "EXTRACTING: 25s", hidden until active)
├── Bottom-Left Panel
│   ├── StaminaBar (Image fill, green-to-red gradient)
│   ├── HealthBar (Image fill, red)
│   ├── WeightIndicator (TMP, "LIGHT / MEDIUM / HEAVY")
│   └── BuffIndicators (Horizontal Layout, icons for active buffs)
├── Bottom-Right Panel
│   ├── InventorySlots (6x Image placeholders, horizontal)
│   └── ShrineItemSlot (Image + cooldown ring overlay + "Q" text)
├── Bottom-Center Panel (NEW — Wearable Slots)
│   ├── WearableSlot_1 (Image + border + ability icon + hotkey "1")
│   └── WearableSlot_2 (Image + border + ability icon + hotkey "2")
├── Center
│   └── Crosshair (Image, small dot)
├── Co-op Prompts (hidden by default)
│   ├── BoostPrompt (TMP, "Press F to boost teammate")
│   ├── ThrowPrompt (TMP, "Press G to throw item")
│   └── RitualPrompt (TMP, "Hold V to vote kick AFK player")
└── 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")
│   ├── EyeTypeName (TMP, "PREDATOR", styled per type)
│   └── 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")
├── Right Panel (NEW — Eyelid Status)
│   ├── EyelidIndicator (Image, eye icon, toggles open/closed)
│   ├── EyelidHint (TMP, "RMB: Close Eyes", small)
│   └── FlashCooldown (TMP, "Flash CD: 12s", shows team cooldown)
├── Minimap Panel (RawImage, top-right corner, for RenderTexture)
└── GraceIndicator (TMP, "GRACE PERIOD - 0:30", yellow, hidden after grace)
```

Add `EyeHUD.cs` component. Wire references.

> **Note:** Ability slots should be shown/hidden based on EyeType. A Watcher won't see the Laser slot. A Trapper won't see the Laser slot either. EyelidIndicator only shows if `hasEyelids = true`.

### 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
   - WearablePickup.prefab
   - Altar.prefab
   - Shrine.prefab
   - SlowField.prefab
   - NoiseTrip.prefab
   - PathBlocker.prefab
   - DynamicProp.prefab
   - ExtractionRoom.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 | WearablePickup | Prefabs/Props/ | YES |
| 5 | Altar | Prefabs/Props/ | YES |
| 6 | Shrine | Prefabs/Props/ | YES |
| 7 | SlowField | Prefabs/Props/ | YES |
| 8 | NoiseTrip | Prefabs/Props/ | YES |
| 9 | PathBlocker | Prefabs/Props/ | YES |
| 10 | DynamicProp | Prefabs/Props/ | YES |
| 11 | ExtractionRoom | Prefabs/Props/ | YES |
| 12 | NetworkManager | Prefabs/ | NO (manages others) |
| 13 | GameBoot | Prefabs/ | NO (singleton) |
| 14 | RunnerHUD | Prefabs/UI/ | NO (local UI) |
| 15 | EyeHUD | Prefabs/UI/ | NO (local UI) |
| 16 | LobbyCanvas | Prefabs/UI/ | NO (local UI) |
| 17 | ResultsScreen | Prefabs/UI/ | NO (local UI) |
| 18-22 | 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-13 | Shrine_FlashOrb/LinkedSprint/SilenceShroud/VitalityLink | Resources/Items/Shrine/ | ShrineItemData_SO |
| 14-16 | Trap_SlowField/NoiseTrip/PathBlocker | Resources/Items/Traps/ | TrapData_SO |
| 17-21 | Room_Small_A/B, Medium_A/B, Large_A | Resources/Items/Rooms/ | RoomNode_SO |
| 22-24 | EyeType_Watcher/Predator/Trapper | Resources/EyeTypes/ | EyeType_SO |
| 25-30 | Wearable_Dash/WallRun/AirDash/Slide/Vault/Grapple | Resources/Items/Wearables/ | WearableData_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 > Extraction Room Prefab Setup` | Scaffolds extraction room (trigger + 6 IncarnationProp slots) |
| `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 > Eye Type SO` | Creates a new EyeType_SO asset in Resources/EyeTypes/ |
| `IStalk > Create > Wearable SO` | Creates a new WearableData_SO asset in Resources/Items/Wearables/ |
| `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 (now includes Wearables + EyeTypes) |
| `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/Resources/Items/Wearables/
Assets/Resources/EyeTypes/
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

---

### EyeType_SO Custom Inspector (NEW)

When you select any `EyeType_SO` asset, the inspector shows:

**Ability Summary** — visual matrix showing which of the 4 abilities are enabled (checkmark/cross for each: Laser, Scan, Traps, Incarnation, Eyelids)

**Effective Stats Preview** — reads GlobalRules_SO and shows computed values:
```
Laser:
  Cooldown: 2.0s (base 4.0 x 0.50)
  Radius: 0.49m (base 0.35 x 1.40)
  DPS potential: 0.50 shots/sec

Scan:
  (Disabled for this type)

Traps:
  (Disabled for this type)

Dread:
  Starting Dread: 0 (default)
  Regen rate: 3.0/s (default)
```

**Quick Actions:**
- "Generate ID from Name" — auto-fills `typeId`
- "Preset: Watcher" — sets Scan+Incarnation, faster scan, wider radius
- "Preset: Predator" — sets Laser+Incarnation+Eyelids, faster laser, wider beam
- "Preset: Trapper" — sets Traps+Scan+Incarnation, cheaper traps, +3 max active

**Validation:** Warns on empty ID, no abilities enabled, missing display name

---

### WearableData_SO Custom Inspector (NEW)

When you select any `WearableData_SO` asset, the inspector shows:

**Icon Preview** — shows assigned sprite at 64x64

**Balance Preview:**
```
Ability Info:
  Type: Dash
  Mode: Active (cooldown-based)
  Cooldown: 3.0s
  Max activation rate: 20.0 uses/min

Movement Granted:
  Ground dash burst (directional)
  GlobalRules cooldown: 3.0s

Economy:
  Shrine cost: 4 loot
  Throw range: 8.0m

Slot Impact:
  Occupies 1 of 2 wearable slots
  Weight: 0 (wearables are weightless)
```

**Quick Actions:**
- "Generate ID from Name"
- "Set as Active Ability" — sets isPassive=false, adds default cooldown
- "Set as Passive Ability" — sets isPassive=true, cooldown=0

**Validation:** Warns on empty ID, missing display name, no world prefab, active with 0 cooldown

---

### ExtractionRoom Custom Inspector (NEW)

When you select a GameObject with `ExtractionRoom.cs`:

**Setup Checklist:**
- Validates trigger collider is present and set as trigger
- Counts networked children (IncarnationProps) in the room
- Shows design notes about extraction mechanics

**Runtime State** (play mode only):
- Shows unlocked/timer/runners-inside in real-time

---

### GlobalRules_SO Custom Inspector (UPDATED)

Now includes additional foldout sections:

- **Eye Type Balance** — flash duration, team cooldown, per-type multiplier preview
- **Wearable Balance** — slot count, all ability cooldowns, throw range
- **Co-op Balance** — boost height/range, linked sprint stats, slow duration
- **Extraction Room** — channel duration, anti-AFK ritual duration, min voters

---

### 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) |
| RunnerWearableManager | — | (SyncList, no inspector refs, max 2 slots from GlobalRules) |
| RunnerCoopActions | — | (owner-only, reads GlobalRules for ranges) |
| RunnerBuffSystem | — | (SyncList, proximity checks via GlobalRules) |
| 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 |
|-----------|-------|-----------|
| EyeTypeController | — | (reads EyeType_SO from ItemDatabase at spawn, enables/disables ability scripts) |
| 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 |
| EyeEyelidController | — | (owner-only, RMB toggle, creates UI overlay at runtime) |
| EyeFlashReceiver | — | (server-side, checks eyelid state before applying blind) |

### 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 | ☐ |

### Eye Types (NEW)

| # | Test | Pass? |
|---|------|-------|
| 45 | Eye type selection in lobby works | ☐ |
| 46 | Watcher: only Scan + Incarnation abilities available | ☐ |
| 47 | Predator: only Laser + Incarnation available, has eyelids | ☐ |
| 48 | Trapper: Traps + Scan + Incarnation, cheaper traps | ☐ |
| 49 | Predator eyelids: RMB closes eyes (full blackscreen) | ☐ |
| 50 | Flash orb hits → eyelids closed = flash dodged | ☐ |
| 51 | Flash orb hits → eyelids open = full blind duration | ☐ |

### Wearables & Co-op (NEW)

| # | Test | Pass? |
|---|------|-------|
| 52 | Pick up wearable from ground → equips to slot | ☐ |
| 53 | Max 2 wearables, third pickup rejected | ☐ |
| 54 | Dash wearable: press ability key → ground dash | ☐ |
| 55 | WallRun wearable: sprint + jump near wall → runs on wall | ☐ |
| 56 | Wearable dropped on death, visible to all | ☐ |
| 57 | Co-op boost: crouch at wall + teammate presses F → boosted up | ☐ |
| 58 | Bag throw: aim at teammate + press G → item flies to them | ☐ |
| 59 | Linked Sprint totem: both runners nearby get speed buff | ☐ |
| 60 | Anti-AFK ritual: 2 voters + 20s timer → AFK runner killed | ☐ |

### Extraction Room (NEW)

| # | Test | Pass? |
|---|------|-------|
| 61 | Room door locked until extraction threshold met | ☐ |
| 62 | All alive runners inside → timer starts (30s) | ☐ |
| 63 | Runner leaves room → timer resets | ☐ |
| 64 | Downed runner not required for extraction | ☐ |
| 65 | Timer completes → all runners extracted → Runners Win | ☐ |
| 66 | Eye can incarnate props inside room during extraction | ☐ |

### Match Flow

| # | Test | Pass? |
|---|------|-------|
| 67 | Lobby: Create room → get code | ☐ |
| 68 | Lobby: Join with code → player count updates | ☐ |
| 69 | Start Game → all load GameScene together | ☐ |
| 70 | Grace period: timer shows, Eye abilities blocked | ☐ |
| 71 | Grace ends → normal play begins | ☐ |
| 72 | Timer reaches 0 → "OVERTIME" message | ☐ |
| 73 | Rooms seal every N seconds (orange barriers appear) | ☐ |
| 74 | Overtime timer expires → Eye wins | ☐ |
| 75 | Results screen shows stats, buttons work | ☐ |
| 76 | Return to Lobby → back in lobby, can play again | ☐ |
| 77 | 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
```
