# Phase F.E — staged event manifests for the 13x13 Holtburg ring

Each `0xXXXX.events.jsonl` file contains the per-LB expected event
manifest baked by Phase F.B (commit `cc42434`). Renderer consumers
fetch one file per LB on demand, mirroring `dist/scenery/` and
`dist/spawns/`.

## Ring

13 x 13 landblocks centred on Holtburg (LB 0xA9B4). 169 LBs total —
identical ring to Phases C.1 (scenery) + D.1 (spawns).

## Schema (per JSONL line)

Three event kinds appear:

### Ambient (`source: "ambient"`)

```jsonc
{
  "source":         "ambient",
  "trigger":        "terrain",
  "terrain_type":   1,
  "scene_type":     0,
  "scene_info_idx": 18,
  "stb_index":      9,
  "stb_id":         "0x2000001B",
  "vertex_indices": [0, 19, 20, ...],  // 81-vertex LB indices
  "ambient_sounds": [
    {"s_type": 70, "volume": 0.25, "base_chance": 0.0,
      "min_rate": 8.27, "max_rate": 8.27, "continuous": true},
    ...
  ]
}
```

- `base_chance == 0 && continuous` → one continuous loop while
  terrain_type is active at the player's vertex.
- `base_chance > 0 && !continuous` → probabilistic roll per
  `[min_rate, max_rate]` interval.

### PhysicsScript particle (`source: "physics_script_particle"`)

```jsonc
{
  "source":           "physics_script_particle",
  "trigger":          "physics_script_particle",
  "default_script_id":"0x3300067A",
  "start_time_s":     0.0,
  "emitter_id":       "0x320002CD",
  "part_index":       0,
  "blocking":         false,
  "anchor":           "entity_origin"
}
```

Each row is one CreateParticle hook in a `PhysicsScript` referenced
from a spawned entity's `default_script_id`. The H2 walker in
`scene3d/entities.js` consumes these at spawn time.

### Anim sound (`source: "anim_sound"`) — DEFERRED

Anim-sound rows are NOT in the F.B bake. The F.B docs flag this as
"channel not yet exercised through synthetic spawn data; awaiting
F.B.5 (wcid -> MotionTableDataId staging)". The F.D validator
reports `anim_sound: 0 observed / 0 expected` for the ring.

## Notes

- **Empty files are intentional.** 0 of
  169 LBs in the ring produced zero events at bake
  time (no ambient + no entity hooks). The runtime treats an empty
  file as "queried, zero events" (not 404 "not yet baked").
- **`event-bake-source.sha256`** carries the input DAT hashes + the
  bake-tool version. F.E consumers verify their DATs match before
  honouring the manifest, same contract as `scenery/bake-source.sha256`.

## Reproducibility

```sh
python3 stage-ring-events.py
```

Deterministic given the same F.B bake input. Source:
`/mnt/wbterminal1/tmp/claude-scratch/event-completeness/b/holtburg-ring` (frozen at commit cc42434).
