This page documents the test coverage, enforced runtime contracts, key implementation details for maintainers, and build/validation commands.
Test coverage map
Tests live in packages/motion-gpu/src/tests/:
Key runtime guarantees verified by tests
Internal implementation details
These notes are for maintainers working on the library internals:
Uniform buffer updates
- Frame uniforms (
time,delta,resolution) are written to the beginning of the buffer every frame. - Material uniforms use dirty-range detection: only byte ranges that actually changed are written to the GPU queue.
- The uniform buffer is always at least 16 bytes (WebGPU minimum binding size).
Texture lifecycle
- Each texture binding maintains a fallback 1×1 texture so the shader always has a valid binding.
- Reallocation happens when the texture format, size, or source object reference changes.
- Dynamic upload policy is resolved from the
TextureUpdateModechain (runtime override → definition → automatic fallback). ImageBitmaptextures are uploaded viacopyExternalImageToTexture.- Loader-side
LoadedTexture.dispose()is idempotent (safe to call multiple times).
Pass lifecycle
- Pass instances are identity-tracked by the renderer (tracked by object reference).
setSize(width, height)is called when a pass first appears in the array or when the canvas/target resolution changes.dispose()is called when a pass is removed from the array or when the renderer is destroyed.
Render target lifecycle
- Resolved definitions are signature-compared each frame:
key:format:widthxheight. - Only targets with changed signatures trigger reallocation.
- Removed targets are destroyed immediately.
Storage buffer lifecycle
- Storage buffers are allocated during renderer creation with
GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC. initialDatais uploaded viadevice.queue.writeBufferimmediately after allocation.- Pending writes from
writeStorageBufferare batched and flushed at the start of each render call. - Readback uses a staging buffer (
MAP_READ | COPY_DST),copyBufferToBuffer,mapAsync, and returns a sliced copy. - All storage buffers are destroyed when the renderer is destroyed.
Compute pipeline lifecycle
- Compute pipelines are built lazily on first dispatch and cached by compute shader source.
- The compute pipeline cache is stateful (
pending,ready,error): a newly seen shader source enterspending, upgrades toreadyafter async compilation validation succeeds, or upgrades toerrorwith structured diagnostics if compilation fails. - Compute storage bind-group layouts are cached by resource topology and reused across frames.
- Compute storage bind groups are reused while bound resource references stay stable.
PingPongComputePassalternates A/B texture bindings across iterations.- Ping-pong A→B and B→A bind groups are cached and reused instead of being recreated each iteration.
- Compute passes share the same
GPUCommandEncoderas render passes within a frame. - Ping-pong A/B textures are explicitly destroyed during renderer teardown.
Diagnostics and profiling
- The scheduler stores last-run timings and an optional rolling window of frame times.
setDiagnosticsEnabled(false)clears all timing state.- Profiling snapshot computes
avg,min,maxfrom the rolling window. applySchedulerPreset(...)andcaptureSchedulerDebugSnapshot(...)are covered in dedicated advanced helper tests.
Build and validation commands
Package (packages/motion-gpu)
Documentation app (apps/web)
Practical caveats
Suggested future hardening areas
- Integration tests for dynamic pass list churn under load.
- Stress tests for frequent render target topology changes.
- Browser-matrix smoke tests for WebGPU feature differences across vendors.
- Dedicated CI runner profile for stable benchmark checks across pull requests.