# @ferret/levels: API (continued)

### CollisionChunksDef

*interface* · `packages/levels/src/collision-chunks.ts:10`

```ts
interface CollisionChunksDef
```

- `loadRadius: number`
- `unloadRadius: number`
- `chunks: CollisionChunkDef[]`

### Environment

*interface* · `packages/levels/src/environment.ts:106`

```ts
interface Environment
```

- `post?: BABYLON.DefaultRenderingPipeline`
- `sun?: BABYLON.DirectionalLight`
- `ambient?: BABYLON.HemisphericLight`
- `sky?: BABYLON.Mesh`
- `particles: BABYLON.ParticleSystem[]`
- `water: WaterSurfaceView[]`
- `lights?: LightBudget`
- `warnings: string[]` — effects that could not be made (an unknown kind)
- `dispose(): void`

### EnvironmentDef

*interface* · `packages/levels/src/environment.ts:16`

```ts
interface EnvironmentDef
```

The look of a level beyond its meshes: sun, ambient light, fog, sky and fixed effects. It is the manifest's `environment`;
`tools/ue-export` writes it from an Unreal level (sun, sky light, height fog, particle emitters). Every part is optional.

- `sun?: { direction: Vec3; color?: Vec3; intensity?: number }` — the directional light; `direction` is where the light travels. `intensity` is in the source engine's units (Unreal lux-like): 4 is about 1 here
- `ambient?: { color?: Vec3; intensity?: number; direction?: Vec3; ground?: Vec3 }` — ambient light from the sky: a hemispheric light, a bit darker below. `direction` is the way its bright side faces (default up: floors are lit most); `ground` is the colour of the dark side (default `color` x 0.45). An interior lit from its ceiling faces it down: [0, -1, 0].
- `fog?: { density?: number; color?: Vec3; heightFalloff?: number; height?: number; maxOpacity?: number; start?: number; cutoff?: number; second?: { density: number; heightFalloff: number; heightOffset?: number } }` — exponential fog; `density` in the source engine's units (per metre, about 10 times smaller here). With `heightFalloff` it is Unreal's ExponentialHeightFog: the density halves every 1 / (falloff x 0.1) metres above `height` (the fog actor's height, metres) and grows below it; the view's density follows the camera's height every frame. `second` is the component's second fog layer. Not done: `maxOpacity`, `start` and `cutoff` (Babylon's exponential fog has no such terms; they are carried in the manifest for a tool that wants them).
- `skyAtmosphere?: AtmosphereDef` — Unreal's SkyAtmosphere: the sky dome is the scattering of the sun's light in the planet's air (see atmosphere.ts) instead of the colour gradient. `{}` is the component's defaults. The sun gives the direction and colour; `top` / `horizon` / `ground` of `sky` still override the colours the water, the reflection and the fog take from it. The level's BP_Sky_Sphere actor adds nothing: the engine's sky sphere only recolours itself when a level asks it to, and the dome replaces it (`postprocess` drops the actor).
- `sky?: { top?: Vec3; horizon?: Vec3; ground?: Vec3 }` — the sky dome: a gradient from `horizon` to `top` with the sun's glow; colours default from the fog colour
- `reflection?: { intensity?: number; top?: Vec3; horizon?: Vec3; ground?: Vec3 }` — what metal and gloss reflect: a small cube map filled with a gradient (`top` / `horizon` / `ground` of its own, else the sky's), as the scene's environment texture. Without it a metal surface has nothing to reflect and draws near black (an interior has no sky for it). `intensity` scales both the reflection and the light the map adds to every surface (default 1; interiors want 0.3-0.6).
- `post?: { bloom?: number; threshold?: number }` — post-processing of the picture: `bloom` is the source engine's bloom intensity (Unreal's post process volume: 0.675 default, a glowing interior 3-4); bright parts (lamps, windows) glow around. A tier for weak GPUs leaves it out. `threshold` is the brightness that starts to glow (default 0.95).
- `probes?: ProbeVolumeDef` — baked global illumination (`tools/ue-export/bake-gi`): when present it lights every surface instead of the flat `ambient` light
- `effects?: { name?: string; kind?: 'fire'; template?: string; position: Vec3; scale?: number }[]` — fixed effects placed in the level
- `water?: WaterDef | WaterDef[]` — open water: an ocean or a lake (see water.ts); swimming in it is the physics medium of the same surface
- `landscapes?: LandscapeDef[]` — layered landscapes (near ground, far backdrop) and the virtual texture blend of the props on them (see landscape.ts); the package loader applies them
- `lights?: LightBudgetDef` — hundreds of lamps and flames under a budget: the nearest few are real lights, the rest glow (see light-budget.ts)

### Focus

*interface* · `packages/levels/src/streaming.ts:24`

```ts
interface Focus
```

A place the player (or a camera) is, with the way it faces: cells ahead are fetched first.

- `position: BABYLON.Vector3`
- `forward?: BABYLON.Vector3`

### HeightFogDef

*interface* · `packages/levels/src/height-fog.ts:9`

```ts
interface HeightFogDef
```

- `density: number`
- `heightFalloff: number`
- `height: number` — height of the fog actor, metres
- `second?: HeightFogLayer`

### HeightFogLayer

*interface* · `packages/levels/src/height-fog.ts:7`

```ts
interface HeightFogLayer
```

- `density: number`
- `heightFalloff: number`
- `heightOffset?: number`

### LandscapeDef

*interface* · `packages/levels/src/landscape.ts:45`

```ts
interface LandscapeDef
```

- `name: string`
- `mesh?: string` — regex source for the landscape's mesh names (default `^<name>$`)
- `rect: [number, number, number, number]` — [minX, minZ, maxX, maxZ], metres, in the mesh's own coordinates; the weightmaps and the virtual texture cover it
- `layers: LandscapeLayerDef[]`
- `weights: string[]` — weightmap images over `rect`: file i holds the weights of layers 4i..4i+3 in R, G, B, A
- `far?: boolean` — the far backdrop: no collision, never picked, always drawn; layers and weights are optional for it
- `virtualTexture?: VirtualTextureDef`

### LandscapeLayerDef

*interface* · `packages/levels/src/landscape.ts:20`

```ts
interface LandscapeLayerDef
```

- `name: string`
- `albedo: string` — colour image (sRGB); with `heightBlend` its alpha channel is the layer's height map
- `normal?: string` — optional tangent-space normal image
- `tile: number` — metres of one repeat of the layer's textures (Unreal: 100 / the material's UV scale)
- `tint?: Vec3` — multiplies the albedo (linear)
- `heightBlend?: number` — 0 = plain weight blend; above 0 = Unreal's height blend, the layer's height (albedo alpha) times this decides who wins where weights overlap

### LandscapeTextures

*interface* · `packages/levels/src/landscape.ts:192`

```ts
interface LandscapeTextures
```

- `weights: BABYLON.BaseTexture[]`
- `albedo: BABYLON.BaseTexture[]`
- `normal: (BABYLON.BaseTexture | undefined)[]`

### LandscapeView

*interface* · `packages/levels/src/landscape.ts:315`

```ts
interface LandscapeView
```

- `def: LandscapeDef`
- `meshes: BABYLON.AbstractMesh[]`
- `virtualTexture?: BABYLON.BaseTexture` — the baked virtual texture (colour in rgb, ground height in a), when the landscape has one
- `requiredMaxZ?: number` — camera depth (maxZ) a far landscape needs to be seen whole: the rectangle's diagonal plus the camera's height over it, rounded up
- `warnings: string[]`
- `dispose(): void`

### LevelContext

*interface* · `packages/levels/src/levels.ts:10`

```ts
interface LevelContext
```

What a level's builder gets. Everything it makes (nodes, lights, materials, entities) is removed again when the level goes.

- `world: World`
- `scene: BABYLON.Scene`
- `level: LevelDef`
- `addSpawn(s: { id: string; position: BABYLON.Vector3 | [number, number, number]; yaw?: number }): void` — declare where the player may start
- `progress(p: number): void` — report progress 0..1 to the loading screen

### LevelDef

*interface* · `packages/levels/src/levels.ts:21`

```ts
interface LevelDef
```

One entry of the level registry (the equivalent of a row of UE's DT_LevelInfo).

- `id: string`
- `name?: string`
- `url?: string` — a level package folder: scene.glb, manifest.json, navmesh.bin (see ./package)
- `build?(ctx: LevelContext): void | Promise<void>` — or code that builds the level: procedural levels, greyboxes, tests
- `spawn?: string` — the spawn used when the level is entered without naming one (default: the first declared)
- `data?: Record<string, unknown>` — anything the game wants to keep with the level: music, weather, display name
- `tags?: string[]` — free tags (a theme, a chapter): handed to the game's choices, never read by the engine
- `prepare?(progress: (p: number) => void, signal?: AbortSignal): Promise<void>` — Get what the level needs ready before the old level is touched (a remote level opens its package here). If it throws the travel fails and the player stays in the current level. `progress` takes 0..1 of this step.
- `plan?(): Promise<LevelPlan>` — What fetching the level will download, known after `prepare`: bytes and files not held yet, and whether everything is already on the device.
- `fetch?(ctx: { signal: AbortSignal; progress(loaded: number, total: number, files: number): void; /** files read at once (default: the level's own choice; a background prefetch asks for 1) */ concurrency?: number }): Promise<void>` — Step 4 of a travel: bring the core set of the level to the device. `progress` takes bytes. A failure or a cancel leaves the old level in place.

### LevelManifest

*interface* · `packages/levels/src/manifest.ts:67`

```ts
interface LevelManifest
```

- `version: number`
- `name?: string`
- `scene?: string` — file names inside the package folder (defaults: scene.glb, navmesh.bin)
- `navmesh?: string`
- `navBuild?: { agentRadius?: number; agentHeight?: number; maxClimb?: number; maxSlope?: number; cellSize?: number; bounds?: NavBoxDef | NavBoxDef[]; exclude?: (NavBoxDef & { yaw?: number })[] }` — how to build the NavMesh from the level's solid meshes: used when navmesh.bin is missing (or being rebuilt by the editor)
- `collision?: string` — a mesh of simple collision shapes (invisible, solid). When present, the visible meshes of the scene do not collide
- `collisionChunks?: CollisionChunksDef` — the solid shapes outside the play area, cut into chunks that are fetched as the player nears them (see CollisionChunksDef); written by tools/ue-export/collision.mjs. Needs `collision`
- `movement?: Partial<Record<(typeof MOVEMENT_KEYS)[number], number>>` — the values of the level's player character (metres, seconds; see CharacterParams in
- `animGraphs?: Record<string, unknown>` — animation graphs by name (see GraphDef in
- `entities?: ManifestEntity[]`
- `spawns?: ManifestSpawn[]`
- `zones?: unknown[]`
- `physics?: Record<string, unknown>` — realistic physics for this level (see PhysicsConfig in
- `libraries?: Record<string, string>` — the library packages the level needs, id -> version range: written by the editor from what the open libraries `provide`; `travel` requires them before the level is built
- `colliders?: { node: string; collide: boolean }[]` — collision overrides by glTF node name: make a node (and its meshes) solid or walk-through whatever the export says
- `defaultSpawn?: string` — the spawn used when the level is entered without naming one
- `environment?: EnvironmentDef` — sun, ambient light, fog, sky and fixed effects (see EnvironmentDef)
- `tags?: string[]` — free tags and data for the game (a theme, a chapter, a mood): handed to the game's choices (`LevelDef.tags` / `data`), never read by the engine
- `data?: Record<string, unknown>`
- `streaming?: StreamingBlock` — streaming inside the level: `scene` is then the core (what is visible and solid at the spawn) and the rest arrives by cell

### LevelOptions

*interface* · `packages/levels/src/levels.ts:80`

```ts
interface LevelOptions
```

Minimum time the loading screen stays up, so it does not flash (ms; 0 in tests).

- `minLoadingMs?: number`
- `slowMs?: number` — no new bytes for this long while the target downloads: `travel:slow` {slow: true} (default 5000)
- `holdMs?: number` — the longest the level waits, after it is built, for what its entities asked to be waited for (`hold`) before it is announced ready anyway (default 20000; what was missing goes to the report's warnings)
- `keepOldUntilReady?: boolean` — true on devices with room: a failed travel rebuilds the old level and returns the player to the spot; false (console): to the hub
- `transitionEnterMs?: number` — how long a transition has to get on screen before the engine's bar replaces it (default 2000)

### LevelPlan

*interface* · `packages/levels/src/levels.ts:45`

```ts
interface LevelPlan
```

- `bytes: number`
- `files: number`
- `cached: boolean`

### LevelReport

*interface* · `packages/levels/src/levels.ts:74`

```ts
interface LevelReport
```

- `warnings: string[]` — things the manifest asked for that the level could not provide: missing nodes, unknown behaviours ...

### LibraryCharacter

*interface* · `packages/levels/src/library.ts:67`

```ts
interface LibraryCharacter
```

- `readonly id: string`
- `readonly item: CharacterItem`
- `readonly model: ModelHandle`
- `readonly clips: ClipRef[]` — the clip sets of the character, resolved from the catalog
- `dispose(): void`

### LibraryContext

*interface* · `packages/levels/src/code.ts:18`

```ts
interface LibraryContext
```

What `install` gets.

- `world: World`
- `ferret: any` — the engine's API (every package's exports in one namespace)
- `pkg: { id: string; version: string; manifest: FerretPackage['manifest'] }` — this package
- `mount: PackageMount`
- `url(path: string): Promise<string>` — a blob URL for a file of this package, or `ferret://dep/path` of a declared dependency
- `require(id: string): unknown` — the exports of a declared dependency's code (already loaded before this one)

### LibraryEntry

*interface* · `packages/levels/src/library.ts:35`

```ts
interface LibraryEntry extends CatalogAsset
```

- `id: string`

### LibraryModel

*interface* · `packages/levels/src/library.ts:54`

```ts
interface LibraryModel
```

A static library model on its way (a tree, a rock): `model` is the handle, `item` its file (bounds, collision).

- `readonly id: string`
- `readonly item: ModelItem`
- `readonly model: ModelHandle`
- `dispose(): void`

### LibraryModule

*interface* · `packages/levels/src/code.ts:32`

```ts
interface LibraryModule
```

What a package's code module exports. `install` may return `{ dispose }` or a promise of it.

- `install?(ctx: LibraryContext): unknown`
- `[name: string]: unknown`

### LibraryQuery

*interface* · `packages/levels/src/library.ts:34`

```ts
interface LibraryQuery
```

- `type?: LibraryItem['type']`
- `tags?: string[]`
- `text?: string`

### LightBudgetDef

*interface* · `packages/levels/src/light-budget.ts:39`

```ts
interface LightBudgetDef
```

- `budget: number` — how many real lights at most. A quality tier sets it in its own manifest (a weak GPU 2-3, a strong one 8-12)
- `items: BudgetLight[]`
- `interval?: number` — seconds between two re-rankings (default 0.25)
- `fade?: number` — seconds a light takes to fade out of / into a real light (default 0.35)
- `hysteresis?: number` — a new light must be nearer than the one it replaces by this share to take its place (default 0.15): no flapping between two equal lamps
- `maxDistance?: number` — lights farther from the camera than this are nothing at all (default 200 m)
- `glow?: { enabled?: boolean; /** colour multiplier (above 1 feeds bloom), default 2 */ boost?: number; /** metres, default from each light's range */ size?: number }` — the dot for lamps that are not real lights
- `sounds?: { budget: number; maxDistance?: number }` — the nearest lamps that have a `sound`: events tell which to start and stop

### LightBudgetOptions

*interface* · `packages/levels/src/light-budget.ts:119`

```ts
interface LightBudgetOptions
```

- `name?: string`
- `viewer?: () => Vec3 | undefined` — where the viewer is, in the level's metres; default the active camera
- `materials?: boolean` — raise the materials' light limit to fit the pool plus the sun and ambient lights (default true)

### LightBudgetStats

*interface* · `packages/levels/src/light-budget.ts:117`

```ts
interface LightBudgetStats
```

- `items: number`
- `budget: number`
- `real: number`
- `glowing: number`
- `reranks: number`
- `soundsOn: number`

### LoadedCode

*interface* · `packages/levels/src/code.ts:37`

```ts
interface LoadedCode
```

- `id: string`
- `version: string`
- `exports: LibraryModule | null` — the module's exports; null for a package without code (only its dependencies were loaded)
- `commands: string[]` — commands and behaviours that appeared while `install` ran
- `behaviours: string[]`

### ManifestEntity

*interface* · `packages/levels/src/manifest.ts:11`

```ts
interface ManifestEntity
```

- `id: string`
- `behaviour?: string` — a behaviour or component registered in the world (`world.components`)
- `components?: { name: string; params?: Record<string, unknown> }[]` — several components, each with its own parameters, when one behaviour is not enough
- `node?: string` — the name of a glTF node to wrap; without it a new empty node is made
- `transform?: { position?: [number, number, number]; rotation?: [number, number, number]; scale?: [number, number, number] }` — local transform applied to the node (or the new node)
- `params?: Record<string, unknown>`
- `tags?: string[]`
- `needs?: string` — the id of a streaming bundle this entity depends on: it is created once the bundle is in, and a placeholder stands at its position until then. It may also be the id of a streaming cell: the entity wraps a node of that cell, is made whenever the cell is resident and destroyed when the cell is released (no placeholder)

### ManifestIssue

*interface* · `packages/levels/src/manifest.ts:105`

```ts
interface ManifestIssue
```

- `path: string`
- `message: string`

### ManifestSpawn

*interface* · `packages/levels/src/manifest.ts:65`

```ts
interface ManifestSpawn
```

- `id: string`
- `position: [number, number, number]`
- `yaw?: number`

### MaterialOptions

*interface* · `packages/levels/src/library.ts:83`

```ts
interface MaterialOptions
```

- `variant?: string`
- `name?: string`
- `scene?: BABYLON.Scene`

### ModelHandle

*interface* · `packages/levels/src/runtime.ts:36`

```ts
interface ModelHandle
```

A model on its way. `node` is the placeholder until the model is in, then the model's root.

- `readonly ref: string`
- `readonly state: ModelState`
- `readonly node: BABYLON.TransformNode | null`
- `readonly ready: Promise<{ root: BABYLON.TransformNode; dispose(): void } | null>` — resolves with the instance, or null when it failed or was disposed (the reason is in `error` and the `asset:failed` event)
- `readonly error?: StreamError`
- `dispose(): void`

### ModelOptions

*interface* · `packages/levels/src/runtime.ts:24`

```ts
interface ModelOptions extends Pick<RequireOptions, 'priority' | 'signal' | 'sha256' | 'size' | 'pkg'>
```

- `placeholder?: PlaceholderSpec` — shown at once, replaced by the model (default: a small box); `'none'` shows nothing until the model is in
- `parent?: BABYLON.TransformNode` — the node the model hangs from (an entity's node): the placeholder and then the model are its children
- `position?: [number, number, number]`
- `name?: string`

### ModelPlacement

*interface* · `packages/levels/src/library.ts:51`

```ts
interface ModelPlacement extends Omit<ModelOptions, 'pkg'>
```

- `tier?: LibraryTier`
- `yaw?: number`

### MountAssets

*interface* · `packages/levels/src/ferret.ts:13`

```ts
interface MountAssets extends PackageAssets
```

What the mount needs from the asset cache (an AssetCache fits).

- `load(url: string, ext?: string): Promise<void>`

### MountOptions

*interface* · `packages/levels/src/ferret.ts:20`

```ts
interface MountOptions
```

- `packages?: PackageSet` — the packages that are open together (default: a new set); `ferret://<id>/<path>` is looked up in it
- `loader?: Partial<PackageLoaderOptions>` — passed on to the level loader (collisions, an editor's draft manifests ...)
- `fetch?: (url: string) => Promise<FetchResult>` — replace `fetch` for urls that are not in a package

### PackageAssets

*interface* · `packages/levels/src/package.ts:12`

```ts
interface PackageAssets
```

What the loader needs from `@ferret/assets` (an AssetCache fits).

- `load(url: string): Promise<void>`
- `instantiate(url: string, name?: string): Promise<{ root: BABYLON.TransformNode; dispose(): void }>`
- `release(url: string): void`

### PackageCommandHooks

*interface* · `packages/levels/src/commands.ts:7`

```ts
interface PackageCommandHooks
```

- `resolve?: (url: string) => PackageInput | Promise<PackageInput>` — turn a url or name into something `FerretPackage.open` reads (default: the url itself)
- `opened?: (pkg: FerretPackage, url: string) => void` — told when a package was opened from `url` (so a host can write changes back to where it came from)
- `write?: (pkg: FerretPackage, name: string, bytes: Uint8Array) => Promise<void>` — write a built `.ferret` (a file next to the source, a download); without it `pkg.pack` only reports what it built
- `publish?: (files: Record<string, Uint8Array>) => Promise<void>` — put the files of `pkg.publish` where the server serves them: { path: bytes }, paths relative to the site root (a folder to upload, a CDN)
- `persist?: (pkg: FerretPackage) => Promise<{ files?: number; bytes?: number; appended?: number; dead?: number; compacted?: boolean } | void>` — keep an edited package: a folder package writes its changed files, a zip is packed again. Called by \`pkg.save\`
- `compact?: (pkg: FerretPackage) => Promise<{ before: number; after: number }>` — write a project (`.fprj`) again without the bytes its saves left behind (`compactZip`): where it came from, or a download. Called by `pkg.compact`
- `behaviours?: () => Iterable<string>` — behaviours the game registers itself (for \`pkg.validate\`)
- `trusted?: () => Iterable<string> | undefined` — key ids the reader trusts (for \`pkg.verify\` and the code check)

### PackageLoaderOptions

*interface* · `packages/levels/src/package.ts:18`

```ts
interface PackageLoaderOptions
```

- `assets: PackageAssets`
- `fetch?: (url: string) => Promise<{ ok: boolean; status: number; json(): Promise<any>; arrayBuffer(): Promise<ArrayBuffer> }>` — replace `fetch` (tests, a Platform file API)
- `collisions?: boolean` — make the level's meshes collide (default true)
- `manifest?: (def: LevelDef) => LevelManifest | undefined` — a manifest to use instead of the one in the package: the editor's draft (return undefined to load the file)
- `streamingRadiusScale?: number` — scale the streaming radii of every streamed level (a tier may ask for less)
- `forceNavBuild?: (def: LevelDef) => boolean` — build the NavMesh from `navBuild` even if navmesh.bin exists (the editor, after a rebuild)

### PrefetchOptions

*interface* · `packages/levels/src/prefetch.ts:15`

```ts
interface PrefetchOptions
```

- `settleMs?: number` — wait this long after a level is ready before the first background download (the level's own first seconds come first)
- `margin?: number` — safety factor on the estimate: start early enough to finish in `eta * margin` (default 1.5)
- `assumedRate?: number` — assumed link speed in bytes/s until something has been measured (default: unknown, so hints start at once)
- `now?: () => number`
- `setTimer?: (fn: () => void, ms: number) => unknown`
- `clearTimer?: (t: unknown) => void`

### PreviewOptions

*interface* · `packages/levels/src/transitions.ts:146`

```ts
interface PreviewOptions
```

- `seconds?: number` — how long the fake download lasts
- `bytes?: number`
- `files?: number`
- `fail?: boolean` — end with a failure instead of readiness (to see the game's failure screen)
- `cached?: boolean` — `cached`: plan says the wait is short
- `signal?: AbortSignal`

### ProbeVolumeDef

*interface* · `packages/levels/src/probe-volume.ts:6`

```ts
interface ProbeVolumeDef
```

Baked global illumination: a regular grid of L1 spherical harmonics (the radiance arriving at each point, RGB), written by
`tools/ue-export/bake-gi`. The shader of every PBR material looks up the grid trilinearly at the surface and adds the diffuse light the
lamps, the sky and the bounces give there. It replaces the flat hemispheric ambient light (which the loader turns off when a volume exists).

- `file: string` — the baked grid, relative to the package: `probes.bin`
- `origin: [number, number, number]` — the position of the first probe, metres
- `spacing: number` — metres between probes
- `dims: [number, number, number]` — probes along x, y, z
- `gain?: number` — scale of the baked light (default 1)
- `fill?: number` — how much of the level's flat `ambient` light stays on beside the baked light, 0..1 (default 0: none). A hemispheric fill that brightens ceilings and darkens floors where the bake's bounce light is short
- `down?: number` — the share of the baked light that faces turned down (ceilings) get, 0..1 (default 1: all of it)

### RunOptions

*interface* · `packages/levels/src/transitions.ts:84`

```ts
interface RunOptions
```

- `enterTimeoutMs?: number`
- `log?: (event: string, detail: Record<string, unknown>) => void`

### RuntimeAssetsOptions

*interface* · `packages/levels/src/runtime.ts:46`

```ts
interface RuntimeAssetsOptions
```

- `store: AssetStore`
- `models: MountAssets` — loads and instantiates glTF (an `AssetCache`, or `mount.assets` when packages are in use)
- `mount?: PackageMount` — needed for `ferret://` references

### SpawnPoint

*interface* · `packages/levels/src/levels.ts:7`

```ts
interface SpawnPoint
```

- `id: string`
- `position: BABYLON.Vector3`
- `yaw: number`

### StreamCellDef

*interface* · `packages/levels/src/manifest.ts:29`

```ts
interface StreamCellDef
```

One grid cell of a streamed level: visual content only; collision is whole-level and resident. `bounds` = [minX, minY, minZ, maxX, maxY, maxZ].

- `bounds: [number, number, number, number, number, number]`
- `file: string`
- `size?: number`
- `priority?: number`
- `pinned?: boolean` — always resident (the play area round the spawn): fetched first, part of the ready gate, never released and never evicted for memory
- `layer?: string` — a key of `layers`: the cell uses that layer's radii instead of the block's (foliage is wanted closer than houses)
- `memory?: number` — bytes the cell takes once resident (geometry plus decoded textures); counted against `memoryBudget`. Default: `size`
- `lod?: string` — a low-poly stand-in shown while the cell is farther than `loadRadius` but within `lodRadius` (a few percent of the cell's triangles, no textures worth the name)

### StreamingBlock

*interface* · `packages/levels/src/manifest.ts:42`

```ts
interface StreamingBlock
```

The `streaming` block. A level without it loads whole, as before.

- `cell: number` — the grid size in metres the cells were cut with (informational for tools)
- `cells: Record<string, StreamCellDef>`
- `loadRadius: number` — metres from the player: cells inside are loaded (and are part of the ready gate at the spawn)
- `unloadRadius: number` — cells farther than this are released; must be at least `loadRadius`
- `bundles?: Record<string, { files: string[]; trigger?: string }>` — groups of files loaded together when a zone is entered (or on demand)
- `lodRadius?: number` — metres from the player within which a cell's `lod` stand-in is shown; at least `loadRadius` (default: `unloadRadius`)
- `layers?: Record<string, { loadRadius?: number; unloadRadius?: number; lodRadius?: number }>` — radii per kind of cell, over the block's: a cell names its layer in `layer`. `unloadRadius` must not be below `loadRadius` (that gap is the hysteresis)
- `memoryBudget?: number` — bytes of cells that may be resident at once (this tier's cap: every tier package has its own block). Pinned cells are counted but never evicted; a nearer cell takes the place of farther ones, and when it still does not fit it waits (event `stream:budget`)
- `maxPerFrame?: number` — pacing over the service's defaults (2 cells and 4 ms per update, 3 fetches at once); the host's options win
- `budgetMs?: number`
- `concurrency?: number`
- `texturesProgressive?: boolean` — reserved: low mips first, upgrade later; nothing acts on it yet

### StreamingOptions

*interface* · `packages/levels/src/streaming.ts:26`

```ts
interface StreamingOptions
```

- `at(file: string): string` — where the level's files are (cell and bundle file names are relative to it)
- `focus?: () => Focus[]` — the places that matter, asked every update; when it gives none (or is left out): the persistent entities of the level service, else the active camera
- `radiusScale?: number` — scale both radii (a tier may ask for less)
- `memoryBudget?: number` — bytes of resident cells, over the block's `memoryBudget` (a tier or a device may ask for less)
- `maxPerFrame?: number` — most cells instantiated in one update
- `budgetMs?: number` — milliseconds of instantiation work per update; at least one cell is always added when something waits, so streaming cannot starve
- `concurrency?: number` — most cells fetched at once
- `now?: () => number`

### Transition

*interface* · `packages/levels/src/transitions.ts:36`

```ts
interface Transition
```

- `enter(ctx: TransitionContext): Promise<void> | void` — The travel starts. Show something at once. Resolve when it is on screen (after 2 s the engine's bar takes over).
- `update(p: TransitionProgress): void` — The target's progress, many times a second.
- `ready(ctx: TransitionContext): Promise<void> | void` — The target is ready. Resolve when the game wants to leave: a door has opened, a button was pressed, a timer ran out.
- `fail(ctx: TransitionContext, err: StreamError): boolean | void | Promise<boolean | void>` — The target failed or the player cancelled. Return true when the transition shows the failure itself (Retry / Back); otherwise the engine's screen is shown.
- `dispose(): void`

### TransitionContext

*interface* · `packages/levels/src/transitions.ts:15`

```ts
interface TransitionContext
```

- `from: LevelDef | null`
- `to: LevelDef`
- `plan: LevelPlan` — what the travel will download; `cached` means a short wait is expected
- `world: World`
- `events: EventBus`
- `ui?: UIService` — the services a game's splash usually wants, when the game has them
- `audio?: unknown`
- `input?: unknown`
- `xr?: { active: boolean; state: string }` — the VR session service when the game has one: a transition may show its interlude world in the headset; `xr.active` says whether a session runs
- `persistent: Set<Entity>` — the player and what travels with them
- `host?: SceneHost` — the scene host (5.3): make a second world for an interlude with `host.create`, show it with `host.show`. The engine shows the level's world again when the player is let in. Present when the game added a `SceneHost`.
- `signal: AbortSignal` — the player cancelled

### TransitionProgress

*interface* · `packages/levels/src/transitions.ts:13`

```ts
interface TransitionProgress
```

What a transition is told, many times a second, while the target downloads. Numbers are honest bytes of what the target needs.

- `loaded: number`
- `total: number`
- `files: number`
- `rate: number`
- `eta: number`
- `phase: string`

### TravelOptions

*interface* · `packages/levels/src/levels.ts:62`

```ts
interface TravelOptions
```

- `spawn?: string`
- `keep?: Entity[]` — keep these entities: they move to the new level's spawn instead of being removed (the player)
- `keepOld?: boolean` — Keep the old level's way back: if the new one fails after the old was released, build the old one again and put the player where they were (default: LevelOptions.keepOldUntilReady, else the hub).
- `signal?: AbortSignal` — Cancel from a menu: before the old level is released the player simply stays; later they are put back.
- `transition?: string` — The game's transition for this travel, by the name it registered (else its chooser, else `default`, else the engine's bar).

### ValidateOptions

*interface* · `packages/levels/src/ferret.ts:167`

```ts
interface ValidateOptions
```

- `packages?: PackageSet` — the other open packages, for `ferret://` references and dependencies
- `behaviours?: Iterable<string>` — behaviours the game registers itself (besides those packages provide); when given, an unknown behaviour is an issue
- `checksums?: boolean` — check the sha256 of every file (default true)
- `engine?: EngineVersions | false` — the engine that is running; default this build's (`FERRET_VERSION`, `BABYLON_VERSION`); `false` skips the check of the manifest's `engine`
- `tierView?: boolean` — set when `pkg` is already one tier's view of a game (its own call for each tier)

### VirtualTextureDef

*interface* · `packages/levels/src/landscape.ts:34`

```ts
interface VirtualTextureDef
```

- `resolution?: number` — texels along the longer side of the rectangle (default 2048)
- `blendHeight?: number` — metres above the ground over which a prop's albedo fades from the ground colour to its own (default 1.5)
- `strength?: number` — 0..1, how much of the ground colour a prop takes at its foot (default 1)
- `meshes: string` — regex source: the meshes (by name, anywhere in the level) whose materials sample the virtual texture

### WaterDef

*interface* · `packages/levels/src/water.ts:19`

```ts
interface WaterDef
```

- `level: number` — y of the surface at rest
- `centre?: [number, number]` — centre (x, z) and size (x, z) of the surface, metres
- `size?: [number, number]`
- `absorption?: Vec3` — the colour of the water seen from above when deep: Unreal's single-layer water `Absorption` is the distance per colour channel (cm) light goes before it is gone, `Scattering` how much the water sends back; the colour is the scattering tinted by those distances
- `scattering?: Vec3`
- `sky?: { top?: Vec3; horizon?: Vec3 }` — the colour of the sky it reflects (default the sky's horizon / top)
- `roughness?: number` — 0..1 (default 0.02)
- `specular?: number` — 0..1, the part of the sky a calm surface reflects head-on (default 0.02, about water's Fresnel at normal incidence)
- `waves?: WaterWave[]`
- `opacity?: number` — 0..1, how opaque the surface draws (default 0.92)
- `foam?: number` — 0..1, how strongly breaking crests turn to white water (default 0.8; a gentle sea has none whatever this is)

### WaterSurfaceView

*interface* · `packages/levels/src/water.ts:142`

```ts
interface WaterSurfaceView
```

- `mesh: BABYLON.Mesh`
- `material: BABYLON.ShaderMaterial`
- `setWaves(waves: WaterWave[]): void`
- `dispose(): void`

### WaterWave

*interface* · `packages/levels/src/water.ts:8`

```ts
interface WaterWave
```

- `wavelength: number` — metres crest to crest
- `amplitude: number` — metres, crest above the rest level
- `steepness?: number` — 0..1: how sharp the crests are (Gerstner Q)
- `direction?: number` — degrees about the vertical, the way the wave travels (0 = +x)

## Types

### ModelState

*type* · `packages/levels/src/runtime.ts:33`

```ts
type ModelState = 'loading' | 'ready' | 'failed'
```

### PlaceholderSpec

*type* · `packages/levels/src/runtime.ts:22`

```ts
type PlaceholderSpec = 'box' | 'none' | { size?: number | [number, number, number]; color?: [number, number, number] } | ((scene: BABYLON.Scene) => BABYLON.TransformNode)
```

### RefKind

*type* · `packages/levels/src/runtime.ts:13`

```ts
type RefKind = 'package' | 'remote' | 'relative'
```

### ResolvedAtmosphere

*type* · `packages/levels/src/atmosphere.ts:58`

```ts
type ResolvedAtmosphere = Required<AtmosphereDef>
```

### TransitionChooser

*type* · `packages/levels/src/transitions.ts:52`

```ts
type TransitionChooser = (from: LevelDef | null, to: LevelDef, plan: LevelPlan) => string | undefined | null
```

## Constants

### ATMOSPHERE_EXPOSURE

*const* · `packages/levels/src/atmosphere.ts:46`

```ts
const ATMOSPHERE_EXPOSURE: 30
```

### ATMOSPHERE_FRAGMENT

*const* · `packages/levels/src/atmosphere.ts:197`

```ts
const ATMOSPHERE_FRAGMENT: "precision highp float;\nvarying vec3 vDir;\n#define N 24\nuniform vec3 rayleigh[N]; uniform vec3 mie[N];\nuniform vec3 sunDir; uniform vec3 sunColor; uniform vec3 sunDisc; uniform vec3 lum; uniform vec3 ground; uniform vec3 horizonFill;\nuniform float g; uniform float ms; uniform float exposure;\nvoid main() {\n  vec3 d = normalize(vDir);\n  float h = d.y;\n  vec3 toSun = -sunDir;\n  float c = do …
```

the sky dome's fragment shader body for the table (arrays of `LUT_SIZE` entries); uniforms: rayleigh[], mie[], sunDir, sunColor (already x strength), g, ms, lum, ground, exposure

### BAR

*const* · `packages/levels/src/transitions.ts:49`

```ts
const BAR: "bar"
```

The engine's own transition: it draws nothing itself, the loading screen of

### barTransition

*const* · `packages/levels/src/transitions.ts:50`

```ts
const barTransition: Transition
```

### DEFAULT_LIBRARY_URL

*const* · `packages/levels/src/library.ts:21`

```ts
const DEFAULT_LIBRARY_URL: "/lib/ferret-assets/catalog.json"
```

### HEIGHT_TRANSITION

*const* · `packages/levels/src/landscape.ts:63`

```ts
const HEIGHT_TRANSITION: 0.2
```

how much height a height-blended layer needs to beat the others (score units), as a transition width

### LUT_SIZE

*const* · `packages/levels/src/atmosphere.ts:48`

```ts
const LUT_SIZE: 24
```

### MANIFEST_VERSION

*const* · `packages/levels/src/manifest.ts:9`

```ts
const MANIFEST_VERSION: 1
```

### MAX_LANDSCAPE_LAYERS

*const* · `packages/levels/src/landscape.ts:59`

```ts
const MAX_LANDSCAPE_LAYERS: 8
```

### MAX_LANDSCAPE_SAMPLERS

*const* · `packages/levels/src/landscape.ts:61`

```ts
const MAX_LANDSCAPE_SAMPLERS: 11
```

WebGL guarantees 16 texture units; the PBR material uses a few, so layers + normals + weightmaps stay under this

### MAX_MATERIAL_LIGHTS

*const* · `packages/levels/src/light-budget.ts:128`

```ts
const MAX_MATERIAL_LIGHTS: 8
```

most lights one material may light with (uniform-block limit of D3D11 through ANGLE, 12 vertex blocks, 4 taken by scene/material/mesh/bones)

### MOVEMENT_KEYS

*const* · `packages/levels/src/manifest.ts:103`

```ts
const MOVEMENT_KEYS: readonly ["radius", "height", "crouchHeight", "eyeHeight", "walkSpeed", "runSpeed", "crouchSpeed", "jumpVelocity", "gravity", "maxStepHeight", "walkableAngle", "acceleration", "braking", "airControl", "swimSpeed", "buoyancy", "swimAcceleration", "outOfWaterZ", "jumpOutOfWaterPitch", "maxOutOfWaterStepHeight"]
```

### MULTI_SCATTER

*const* · `packages/levels/src/atmosphere.ts:47`

```ts
const MULTI_SCATTER: 0.3
```

