Skip to main content

@realitycollective/xrblocks-environment

The Google XR Blocks adapter for the Reality Collective WebXR Environment Extensions. EXPERIMENTAL, in the same sense as the other XR Blocks adapters in this estate: it is written against the shape of XR Blocks rather than importing it, and XR Blocks is moving quickly.

It re-exports @realitycollective/threejs-environment, which re-exports the engine-free core, so this is the only package you install.

npm install @realitycollective/xrblocks-environment three

Use

import {
createXRBlocksEnvironment,
DEFAULT_OCCLUSION,
STOCK_PRESETS,
} from "@realitycollective/xrblocks-environment";

const { director } = createXRBlocksEnvironment(
xb.core.scene,
{ depth: xb.core.depth, lighting: xb.core.lighting },
{ presets: STOCK_PRESETS, initial: STOCK_PRESETS.noon },
);

director.setPassthrough(true);
director.setOcclusion(DEFAULT_OCCLUSION); // real-world depth hides your content
director.setLightEstimation(true); // the real room lights it

// From your XR Blocks Script's own update. Nothing here ticks itself, and on
// this host that matters more than on the others: both sensors are polled here.
director.update(deltaMs);

What the adapter does

  • Sky, fog, lights and image-based lighting come from the three.js adapter it extends. XR Blocks renders through three.js, so reimplementing four slots would only let them drift.
  • Depth occlusion - registers as a client of XR Blocks' Depth manager (resumeDepth / pauseDepth), turns its occlusion pass on, and chooses the depth-texture blur from the requested mode and softness.
  • Light estimation - reads the Lighting manager, which already owns the WebXR half, and turns its directional light and ambient probe into the same specs an app writes by hand. The director then lays them over the ambient, key and ibl slots.
  • The room - createXRBlocksWorldSensing(xb.core.world) reads XR Blocks' PlaneDetector and MeshDetector. Anchors and hit testing report unsupported: XR Blocks has placeOnSurface and anchorObjectAtReticle, which move an object for you and hand nothing back, so neither can answer where a ray would land.

Two things worth knowing

XR Blocks is configured before you get here. Its depth and lighting managers are set up during xb.init, so this adapter can start and stop them and cannot conjure an occlusion pass that was never built. Anything it arrives too late to change is named in a sensing report - which option to set, which preference the session was actually requested with - rather than silently dropped. Read them with director.getSensing("occlusion") and director.onSensing(...).

Do not light the room twice. If XR Blocks' own estimated lights are on (useAmbientSH, useDirectionalLight), and this package applies the same estimate to the ambient and key slots, you get both. Turn the XR Blocks lights off and let the director own them; the adapter says so in the report if it sees both.

Peer dependency

three >= 0.170.0, plus an XR Blocks build to hand in. xrblocks itself is not a dependency: the depth and lighting managers are described structurally, so nothing here pins a version of it. Verified against xrblocks 0.21.1.

Licence

MIT.

Classes

ClassDescription
AudioDirector-
EnvironmentDirector-
ThreeAudioPortPlays sounds.
ThreeEnvironmentPortApplies an environment to a scene.
ThreeWorldSensingPortWhat an adapter implements. Everything except observe is optional, because every host has a different subset and a missing method is reported rather than thrown.
WorldSensingDirector-
XRBlocksEnvironmentPortApplies an environment to a scene.
XRBlocksWorldSensingPortWhat an adapter implements. Everything except observe is optional, because every host has a different subset and a missing method is reported rather than thrown.

Interfaces

