Log inGet started
▣
module · drop-in viewer
asset⌬ modulemoduleprimary: init.luau·originates fromworld 07158574-5…

environment

Environment / reflection capture — bake the scene into reflection-probe cube slots from world positions, persist them as `faces6` `.texture` assets, set per-probe blend data so surfaces reflect the probes covering them, and capture the sky into its own slot as the fallback under…

byzero-proxy @ DESKTOP-DB3UJOJ·posted 2mo ago
What it does

environment Module

Environment / reflection capture — bake the scene into reflection-probe cube slots from world positions, persist them as faces6 .texture assets, set per-probe blend data so surfaces reflect the probes covering them, and capture the sky into its own slot as the fallback under them. Public Luau surface over the __environment Internal FFI namespace, auto-injected as _G.environment via the prelude.

Purpose

The generic "render the scene into a cubemap from a point" capability the reflection-probe system is built on. Captures are queued for the render system (which owns the live scene); captureSlotToAsset additionally yields a few frames while the GPU readback completes. Persisted cubes are faces6 .texture assets (px/nx/py/ny/pz/nz PNGs + a cube.yaml sidecar — see docs/specs/cubemap-textures.md §4 for the face convention).

For probe authoring use the higher-level reflectionProbe module; reach for environment when you need the raw per-slot primitives.

Usage

-- Register probe blend data: index i maps to cube slot i.
environment.setProbes({ { x = 0, y = 2, z = 0, radius = 12 } })

-- Bake slot 0 from a point (queued, next frame).
environment.captureSlot(0, 0, 2, 0)

-- Bake + persist to /source/probe_lobby.texture/ (yields; call from a
-- task/coroutine/execute context).
local path, err = environment.captureSlotToAsset("probe_lobby", 0, 0, 2, 0)

-- Restore a persisted cube into a slot WITHOUT re-rendering.
environment.loadSlotFromAsset("probe_lobby", 0)

-- Capture the sky alone into the fallback slot: a surface no probe covers
-- reflects the sky rather than black.
environment.captureSky()

Exports

  • environment.setProbes(probes) -> boolean — set active probes' blend data; array of { x, y, z, radius, priority? }, index i → cube slot i, gathered highest priority first
  • environment.captureSky(x?, y?, z?) -> boolean — render the sky alone into the fallback slot and arm it (queued)
  • environment.setSkyFallback(active) -> boolean — arm/disarm the fallback against the sky already captured (arming is refused while the slot holds none)
  • environment.captureSlot(slot, x, y, z) -> boolean — bake the scene into a slot from a point (queued)
  • environment.captureSlotToAsset(name, slot, x, y, z, timeoutFrames?) -> (string?, string?) — bake + persist as a faces6 .texture; yields
  • environment.loadSlotFromAsset(name, slot) -> (boolean, string?) — upload a persisted cube into a slot without re-rendering

Back-compat single-global-reflection helpers (slot 0 + one full-coverage probe):

  • environment.capture(x, y, z) -> boolean
  • environment.captureToAsset(name, x, y, z) -> (string?, string?)
  • environment.loadFromAsset(name) -> (boolean, string?)

Interface

What this asset declares: the schema it conforms to, what it exposes, and the rendered structured payload.

conforms to

zero/source-extract/v2

module environment Environment / reflection capture — bake the scene into reflection-probe cube slots from world positions, persist them as `faces6` `.texture` assets, and set per-probe blend data so surfaces reflect the nearest probe(s). Public Luau surface over the `__environment` Internal FFI namespace. The generic "render the scene into a cubemap from a point" capability the reflection probe system is built on. global environment require modules/api/engine/environment

cubeYaml( ) → string

Minimal `cube.yaml` sidecar describing a `faces6` cubemap stored inside a `.texture` asset. This is the metadata that marks a `.texture` as a cubemap (vs a flat 2D image). v1 stores PNG faces (no codec for KTX2/HDR yet).

setProbes(probes: { any }) → boolean

Set the active reflection probes' blend data. `probes` is an array of `{ x, y, z, radius }` (or `{ position = {x,y,z}, radius = r }`); index i is probe slot i. Surfaces blend the probe slots by proximity to these positions, gathering the highest `priority` first — each rank takes the coverage the ranks above it left, so a small interior probe ranked above a large exterior one wins outright wherever it reaches full weight. Coverage left over reflects the sky once `captureSky` has run. Queued for next frame. slot. `priority` defaults to 0.

argtypedescription
probes{ any }Array of `{ x, y, z, radius, priority? }`, one per active probe

examples

environment.setProbes({ { x = 0, y = 2, z = 0, radius = 12 } })

captureSky(x: number?, y: number?, z: number?) → boolean

Render the SKY alone into the environment's sky slot from `(x, y, z)` and arm the 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. The capture holds whatever the scene's sky draws — a gradient, a physical atmosphere, a skybox material — with no geometry in it, so it stays correct wherever the camera goes. Once captured, the slot follows the sky the scene draws: a sky that changes is recaptured from the same position. Queued — takes effect on the next frame. atmosphere is sampled at. Defaults to 0.

argtypedescription
xnumber?World X of the capture position. Defaults to 0.
ynumber?World Y of the capture position — the altitude a height-dependent
znumber?World Z of the capture position. Defaults to 0.

examples

environment.captureSky()

setSkyFallback(active: boolean) → boolean

Arm or disarm the sky fallback against the sky already captured, with no recapture. Disarmed, reflections come from the probes alone. Arming is refused while the sky slot holds no capture (`captureSky` fills it), since an uncaptured slot reflects black; `renderer.reflectionEnvironment()` reports whether the fallback ended up armed.

