# @three-blocks/devtools

The account-free command engine behind `npx three-blocks`: shader precompilation,
text atlases, environment lighting, asset optimization, and integration checks.
The runtime overlay and shader hydrator ship in `three-blocks/devtools` and
`three-blocks/shaders`.

Captures and checks run in isolated Node.js processes with native ANGLE/WebGL,
Dawn/WebGPU, worker threads, and native media decoding. No browser installation
is needed. Image preparation uses Skia; PNG and JPEG captures use dedicated decoders.

## Set up a project

The Three Blocks starter includes this setup. For an existing Vite app:

```bash
npm install --save-dev @three-blocks/devtools
```

```typescript
import { defineConfig } from "vite";
import { threeBlocks } from "three-blocks/vite";

export default defineConfig(({ mode }) => ({
  plugins: [threeBlocks({ shaders: { strict: mode === "strict" } })],
}));
```

Register your page-owned renderer once:

```typescript
import { registerDevtools } from "three-blocks/devtools";

registerDevtools({ renderer });
```

Click **Capture** in the development overlay, or run:

```bash
npx three-blocks shaders capture
```

The first capture creates `three-blocks.shaders.json` for `/`. It writes source
artifacts to `.three-blocks/shaders/` and runtime manifests to
`public/three-blocks/shaders/`. Commit both. In a build, `registerDevtools()` loads the
active backend's manifest before the first shader build. Apps with custom transport can
use `installShaderCache()`.

The development server always compiles TSL live, because the next edit strands the
receipt. **Preview production shaders** in the overlay (`?tbShaders=precompiled`) hydrates
the captured manifest on request and returns to live once it goes stale.

The overlay shows **Live** or **Precompiled**, switches between WebGPU and WebGL,
and displays timing only when it matches the current receipt. Capture writes a
local estimate; `shaders test` replaces it with repeated measurements.
`--commit-timing` writes a shareable, hardware-labelled `timing.json`.

## Commands

Run these through your project's installed package. All commands support `--json`
and `--reporter json`; `--root project_path` selects a different project.

| Command | Purpose |
| --- | --- |
| `npx three-blocks status` | Worker, asset, shader, and text state |
| `npx three-blocks shaders status --check` | GPU-free freshness verification |
| `npx three-blocks shaders capture --if-stale` | Capture changed scenes and optimize public GLB/HDR assets |
| `npx three-blocks shaders test --parity-only` | One live/precompiled correctness pair per scene |
| `npx three-blocks shaders test` | Parity, repeated timing, and published-page checks |
| `npx three-blocks text generate` | MSDF atlases and receipts |
| `npx three-blocks text status` | Text checksums and glyph coverage |
| `npx three-blocks environment bake --size 256` | Prefiltered environment KTX2 |
| `npx three-blocks optimize` | GLB, texture, and HDR compression to meshopt/KTX2 |
| `npx three-blocks assets status --check` | Optimized-asset receipt verification |
| `npx three-blocks browser smoke --route /` | Development readiness and HMR in Node |
| `npx three-blocks browser preview --route /` | Build and verify the production preview in Node |

During development, use live compilation while editing and capture through the
overlay when ready. Reserve batch capture for an explicit request or a final
release check. A GPU-free CI gate is:

```bash
npx three-blocks shaders test --skip-browser --mode strict
```

`--skip-browser` is the existing command spelling for static-only verification.
The default capture backend is `both`; `--backend webgpu` or `--backend webgl`
selects one lane. Each scene/backend has its own manifest and freshness result.

## Capture contracts

For multiple routes or explicit readiness, configure:

```json
{
  "schemaVersion": 1,
  "backend": "both",
  "scenes": [
    { "key": "main", "url": "/" },
    { "key": "text", "url": "/text", "requiresText": true }
  ],
  "readiness": { "global": "__THREE_BLOCKS_READY__" }
}
```

Readiness can be a boolean global, a promise, or a selector. Without an override,
capture waits for settled-frame and first-frame readiness. Explicit stable keys
help with conditional scene matrices; otherwise capture assigns scene-scoped
keys. `allowLiveBuilds: false` requires every build to belong to the matrix.

