Passes
A pass is a render-pass section inside a frame. It has one target, one clear color, and any number of draw calls. Open a pass by hand when you want to composite multiple draws into the same render target — here, an ocean and a boat rendered straight to the canvas:
const ocean = effect(gpu, oceanSource);
const boat = effect(gpu, boatSource);
frame(gpu, (currentFrame) => {
currentFrame.pass({ target: canvasSurface, clear: [0, 0, 0, 1] }, (pass) => {
pass.draw(ocean); // fill the canvas with water
pass.draw(boat); // paint the boat on top — same target
});
});Both draws share one render pass and one target. Order inside the pass is paint order: the ocean fills the canvas first, then the boat draws on top of it.
Good to know:
FramePass.draw()accepts a fullscreenEffector an explicitDraw. Usedraw(gpu)when you need meshes, vertex counts, instancing, or raw bind groups.
One shader? Draw it directly
Now add postprocessing. The pass is the same — the only change is its target: an offscreen Target with the same size as the canvas. Then the postprocessing effect (bound with set({ src: scene })) needs no pass ceremony to reach the screen:
const scene = target(gpu, { size: [canvasSurface.size[0], canvasSurface.size[1]] });
const postprocessing = effect(gpu, postSource);
postprocessing.set({
src: scene,
samp: sampler(gpu, { minFilter: 'linear', magFilter: 'linear' }),
}); // the offscreen scene becomes the post input
frame(gpu, (currentFrame) => {
currentFrame.pass({ target: scene, clear: [0, 0, 0, 1] }, (pass) => {
pass.draw(ocean);
pass.draw(boat);
});
});
postprocessing.draw(canvasSurface); // rendering an effect creates a passThe one-shot draw() runs after the frame has submitted, so the scene is already rendered when postprocessing reads it. Under the hood it creates an encoder, opens a render pass on canvasSurface, encodes the draw, and submits — the same GPU work you would write by hand with frame.pass.
Good to know:
frame.pass()always needs a target. Use a canvas-backedSurfacefromsurface(gpu, canvas)or an offscreenTargetfromtarget(gpu, { size }).
Good to know: a pass takes more than a target and a clear color.
FramePassOptionsalso setsclearDepth(0for reversed-Z),clearStencil, aviewportorscissorrectangle for split-screen and partial redraws,depthReadOnlyto depth-test while sampling the depth texture, atimerspan for GPU timing, andvisibilityfor occlusion queries.