---
title: "reflectionProbe"
description: "The reflectionProbe namespace — the engine's Luau API reference for reflectionProbe."
section: "API Reference"
slug: "api-reflectionprobe"
canonical: "https://origozero.ai/docs/api-reflectionprobe"
updated: "2026-09-05T23:13:47.055341370+00:00"
tags: ["api", "reference"]
---

# reflectionProbe

The `reflectionProbe` namespace — 40 functions.

## globals/reflectionProbe/add {#globals-reflectionprobe-add}

```lua
reflectionProbe.add(x: number, y: number, z: number, opts: { [string]: any }?) -> string
```

Add a reflection probe at `(x, y, z)` in one call: spawns a probe entity
carrying a ReflectionProbe component (which registers it and, unless
`opts.bake == false`, bakes it). The probe is an editor gizmo — invisible in
play mode. Returns the probe entity id.

**Parameters**

- `x` `number` — World X.
- `y` `number` — World Y.
- `z` `number` — World Z.
- `opts` `{ [string]: any }` _(optional)_ — Optional `{ radius = 12, probeId = "...", name = "..." }`. `probeId`
is the STABLE asset identity (so a re-created probe reloads the same baked
cube); defaults to the entity id. The probe does NOT bake on add — call
`bakeAll()` once the scene is built (baking is an authoring step).

**Returns** `string` — The probe entity id.

```lua
reflectionProbe.add(0, 3, 0, { radius = 15, probeId = "lobby" })
```

## globals/reflectionProbe/apply {#globals-reflectionprobe-apply}

```lua
reflectionProbe.apply() -> number
```

Push the current active-probe blend data (live positions + radii) to the
renderer. Builds a dense slot array so each probe's data lands at its cube
slot; freed/missing slots become inert placeholders. Called automatically by
add / bake / remove; call it directly after moving a probe entity.

**Returns** `number` — The number of active probes applied.

## globals/reflectionProbe/bake {#globals-reflectionprobe-bake}

```lua
reflectionProbe.bake(id: string) -> (string?, string?)
```

Bake the scene into probe `id`'s cube slot from its current position AND
persist it to a `faces6` `.texture` asset (so it survives reload + syncs),
then re-apply the probe set. Yields a few frames; call from a task/coroutine
context (component hook via task.spawn, `bakeAll`, or `execute`).

**Parameters**

- `id` `string` — Probe entity id.

**Returns** `(string?, string?)` — The asset path on success, or `(nil, errorMessage)` on failure.

## globals/reflectionProbe/bakeAll {#globals-reflectionprobe-bakeall}

```lua
reflectionProbe.bakeAll() -> { baked: number, failed: number, errors: { string } }
```

Bake EVERY registered probe in the active layers, in one call. Captures
the sky into the fallback slot, then each probe's scene from its position
into its slot, persists it, and applies the full probe set. The agent/editor
one-liner. Yields; call from a task/coroutine context (`execute`, a tool, or
`task.spawn`).

**Returns** `{ baked: number, failed: number, errors: { string } }` — `{ baked = N, failed = M, errors = { ... } }`.

```lua
reflectionProbe.bakeAll()
```

## globals/reflectionProbe/count {#globals-reflectionprobe-count}

```lua
reflectionProbe.count() -> number
```

Number of registered probes.

**Returns** `number`

## globals/reflectionProbe/ensureSkyFallback {#globals-reflectionprobe-ensureskyfallback}

```lua
reflectionProbe.ensureSkyFallback() -> boolean
```

Ensure the scene's sky is in the environment's sky fallback: a reflective
surface no probe covers then reflects the sky rather than black, and a
partially covered one blends the shortfall against it. Queues a capture
when the sky slot holds none, and re-arms the fallback when a capture is
there but switched off. The engine's own state answers both questions, so
calling this on every probe that comes up costs one capture between them,
and a scene that lost its fallback gets it back. Once captured, the
fallback follows the sky the scene draws on its own.

**Returns** `boolean` — True if a capture was queued, false if the sky slot already holds one.

```lua
reflectionProbe.ensureSkyFallback()
```