InterfaceDescription
AmbientLightSpecUniform illumination from every direction.
AudioConeA directional sound, in this package's own terms.
AudioCueA sound the app knows how to make. Registered once, played by id.
AudioDirectorOptions-
AudioPortPlays sounds.
AudioSpatialHow a positional voice gets quieter with distance.
AudioVoiceA sounding voice. Opaque to the app apart from the fields shown.
AudioVoiceRequestA play request with every decision already made: which file, how loud in absolute terms, looping or not, and where from. An adapter implementing AudioPort has no mixing left to do.
ColourLikeA THREE.Color, seen through the two things this adapter reads.
EnvironmentDirectorOptions-
EnvironmentPortApplies an environment to a scene.
EnvironmentPortHostWhat a port is handed so it can talk back. Implemented by the director.
EnvironmentSpecA PARTIAL description of the environment.
EquirectLoaderAnything that can turn a URL into a texture: TextureLoader, RGBELoader.
EstimatedLightingLighting the host measured from the real world.
FogExponentialFog that thickens exponentially with distance.
FogLinearFog that ramps between two distances.
HitTestRequestA standing question: "where does this ray meet the room".
IblEstimatedThe reflections the HOST measured from the real room.
IblGradientImage-based lighting: what the world reflects and how it lights everything that is not lit by the key light.
IblRoomThe host's built-in neutral room probe. Neither authored nor measured.
IblTexture@realitycollective/webxr-environment - the engine-free core.
KeyLightSpecThe one directional light most scenes need: a sun, a moon, a work lamp.
LightEstimationSpecWhich slots a live estimate may take over.
OcclusionSourceHow the app would like the depth sensor configured.
OcclusionSpec-
PlayOptionsPer-play overrides. Everything here beats the cue's own value.
ResolvedEnvironmentEvery slot decided. This is what the director holds and adapters receive.
ResolvedLightEstimationspec with every default filled in, which is what a port receives.
ResolvedWorldDetection-
SensingReport-
SkyGradientA vertical gradient sky. top sits at the zenith and bottom at the nadir; horizon is where they meet, as a fraction of the way up the sphere.
SkySolidA single flat colour behind everything. The cheapest sky there is.
SkyTextureAn authored sky: an equirectangular image wrapped around the world.
ThreeAudioPortOptions-
ThreeAudioSetup-
ThreeEnvironmentPortOptions-
ThreeEnvironmentSetup-
ThreeWorldSensingPortOptions-
ThreeWorldSensingSetup-
TransitionOptions-
Vec3Like-
WorldAnchorA point in the real world the runtime promises to keep track of.
WorldChangeWhat moved since the last flush, per feature. Ids only; read the lists.
WorldDetectionSpecWhich of them to turn on. Everything defaults OFF: each one costs.
WorldHitWhere a ray met the world.
WorldMeshScanned geometry: furniture, walls, whatever the room-scan produced.
WorldPlaneA flat surface the host found: a floor, a wall, a table top.
WorldPoseWhere something is, in whatever reference space the app is using.
WorldSensingDirectorOptions-
WorldSensingPortWhat an adapter implements. Everything except observe is optional, because every host has a different subset and a missing method is reported rather than thrown.
WorldSensingPortHostWhat a port is handed so it can report what the room looks like.
XBDepthLikexb.core.depth.
XBDepthOptionsLikeDepthOptions, of which this adapter writes only the blur flags.
XBDetectedMeshLikeDetectedMesh.
XBDetectedPlaneLikeDetectedPlane: a mesh built from the polygon, with the label beside it.
XBLightingLikexb.core.lighting.
XBLightingOptionsLikeLightingOptions.
XBMeshDetectorLike-
XBObject3DLikeThe three.js object XR Blocks builds for a detected surface or mesh.
XBPlaneDetectorLike-
XBWorldLikexb.core.world. Both detectors are absent unless enabled at init.
XrAnchorLikeOne XRAnchor.
XRBlocksAudioSetup-
XRBlocksEnvironmentContextWhat an app hands this adapter. Both members are optional and both degrade.
XRBlocksEnvironmentSetup-
XRBlocksWorldSensingSetup-
XrFrameLike-
XrHitTestResultLike-
XrLightEstimateLikeOne XRLightEstimate. The three products WebXR's light estimation makes.
XrManagerLikeThe part of renderer.xr this port uses.
XrMeshLikeOne XRMesh. The buffers are the runtime's and are never copied here.
XrPlaneLikeOne XRPlane. polygon points are in the plane's own space, metres.
XrPoseLikeWhat frame.getPose hands back: a transform, or null when tracking is lost.
XrRendererLikeA WebGLRenderer, seen through the keyhole this port looks through.
XrSessionLike-

Type Aliases

