I come from an environment art and tech art background.
For years, my main tools were Unreal Engine 5 and the usual real-time engine stack. When you work inside engines, you get used to seeing more than the final frame.
You check normals.
You check depth.
You isolate lighting.
You inspect albedo, roughness, wireframe, buffers, masks, and whatever else helps explain why the frame looks the way it does.
That workflow sticks.
Lately, while doing more rendering work in Three.js, especially around WebGPU and TSL, I started missing that layer.
Three.js gives you a lot of freedom, but once the scene grows, the final image is not enough.
A material looks wrong.
Is it the normal map?
Is roughness packed wrong?
Is depth doing something weird?
Is lighting hiding the issue?
Is the shader fine but the input wrong?
Without debug views, you start guessing.
So I built threejs-debug-view.
GitHub:
https://github.com/tonyblu331/threejs-debug-compose
Docs:
https://github.com/tonyblu331/threejs-debug-compose#readme
pnpm add threejs-debug-view
What it is
threejs-debug-view is a WebGPU-first helper for inspecting render debug views in Three.js + TSL.
It gives you a way to see what your render pipeline is producing while you build.
Not a full scene inspector.
Not an EffectComposer helper.
Not a WebGL fallback.
Just a dev component for render debugging.
What it shows
Built-in views include:
beauty
normals
depth
albedo
roughness
metallic
AO
opacity
emissive
material normals / normal maps
wireframe
lighting-only
reflection-only
estimated shader complexity
The goal is not to expose every possible render state.
The goal is to make the useful layers easy to reach.
Beauty tells you what the user sees.
Debug views tell you why it looks like that.
Layouts
You can display views as:
single
overlay
split
row
column
quad
grid
So you can compare the frame against the data behind it.
Beauty next to normals.
Depth next to roughness.
Lighting-only next to reflection-only.
Shader cost next to the final output.
That is the part I wanted from engine workflows.
Less guessing.
More looking.
import { DebugViews } from "threejs-debug-view/react"
import { DEFAULT_DEBUG_VIEWS } from "threejs-debug-view"
<DebugViews
views={DEFAULT_DEBUG_VIEWS}
layout="grid"
columns={4}
rows={1}
showLabels
/>
R3F adapter
The package includes an R3F adapter and Leva controls.
import { DebugViews, useDebugViewsControls } from "threejs-debug-view/react"
import { DEFAULT_DEBUG_VIEWS, getDebugViewLabels } from "threejs-debug-view"
function DebugLayer() {
const controls = useDebugViewsControls({
viewLabels: getDebugViewLabels(DEFAULT_DEBUG_VIEWS),
})
return <DebugViews views={DEFAULT_DEBUG_VIEWS} {...controls} />
}
This makes it easier to switch views and layouts at runtime without rewriting the scene every time you want to inspect another layer.
Custom TSL layers
The built-in views are only the base.
You can also add your own TSL debug layers.
That matters once the useful view becomes project-specific.
A mask.
A falloff.
A weight.
A confidence value.
A reconstruction term.
A material signal.
Some temporary output that only makes sense for the shader you are building.
import { float, vec4 } from "three/tsl"
import { createCustomDebugView, DEFAULT_DEBUG_VIEWS } from "threejs-debug-view"
import { DebugViews } from "threejs-debug-view/react"
const customLayer = createCustomDebugView({
id: "debug:custom-layer",
label: "Custom Layer",
node: vec4(float(1), float(0), float(0), float(1)),
})
<DebugViews views={[...DEFAULT_DEBUG_VIEWS, customLayer]} />
Use a stable id when the node can be recreated between React renders.
That helps the render graph dedupe equivalent views instead of treating them as new work every render.
WebGPU-first
This is WebGPU-first.
No WebGL fallback yet.
It is built around Three.js WebGPU, TSL, MRT passes, and a fullscreen render pipeline.
So the scope is clear:
WebGPU-first.
TSL-first.
R3F-friendly.
Why I made it
I did not want a full editor inside Three.js.
I just missed the speed of engine debug views.
The ability to stop looking only at the final image and quickly check the layers underneath.
That is how I am used to debugging render work.
So I packaged the helper I wanted while building.
GitHub:
https://github.com/tonyblu331/threejs-debug-compose
Docs:
https://github.com/tonyblu331/threejs-debug-compose#readme
pnpm add threejs-debug-view
Feedback welcome, especially from people working with Three.js WebGPU, TSL, R3F, custom materials, or engine-style rendering workflows on the web.
Top comments (0)