## globals/reflectionProbe/list {#globals-reflectionprobe-list}

```lua
reflectionProbe.list() -> { any }
```

List every registered probe: `{ { id, slot, radius, priority, asset, position }, ... }`.

**Returns** `{ any }` — The probe list.

## globals/reflectionProbe/loadBaked {#globals-reflectionprobe-loadbaked}

```lua
reflectionProbe.loadBaked(id: string) -> boolean
```

Load probe `id`'s PERSISTED baked cube (`probe_<key>.texture`) into its
slot WITHOUT re-rendering the scene — the runtime path. A probe bakes once at
authoring time and loads the asset on every subsequent scene load. Returns
false (not an error) when no baked asset exists yet.

**Parameters**

- `id` `string` — Probe entity id.

**Returns** `boolean` — True if a baked asset was loaded, false if none exists / load failed.

## globals/reflectionProbe/register {#globals-reflectionprobe-register}

```lua
reflectionProbe.register(id: string, radius: number, key: string?) -> number?
```

Register a reflection probe for entity `id` with influence `radius`.
Assigns a free cube slot and applies the updated probe set. Idempotent — a
re-register keeps the same slot and just updates the radius. Called by the
ReflectionProbe component's awake; rarely called directly.

**Parameters**

- `id` `string` — Probe entity id.
- `radius` `number` — Influence radius (world units) — surfaces within blend it.
- `key` `string` _(optional)_ — Optional STABLE asset identity (the probe's probeId). Defaults to `id`.
The baked cube persists at `probe_<key>.texture` so an authored probe keeps
the same asset across reloads even though its runtime entity id changes.

**Returns** `number?` — The assigned cube slot, or nil if all MAX_PROBES slots are taken.

## globals/reflectionProbe/setPriority {#globals-reflectionprobe-setpriority}

```lua
reflectionProbe.setPriority(id: string, priority: number)
```

Set a probe's blend rank against the probes it overlaps, and re-apply.
Probes are gathered highest rank first and each rank takes the coverage the
ranks above it left, so a small interior probe ranked above the large
exterior one it sits inside wins outright wherever it reaches full weight,
while probes of equal rank crossfade by proximity as before.

**Parameters**

- `id` `string` — Probe entity id.
- `priority` `number` — Blend rank. Defaults to 0 on every probe.

```lua
reflectionProbe.setPriority(interiorId, 1)
```

## globals/reflectionProbe/setProxy {#globals-reflectionprobe-setproxy}

```lua
reflectionProbe.setProxy(id: string, kind: string, x: number, y: number, z: number)
```

Anchor a probe's reflections to a proxy volume and re-apply. A cube
records the environment from one point, so sampling it along the raw
reflection vector puts everything it recorded at infinity and the
reflection slides across a surface as the camera moves. Sizing a proxy to
the geometry the probe recorded — a room's walls, say — keeps the
reflection anchored to what it depicts.

**Parameters**

- `id` `string` — Probe entity id.
- `kind` `string` — "box" (sized by all three half-extents), "sphere" (sized by `x`),
or "none" to sample along the raw reflection vector.
- `x` `number` — Half-extent along X, in world units — the sphere radius for "sphere".
- `y` `number` — Half-extent along Y.
- `z` `number` — Half-extent along Z.

```lua
reflectionProbe.setProxy(id, "box", 5, 3, 4)  -- a 10x6x8 room
```

## globals/reflectionProbe/setRadius {#globals-reflectionprobe-setradius}

```lua
reflectionProbe.setRadius(id: string, radius: number)
```

Update a probe's influence radius and re-apply.

**Parameters**

- `id` `string` — Probe entity id.
- `radius` `number` — New influence radius.

## globals/reflectionProbe/unregister {#globals-reflectionprobe-unregister}

```lua
reflectionProbe.unregister(id: string)
```

Unregister entity `id`'s probe, freeing its cube slot, and re-apply.

**Parameters**

- `id` `string` — Probe entity id.

## modules/reflectionProbe/README {#modules-reflectionprobe-readme}

```lua
require("@builtin/modules/api/engine/reflectionProbe") -- reflectionProbe (also available as global 'reflectionProbe')
```

Reflection-probe system — multiple proximity-blended reflection probes in a scene. Each probe bakes the scene into its own cube slot from its position; surfaces reflect the probes covering them, gathered highest `priority` first and blended by proximity within a rank (the renderer's per-fragment probe blend), with the scene's sky under whatever coverage the probes leave. One-liner authoring (`reflectionProbe.add`) and a one-call bake-everything (`reflectionProbe.bakeAll`).

Usage: local reflectionProbe = require("@builtin/modules/api/engine/reflectionProbe")
Also available as global: reflectionProbe

## modules/reflectionProbe/add {#modules-reflectionprobe-add}

```lua
add(x: number, y: number, z: number, opts: { [string]: any }?): string
```

Add a reflection probe at `(x, y, z)` in one call: spawns a probe entity
carrying a ReflectionProbe component (which registers it and, unless
`opts.bake == false`, bakes it). The probe is an editor gizmo — invisible in
play mode. Returns the probe entity id.

**Parameters**

- `x` `number` — World X.
- `y` `number` — World Y.
- `z` `number` — World Z.
- `opts` `{ [string]: any }?` _(optional)_ — Optional `{ radius = 12, probeId = "...", name = "..." }`. `probeId`
is the STABLE asset identity (so a re-created probe reloads the same baked
cube); defaults to the entity id. The probe does NOT bake on add — call
`bakeAll()` once the scene is built (baking is an authoring step).

```lua
reflectionProbe.add(0, 3, 0, { radius = 15, probeId = "lobby" })
```

## modules/reflectionProbe/apply {#modules-reflectionprobe-apply}

```lua
apply(): number
```

Push the current active-probe blend data (live positions + radii) to the
renderer. Builds a dense slot array so each probe's data lands at its cube
slot; freed/missing slots become inert placeholders. Called automatically by
add / bake / remove; call it directly after moving a probe entity.

## modules/reflectionProbe/bake {#modules-reflectionprobe-bake}

```lua
bake(id: string): (string?, string?)
```

Bake the scene into probe `id`'s cube slot from its current position AND
persist it to a `faces6` `.texture` asset (so it survives reload + syncs),
then re-apply the probe set. Yields a few frames; call from a task/coroutine
context (component hook via task.spawn, `bakeAll`, or `execute`).

**Parameters**

- `id` `string` — Probe entity id.

## modules/reflectionProbe/bakeAll {#modules-reflectionprobe-bakeall}

```lua
bakeAll(): { baked: number, failed: number, errors: { string } }
```

Bake EVERY registered probe in the active layers, in one call. Captures
the sky into the fallback slot, then each probe's scene from its position
into its slot, persists it, and applies the full probe set. The agent/editor
one-liner. Yields; call from a task/coroutine context (`execute`, a tool, or
`task.spawn`).

```lua
reflectionProbe.bakeAll()
```

## modules/reflectionProbe/count {#modules-reflectionprobe-count}

```lua
count(): number
```

Number of registered probes.

## modules/reflectionProbe/ensureSkyFallback {#modules-reflectionprobe-ensureskyfallback}

```lua
ensureSkyFallback(): boolean
```

Ensure the scene's sky is in the environment's sky fallback: a reflective
surface no probe covers then reflects the sky rather than black, and a
partially covered one blends the shortfall against it. Queues a capture
when the sky slot holds none, and re-arms the fallback when a capture is
there but switched off. The engine's own state answers both questions, so
calling this on every probe that comes up costs one capture between them,
and a scene that lost its fallback gets it back. Once captured, the
fallback follows the sky the scene draws on its own.

```lua
reflectionProbe.ensureSkyFallback()
```

## modules/reflectionProbe/list {#modules-reflectionprobe-list}

```lua
list(): { any }
```

List every registered probe: `{ { id, slot, radius, priority, asset, position }, ... }`.

## modules/reflectionProbe/loadBaked {#modules-reflectionprobe-loadbaked}

```lua
loadBaked(id: string): boolean
```

Load probe `id`'s PERSISTED baked cube (`probe_<key>.texture`) into its
slot WITHOUT re-rendering the scene — the runtime path. A probe bakes once at
authoring time and loads the asset on every subsequent scene load. Returns
false (not an error) when no baked asset exists yet.

**Parameters**

- `id` `string` — Probe entity id.

## modules/reflectionProbe/register {#modules-reflectionprobe-register}

```lua
register(id: string, radius: number, key: string?): number?
```

Register a reflection probe for entity `id` with influence `radius`.
Assigns a free cube slot and applies the updated probe set. Idempotent — a
re-register keeps the same slot and just updates the radius. Called by the
ReflectionProbe component's awake; rarely called directly.

**Parameters**

- `id` `string` — Probe entity id.
- `radius` `number` — Influence radius (world units) — surfaces within blend it.
- `key` `string?` _(optional)_ — Optional STABLE asset identity (the probe's probeId). Defaults to `id`.
The baked cube persists at `probe_<key>.texture` so an authored probe keeps
the same asset across reloads even though its runtime entity id changes.

## modules/reflectionProbe/setPriority {#modules-reflectionprobe-setpriority}

```lua
setPriority(id: string, priority: number)
```

Set a probe's blend rank against the probes it overlaps, and re-apply.
Probes are gathered highest rank first and each rank takes the coverage the
ranks above it left, so a small interior probe ranked above the large
exterior one it sits inside wins outright wherever it reaches full weight,
while probes of equal rank crossfade by proximity as before.

**Parameters**

- `id` `string` — Probe entity id.
- `priority` `number` — Blend rank. Defaults to 0 on every probe.

```lua
reflectionProbe.setPriority(interiorId, 1)
```

## modules/reflectionProbe/setProxy {#modules-reflectionprobe-setproxy}

```lua
setProxy(id: string, kind: string, x: number, y: number, z: number)
```

Anchor a probe's reflections to a proxy volume and re-apply. A cube
records the environment from one point, so sampling it along the raw
reflection vector puts everything it recorded at infinity and the
reflection slides across a surface as the camera moves. Sizing a proxy to
the geometry the probe recorded — a room's walls, say — keeps the
reflection anchored to what it depicts.

**Parameters**

- `id` `string` — Probe entity id.
- `kind` `string` — "box" (sized by all three half-extents), "sphere" (sized by `x`),
or "none" to sample along the raw reflection vector.
- `x` `number` — Half-extent along X, in world units — the sphere radius for "sphere".
- `y` `number` — Half-extent along Y.
- `z` `number` — Half-extent along Z.

```lua
reflectionProbe.setProxy(id, "box", 5, 3, 4)  -- a 10x6x8 room
```

## modules/reflectionProbe/setRadius {#modules-reflectionprobe-setradius}

```lua
setRadius(id: string, radius: number)
```

Update a probe's influence radius and re-apply.

**Parameters**

- `id` `string` — Probe entity id.
- `radius` `number` — New influence radius.

## modules/reflectionProbe/unregister {#modules-reflectionprobe-unregister}

```lua
unregister(id: string)
```

Unregister entity `id`'s probe, freeing its cube slot, and re-apply.

**Parameters**

- `id` `string` — Probe entity id.

## typed/builtin//modules/api/engine/reflectionProbe/reflectionProbe/add {#typed-builtin-modules-api-engine-reflectionprobe-reflectionprobe-add}

```lua
reflectionProbe.add(x: number, y: number, z: number, opts: { [string]: any }?) -> string
```

Add a reflection probe at `(x, y, z)` in one call: spawns a probe entity
carrying a ReflectionProbe component (which registers it and, unless
`opts.bake == false`, bakes it). The probe is an editor gizmo — invisible in
play mode. Returns the probe entity id.

**Parameters**

- `x` `number` — World X.
- `y` `number` — World Y.
- `z` `number` — World Z.
- `opts` `{ [string]: any }` _(optional)_ — Optional `{ radius = 12, probeId = "...", name = "..." }`. `probeId`
is the STABLE asset identity (so a re-created probe reloads the same baked
cube); defaults to the entity id. The probe does NOT bake on add — call
`bakeAll()` once the scene is built (baking is an authoring step).

**Returns** `string` — The probe entity id.

```lua
reflectionProbe.add(0, 3, 0, { radius = 15, probeId = "lobby" })
```

## typed/builtin//modules/api/engine/reflectionProbe/reflectionProbe/apply {#typed-builtin-modules-api-engine-reflectionprobe-reflectionprobe-apply}

```lua
reflectionProbe.apply() -> number
```

Push the current active-probe blend data (live positions + radii) to the
renderer. Builds a dense slot array so each probe's data lands at its cube
slot; freed/missing slots become inert placeholders. Called automatically by
add / bake / remove; call it directly after moving a probe entity.

**Returns** `number` — The number of active probes applied.

## typed/builtin//modules/api/engine/reflectionProbe/reflectionProbe/bake {#typed-builtin-modules-api-engine-reflectionprobe-reflectionprobe-bake}

```lua
reflectionProbe.bake(id: string) -> (string?, string?)
```

Bake the scene into probe `id`'s cube slot from its current position AND
persist it to a `faces6` `.texture` asset (so it survives reload + syncs),
then re-apply the probe set. Yields a few frames; call from a task/coroutine
context (component hook via task.spawn, `bakeAll`, or `execute`).

**Parameters**

- `id` `string` — Probe entity id.

**Returns** `(string?, string?)` — The asset path on success, or `(nil, errorMessage)` on failure.

## typed/builtin//modules/api/engine/reflectionProbe/reflectionProbe/bakeAll {#typed-builtin-modules-api-engine-reflectionprobe-reflectionprobe-bakeall}

```lua
reflectionProbe.bakeAll() -> { baked: number, failed: number, errors: { string } }
```

Bake EVERY registered probe in the active layers, in one call. Captures
the sky into the fallback slot, then each probe's scene from its position
into its slot, persists it, and applies the full probe set. The agent/editor
one-liner. Yields; call from a task/coroutine context (`execute`, a tool, or
`task.spawn`).

**Returns** `{ baked: number, failed: number, errors: { string } }` — `{ baked = N, failed = M, errors = { ... } }`.

```lua
reflectionProbe.bakeAll()
```

## typed/builtin//modules/api/engine/reflectionProbe/reflectionProbe/count {#typed-builtin-modules-api-engine-reflectionprobe-reflectionprobe-count}

```lua
reflectionProbe.count() -> number
```

Number of registered probes.

**Returns** `number`

## typed/builtin//modules/api/engine/reflectionProbe/reflectionProbe/ensureSkyFallback {#typed-builtin-modules-api-engine-reflectionprobe-reflectionprobe-ensureskyfallback}

```lua
reflectionProbe.ensureSkyFallback() -> boolean
```

Ensure the scene's sky is in the environment's sky fallback: a reflective
surface no probe covers then reflects the sky rather than black, and a
partially covered one blends the shortfall against it. Queues a capture
when the sky slot holds none, and re-arms the fallback when a capture is
there but switched off. The engine's own state answers both questions, so
calling this on every probe that comes up costs one capture between them,
and a scene that lost its fallback gets it back. Once captured, the
fallback follows the sky the scene draws on its own.

**Returns** `boolean` — True if a capture was queued, false if the sky slot already holds one.

```lua
reflectionProbe.ensureSkyFallback()
```

## typed/builtin//modules/api/engine/reflectionProbe/reflectionProbe/list {#typed-builtin-modules-api-engine-reflectionprobe-reflectionprobe-list}

```lua
reflectionProbe.list() -> { any }
```

List every registered probe: `{ { id, slot, radius, priority, asset, position }, ... }`.

## typed/builtin//modules/api/engine/reflectionProbe/reflectionProbe/loadBaked {#typed-builtin-modules-api-engine-reflectionprobe-reflectionprobe-loadbaked}

```lua
reflectionProbe.loadBaked(id: string) -> boolean
```

Load probe `id`'s PERSISTED baked cube (`probe_<key>.texture`) into its
slot WITHOUT re-rendering the scene — the runtime path. A probe bakes once at
authoring time and loads the asset on every subsequent scene load. Returns
false (not an error) when no baked asset exists yet.

**Parameters**

- `id` `string` — Probe entity id.

**Returns** `boolean` — True if a baked asset was loaded, false if none exists / load failed.

## typed/builtin//modules/api/engine/reflectionProbe/reflectionProbe/register {#typed-builtin-modules-api-engine-reflectionprobe-reflectionprobe-register}

```lua
reflectionProbe.register(id: string, radius: number, key: string?) -> number?
```

Register a reflection probe for entity `id` with influence `radius`.
Assigns a free cube slot and applies the updated probe set. Idempotent — a
re-register keeps the same slot and just updates the radius. Called by the
ReflectionProbe component's awake; rarely called directly.

**Parameters**

- `id` `string` — Probe entity id.
- `radius` `number` — Influence radius (world units) — surfaces within blend it.
- `key` `string` _(optional)_ — Optional STABLE asset identity (the probe's probeId). Defaults to `id`.
The baked cube persists at `probe_<key>.texture` so an authored probe keeps
the same asset across reloads even though its runtime entity id changes.

**Returns** `number?` — The assigned cube slot, or nil if all MAX_PROBES slots are taken.

## typed/builtin//modules/api/engine/reflectionProbe/reflectionProbe/setPriority {#typed-builtin-modules-api-engine-reflectionprobe-reflectionprobe-setpriority}

```lua
reflectionProbe.setPriority(id: string, priority: number)
```

Set a probe's blend rank against the probes it overlaps, and re-apply.
Probes are gathered highest rank first and each rank takes the coverage the
ranks above it left, so a small interior probe ranked above the large
exterior one it sits inside wins outright wherever it reaches full weight,
while probes of equal rank crossfade by proximity as before.

**Parameters**

- `id` `string` — Probe entity id.
- `priority` `number` — Blend rank. Defaults to 0 on every probe.

```lua
reflectionProbe.setPriority(interiorId, 1)
```

## typed/builtin//modules/api/engine/reflectionProbe/reflectionProbe/setProxy {#typed-builtin-modules-api-engine-reflectionprobe-reflectionprobe-setproxy}

```lua
reflectionProbe.setProxy(id: string, kind: string, x: number, y: number, z: number)
```

Anchor a probe's reflections to a proxy volume and re-apply. A cube
records the environment from one point, so sampling it along the raw
reflection vector puts everything it recorded at infinity and the
reflection slides across a surface as the camera moves. Sizing a proxy to
the geometry the probe recorded — a room's walls, say — keeps the
reflection anchored to what it depicts.

**Parameters**

- `id` `string` — Probe entity id.
- `kind` `string` — "box" (sized by all three half-extents), "sphere" (sized by `x`),
or "none" to sample along the raw reflection vector.
- `x` `number` — Half-extent along X, in world units — the sphere radius for "sphere".
- `y` `number` — Half-extent along Y.
- `z` `number` — Half-extent along Z.

```lua
reflectionProbe.setProxy(id, "box", 5, 3, 4)  -- a 10x6x8 room
```

## typed/builtin//modules/api/engine/reflectionProbe/reflectionProbe/setRadius {#typed-builtin-modules-api-engine-reflectionprobe-reflectionprobe-setradius}

```lua
reflectionProbe.setRadius(id: string, radius: number)
```

Update a probe's influence radius and re-apply.

**Parameters**

- `id` `string` — Probe entity id.
- `radius` `number` — New influence radius.

## typed/builtin//modules/api/engine/reflectionProbe/reflectionProbe/unregister {#typed-builtin-modules-api-engine-reflectionprobe-reflectionprobe-unregister}

```lua
reflectionProbe.unregister(id: string)
```

Unregister entity `id`'s probe, freeing its cube slot, and re-apply.

**Parameters**

- `id` `string` — Probe entity id.
