Renderer · interface
PassDefinition
Explained in Hello world.
interface PassDefinitionimport type { PassDefinition } from '@driftengine/core';Properties
| Name | Type | Description |
|---|---|---|
labelreadonly | string | For diagnostics, and for the label a backend gives the work. |
readsreadonlyoptional | readonly FrameResource[] | Attachments this pass samples.MoreReads only, and that asymmetry is deliberate. What a pass writes is wherever the caller is drawing, and is not negotiable: every built-in verb writes the current target and the executor replays a flush's nodes into one open pass, so a node declaring some other write-set schedules as a separate pass that nothing opens. Letting a package name its writes would hand it the single declaration nothing can enforce, whose failure mode is a scene quietly losing draws. A read, by contrast, is exactly what the scheduler needs from outside: declare |
Methods
prepareoptional
prepare?(ctx: PrepareContext): voidFill a target the pass owns, once a frame, before anything opens the frame's own.
| Parameter | Type | Description |
|---|---|---|
ctx | PrepareContext |
More
Shipped 2026-08-27, to the design this comment used to carry as a plan. A package's own
shadow map, blur pyramid or picking buffer: rendered here, sampled from draw. What a pass
writes into the frame stays refused for the reason reads gives above, and a pass-owned
target is outside that set by construction, which is what makes this declarable when a write
to the frame is not. createPassAttachment builds one from the PassDevice this pass was
handed at init; the pass releases it in its own dispose.
Called at one fixed point, for every pass that declares it, in registration order — which must not become dependency ordering. Gate 1.2 withdrew that with a reason on record and this does not reintroduce it: registration order is an order, not a dependency graph, and a pass that needs another's output has to be registered after it and know that it does.
It costs nothing for a pass that does not declare it. Both renderers keep a count of the passes that do and skip the whole step at zero, rather than walking the registry every frame to find out that nobody wants it.
Allocates nothing, like draw. On WebGL2, leaves the default framebuffer bound — see
PrepareContext, which is where that contract is written out.
initoptional
init?(device: PassDevice): voidBuild pipelines, buffers and textures. Called once, when the pass is registered.
| Parameter | Type | Description |
|---|---|---|
device | PassDevice |
draw
draw(ctx: PassContext): voidDraw. Called once a frame, at the point the caller invoked drawPass.
| Parameter | Type | Description |
|---|---|---|
ctx | PassContext |
More
Allocates nothing. This is a per-frame hot path and the engine's own rule about them binds a contributor exactly as it binds the renderer.
Leaves the context as it found it. On WebGL2 that means the program, the bound vertex array, the blend and depth state and the viewport; the renderer's own verbs assume what they left. On WebGPU the pass encoder's pipeline and bind groups are set by every verb before it draws, so only the viewport and the scissor persist and only those two matter.
disposeoptional
dispose?(device: PassDevice): voidRelease what init built. Called on unregisterPass and when the renderer is disposed.
| Parameter | Type | Description |
|---|---|---|
device | PassDevice |