argtypedescription
activebooleanWhether reflections fall back to the captured sky.

examples

environment.setSkyFallback(false)

ensureSkyFallback( ) → boolean

Ensure the scene's sky is in the environment's sky slot: 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 everything that stands a sky up can call this and one capture is shared between them. Once captured, the slot follows the sky the scene draws on its own.

examples

environment.ensureSkyFallback()

captureSlot(slot: number, x: number, y: number, z: number) → boolean

Bake the scene into reflection-probe `slot` from `(x, y, z)`. Renders the FULL scene (geometry + sky) six times from that point into that slot. Register the probe's position+radius via `setProbes` so surfaces blend it by proximity. Queued — takes effect next frame.

argtypedescription
slotnumberReflection-probe slot (0-based).
xnumberWorld X of the capture position.
ynumberWorld Y of the capture position.
znumberWorld Z of the capture position.

examples

environment.captureSlot(0, 0, 2, 0)

captureSlotToAsset(name: string, slot: number, x: number, y: number, z: number, timeoutFrames: number?) →

Bake the scene into reflection-probe `slot` from `(x, y, z)` AND persist the 6 rendered faces into a `faces6` `.texture` cubemap asset at `/source/<name>.texture/` (px/nx/py/ny/pz/nz PNGs + a `cube.yaml` sidecar). Survives an engine restart and syncs like any other texture. Yields a few frames while the bake + GPU readback complete; must be called from a task/coroutine context (component hook, `task.spawn`, or `execute`). past the frames the engine gives a readback before it gives up on one, so what ends the wait is the readback's own answer).

argtypedescription
namestringDestination asset identity (writes `/source/<name>.texture/`).
slotnumberReflection-probe slot (0-based).
xnumberWorld X of the capture position.
ynumberWorld Y of the capture position.
znumberWorld Z of the capture position.
timeoutFramesnumber?Optional max frames to wait for the readback (default 900,

examples

environment.captureSlotToAsset("probe_lobby", 0, 0, 2, 0)

loadSlotFromAsset(name: string, slot: number) →

Load a persisted `faces6` `.texture` cubemap (written by `captureSlotToAsset`) into reflection-probe `slot` WITHOUT re-rendering the scene. Reads the 6 face PNGs from `/source/<name>.texture/` and uploads them into the slot's cube layers. How a persisted probe restores its baked environment on reload.

argtypedescription
namestringSource asset identity (reads `/source/<name>.texture/`).
slotnumberReflection-probe slot (0-based).

examples

environment.loadSlotFromAsset("probe_lobby", 0)

stateFromAsset(identity: string) →

Make a `faces6` `.texture` cubemap the environment that cameras stating it reflect. A camera rendering an isolated environment reflects only what it states — never the world's sky or reflection probes — so this is what a mirror or a pane of glass in its frame shows. The cube is stated under `identity`, which is the name a camera's `environmentMap` gives it; stating one already stated, from the same bytes, reads nothing. Called from a task, it waits for faces whose bytes are still being fetched (the web build fetches builtin images); called outside one, a face not yet fetched is answered as missing.

argtypedescription
identitystringThe cube texture, by the identity `asset.resolve` takes.

examples

task.spawn(environment.stateFromAsset, "@builtin::textures.studio_environment")

capture(x: number, y: number, z: number) → boolean

Bake the scene into the environment from `(x, y, z)` as the single global reflection (slot 0 + one full-coverage probe). Every PBR surface reflects it. Queued — takes effect on the next frame. For multiple proximity-blended probes use the reflectionProbe system instead.

argtypedescription
xnumberWorld X of the capture position.
ynumberWorld Y of the capture position.
znumberWorld Z of the capture position.

examples

environment.capture(0, 2, 0)

captureToAsset(name: string, x: number, y: number, z: number) →

Bake the single global reflection AND persist it to a `faces6` `.texture` asset (slot 0). Yields a few frames; call from a task/coroutine context.

argtypedescription
namestringDestination asset identity (writes `/source/<name>.texture/`).
xnumberWorld X of the capture position.
ynumberWorld Y of the capture position.
znumberWorld Z of the capture position.

examples

environment.captureToAsset("env_main", 0, 2, 0)

loadFromAsset(name: string) →

Load a persisted global reflection asset into slot 0 and make it the active single reflection (one full-coverage probe).

argtypedescription
namestringSource asset identity (reads `/source/<name>.texture/`).

examples

environment.loadFromAsset("env_main")

Sub-parts

Everything contained inside this part. Assets are composite children (clickable cards). Files are leaf payloads. Expand any row to view its source.

2items
This part has no composite children. See the Files segment for its leaf payloads.
backing path · modules/api/engine/environment.module

Problems

Everything affecting this asset right now: its own problems, anything wrong inside it, and problems on its direct dependencies.

0problems
No problems reported. This asset, its contents, and its direct deps are clean as of the latest commit.
⌬ZeroMind agent review · awaiting first pass
Findings
Reviewer findings (handle · model · tag · quoted note) appear here once the per-pass review log lands. Today only the rolled-up agent_score is exposed.
usability—
did it work as advertised
quality—
authoring polish + cohesion
performance—
frame & memory budget held
agent review score
—
/ 100
awaiting first pass
usability × 0.40
+ quality × 0.35
+ performance × 0.25
± compat factor

Usability ratings

Did the part work as advertised when consumers tried to drop it in. Separate from upvotes: those are taste; this is "did it function".

—%no reports yet
Sign in to report whether this part worked for you.
Discussion

Scoped to this part · feeds back into the world's score.

0comments
Sign in to post.sign in
No comments yet. Be the first.