Debug views for Three.js WebGPU + TSL render pipelines.
Native WebGPU runtime first; optional R3F adapter via DebugViewLayer.
Docs: Starlight site · Live demo
Native:
pnpm add threejs-debug-view threeR3F (optional adapter):
pnpm add threejs-debug-view three react react-dom @react-three/fiber @react-three/drei levaThe root export is the main path. /r3f needs the peers above.
| Path | Import | Use when |
|---|---|---|
| Native | threejs-debug-view |
You own the WebGPU render loop. |
| R3F | threejs-debug-view/r3f → DebugViewLayer |
Optional adapter with built-in views, layouts, and Leva. |
| Controlled R3F | threejs-debug-view/r3f → DebugViews + useDebugViewsControls |
Your app owns UI state or part of the surface. |
Guides: Quick Start · Native Runtime · R3F
Native — wire into your frame loop:
import {
DEFAULT_DEBUG_VIEWS,
createDebugRenderPlan,
createDebugPipelineRuntime,
createDebugViewUniforms,
resolveDebugViewLayout,
updateDebugViewUniforms,
} from "threejs-debug-view"
const layout = resolveDebugViewLayout("single")
const plan = createDebugRenderPlan(DEFAULT_DEBUG_VIEWS, 0, layout)
const uniforms = createDebugViewUniforms()
const runtime = createDebugPipelineRuntime(scene, camera, plan, layout, renderer, uniforms)
function animate() {
updateDebugViewUniforms(uniforms, plan.activePipelineView, layout, plan.pipelineViews.length, 1)
runtime.pipeline.render()
requestAnimationFrame(animate)
}R3F (optional) — drop in inside <Canvas>:
import { DebugViewLayer } from "threejs-debug-view/r3f"
function DebugLayer() {
if (!import.meta.env.DEV) return null
return <DebugViewLayer />
}Keep debug views behind a dev flag unless you intentionally ship them in production.
DEFAULT_DEBUG_VIEWS ships sixteen named sources. Override and heatmap passes are demand-driven: they render only when the active view or layout needs them.
| Source | Mode | What it shows |
|---|---|---|
beauty |
passthrough | Final lit color |
normal |
passthrough | View-space geometry normals |
depth |
depth | View-space depth |
albedo |
passthrough | Base color without lighting |
materialNormal |
passthrough | Material normal map output |
emissive |
passthrough | Emissive color |
roughness |
passthrough | Packed scalar (R of material target) |
metallic |
passthrough | Packed scalar (G) |
ao |
passthrough | Packed scalar (B); material AO, not SSAO |
opacity |
passthrough | Packed scalar (A) |
wireframe |
passthrough | Wireframe override pass |
lightingOnly |
passthrough | Neutral lighting-only override |
reflectionOnly |
passthrough | Reflection-only override |
overdraw |
heatmap | Measured contributor layer count |
lightComplexity |
heatmap | Light overlap (v1 analytic counter) |
shaderCost |
heatmap | Shader-cost estimate (not native GPU counters) |
Full tables and pass behavior: Built-in Views · Overlap & light diagnostics · Shader cost
Unsupported material properties use shader-side defaults; the runtime does not patch scene materials to force a view to compile.
Add a TSL node view, or use createCustomDebugView() when React may recreate the node and you need a stable render-graph id:
import { float, vec4 } from "three/tsl"
import { createCustomDebugView, DEFAULT_DEBUG_VIEWS } from "threejs-debug-view"
import { DebugViews } from "threejs-debug-view/r3f"
const fresnelView = createCustomDebugView({
id: "shader:fresnel",
label: "Fresnel",
node: vec4(float(1), float(0), float(0), float(1)),
})
<DebugViews views={[...DEFAULT_DEBUG_VIEWS, fresnelView]} />Pass-backed views that need their own target, material override, or camera belong in a dedicated pass — not forced into node. Details: Custom Debug Views.
User docs live in packages/docs/ (Astro + Starlight). They are not published to npm.
pnpm docs:dev # local Starlight dev server
pnpm docs:build # production build (included in verify)
pnpm docs:preview # preview the built siteHosted at tonyblu331.github.io/threejs-debug-view.
| Gate | Command | What it checks |
|---|---|---|
| Typecheck | pnpm typecheck |
TypeScript across library + demo |
| Unit tests | pnpm test |
Vitest (render plans, views, helpers) |
| Library build | pnpm build |
ESM dist/ + declaration emit |
| npm surface | pnpm pack:check |
Tarball contains only dist/, logo, LICENSE, README; bundle badge |
| Docs build | pnpm docs:build |
Starlight site compiles |
| Full verify | pnpm verify |
All of the above |
| E2E demo | pnpm test:e2e |
Playwright against the Vite demo (WebGPU required; fails in CI without it) |
For WebGPU or demo changes, run pnpm test:e2e and smoke-test pnpm dev in a browser with native WebGPU.
components/debug-views/— library sourcethreejs-debug-view— view definitions, render planning, TSL helpers, native runtimethreejs-debug-view/r3f—DebugViewLayer,DebugViews, Leva controlssrc/— local demo (not on npm)packages/docs/— Starlight docs + hosted demo build output (not on npm)
The npm tarball ships dist/, assets/logo.svg, LICENSE, and README.md only.
- WebGPU-first, TSL-first, no WebGL fallback
- Not an
EffectComposerhelper - Uses
three/webgpu,three/tsl, WebGPU MRT passes, and fullscreenRenderPipelinecomposition
The badge reports gzipped published ESM in dist/ (~30 kB). Peers (three, React, R3F, Leva) are excluded. Measured locally via pnpm pack:check because Bundlephobia does not reliably analyze WebGPU/TSL peer imports.