Type AliasDescription
AudioBusA mix group. Any string works; the conventional set is below.
CuePolicyWhat a second play request does while a cue is already sounding.
EasingFunctiont in 0..1 -> eased t in 0..1.
EasingNameThe named easing curves. A transition may also carry its own function.
EnvironmentBlendModeHow the host composites what is rendered over the real world.
EnvironmentListenerFired whenever what the port holds, or what the app asked for, changes.
EnvironmentSlot@realitycollective/webxr-environment - the engine-free core.
FogSpec@realitycollective/webxr-environment - the engine-free core.
IblSpec@realitycollective/webxr-environment - the engine-free core.
OcclusionModeHow hard the edge between real and virtual is drawn.
OcclusionScopeWhich content the real world is allowed to hide.
QuatA rotation as [x, y, z, w]. Normalised; the adapters guarantee that.
RampGradientA gradient with or without a horizon stop, from either slot.
RgbAn sRGB colour, one channel per component, each in 0..1.
SensingFeature-
SensingListener-
SensingStateHow a feature is doing, in the order things usually go wrong:
SkySpec@realitycollective/webxr-environment - the engine-free core.
Vec3A direction or position in world space, metres. Need not be normalised.
WorldChangeListener-
WorldFeature-
WorldPlaneOrientationRoughly which way a surface faces.
XrLightProbeLikeAn XRLightProbe. Opaque: it is only ever handed back to getLightEstimate.

Variables

VariableDescription
ALL_WORLD_DETECTIONEverything on: what setDetection(true) means.
DAWN-
DEFAULT_BUSThe bus a cue lands on when it does not name one.
DEFAULT_BUSESThe buses a director starts with, each at unity gain. Any other name works too - a bus springs into existence at unity the first time it is named. master is NOT in here: it is a separate scalar over all buses, so that "duck everything" and "turn the music down" never fight over one number.
DEFAULT_LIGHT_ESTIMATION-
DEFAULT_OCCLUSIONSoft edges over everything, from a GPU texture.
DUSK-
EMPTY_ENVIRONMENTAn environment with nothing in it: a black void with no light.
ENVIRONMENT_SLOTSThe slot names, in the order the director pushes them to the port.
NIGHT-
NOON-
OVERCAST-
SENSING_FEATURESThe sensor-backed features an adapter can report on.
SH_DC_TO_IRRADIANCEThe L0 band of a spherical-harmonic probe, scaled to irradiance.
SKY_TEXTURE_HEIGHTDefault rows. Sixty-four is smooth to the eye and 512 bytes of texture.
SKY_TEXTURE_WIDTHColumns in the generated texture. Two, because a 1px-wide equirect filters badly.
STOCK_PRESETSAll of the above, ready to hand to EnvironmentDirector's presets.
VOIDNothing at all: black, unlit, empty. The starting point of a void scene.
WORLD_FEATURESThe world features an app can ask for. They are named separately from the environment's because a host can have any subset: Quest has planes, meshes and anchors; a phone AR runtime may have only planes and hit test.

Functions

FunctionDescription
ambientFromSphericalHarmonicsThe ambient term of an estimate, or null when the runtime sent no probe.
clampClamp to an arbitrary range.
clamp01Clamp to the unit interval.
clearedFogThe same fog, pushed far enough away to be invisible.
createSkyTextureBuild the equirectangular background texture for a gradient sky.
createThreeAudioWire an audio director to a three.js AudioListener (the one on your camera). Remember port.resume() from a user gesture.
createThreeEnvironmentWire an environment director to a three.js scene.
createThreeWorldSensingWire a world-sensing director to a three.js renderer.
createXRBlocksAudioWire an audio director to an XR Blocks scene.
createXRBlocksEnvironmentWire an environment director to an XR Blocks scene.
createXRBlocksWorldSensingWire a world-sensing director to XR Blocks' world module.
deepEqualsStructural equality for the plain-data specs.
estimatedFromLightingOne reading of the XR Blocks lighting manager, as environment specs.
gradientColourAtThe colour at a height up the sphere.
gradientPixelsRGBA bytes for the gradient, nadir row first. Pure - no three.js, no DOM.
interpolateEnvironmentBlend two resolved environments. t is the EASED progress in 0..1; the director has already applied the curve, so this stays linear per channel.
keyFromEstimateThe primary light of an estimate, or null when there is not one.
lerpLinear interpolation. t is NOT clamped - the callers already clamp it.
lerpRgbComponent-wise colour interpolation.
resolveEasingResolve an easing name or function to a function. Unknown names are linear.
resolveLightEstimation-
resolveWorldDetection-
rgbEqualsTrue when two colours are identical channel for channel.
rgbFromHex0xff8800 -> [1, 0.533…, 0]. Convenience for authoring presets.
rgbToHex[1, 0.533…, 0] -> 0xff8800. The inverse, for adapters that want a hex.
skyMixThe blend weight for bottom -> top at a given height up the sphere.
toEstimatedLightingOne estimate, as the slots it is allowed to take over.
unsupportedThe report a feature has before any adapter has said otherwise.
worldEntryChangedHas this entry changed since the last one with the same id?