Image Pipeline

Coordinate Three.js WebGPU/TSL final-image graphs. Use when effects share scene-pass signals or output ownership, when choosing MRT versus reconstruction or narrow passes, when admitting temporal history, or when whole-graph budgets and lifetimes decide the design.

Image: Accepted demo-sourced runtime evidence. Source lab: creature-habitat.

$threejs-image-pipeline 7 primary targets 5 flagships 1 secondary surface accepted runtime evidence Latest skill update commit 8749183 ↗ SKILL.md on GitHub ↗ raw (for agents) ↗

Primary target surface

These rendering routes are generated from canonical source. Native-WebGPU acceptance remains separate from entrypoint availability.

Canonical capture Runtime evidence pending 367f880e1d52 source hash 10 fixed states · 8 runtime proof requirements Canonical labEvidence pending

WebGPU Image Pipeline

1 fixed scenarios, 6 mechanism routes, and 3 locked tiers.

Open published implementation →
Canonical capture Accepted evidence published 2f41080c1ecb source hash 3 fixed states · 4 runtime proof requirements Mechanism benchAccepted

WebGPU Temporal History

1 fixed scenarios, 1 mechanism routes, and 1 locked tiers.

Open published implementation →
Accepted demo-sourced runtime evidence for Creature Habitat Accepted demo-sourced runtime evidence IntegrationAccepted

Creature Habitat

1 fixed scenarios, 5 mechanism routes, and 3 locked tiers.

Open published implementation →
Accepted demo-sourced runtime evidence for Final Image Flight Accepted demo-sourced runtime evidence IntegrationAccepted

Final Image Flight

1 fixed scenarios, 6 mechanism routes, and 3 locked tiers.

Open published implementation →
Canonical capture Runtime evidence pending 3c2448b5b07d source hash 10 fixed states · 4 runtime proof requirements IntegrationEvidence pending

Procedural District

1 fixed scenarios, 6 mechanism routes, and 3 locked tiers.

Open published implementation →
Canonical capture Runtime evidence pending e2e9d6b673af source hash 10 fixed states · 4 runtime proof requirements IntegrationEvidence pending

Relativistic Space Shot

1 fixed scenarios, 6 mechanism routes, and 3 locked tiers.

Open published implementation →
Canonical capture Runtime evidence pending 76b06d2596d9 source hash 10 fixed states · 5 runtime proof requirements IntegrationEvidence pending

Weathered World

1 fixed scenarios, 6 mechanism routes, and 3 locked tiers.

Open published implementation →

The approach, mathematically

The final image is a graph with single ownership of every shared signal. One scene pass publishes MRT outputs — depth, normal, albedo, emissive, velocity — and every effect consumes the same copies:

$$\text{pass}(scene) \Rightarrow \{D, \mathbf N, A, E, \mathbf v\} \;\to\; \text{GTAO} \to \text{bloom} \to \text{exposure} \to \text{tonemap} \to \text{LUT} \to \text{output}$$

Velocity is the derivative of the reprojection chain — current clip position against previous-frame clip position through both model and camera history:

$$\mathbf v = \Pi\big(V_t M_t\, \mathbf p\big) - \Pi\big(V_{t-1} M_{t-1}\, \mathbf p\big)$$

Ordering is semantic, not aesthetic: AO modulates indirect light (pre-tonemap), bloom reads scene-linear HDR (pre-tonemap), grading reads display-referred color (post-tonemap). The validator's job is to enumerate the live pass graph and assert each signal has exactly one producer.

Accepted primary labs

Only schema-v2 labs with accepted runtime and evidence contracts appear here. Other source directories remain visible through the demo registry without being promoted to runnable proof.

Preview and evidence ledger

Every image identifies what it proves. Page screenshots demonstrate the published presentation only; generated inputs demonstrate asset channels only; rendering acceptance still requires same-lab readback and a schema-v2 bundle.

Accepted runtime evidence available20 published images
Native WebGPU runtime evidence preview

Creature Habitat

Accepted
visualCorrectness
PASS
mechanismCorrectness
PASS
performanceCompliance
NOT_CLAIMED
gpuAttribution
NOT_CLAIMED
lifecycleStability
PASS
  • hardwarePerformance remains NOT_CLAIMED without finite GPU timestamp windows
Native WebGPU runtime evidence preview

Final Image Flight

Accepted
visualCorrectness
PASS
mechanismCorrectness
PASS
performanceCompliance
NOT_CLAIMED
gpuAttribution
NOT_CLAIMED
lifecycleStability
PASS
  • hardwarePerformance remains NOT_CLAIMED without finite GPU timestamp windows

The full skill

The complete SKILL.md as loaded by agents, rendered verbatim.

Image Pipeline

Build one causal image graph: one HDR scene pass with depth, selected shared signals, and one final output conversion. Add a scene traversal or attachment only when its measured alternative is worse.

Use the atomic owner for each admitted effect:

  • $threejs-ambient-contact-shading for GTAO and indirect-light composition;
  • $threejs-bloom for glare source selection and BloomNode controls;
  • $threejs-exposure-color-grading for metering, adaptation, tone mapping, and LUT domains;
  • $threejs-dynamic-surface-effects for feature-local screen history;
  • $threejs-visual-validation for capture, timing, and lifecycle evidence.

1. Fix the baseline

