API reference

Every public class, method, and event in @codexo/exojs. Generated from source.

C

classMultiRenderTarget

@codexo/exojs / rendering / stable

An off-screen render target with several colour attachments, written in one pass. One draw can produce more than one image: a colour pass that also writes a selection id, a normal buffer, a velocity buffer. Without it the same information costs one full pass per output, re-transforming and re-rasterizing the same geometry each time. Each attachment is an ordinary RenderTexture and is sampled like any other texture once the pass has run. They are OWNED by this target - created, resized and destroyed with it - because a mismatched attachment size is a framebuffer-completeness error on WebGL2 and a validation error on WebGPU, and that is not a failure worth handing to callers to avoid. # What can draw into one A Mesh or a Sprite carrying a material whose fragment shader declares one output per attachment - a `MeshMaterial` or a `SpriteMaterial` respectively. Both renderers build their pipeline from the attachment formats of the pass they run in, so a material that declares the outputs is drawn; one that declares fewer is refused with a `RenderError` rather than writing attachment 0 on WebGL2 and failing pipeline creation on WebGPU. Every other renderer - text, nine-slice, repeating sprites, video - and both default materials declare a single output, so drawing one into this target throws a `RenderError` naming the reason rather than minting pipeline variants nothing writes to. Mask and backdrop-blend compositing stay single-target for the same reason. A single-attachment target is still just a RenderTexture - reach for this only when one pass genuinely has to produce two images.

11
props
13
methods
0
events
Import
import { MultiRenderTarget } from '@codexo/exojs'

An off-screen render target with several colour attachments, written in one pass.

One draw can produce more than one image: a colour pass that also writes a selection id, a normal buffer, a velocity buffer. Without it the same information costs one full pass per output, re-transforming and re-rasterizing the same geometry each time.

Each attachment is an ordinary RenderTexture and is sampled like any other texture once the pass has run. They are OWNED by this target - created, resized and destroyed with it - because a mismatched attachment size is a framebuffer-completeness error on WebGL2 and a validation error on WebGPU, and that is not a failure worth handing to callers to avoid.

# What can draw into one

A Mesh or a Sprite carrying a material whose fragment shader declares one output per attachment - a `MeshMaterial` or a `SpriteMaterial` respectively. Both renderers build their pipeline from the attachment formats of the pass they run in, so a material that declares the outputs is drawn; one that declares fewer is refused with a `RenderError` rather than writing attachment 0 on WebGL2 and failing pipeline creation on WebGPU.

Every other renderer - text, nine-slice, repeating sprites, video - and both default materials declare a single output, so drawing one into this target throws a `RenderError` naming the reason rather than minting pipeline variants nothing writes to. Mask and backdrop-blend compositing stay single-target for the same reason.

A single-attachment target is still just a RenderTexture - reach for this only when one pass genuinely has to produce two images.

Constructors1
new(width: number, height: number, options: MultiRenderTargetOptionsConstruction options for MultiRenderTarget.): MultiRenderTarget
Methods13
_enableDepthTexture(): void
Give this target a sampleable depth attachment. Called once, from the constructor of a subclass whose options asked for one.
_syncDepthSize(): void
Keep the depth attachment at the target's size. A subclass that resizes through a path other than resize calls this itself - a depth attachment left at the old size makes the whole framebuffer incomplete.
_touch(): void
addDestroyListener(listener: () => void): this
Subscribe to the moment this target (or any subclass - including RenderTexture) is destroyed. Backends use this to release GPU-side resources (framebuffer + attached texture) tied to the target. Listeners fire exactly once.
The attachment at index, in the order its format was declared - the same order the fragment shader's outputs are in.
destroy(): void
removeDestroyListener(listener: () => void): this
Remove a previously registered destroy listener. No-op if absent.
resize(width: number, height: number): this
Point this target at view, or back at its own default view when passed null. The view is caller-owned - neither this call nor destroy releases it.
updateViewport(): this
Properties11
needsStencil: boolean
Whether this target needs a stencil attachment for geometric stencil clipping (RenderNode.clip with a Geometry clipShape). Set by the WebGL2 backend when such a clip is rendered into an offscreen RenderTexture, so its framebuffer gets a depth/stencil renderbuffer; the WebGL2 on-screen root uses the default framebuffer's stencil (requested at context creation), so the flag only affects offscreen WebGL2 targets. The WebGPU backend does not consult this flag: it allocates a separate depth24plus-stencil8 attachment per clipped target (root included) on demand, sized to the colour attachment's physical pixels.
Sampleable depth attachment, or null on a target that did not opt in - the on-screen root target always answers null. Opting in ({ depth: true } on a RenderTexture or a MultiRenderTarget) buys a depth buffer that survives the pass and can be read back as a texture; a MeshMaterial with writesDepth fills it. Without the opt-in a depth-writing material still draws, it just writes depth nowhere.
destroyed: boolean
true once destroy has run. A destroyed target must not be rendered into - the backend throws rather than drawing into released GPU state.
height: number
root: boolean
version: number
width: number
Source