Primary implementation surface
These routes are generated from canonical source. Their exact status remains separate from implementation availability.
Build general-purpose Three.js WebGPU/TSL camera systems for product inspection, architecture, scientific visualization, geospatial scenes, and authored cinematography. Use for bounds-derived framing, perspective and orthographic projection, controls/shot ownership, temporal jitter, camera-relative coordinates, large-world precision, constraints, and lifecycle restoration.
These routes are generated from canonical source. Their exact status remains separate from implementation availability.
This skill contributes to the following cross-skill owner graphs.
Related skill preview · Live concept-proxy screenshot · not canonical evidence
Final image systemsEvidence pending
Related skill preview · Live concept-proxy screenshot · not canonical evidence
Actors and environmentEvidence pending
Related skill preview · Live concept-proxy screenshot · not canonical evidence
Relativistic cinematicEvidence pending
Rigs are authored dynamical systems. Follow cameras track targets through damped springs — critically damped so they never oscillate:
$$\ddot{\mathbf x} = \omega^2(\mathbf x_{target} - \mathbf x) - 2\zeta\omega\,\dot{\mathbf x}, \qquad \zeta = 1$$Frame-rate independence comes from exact exponential smoothing rather than per-frame lerp:
$$\mathbf x_{t+dt} = \mathbf x_{target} + (\mathbf x_t - \mathbf x_{target})\,e^{-\lambda\,dt}$$Orientation blends on the quaternion manifold — $q(t) = \operatorname{slerp}(q_0, q_1, t)$ with hemisphere correction ($q \equiv -q$) — and body-relative up vectors keep orbits sane on planets: $\hat{\mathbf u} = \widehat{\mathbf p - \mathbf c}$. At planetary scale, floating origin subtracts a world offset from every position via storage buffer so camera-local coordinates stay in float32-safe range ($|\mathbf p| < 10^4$ m keeps sub-millimeter precision).
Every image identifies what it proves. Page screenshots demonstrate the published presentation only; generated inputs demonstrate asset channels only; canonical acceptance still requires render-target readback and a schema-v2 bundle.
1 published image
concept proxy preview
The complete SKILL.md as loaded by agents — verbatim, rendered.
A camera system emits exactly one semantic pose, one unjittered projection, and one coordinate-origin epoch per frame. Controls, fit solvers, authored shots, temporal jitter, and post effects are separate owners with an explicit handoff; they must not all mutate the camera opportunistically.
Label every consequential number in an implementation or review:
Unlabelled millisecond targets and universal camera distances are invalid.
| Workload | First camera architecture | Primary correctness test |
|---|---|---|
| Product/asset inspection | bounds-fit perspective or orthographic camera plus OrbitControls |
every required bound remains inside the safe frame through a full rotation |
| Architecture/interior | eye- or section-plane anchors, lens shift, constrained orbit/pan/walkthrough | vertical/horizon policy, near-plane clearance, and room-scale navigation remain stable |
| Scientific/data visualization | reproducible pose records, declared axes/units, perspective or orthographic projection selected by measurement semantics | projected scale, clipping, and axis conventions are deterministic |
| Geospatial/astronomical scale | local tangent frame plus rebased or high/low camera-relative coordinates | no float32 jitter, origin pop, or temporal-history discontinuity at representative coordinates |
| Cinematic/editorial | authored pose/projection tracks with explicit cut and blend epochs | frame-rate-independent endpoints and intentional temporal-history resets |
Use planar getViewSize() only for centered size occupancy when subject depth
is small; it discards principal-point translation. Use getViewBounds() for an
asymmetric frame. For volumes, bisect only the XY occupancy residual under
fixed orientation/intrinsics and a safe frame containing the principal point,
then intersect its distance bracket with the independently Derived near/far
feasible interval. Otherwise solve frustum shift/pose too or report infeasible.
Orthographic framing changes frustum or zoom; dolly does not change occupancy.
-Z, right is +X, and up is +Y.Input systems produce intents while inactive. They do not write the camera.
When the view follows or frames simulated content, use the acyclic lifecycle
defined by the
physics domain and interaction contract.
Camera follow/framing consumes the immutable PhysicsPresentationCandidate
created after simulation and any physics-origin transaction. That candidate is
view-independent and contains no camera, render origin, view matrix, shadow
epoch, or global-to-render mapping. The camera owner emits one immutable
CameraViewPublication per target/view; visibility/shadow/cache owners consume
both records and emit ViewPreparationPublication; only then does the assembler
seal PhysicsPresentationSnapshot. Do not read a solver buffer,
external-engine transform, or fixed-step endpoint directly from the camera
loop.
Validate the exact central Candidate, CameraViewPublication,
ViewPreparationPublication, Snapshot, and every referenced
PhysicsSignalDescriptor; do not redeclare a reduced camera-local schema. Each
phase has one writer and emits a new immutable version. Camera, culling,
shadows, velocity, post, picking, and diagnostics consume only their declared
prior publication and never independently resample physics.
The camera owner writes the exact CameraViewPublication: publication,
candidate, target/view/camera and owner IDs; view scope; camera/projection
versions; previous/current render-sample instants; complete previous/current
RenderSimilarityTransforms; unjittered view/projection matrices; jitter;
viewport; DPR/extent; depth convention; and projection validity/error. Origin
epoch numbers alone cannot reconstruct a cross-rebase trajectory.
The sealed Snapshot is deliberately small: it references candidate binding IDs,
cameraPublicationId, viewPreparationId, lease refs, and event ranges. Render
consumers resolve the matrices/transforms through cameraPublicationId and the
reactive/reset plan through viewPreparationId; they do not copy mutable local
subsets. A separate temporal owner supplies jitterSampleAndConvention. Motion
vectors never use jittered projections.
Each per-binding/provider PresentedStatePair contains independent
previousPresented and currentPresented provenance, presented instants, state
handles, and global bindings after that signal's declared clock mapping and
interpolation/extrapolation policy. Solver brackets are provenance, not the two
rendered poses. Downstream motion vectors project the presented pair. Using
solver endpoints produces false velocity whenever render and simulation cadence
differ.
An external physics stream enters through one adapter that converts its units, axes, origin, IDs, timestamps, and discontinuity flags into the common context, buffers enough timestamped samples for the declared presentation policy, and publishes bounded error or invalidity when either requested presentation instant cannot be represented. It never writes the Three.js camera or object transforms beside the snapshot writer.
Spawn, despawn, teleport, reparent, incompatible LOD, stream discontinuity, or
identity change invalidates follow smoothing and temporal motion according to
the ViewPreparationPublication.resetDependencies; it is not interpolated as
ordinary locomotion. The reset record is a plan. Actual completion/failure belongs in the append-only
FrameExecutionRecord, not a mutation of the sealed snapshot.
The camera owner returns CameraViewPublication; preparation owners return
ViewPreparationPublication; neither mutates an earlier record. Same-frame
results are included only before sealing. An explicitly declared alternate
schedule may defer feedback by one frame, in which case the sealed snapshot and
render continue to name the prior committed resource/version.
If required camera/projection preparation or sealing fails, append a
FrameExecutionRecord with overallStatus: aborted (or partial-failure when
another target survives), exclude the failed target from snapshotIds, store
typed absence in its target execution's snapshotId, cancel or defer actions,
and retire only failed-target-exclusive ViewPreparationPublication.resourceLeases through
leaseDispositionById. Candidate/shared leases remain retained until every
surviving snapshot consumer joins. Device loss
appends overallStatus: device-lost and affected target statuses device-lost, advances
deviceLossGeneration, cancels dependent actions, and invalidates resources
and leases from the lost generation without mutating Candidate/Snapshot records
or inventing a completion token. Rebuild under the new backend/resource
generation.
For a rebase, transform both presented states through their respective origin epochs. A pure coordinate change representing the same global trajectory must leave camera-relative pose, obstruction result, and projected motion invariant. If either epoch transform is missing or the bound is exceeded, increment the appropriate reactive epoch and execute the declared reset dependencies before rendering; do not encode the origin jump as physical motion.
Stock r185 TRAANode cannot preserve its previous-depth history across any
render-origin translation or tangent-basis rebase, even when custom velocity is
rebase-correct. Rebuild/reseed it. Only a custom/patched temporal node using
both complete global-to-render transforms may preserve history after proof.
import { WebGPURenderer, RenderPipeline } from "three/webgpu";
import { pass, mrt, output, velocity, renderOutput } from "three/tsl";
import { traa } from "three/addons/tsl/display/TRAANode.js";
const renderer = new WebGPURenderer({ reversedDepthBuffer: true });
await renderer.init();
if (renderer.backend.isWebGPUBackend !== true) {
throw new Error("This camera architecture requires the WebGPU backend.");
}
r185 source establishes these constraints:
PerspectiveCamera.getViewSize(distance, target) and
getViewBounds(distance, minTarget, maxTarget) use the current projection
matrix, including zoom, film offset, and active view offset.PerspectiveCamera.setViewOffset() stores offsetX/offsetY, changes
aspect, and updates projection; orthographic view offset does not own
aspect. Snapshot the complete camera.view object.reversedDepthBuffer and logarithmicDepthBuffer are read-only renderer
construction options, not per-shot state. Choose once and validate the whole
depth/post/shadow pipeline.renderer.highPrecision = true computes model-view and normal-view matrices
in JavaScript number precision before upload, but r185 explicitly excludes
InstancedMesh and SkinnedMesh from that path. Choose it before compile/
warmup; late changes require graph invalidation/recompile.TRAANode installs RenderPipeline before/after hooks, calls its own
camera.setViewOffset(), then calls camera.clearViewOffset(). It does not
compose or restore an authored nonzero view offset and exposes no public
history-reset method. On PerspectiveCamera it also overwrites aspect; it
assumes drawing-buffer-sized inputs for depth history and is not an
XR/ArrayCamera contract.OrbitControls.update(deltaTime) reconstructs camera orientation from
position, target, and an up-basis cached at construction. deltaTime
affects auto-rotate but not damping. A handoff must reconstruct target,
recreate/flush latent control state, and recreate controls if camera.up
changed; copying a quaternion then calling update() is not a contract.Therefore one projection owner supplies the unjittered matrix before
RenderPipeline.render(). Do not manually jitter the same camera. Do not use
the stock r185 TRAANode on a camera that simultaneously needs authored,
tiled, or multi-viewport view offsets; use a separately owned camera/pass or
an explicitly composed WebGPU temporal node. Recreate and dispose the temporal
node at hard cuts or incompatible origin/projection epochs when history cannot
remain valid. Do not resolution-scale stock TRAA inputs. Stock r185 TAAUNode
is not a canonical alternative: it lacks reversed/logarithmic/orthographic
depth paths, can copy incompatible depth formats, does not scale jitter to
output pixels as documented, and mutates the singleton velocity node rather
than an arbitrary supplied producer. Gate it to a standard non-log
perspective/canonical-velocity experiment, or patch and validate depth format,
jitter, velocity, and history.
Box3, Sphere, oriented bounds, or declared data
extents. Never reuse one fixed distance across differently scaled content.
Six axis extrema are not a conservative perspective projection of a sphere;
use its tangent cone or a conservative enclosing box/hull.lookAt() through non-uniformly scaled parents.updateWorldMatrix() before hierarchy reads and use
localToWorld(), worldToLocal(), getWorldPosition(), and
getWorldQuaternion() at space boundaries.position/quaternion.near must be positive and as large as visibility permits.
r185 OrthographicCamera permits near = 0; fit its near/far interval to the
required view volume. Reversed depth improves float-depth distribution; it
does not excuse an unbounded projection or imprecise world coordinates.updateProjectionMatrix() after changing fov, near, far,
aspect, zoom, filmGauge, filmOffset, or view offset.lerp for translation and shortest-path slerp for orientation. Clamp
stalled dt; use 1 - exp(-lambda * dt) or a substepped bounded spring only
when inertia is Authored.Never subtract two large float32 world positions in a vertex node. Keep global coordinates as JavaScript doubles on the CPU, then use one of these paths:
renderer.highPrecision before compile/warmup and verify object types. It
stabilizes current CPU-composed model-view only; built-in velocity and TRAA
previous/world matrices remain float32.StorageBufferAttribute /
StorageInstancedBufferAttribute and consume them in one shared
positionNode/caster path.Rebase at cell/threshold crossings, not automatically every frame. Carry both current and previous global-to-local transforms, including tangent-frame basis rotation, into velocity reconstruction or invalidate temporal history at the epoch. Stock velocity/TRAA require small current and previous camera-relative matrices; a custom high/low position path also needs matching previous-position velocity logic.
const renderPipeline = new RenderPipeline(renderer);
const scenePass = pass(scene, camera);
scenePass.setMRT(mrt({
output,
velocity,
}));
const colorTexture = scenePass.getTextureNode("output");
const depthTexture = scenePass.getTextureNode("depth");
const velocityTexture = scenePass.getTextureNode("velocity");
const temporalColor = traa(colorTexture, depthTexture, velocityTexture, camera);
renderPipeline.outputNode = renderOutput(temporalColor);
renderPipeline.outputColorTransform = false;
This minimal TRAA graph deliberately omits normal and emissive attachments. Add MRT channels only when another declared consumer needs them. Do not combine TRAA with MSAA or scale its input pass below drawing-buffer resolution in r185. Treat it as one AA candidate—not the mobile default—against a patched/gated TAAU, MSAA, spatial AA, or none using Measured quality, bandwidth, persistent memory, copies, and resolve cost. Keep one tone-map owner and one output- transform owner.
changedChunks * bytesPerRelativeOrigin; choose
CPU group transforms, storage updates, or high/low evaluation from this
workload and Measured transfer/vertex cost.1000 / targetHz and test
the predeclared gates; the trace cannot define its own threshold. GPU claims
require timestamp-query support and resolved timestamps, otherwise mark them
unavailable. r185 render timestamps cover timestamped render passes, not
compute, copies, queue gaps, or presentation; use a target profiler for
end-to-end claims.Select degradation from evidence: cache/accelerate when CPU-bound; remove MRT and AA/post bandwidth when GPU-memory-bound; reduce overdraw/LOD when raster- bound; change DPR/refresh policy when thermally or presentation-bound. Preserve declared measurement, framing, and authorship invariants instead of applying a universal reduction order.
Read references/camera-rig-and-cinematic-systems.md for the detailed frame contracts, occupancy solvers, projection precision, controls handoff, temporal jitter, large-coordinate representations, budgets, and validation matrix.
Use $threejs-procedural-motion-systems for motion of scene objects. Use this
skill for view pose, framing, projection, control ownership, temporal camera
state, and camera-relative coordinates. Route shadow fitting to
$threejs-scalable-real-time-shadows, post ownership to
$threejs-image-pipeline, and fixed-view/replay evidence to
$threejs-visual-validation.
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.