The v3 manifest records actual render and compute NodeBuilder states. Receipt
writes are transactional; relevant source changes or capture failures preserve
the previous committed artifacts. Missing keys, stale receipts, incompatible
Three.js versions, unavailable GLSL extensions, and hydration mismatches fall
back to live shader building.

Parity requires a live baseline that builds every registered pipeline and
kernel, followed by zero registered builds, no misses, first-frame readiness,
non-black output, and matching deterministic pixels on the precompiled path.
Successful scenes are checkpointed against their receipts and shared tool/runtime
contract. Failures write live, precompiled, and diff PNGs to
`.three-blocks/shaders/parity/`. The default per-scene timeout is 240 seconds.

Shader precompilation supports Three.js `>=0.185.0 <0.186.0`. Adapters apply the
same version-gated transform in memory and never modify `node_modules`.
`npx three-blocks shaders` reports the installed compatibility requirements.
Unknown or partially patched builds fail closed; recapture older artifacts.

The supported WebGL path is `WebGPURenderer`'s fallback backend. Standalone
`WebGLRenderer` has no provider seam. Compute, storage writes, subgroups, and
PBO-backed storage reads stay live on WebGL, with a warning.

## Other bundlers

Capture detects Next.js, webpack, Rollup, and esbuild. Missing adapter wiring
produces a configuration diff requiring confirmation; review it before using
`--yes` in automation. Manual adapter exports from `@three-blocks/devtools/transform`:

| Bundler | Adapter |
| --- | --- |
| esbuild | `createEsbuildShaderPlugin({ root: process.cwd() })` |
| Rollup | `createRollupShaderPlugin({ root: process.cwd() })` |
| webpack | `withThreeBlocksWebpack(config)` |
| Next.js | `withThreeBlocksNext(config)` |

Adapters always install the provider hook. Capture instrumentation requires
`THREE_BLOCKS_SHADER_TOOL=1`, set automatically for tool-managed servers.
Set it yourself when attaching to a manually started transformed server with
`--url http://localhost:3000`. For other output directories use
`--driver static --serve build_directory`. Explicit driver/URL choices do not
edit bundler configuration.

## Integration and environment checks

Smoke starts Vite on loopback and verifies worker, asset, compile, and optional
text readiness; Draco/KTX2 routes; Meshopt initialization; and non-black rendered
output. Page and console errors fail the run apart from the explicitly documented
ambient-noise rules. `--hmr project_relative_module` triggers Vite's watcher
without editing source and verifies the update and lifecycle readiness.

Environment bake renders Three.js `RoomEnvironment` in Node, validates the RGBA16F
PMREM atlas, checks zstd round trips byte-for-byte, and transactionally replaces
the KTX2/metadata pair. Use `--output path` or `--no-zstd` when needed.

Production includes hydration without the development overlay/statistics code.
`threeBlocks({ stats: { production: true } })` enables a local console receipt;
no telemetry leaves the app. No Devtools command checks accounts or entitlements.

See the [Devtools guide](https://threejs-blocks.com/docs/tools/devtools) for full
integration examples, compatibility patches, and troubleshooting.

## License and Pro terms

This package uses [PolyForm Noncommercial 1.0.0](./LICENSE). Personal and noncommercial projects can install and run every Devtools command without an account, Pro seat, or runtime entitlement check. Keep the Required Notice when redistributing the package.

Pro is a per-seat subscription. During an active period, each person who starts or develops a new commercial Project, adopts a later software version, or downloads or updates a Pro Tool needs a named seat. Each Project started during that period receives a lifetime commercial license for versions released during the same period. After cancellation, the Project may be maintained, updated, and distributed with those covered versions, and Pro Tool versions obtained during the active period may keep running locally and offline for that Project. Starting another commercial Project, adopting a later release, or downloading or updating a Pro Tool requires an active subscription. Devtools remains account-free because commercial permission is a license boundary, not a feature gate. See the [Commercial License Agreement](https://threejs-blocks.com/license) and [pricing](https://threejs-blocks.com/pricing).
