Log inGet started

Reflections

Updated October 15, 2026

Reflections — the sky, probes, and the screen

Every standard-PBR surface reflects its surroundings through the environment term: a metal mirrors them at its own colour, a dielectric takes them at a Fresnel weight that is a few percent head-on and rises toward a grazing angle, and the surface's roughness picks how blurred the reflection is. What "the surroundings" are comes from three sources, and a scene picks up the first one with nothing set up.

The sky, by default. The scene's sky is captured once into the environment and follows the sky from there, so a chrome ball reflects the sky it stands under and a wet floor reflects the horizon at a grazing angle. A scene with no probe reflects this everywhere. renderer.reflectionEnvironment() reports it as sky / skyCaptured.

A reflection probe, where a surface should reflect the room. A probe bakes the scene around one point into a cube; surfaces within its radius reflect that cube instead of the sky, at a weight that falls from full at the probe to zero at the radius, and beyond every probe's radius a surface reflects the sky again. Place one per room, size radius to the room, and give it a box proxy sized to the walls so the reflection stays anchored as the camera moves:

entity.find("lobby").component.add("ReflectionProbe", {
    radius = 12, proxy = "box", proxyExtentX = 6, proxyExtentY = 3, proxyExtentZ = 6,
    probeId = "lobby",       -- the baked cube's stable identity across reloads
})
reflectionProbe.bakeAll()    -- bake every probe once the scene is built

Every field is live in the inspector. Two probes that overlap crossfade by proximity; a small probe ranked above the large one it sits inside (priority) wins outright where it reaches full weight. The baking toolbox's reflections tool places and bakes a covering set across the scene in one call, and its clear tool removes them. Up to eight probes are seated at once; reflectionProbe.list() names them. A probe reflects once it holds a baked cube: one that is placed and never baked adds nothing to the frame, reads baked = false in reflectionProbe.list() and in lighting.get's environment, and the engine log names it with the call that bakes it.

Screen-space reflections, for what moves. A probe records the room as it was baked; a character walking across a polished floor is not in it. The @builtin::systems.reflections.ssr render feature reflects whatever the camera can see this frame, on every surface below its roughnessCutoff, with nothing authored per surface. List it on the scene's RenderFeatures entity:

entity(entity.spawn("render features").id).component.add("RenderFeatures", {
    features = {
        { feature = "@builtin::systems.reflections.ssr", settings = { intensity = 1.0, maxDistance = 40, quality = "high" } },
    },
})

Only what is on screen can be reflected, so reflections fade toward the frame edge, and where the ray finds nothing the surface keeps the probe or sky it reflected already. A hit stands in for the environment inside the material's own shading — the trace writes the scene's reflection channel at the afterDepthPrepass seam, once the visibility raster has laid this frame's depth, and the material's environment term reads it the same frame — so a floor's roughness blurs it, a metal's colour tints it and a dielectric shows it by its angle, each by the rule the material states, the reflection stands where the camera is now, and the reflection capture pass shows it. The package's guide covers every knob: guides { path = "systems/reflections" }.

Which to reach for: the sky is already there; add probes when a room's walls should show in its floor; add the component when moving things should.

Seeing what a surface reflects. capture { pass = "reflection" } draws every surface as the environment it reflects — the probes whose radius reaches it and the sky under them, along its reflection vector at its own roughness mip, and the screen-space reflection traced for it where one was — before Fresnel and albedo weigh it into the lit frame. A mirror reads as the room it mirrors, a rough surface as that room blurred, a point no probe reaches as the sky, and with the sky fallback off as black. It answers whether a probe reaches a surface, whether its proxy anchors the room as the camera moves, and how far a roughness blurs it, without the lit pixel in the way.

  • documentation
  • guide
  • rendering