threejs-debug-view
v0.2.15
Published
Batteries-included TSL debug views for Three.js WebGPU render pipelines.
Maintainers
Readme
threejs-debug-view
Docs: Starlight site · Live demo
Install
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.
Get started
| 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.
Built-in views
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.
Custom debug view
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.
Documentation site
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.
Quality gates
| 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.
Project shape
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.
Status
- WebGPU-first, TSL-first, no WebGL fallback
- Not an
EffectComposerhelper - Uses
three/webgpu,three/tsl, WebGPU MRT passes, and fullscreenRenderPipelinecomposition
Bundle size
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.