Declare physical canvas pixels, target browser/GPU, frame budget, primary visual contract, and a readable no-post view. Initialize one WebGPURenderer, confirm renderer.backend.isWebGPUBackend, create one RenderPipeline, and make one pass(scene, camera) own scene-linear HDR plus its depth texture. Set trackTimestamp before renderer.init() when GPU timing is requested.

This step is complete when the baseline renders without optional post, the HDR and depth producers are named, and exactly one component owns presentation.

2. Inventory signals

For every candidate signal—HDR color, depth, normal, emissive, velocity, diffuse/base color, IDs, histories, exposure, and UI—record:

writer | readers | mathematical/color domain | physical format and extent
first write -> last read | history/reset owner | disable path

Treat depth as the pass depth texture rather than an MRT color output. Request only signals with a real reader.

This step is complete when every graph edge has one writer, all consumers agree on domain and extent, and every optional signal has a working disable path.

3. Admit attachments

Compare each candidate attachment with reconstruction or a narrow rerender on the target graph:

costMRT(a) = export + store/resolve + all later reads
costAlt(a) = reconstruction or narrow rerender + its traffic

Keep the attachment when paired evidence shows costMRT(a) < costAlt(a) and the peak resident budget still passes. Inspect compiled physical formats: r185 named PassNode attachments clone the pass output by default, so compact normal or velocity storage exists only after explicit configuration and verification.

This step is complete when every retained attachment has a named reader, verified physical format, measured winning alternative, and accounted peak bytes.

When implementing pass(), MRT, compact formats, or depth branches, read Graph construction and signal formats.

4. Admit temporal history

Enable temporal output only after all rendered motion has valid previous and current presentation state:

  • rigid transforms, instances, bones, and procedural deformation;
  • stable particle/slot identity where particles enter history;
  • unjittered previous/current camera transforms and one jitter owner;
  • depth, velocity, neighborhood, and out-of-bounds rejection;
  • resets for resize/DPR, cut, projection or origin change, scene load, spawn/despawn, teleport, reparent, LOD/topology change, and discontinuous deformation;
  • current, history, rejected-history, velocity, jitter, and reset diagnostics.

r185 velocity is currentNDC - previousNDC; TRAA converts it to UV with a negative Y scale. Stock TRAANode requires matching color/depth/velocity/input extents and MSAA off. A composite temporal input materializes another texture and fullscreen draw. Stock TRAA has no public general reset or reactive-mask input, so cuts and discontinuities require an evidenced rebuild or bypass/reseed policy.

This step is complete when horizontal and vertical motion reproject correctly, every rendered representation has a velocity policy, each discontinuity fires an executable reset, and every temporal allocation has an owner.

When temporal reconstruction is present, read Temporal admission and resets before creating velocity or history nodes.

5. Compose once

Use this default order:

HDR scene pass + depth + admitted MRT
  -> effect-local lighting histories
  -> lighting/AO/atmosphere with valid temporal inputs
  -> temporal scene-radiance resolve, when admitted
  -> excluded transparent or refractive layers
  -> meter tap from resolved pre-bloom HDR, when admitted
  -> bloom and other scene-linear optical effects, when admitted
  -> fixed or adapted exposure, when admitted
  -> tone map, when admitted
  -> LUT in its declared domain, when admitted
  -> one output conversion
  -> display-domain AA, dither, diagnostics, and UI

Keep history in stable pre-exposure scene radiance by default. Add bloom RGB while preserving scene alpha. If renderOutput() owns presentation, set renderPipeline.outputColorTransform = false; after any output-node change, set renderPipeline.needsUpdate = true.

This step is complete when every present meter, bloom, exposure, tone map, LUT, alpha operation, and output conversion has one owner, and every transparent/refractive layer has an explicit position.

When choosing a LUT/output ending or handling transparent alpha, read Color, alpha, and legal endings.

6. Own toggles, size, and lifetime

Count persistent private targets owned by built-in BloomNode, GTAONode, TRAANode, and PassNode. Rebuild the pass to reclaim an attachment previously requested with getTextureNode(); a logical MRT toggle does not reclaim it. On resize or DPR change, update every explicit extent and reseed all affected histories. Dispose removed nodes, passes, targets, materials, and storage after their final GPU use.

Add adaptive DPR only after the fixed-DPR graph has sustained timings. Use asymmetric dwell and cooldown, distinguish fixed from pixel-scaled work, and remeasure every quality tier after a size change.

This step is complete when repeated enable/disable, resize, tier-switch, and dispose cycles stabilize resource counts and every graph mutation marks the pipeline dirty.

When estimating traffic, private target residency, marginal cost, or adaptive DPR, read Memory, timing, and adaptive resolution.

7. Prove the graph

Capture the no-post baseline, each admitted signal, the diagnostics for each admitted temporal/meter/bloom/color branch, final output, and physical target inventory. Measure the complete warmed graph and paired marginal variants at identical scene state. Exercise negative controls: disable each effect, force each reset class, resize, and destroy/recreate the graph.

When a capture, timing scope, reset, output-isolation, or lifecycle control fails, read Diagnostics and failure signatures.

The pipeline is complete when all shipping tiers preserve the visual contract, the full graph and resident targets meet declared budgets, output isolation shows one output conversion and—when admitted—one tone map, diagnostics pass for every admitted temporal branch and axis, and lifecycle counts plateau after disposal.

Secondary provider surfaces

Preserved concept proxies and generated-asset previews. They are excluded from primary completion counts and link to the canonical lab through the schema-v2 registry.