Inspect HTML textures on React Three Fiber meshes
npm install inspectable-r3f to your scene
bash
npm install inspectable-r3f
`
Peer Dependencies:
`json
{
"@react-three/fiber": ">=8.0.0",
"react": ">=18.0.0",
"react-dom": ">=18.0.0",
"three": ">=0.150.0"
}
`
---
Quick Start
$3
`tsx
import { Canvas } from '@react-three/fiber';
import { Inspectable } from 'inspectable-r3f';
function App() {
return (
);
}
`
$3
Replace direct html2canvas imports with the InspectableR3F wrapper for automatic tracking:
`tsx
// ❌ Before
import html2canvas from 'html2canvas';
// ✅ After
import { html2canvas } from 'inspectable-r3f';
`
$3
- Right-click any mesh with an HTML texture
- Select "Inspect Texture"
- Edit HTML with DevTools (F12) and watch changes reflect in real-time on the 3D mesh (currently works only if using html2canvas)
---
Usage Examples
$3
`tsx
import { useEffect, useRef } from 'react';
import { createRoot } from 'react-dom/client';
import { html2canvas } from 'inspectable-r3f'; // Use wrapper
import * as THREE from 'three';
function HtmlTexturePlane() {
const meshRef = useRef(null);
useEffect(() => {
const container = document.createElement('div');
container.style.position = 'absolute';
container.style.left = '-9999px';
container.style.width = '512px';
container.style.height = '512px';
document.body.appendChild(container);
const root = createRoot(container);
root.render(
Inspectable HTML
Right-click to inspect!
);
setTimeout(async () => {
const canvas = await html2canvas(container, { width: 512, height: 512 });
const texture = new THREE.CanvasTexture(canvas);
texture.needsUpdate = true;
if (meshRef.current) {
(meshRef.current.material as THREE.MeshBasicMaterial).map = texture;
}
}, 100);
return () => root.unmount();
}, []);
return (
);
}
`
$3
`tsx
function Canvas2DBox() {
const meshRef = useRef(null);
useEffect(() => {
const canvas = document.createElement('canvas');
canvas.width = 512;
canvas.height = 512;
const ctx = canvas.getContext('2d')!;
// Draw using Canvas 2D API
ctx.fillStyle = '#059669';
ctx.fillRect(0, 0, 512, 512);
ctx.fillStyle = 'white';
ctx.font = 'bold 48px Arial';
ctx.textAlign = 'center';
ctx.fillText('Select Me!', 256, 256);
const texture = new THREE.CanvasTexture(canvas);
if (meshRef.current) {
(meshRef.current.material as THREE.MeshBasicMaterial).map = texture;
}
}, []);
return (
);
}
`
$3
For complex scenarios where automatic detection doesn't work:
`tsx
function ComplexMesh() {
const meshRef = useRef(null);
useEffect(() => {
const container = document.createElement('div');
container.innerHTML = 'Custom Content
';
// ... create texture ...
if (meshRef.current) {
// Manually associate the DOM element
meshRef.current.userData.inspectableContainer = container;
}
}, []);
return {/ ... /} ;
}
`
---
API Reference
$3
The main component that enables inspection globally.
#### Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| enableCanvas2DPatch | boolean | true | Enable Canvas 2D API patching for text selection. Disable if conflicts with third-party canvas libraries occur. |
#### Example
`tsx
`
---
$3
Drop-in replacement for the standard html2canvas function. Automatically registers canvases for inspection.
#### Parameters
- element: HTMLElement – The DOM element to capture
- options?: Html2CanvasOptions – Standard html2canvas options
#### Returns
Promise – The rendered canvas
#### Example
`tsx
const canvas = await html2canvas(divElement, {
width: 512,
height: 512,
scale: 2,
backgroundColor: null
});
`
---
How It Works
$3
InspectableR3F uses several strategies to associate meshes with DOM content:
1. Registry Tracking: Canvases created via the html2canvas() wrapper are automatically tracked
2. Canvas 2D Patching: Canvas 2D API methods are monkey-patched to create a "ghost DOM" layer
3. UserData Override: Manual association via mesh.userData.inspectableContainer
$3
When you use Canvas 2D methods like fillText(), InspectableR3F:
- Creates invisible DOM elements positioned at the exact canvas coordinates
- Tracks transform state (translate, rotate, scale)
- Makes text selectable while keeping it visually hidden
- Allows DevTools inspection of the ghost elements
$3
When you edit HTML in the inspector:
- A MutationObserver watches for DOM changes
- Changes trigger a re-capture via html2canvas
- The texture is automatically updated on the mesh
- No manual refresh needed!
---
Configuration
$3
If you're using third-party canvas libraries that conflict:
`tsx
`
This disables the ghost DOM system but keeps inspection working for html2canvas-based textures.
$3
InspectableR3F is automatically disabled in production (NODE_ENV === 'production'). No manual configuration needed.
---
Troubleshooting
$3
Cause: The mesh doesn't have a tracked texture.
Solution:
- Use the html2canvas wrapper from inspectable-r3f
- Enable Canvas 2D patching with enableCanvas2DPatch={true}
- Manually set mesh.userData.inspectableContainer
$3
Cause: Cross-origin images block toDataURL().
Solution: Use CORS-enabled images or proxy them through your server.
$3
Cause: Canvas 2D patching is disabled.
Solution: Ensure
$3
Cause: Canvas 2D patching adds overhead to drawing calls.
Solution:
- Only enable InspectableR3F in development
- Disable patching for specific scenes: enableCanvas2DPatch={false}
---
Contributing
Contributions are welcome! Please follow these guidelines:
1. Fork the repository
2. Create a branch: git checkout -b feature/amazing-feature
3. Commit changes: git commit -m 'Add amazing feature'
4. Push: git push origin feature/amazing-feature
5. Open a Pull Request
$3
`bash
Clone the repo
git clone https://github.com/IrfanulM/InspectableR3F.git
cd InspectableR3F
Install dependencies
npm install
Start playground
npm run dev
Build package
npm run build --workspace=inspectable-r3f
``