@three-blocks/devtools 11.1.0 → 12.0.0-alpha.399.g24d19fd0f1a1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +33 -0
- package/README.md +6 -2
- package/dist/{asset-optimize-YJGWKD4Y.js → asset-optimize-AC3RBHSK.js} +1 -1
- package/dist/browser/shader-capture.js +2 -2
- package/dist/browser-smoke-ZHNB3MIO.js +1 -0
- package/dist/{chunk-BBODS5RH.js → chunk-2SGYUV6P.js} +1 -1
- package/dist/chunk-75JSWKB4.js +2 -0
- package/dist/chunk-7YWPJCDF.cjs +1 -0
- package/dist/chunk-EX34XRLW.js +78 -0
- package/dist/chunk-HIS44NIG.js +23 -0
- package/dist/chunk-RITS37ER.js +1 -0
- package/dist/{chunk-S5LI2C2H.js → chunk-SNPGWQMW.js} +2 -2
- package/dist/chunk-UDMY6S4M.js +16 -0
- package/dist/chunk-UO6IYJA3.js +257 -0
- package/dist/chunk-WWBW6MPB.js +2 -0
- package/dist/cli.js +28 -27
- package/dist/index.d.ts +87 -48
- package/dist/index.js +1 -1
- package/dist/shader-browser-N5LY2NJX.js +1 -0
- package/dist/shader-capture-server.d.ts +13 -1
- package/dist/shader-capture-server.js +14 -14
- package/dist/{shader-config-AKZEKIRB.js → shader-config-TOBHWNCD.js} +1 -1
- package/dist/shader-workflow-JU5VYBN7.js +1 -0
- package/dist/status-CJTXLJBV.js +1 -0
- package/dist/transform.cjs +1 -1
- package/dist/transform.js +1 -1
- package/dist/webpack-loader.cjs +1 -1
- package/dist/webpack-loader.js +1 -1
- package/node/index.d.mts +2 -1
- package/node/index.mjs +10 -2
- package/node/layout.mjs +14 -2
- package/node/loader.mjs +5 -2
- package/node/worker.mjs +29 -6
- package/package.json +9 -4
- package/dist/browser-smoke-4MYMHKWB.js +0 -1
- package/dist/chunk-4SVF5BRM.js +0 -2
- package/dist/chunk-DCLDEPPB.js +0 -253
- package/dist/chunk-LMLJIVNY.cjs +0 -1
- package/dist/chunk-LSH64HEU.js +0 -80
- package/dist/chunk-NDIPQLTU.js +0 -16
- package/dist/chunk-NJITVI23.js +0 -2
- package/dist/chunk-O5FU2ASS.js +0 -16
- package/dist/chunk-QQKHDH26.js +0 -1
- package/dist/chunk-SBUKHO24.js +0 -1
- package/dist/shader-browser-6ICBHK3S.js +0 -1
- package/dist/shader-watch-JBUA4LP5.js +0 -1
- package/dist/shader-workflow-5EHHR32D.js +0 -1
- package/dist/status-GDVSLQWV.js +0 -1
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import {b as b$1,a as a$2}from'./chunk-2SGYUV6P.js';import {b}from'./chunk-ZG3LO3VB.js';import {a as a$1}from'./chunk-WNSGAV6N.js';import {j,a as a$3,c}from'./chunk-ECQE4D2U.js';import {a}from'./chunk-7X4DHW36.js';import {launchNodeRenderer}from'@three-blocks/devtools/node';import {spawnSync}from'child_process';import {randomUUID}from'crypto';import {existsSync}from'fs';import {mkdir,realpath,writeFile,rename,rm}from'fs/promises';import {createRequire}from'module';import g from'path';import {PNG}from'pngjs';var me="virtual:three-blocks-devtools/browser-smoke",be=`\0${me}`,Je=`/@id/__x00__${me}`,Be=9e4;async function Ee(){return {vite:await import('vite')}}a(Ee,"loadBrowserSmokeTools");function V(e,o,t,r,s){let n=e??s;if(!Number.isSafeInteger(n)||n<t||n>r)throw new Error(`${o} must be an integer in ${t}...${r}.`);return n}a(V,"boundedInteger");function _e(e,o,t,r,s){let n=e??s;if(!Number.isFinite(n)||n<t||n>r)throw new Error(`${o} must be a finite number in ${t}...${r}.`);return n}a(_e,"boundedRatio");function Pe(e){let o=e??"/";if(o.length===0||o.length>2048||/[\u0000-\u001f\u007f]/u.test(o))throw new Error("Browser smoke route must be a bounded project URL.");let t=new URL(o,"http://three-blocks.invalid/");if(t.origin!=="http://three-blocks.invalid"||t.hash.length>0)throw new Error("Browser smoke route must stay within the project and have no fragment.");return `${t.pathname}${t.search}`}a(Pe,"safeRoute");function z(e,o){return e[o]===true}a(z,"booleanField");function I(e,o){if(!a$1(e)||!a$1(e.value))return {source:"missing",backend:"unknown",worker:false,workerReady:false,assetsReady:false,compileEnd:false,textEnabled:o,textReady:!o,firstFrame:false};let t=e.value,r=e.source==="public";if(r&&t.protocolVersion!==1)return {source:"public",backend:"unknown",worker:false,workerReady:false,assetsReady:false,compileEnd:false,textEnabled:o,textReady:!o,firstFrame:false};let s=a$1(t.readiness)?t.readiness:t,n=t.worker,l=r&&a$1(n)?n.offscreenCanvas===true&&n.visible===true:n===true;return {source:r?"public":"legacy",backend:r&&a$1(n)?n.offscreenCanvas===true?"OffscreenCanvas":"MainThread":n===true?"OffscreenCanvas":"unknown",worker:l,workerReady:z(s,"workerReady"),assetsReady:z(s,"assetsReady")||z(s,"loadEnd"),compileEnd:z(s,"compileEnd"),textEnabled:o,textReady:!o||z(s,"textReady"),firstFrame:z(s,"firstFrame")}}a(I,"parseBrowserSmokeLifecycle");function le(e){let o=PNG.sync.read(e),t=Math.floor(o.width*.25),r=Math.floor(o.width*.75),s=Math.floor(o.height*.25),n=Math.floor(o.height*.75),l=0,c=0;for(let y=s;y<n;y+=2)for(let p=t;p<r;p+=2){let b=(y*o.width+p)*4,i=o.data[b],a=o.data[b+1],m=o.data[b+2];i===void 0||a===void 0||m===void 0||(l+=Math.max(i,a,m),c+=1);}return c===0?0:l/c}a(le,"screenshotLuminance");function Xe(){return `
|
|
2
|
+
import * as THREE from 'three/webgpu';
|
|
3
|
+
import { createAssetLoaderRegistry, createAssetManager, createThreeAssetAdapters, defineAssets } from 'three-blocks/assets';
|
|
4
|
+
import { SceneHotReloader } from 'three-blocks/hmr';
|
|
5
|
+
import { createShaderCache } from 'three-blocks/shaders';
|
|
6
|
+
import { createStatsWorker } from 'three-blocks/stats';
|
|
7
|
+
import { threeBlocksBuildReceipt, threeBlocksConfig, loadThreeBlocksMeshoptDecoder } from 'three-blocks/vite/config';
|
|
8
|
+
|
|
9
|
+
const root = globalThis;
|
|
10
|
+
const hmr = root.__threeBlocksSmokeProbe ??= { before: 0, after: 0 };
|
|
11
|
+
if ( import.meta.hot ) {
|
|
12
|
+
import.meta.hot.on( 'vite:beforeUpdate', () => { hmr.before += 1; } );
|
|
13
|
+
import.meta.hot.on( 'vite:afterUpdate', () => { hmr.after += 1; } );
|
|
14
|
+
import.meta.hot.accept();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async function externalCodec( name, config, pathKey ) {
|
|
18
|
+
if ( config === false ) return { name, state: 'disabled', routes: [], decoded: false, evidence: 'delivery', blocker: null, error: null };
|
|
19
|
+
const routes = [];
|
|
20
|
+
try {
|
|
21
|
+
for ( const file of config.files ) {
|
|
22
|
+
const route = config[ pathKey ] + file;
|
|
23
|
+
const response = await fetch( new URL( route, location.origin ), { cache: 'no-store' } );
|
|
24
|
+
const body = await response.arrayBuffer();
|
|
25
|
+
if ( ! response.ok ) throw new Error( route + ' returned HTTP ' + response.status );
|
|
26
|
+
if ( body.byteLength === 0 ) throw new Error( route + ' returned an empty body' );
|
|
27
|
+
routes.push( { route: new URL( route, location.origin ).pathname, bytes: body.byteLength, contentType: response.headers.get( 'content-type' ) ?? '' } );
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
name,
|
|
31
|
+
state: 'ready',
|
|
32
|
+
routes,
|
|
33
|
+
decoded: false,
|
|
34
|
+
evidence: 'delivery',
|
|
35
|
+
blocker: null,
|
|
36
|
+
error: null,
|
|
37
|
+
};
|
|
38
|
+
} catch ( error ) {
|
|
39
|
+
return { name, state: 'error', routes, decoded: false, evidence: 'delivery', blocker: null, error: error instanceof Error ? error.message : String( error ) };
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function meshoptCodec() {
|
|
44
|
+
if ( threeBlocksConfig.codecs.meshopt === false ) return { name: 'meshopt', state: 'disabled', routes: [], decoded: false, evidence: 'decoder-ready', blocker: null, error: null };
|
|
45
|
+
try {
|
|
46
|
+
const decoder = await loadThreeBlocksMeshoptDecoder();
|
|
47
|
+
await decoder.ready;
|
|
48
|
+
if ( decoder.supported !== true ) throw new Error( 'Meshopt decoder reports supported=false' );
|
|
49
|
+
return {
|
|
50
|
+
name: 'meshopt',
|
|
51
|
+
state: 'ready',
|
|
52
|
+
routes: [],
|
|
53
|
+
decoded: false,
|
|
54
|
+
evidence: 'decoder-ready',
|
|
55
|
+
blocker: null,
|
|
56
|
+
error: null,
|
|
57
|
+
};
|
|
58
|
+
} catch ( error ) {
|
|
59
|
+
return { name: 'meshopt', state: 'error', routes: [], decoded: false, evidence: 'decoder-ready', blocker: null, error: error instanceof Error ? error.message : String( error ) };
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async function decodeCodecFixtures() {
|
|
64
|
+
const fixtureRoot = '/__three-blocks-codec-fixtures';
|
|
65
|
+
const available = await fetch( fixtureRoot + '/Box.gltf', { cache: 'no-store' } ).then( async response => {
|
|
66
|
+
if ( ! response.ok ) return false;
|
|
67
|
+
try {
|
|
68
|
+
const value = JSON.parse( await response.text() );
|
|
69
|
+
return Array.isArray( value?.extensionsUsed ) && value.extensionsUsed.includes( 'KHR_draco_mesh_compression' );
|
|
70
|
+
} catch {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
}, () => false );
|
|
74
|
+
if ( ! available ) return null;
|
|
75
|
+
const canvas = document.createElement( 'canvas' );
|
|
76
|
+
canvas.width = 4;
|
|
77
|
+
canvas.height = 4;
|
|
78
|
+
const renderer = new THREE.WebGPURenderer( { canvas, antialias: false } );
|
|
79
|
+
let runtime;
|
|
80
|
+
let manager;
|
|
81
|
+
try {
|
|
82
|
+
await renderer.init();
|
|
83
|
+
runtime = createThreeAssetAdapters( {
|
|
84
|
+
renderer,
|
|
85
|
+
codecs: threeBlocksConfig.codecs,
|
|
86
|
+
loadMeshopt: loadThreeBlocksMeshoptDecoder,
|
|
87
|
+
} );
|
|
88
|
+
manager = createAssetManager( runtime.registry );
|
|
89
|
+
const load = async ( name, definition, validate ) => {
|
|
90
|
+
try {
|
|
91
|
+
const lease = await manager.lease( defineAssets( { fixture: definition } ) );
|
|
92
|
+
try {
|
|
93
|
+
if ( ! validate( lease.assets.fixture ) ) throw new Error( name + ' returned the wrong decoded object.' );
|
|
94
|
+
return { ok: true, error: null };
|
|
95
|
+
} finally {
|
|
96
|
+
lease.release();
|
|
97
|
+
}
|
|
98
|
+
} catch ( error ) {
|
|
99
|
+
return { ok: false, error: error instanceof Error ? error.message : String( error ) };
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
return {
|
|
103
|
+
draco: await load( 'Draco', { type: 'gltf', url: fixtureRoot + '/Box.gltf' }, value => value?.scene?.isObject3D === true ),
|
|
104
|
+
meshopt: await load( 'Meshopt', { type: 'gltf', url: fixtureRoot + '/Meshopt.gltf' }, value => value?.scene?.isObject3D === true ),
|
|
105
|
+
ktx2: await load( 'KTX2', { type: 'ktx2', url: fixtureRoot + '/geist.msdf.ktx2' }, value => value?.isTexture === true ),
|
|
106
|
+
};
|
|
107
|
+
} finally {
|
|
108
|
+
await manager?.shutdown();
|
|
109
|
+
await runtime?.dispose();
|
|
110
|
+
renderer.dispose();
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
async function proveHotRuntime() {
|
|
115
|
+
const sharedAsset = { id: 'shared-browser-smoke-asset' };
|
|
116
|
+
let disposedAssets = 0;
|
|
117
|
+
const registry = createAssetLoaderRegistry( {
|
|
118
|
+
json: {
|
|
119
|
+
type: 'json',
|
|
120
|
+
load: async () => sharedAsset,
|
|
121
|
+
dispose: () => { disposedAssets += 1; },
|
|
122
|
+
},
|
|
123
|
+
} );
|
|
124
|
+
const manager = createAssetManager( registry );
|
|
125
|
+
const manifest = { shared: { type: 'json', url: '/__three-blocks-smoke-shared.json' } };
|
|
126
|
+
const createScene = async ( name ) => {
|
|
127
|
+
const scope = manager.createScope();
|
|
128
|
+
const assets = await scope.load( manifest );
|
|
129
|
+
return {
|
|
130
|
+
name,
|
|
131
|
+
asset: assets.shared,
|
|
132
|
+
hot: { state: 0 },
|
|
133
|
+
dispose() { scope.dispose(); },
|
|
134
|
+
};
|
|
135
|
+
};
|
|
136
|
+
const first = await createScene( 'first' );
|
|
137
|
+
first.hot.state = 37;
|
|
138
|
+
let now = 0;
|
|
139
|
+
const pushed = [];
|
|
140
|
+
const profiler = {
|
|
141
|
+
init() {}, begin() {}, end() {}, update() {}, dispose() {},
|
|
142
|
+
getData: () => ( { fps: 60, cpu: 1, gpu: 2, gpuCompute: 3 } ),
|
|
143
|
+
};
|
|
144
|
+
const stats = createStatsWorker( {
|
|
145
|
+
sampleRate: 4,
|
|
146
|
+
now: () => now,
|
|
147
|
+
publish: ( value ) => pushed.push( value ),
|
|
148
|
+
createProfiler: async () => profiler,
|
|
149
|
+
} );
|
|
150
|
+
await stats.init( {} );
|
|
151
|
+
stats.beginFrame();
|
|
152
|
+
stats.endFrame();
|
|
153
|
+
const stableStats = stats;
|
|
154
|
+
const reloader = new SceneHotReloader( first, {
|
|
155
|
+
context: { manager, stats },
|
|
156
|
+
compile: ( candidate ) => {
|
|
157
|
+
if ( candidate.name === 'failed' ) throw new Error( 'intentional browser-smoke compile failure' );
|
|
158
|
+
},
|
|
159
|
+
} );
|
|
160
|
+
const replaced = await reloader.replace( () => createScene( 'second' ) );
|
|
161
|
+
now = 300;
|
|
162
|
+
stats.beginFrame();
|
|
163
|
+
stats.endFrame();
|
|
164
|
+
const cacheAfterCommit = manager.cacheSnapshot();
|
|
165
|
+
const committed = reloader.current;
|
|
166
|
+
let rollbackPhase = null;
|
|
167
|
+
try {
|
|
168
|
+
await reloader.replace( () => createScene( 'failed' ) );
|
|
169
|
+
} catch ( error ) {
|
|
170
|
+
rollbackPhase = error && typeof error === 'object' ? error.phase : null;
|
|
171
|
+
}
|
|
172
|
+
const cacheAfterRollback = manager.cacheSnapshot();
|
|
173
|
+
const shaderCache = createShaderCache( 'browser-smoke' );
|
|
174
|
+
const firstMaterial = {};
|
|
175
|
+
const firstRegistration = shaderCache.forScene( 'browser-smoke' ).material( 'browser-smoke/material', firstMaterial );
|
|
176
|
+
const nextMaterial = {};
|
|
177
|
+
const nextRegistration = shaderCache.forScene( 'browser-smoke', { replaceExisting: true } )
|
|
178
|
+
.material( 'browser-smoke/material', nextMaterial );
|
|
179
|
+
firstRegistration.dispose();
|
|
180
|
+
const invalidation = shaderCache.invalidationFor( 'browser-smoke/material', 'browser-smoke' );
|
|
181
|
+
const shaderReplacementActive = shaderCache.registration( 'browser-smoke/material', 'browser-smoke' )?.target === nextMaterial;
|
|
182
|
+
nextRegistration.dispose();
|
|
183
|
+
const result = {
|
|
184
|
+
sceneIdentityReplaced: replaced.previous === first && replaced.current === committed && committed !== first,
|
|
185
|
+
stateRestored: committed.hot.state === 37,
|
|
186
|
+
assetIdentityPreserved: first.asset === committed.asset && committed.asset === sharedAsset,
|
|
187
|
+
assetReferencesPreserved: cacheAfterCommit.length === 1 && cacheAfterCommit[ 0 ]?.references === 1 && disposedAssets === 0,
|
|
188
|
+
statsIdentityPreserved: stats === stableStats,
|
|
189
|
+
statsSequenceAdvanced: pushed.length === 2 && pushed[ 0 ]?.sequence === 0 && pushed[ 1 ]?.sequence === 1,
|
|
190
|
+
shaderInvalidated: shaderReplacementActive && invalidation?.key === 'browser-smoke/material' && /replaced during HMR/.test( invalidation.reason ),
|
|
191
|
+
rollbackPreserved: rollbackPhase === 'compile' && reloader.current === committed && cacheAfterRollback.length === 1 && cacheAfterRollback[ 0 ]?.references === 1,
|
|
192
|
+
};
|
|
193
|
+
committed.dispose();
|
|
194
|
+
stats.dispose();
|
|
195
|
+
await manager.shutdown();
|
|
196
|
+
return result;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export async function probe() {
|
|
200
|
+
const codecs = [
|
|
201
|
+
await externalCodec( 'draco', threeBlocksConfig.codecs.draco, 'decoderPath' ),
|
|
202
|
+
await externalCodec( 'ktx2', threeBlocksConfig.codecs.ktx2, 'transcoderPath' ),
|
|
203
|
+
await meshoptCodec(),
|
|
204
|
+
];
|
|
205
|
+
const decoded = await decodeCodecFixtures();
|
|
206
|
+
if ( decoded ) {
|
|
207
|
+
for ( const codec of codecs ) {
|
|
208
|
+
const result = decoded[ codec.name ];
|
|
209
|
+
if ( result?.ok ) {
|
|
210
|
+
codec.decoded = true;
|
|
211
|
+
codec.evidence = 'asset-manager-decoded';
|
|
212
|
+
codec.blocker = null;
|
|
213
|
+
} else if ( result ) {
|
|
214
|
+
codec.state = 'error';
|
|
215
|
+
codec.error = result.error;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return {
|
|
220
|
+
textEnabled: threeBlocksConfig.text.enabled,
|
|
221
|
+
receipt: threeBlocksBuildReceipt,
|
|
222
|
+
hmrEvidence: await proveHotRuntime(),
|
|
223
|
+
codecs,
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
`}a(Xe,"browserProbeSource");function Ye(){return {name:"three-blocks:browser-smoke-probe",enforce:"post",resolveId(e){return e===me?be:void 0},load(e){return e===be?Xe():void 0}}}a(Ye,"browserProbePlugin");function Te(e){let o={console:[],page:[]};return e.on("console",t=>{t.type()!=="error"||b(t.text())||o.console.push(t.text());}),e.on("pageerror",t=>{b(t.message)||o.page.push(t.message);}),o}a(Te,"collectPageErrors");async function G(e){return e.evaluate(()=>{let o=globalThis,t=o.__threeBlocksSmoke;if(t!==void 0)return {source:"public",value:t};let r=o.__threeBlocksBrowserTools;if(r&&typeof r=="object"){let s=Reflect.get(r,"smoke");if(s!==void 0)return {source:"public",value:s}}return {source:o.__threeBlocks===void 0?"missing":"legacy",value:o.__threeBlocks??null}})}a(G,"readBridge");async function Ze(e){return e.evaluate(()=>{let o=globalThis,t=o.document.querySelector("[data-tb-fatal-code]"),r=t?.getAttribute("data-tb-fatal-code")??"",s=(t?.title||t?.textContent||"")?.replace(/^three-blocks — error:\s*/u,"").replace(/^Uncaught(?:\s+Error)?:\s*/u,"").trim()??"";return {fatalVisible:t!==null&&/^[a-z][a-z0-9-]{0,63}$/u.test(r)&&o.getComputedStyle(t).display!=="none"&&o.getComputedStyle(t).visibility!=="hidden",code:r.length>0?r:null,detail:s.length>0?s:null}})}a(Ze,"readCompatibilityFailure");async function ke(e){return e.evaluate(()=>{let o=globalThis,t=o.__threeBlocksTextFallbackProbe?.states,r=Array.isArray(t)?t.filter(c=>typeof c=="string").slice(0,32):[],s=r.indexOf("fallback"),n=r.lastIndexOf("ready"),l=[...o.document.querySelectorAll("[data-canvas-text]")];return {states:r,fallbackObserved:s>=0,recovered:s>=0&&n>s,visibleElements:l.filter(c=>c.getAttribute("data-canvas-text-fallback")!=="false").length,totalElements:l.length}})}a(ke,"readTextFallbackEvidence");async function Z(e){return e.evaluate(()=>{let o=globalThis,t=o.__threeBlocksSmoke?.diagnostics?.shaderMode,r=o.__threeBlocksSmoke?.shaders;return {snapshots:Math.max(0,Number(o.__threeBlocksSmoke?.stats?.snapshots)||0),textures:Math.max(0,Number(o.__threeBlocksSmoke?.stats?.textures)||0),shaderMode:t==="precompiled"||t==="live"?t:null,shaders:r===void 0?null:{injected:Number(r.injected)||0,missed:Number(r.missed)||0,live:Number(r.live)||0},mainPanels:o.document.querySelector("[data-three-blocks-stats-mode]")!==null}})}a(Z,"readBrowserRuntimeObservation");async function Qe(e,o){let t=Buffer.from(`${JSON.stringify(o,null,2)}
|
|
227
|
+
`,"utf8");if(t.byteLength>b$1)throw new Error(`Runtime status receipt exceeds ${b$1} bytes.`);let r=g.join(e,...a$2.split("/")),s=g.dirname(r);await mkdir(s,{recursive:true});let n=await realpath(s),l=g.relative(e,n);if(l.startsWith("..")||g.isAbsolute(l))throw new Error("Runtime status receipt directory escapes the project root.");let c=g.join(n,`.status.${process.pid}.${randomUUID()}.tmp`);try{await writeFile(c,t,{flag:"wx",mode:384}),await rename(c,r);}finally{await rm(c,{force:true});}}a(Qe,"writeRuntimeStatusReceipt");async function Q(e,o,t){await e.waitForFunction(r=>{let s=globalThis,n=s.__threeBlocksSmoke,l=n!==void 0;if(n===void 0){let i=s.__threeBlocksBrowserTools;i&&typeof i=="object"&&(n=Reflect.get(i,"smoke")),l=n!==void 0;}if(n===void 0&&(n=s.__threeBlocks),!n||typeof n!="object")return false;let c=n;if(l&&c.protocolVersion!==1)return false;let y=c.readiness&&typeof c.readiness=="object"?c.readiness:c,p=c.worker;return (l&&p&&typeof p=="object"?Reflect.get(p,"offscreenCanvas")===true&&Reflect.get(p,"visible")===true:p===true)&&y.workerReady===true&&(y.assetsReady===true||y.loadEnd===true)&&y.compileEnd===true&&y.firstFrame===true&&(!r||y.textReady===true)},o,{timeout:t});}a(Q,"waitForLifecycle");async function ge(e,o){await e.waitForFunction(()=>{let r=[...globalThis.document.querySelectorAll("[data-canvas-text]")];return r.length>0&&r.every(s=>s.getAttribute("data-canvas-text-fallback")==="true")},void 0,{timeout:Math.min(o,3e4)});}a(ge,"waitForTextFallback");async function de(e,o,t){await o();let r=250,s=performance.now()+Math.min(t,5e3),n=performance.now(),l=a(()=>{n=performance.now();},"navigated");e.on("framenavigated",l);try{for(;performance.now()-n<r;){if(performance.now()>=s)throw new Error("Timed out waiting for startup navigation to settle.");await e.waitForTimeout(25);}}finally{e.off("framenavigated",l);}await o();}a(de,"waitForStableReadiness");async function ve(e,o){return await e(),o()}a(ve,"readAfterInitialReadiness");function er(e,o,t){if(!a$1(e)||typeof e.route!="string"||!e.route.startsWith("/")||e.route.length>2048||!Number.isSafeInteger(e.bytes)||Number(e.bytes)<=0||typeof e.contentType!="string"||e.contentType.length>256)throw new Error(`Browser codec ${o} route ${t} is invalid.`);let r=e.route.endsWith(".wasm")?"application/wasm":"javascript";if(!e.contentType.includes(r))throw new Error(`Browser codec route ${e.route} returned unexpected content-type ${JSON.stringify(e.contentType)}.`);return {route:e.route,bytes:Number(e.bytes),contentType:e.contentType}}a(er,"parseCodecRoute");function N(e,o,t){if(typeof e!="string"||!o.includes(e))throw new Error(`${t} is invalid.`);return e}a(N,"literal");function ie(e,o){if(!Number.isSafeInteger(e)||Number(e)<0)throw new Error(`${o} is invalid.`);return Number(e)}a(ie,"nonnegativeInteger");function rr(e){if(!a$1(e)||e.schemaVersion!==2||!a$1(e.renderer)||!a$1(e.assets)||!a$1(e.shaders)||!a$1(e.stats)||typeof e.output!="string"||e.output.length===0||e.output.length>2048||typeof e.threeVersion!="string"||e.threeVersion.length===0||e.threeVersion.length>128)throw new Error("Browser build receipt is invalid.");if(e.renderer.owner!=="worker"||e.renderer.api!=="WebGPU"||e.renderer.fallback!=="WebGL")throw new Error("Browser build receipt does not declare the worker-owned WebGPU/WebGL renderer contract.");let o=e.text;if(o!==void 0&&(!a$1(o)||!["ready","generating","fallback","missing","invalid"].includes(String(o.state))))throw new Error("Browser build receipt text state is invalid.");return {schemaVersion:2,renderer:{owner:"worker",api:"WebGPU",fallback:"WebGL"},assets:{draco:N(e.assets.draco,["ready","disabled"],"Browser build receipt Draco state"),ktx2:N(e.assets.ktx2,["ready","disabled"],"Browser build receipt KTX2 state"),meshopt:N(e.assets.meshopt,["lazy","disabled"],"Browser build receipt Meshopt state")},shaders:{state:N(e.shaders.state,["fresh","stale","invalid","missing"],"Browser build receipt shader state"),mode:N(e.shaders.mode,["precompiled","live"],"Browser build receipt shader mode"),pipelines:ie(e.shaders.pipelines,"Browser build receipt shader pipeline count")},...o===void 0?{}:{text:{state:N(o.state,["ready","generating","fallback","missing","invalid"],"Browser build receipt text state"),atlases:ie(o.atlases,"Browser build receipt text atlas count"),glyphs:ie(o.glyphs,"Browser build receipt text glyph count")}},stats:{enabled:e.stats.enabled===true,production:e.stats.production===true},output:e.output,threeVersion:e.threeVersion}}a(rr,"parseBuildReceipt");var ce=Object.freeze({sceneIdentityReplaced:false,stateRestored:false,assetIdentityPreserved:false,assetReferencesPreserved:false,statsIdentityPreserved:false,statsSequenceAdvanced:false,shaderInvalidated:false,rollbackPreserved:false}),X=Object.freeze({requested:false,appIdentityStable:false,contentIdentityStable:false,canvasReplaced:false,workerIdentityChanged:false,generationAdvanced:false,restartCountAdvanced:false,stateReplayed:false,readinessRestored:false,shaderModeStable:false,statsSnapshotsAdvanced:false,statsTextureTransferred:false,statsTextureStopped:false,error:null}),tr=Object.freeze(["three-blocks/assets","three-blocks/hmr","three-blocks/runtime","three-blocks/shaders","three-blocks/stats","three-blocks/text","three-blocks/worker"]);function or(e){if(!a$1(e))throw new Error("Browser HMR evidence is invalid.");let o={...ce};for(let t of Object.keys(o)){if(e[t]!==true)throw new Error(`Browser HMR evidence ${t} did not pass.`);o[t]=true;}return o}a(or,"parseHmrEvidence");function nr(e){if(!a$1(e)||typeof e.textEnabled!="boolean"||!Array.isArray(e.codecs)||e.codecs.length!==3)throw new Error("Browser codec probe returned an invalid payload.");let o=["draco","ktx2","meshopt"],t=e.codecs.map((r,s)=>{let n=o[s];if(n===void 0||!a$1(r)||r.name!==n||!["ready","disabled","error"].includes(String(r.state))||!Array.isArray(r.routes)||r.error!==null&&typeof r.error!="string")throw new Error(`Browser codec probe entry ${s} is invalid.`);let l=r.state,c=r.routes.map((p,b)=>er(p,n,b)),y=N(r.evidence,["delivery","decoder-ready","text-atlas-decoded","asset-manager-decoded"],`Browser codec ${n} evidence`);if(typeof r.decoded!="boolean"||r.blocker!==null&&typeof r.blocker!="string")throw new Error(`Browser codec ${n} decode evidence is invalid.`);if(l==="ready"&&n!=="meshopt"&&c.length===0)throw new Error(`Browser codec ${n} exposed no routes.`);if(l==="error"&&(typeof r.error!="string"||r.error.length===0||r.error.length>8192))throw new Error(`Browser codec ${n} has an invalid error.`);return {name:n,state:l,routes:c,decoded:r.decoded,evidence:y,blocker:typeof r.blocker=="string"?r.blocker:null,error:typeof r.error=="string"?r.error:null}});return {textEnabled:e.textEnabled,codecs:t,receipt:rr(e.receipt),hmrEvidence:or(e.hmrEvidence)}}a(nr,"parseCodecProbe");async function ar(e){let o=await e.evaluate(async t=>{let r=await import(t);if(typeof r.probe!="function")throw new Error("Browser smoke probe module has no probe() export.");return await r.probe()},Je);return nr(o)}a(ar,"probeCodecs");function sr(e){return e instanceof Error&&/execution context was destroyed|most likely because of a navigation/iu.test(e.message)}a(sr,"isNavigationRace");async function ir(e,o,t){for(let r=0;r<3;r++)try{return await ar(e)}catch(s){if(!sr(s)||r===2)throw s;await de(e,o,t);}throw new Error("Browser codec probe did not complete.")}a(ir,"probeCodecsAfterNavigation");async function ue(e){return e.evaluate(()=>{let o=globalThis,t=0;for(let r of o.document.querySelectorAll("canvas")){if(r.width<=0||r.height<=0)continue;let s=null;try{s=r.getContext("2d");}catch{continue}if(s)try{let n=s.getImageData(0,0,r.width,r.height).data,l=0,c=0;for(let y=0;y+2<n.length;y+=4)l+=Math.max(n[y]??0,n[y+1]??0,n[y+2]??0),c+=1;c>0&&(t=Math.max(t,l/c));}catch{}}return t})}a(ue,"panelLuminance");function lr(e){return e.split(g.sep).join("/")}a(lr,"portablePath");async function dr(e){return e.evaluate(()=>{let t=globalThis.__threeBlocksSmokeProbe;if(!t||typeof t!="object")return 0;let r=Reflect.get(t,"after");return typeof r=="number"&&Number.isSafeInteger(r)?r:0})}a(dr,"hmrEventCount");async function cr(e,o,t,r,s,n,l){if(r===void 0)return {requested:false,module:null,dispatched:false,acknowledged:false,lifecycleStable:true,sourceUnchanged:true,evidenceSource:"public-runtime-node-probe",evidence:l,restart:X,error:null};let c$1=lr(r),y=false,p=false,b=false,i=false;try{let a=await j(t,g.join(t,r),a$3.semanticInput,"HMR scene module"),m=c(a.data),u=e.moduleGraph.getModulesByFile(a.path);if(!u||u.size===0)throw new Error(`HMR scene module ${JSON.stringify(c$1)} is not in Vite's module graph.`);let h=await dr(o);e.watcher.emit("change",a.path),y=!0,await o.waitForFunction(H=>{let C=globalThis.__threeBlocksSmokeProbe;return !!(C&&typeof C=="object"&&Number(Reflect.get(C,"after"))>H)},h,{timeout:Math.min(s,3e4)}),p=!0,await Q(o,n,Math.min(s,3e4)),b=!0;let M=await j(t,a.path,a$3.semanticInput,"HMR scene module");if(i=c(M.data)===m,!i)throw new Error("HMR scene source changed during the smoke run.");return {requested:!0,module:c$1,dispatched:y,acknowledged:p,lifecycleStable:b,sourceUnchanged:i,evidenceSource:"public-runtime-node-probe",evidence:l,restart:X,error:null}}catch(a){return {requested:true,module:c$1,dispatched:y,acknowledged:p,lifecycleStable:b,sourceUnchanged:i,evidenceSource:"public-runtime-node-probe",evidence:l,restart:X,error:a instanceof Error?a.message:String(a)}}}a(cr,"exerciseHmr");async function ur(e,o,t,r){let s="stats-baseline";try{let n=await e.evaluate(()=>{let i=globalThis;return new URL(i.location.href).searchParams.get("tbStats")==="1"});n&&(s="stats-query-boot",await e.waitForFunction(()=>globalThis.__threeBlocksSmoke?.stats?.panelVisible===!0,void 0,{timeout:Math.min(o,3e4)}));let l=await e.evaluate(()=>{let i=globalThis;return {panelVisible:i.__threeBlocksSmoke?.stats?.panelVisible,textures:Number(i.__threeBlocksSmoke?.stats?.textures)||0,panelAttached:i.document.querySelector("[data-three-blocks-stats-mode]")!==null}});if(!n&&(l.panelVisible!==!1||l.textures!==0||l.panelAttached))throw new Error("Generated stats panel is not default-off before browser-smoke activation.");s="stats-enable",await e.evaluate(async()=>{let a=globalThis.__threeBlocksSmoke?.stats;if(!a||typeof a.setPanelVisible!="function"||typeof a.setPanelMode!="function")throw new Error("Generated stats panel controls are unavailable.");if(await Reflect.apply(a.setPanelVisible,a,[!0])!==!0)throw new Error("Generated stats panel could not be enabled.");if(await Reflect.apply(a.setPanelMode,a,["expanded"])!==!0)throw new Error("Generated stats panel could not be expanded.")}),s="stats-expanded",await e.waitForFunction(()=>{let i=globalThis;return i.__threeBlocksSmoke?.stats?.panelVisible===!0&&i.document.querySelector('[data-three-blocks-stats-mode="expanded"]')!==null},void 0,{timeout:Math.min(o,3e4)}),s="stats-initial-texture",await e.waitForFunction(i=>Number(globalThis.__threeBlocksSmoke?.stats?.textures)>i,l.textures,{timeout:Math.min(o,3e4)}),s="snapshot";let c=await e.evaluate(()=>{let i=globalThis,a=i.__threeBlocksSmoke,m=i.document.querySelector("#app"),u=i.document.querySelector("#scene"),h=i.document.querySelector("main")??m;if(!a||typeof a.restartWorker!="function"||!m||!u||!h||typeof a.diagnostics?.workerId!="string")throw new Error("Generated worker restart diagnostics are unavailable.");return i.__threeBlocksWorkerRestartProbe={app:m,content:h,canvas:u},{workerId:a.diagnostics.workerId,generation:a.worker.generation,restartCount:a.restart.count,snapshots:a.stats.snapshots,textures:a.stats.textures}});s="restart-call",await e.evaluate(async()=>{let i=globalThis,a=i.__threeBlocksSmoke?.restartWorker;if(typeof a!="function")throw new Error("Generated restartWorker() is unavailable.");await Reflect.apply(a,i.__threeBlocksSmoke,["browser smoke worker restart"]);}),s="restart-readiness",await e.waitForFunction(i=>{let m=globalThis.__threeBlocksSmoke,u=m?.readiness;return typeof m?.diagnostics?.workerId=="string"&&m.diagnostics.workerId!==i.workerId&&Number(m.worker?.generation)>i.generation&&m.restart?.stateReplayed===!0&&u?.workerReady===!0&&u.assetsReady===!0&&u.compileEnd===!0&&u.firstFrame===!0&&(!i.textEnabled||u.textReady===!0)},{workerId:c.workerId,generation:c.generation,textEnabled:t},{timeout:Math.min(o,45e3)}),s="stats-snapshot",await e.waitForFunction(i=>Number(globalThis.__threeBlocksSmoke?.stats?.snapshots)>i,c.snapshots,{timeout:Math.min(o,3e4)}),s="stats-texture",await e.waitForFunction(i=>Number(globalThis.__threeBlocksSmoke?.stats?.textures)>i,c.textures,{timeout:Math.min(o,3e4)});let y=await e.evaluate(i=>{let a=globalThis,m=a.__threeBlocksSmoke,u=a.__threeBlocksWorkerRestartProbe,h=m?.readiness;if(!m||!u||!h)throw new Error("Generated restart evidence disappeared.");return {requested:!0,appIdentityStable:u.app===a.document.querySelector("#app"),contentIdentityStable:u.content===(a.document.querySelector("main")??a.document.querySelector("#app")),canvasReplaced:m.restart.canvasReplaced&&u.canvas!==a.document.querySelector("#scene"),workerIdentityChanged:typeof m.diagnostics?.workerId=="string"&&m.diagnostics.workerId!==i.workerId,generationAdvanced:m.worker.generation===i.generation+1,restartCountAdvanced:m.restart.count===i.restartCount+1,stateReplayed:m.restart.stateReplayed&&m.restart.lastReason==="browser smoke worker restart",readinessRestored:h.workerReady===!0&&h.assetsReady===!0&&h.compileEnd===!0&&h.firstFrame===!0&&(!i.textEnabled||h.textReady===!0),shaderModeStable:m.diagnostics?.shaderMode===i.expectedShaderMode,statsSnapshotsAdvanced:m.stats.snapshots>i.snapshots,statsTextureTransferred:m.stats.textures>i.textures,statsTextureStopped:!1,error:null}},{...c,textEnabled:t,expectedShaderMode:r});s="stats-disable",await e.evaluate(async()=>{let a=globalThis.__threeBlocksSmoke?.stats;if(!a||typeof a.setPanelVisible!="function")throw new Error("Generated stats visibility control disappeared before disable.");if(await Reflect.apply(a.setPanelVisible,a,[!1])!==!0)throw new Error("Generated stats panel could not be disabled.")}),await e.waitForFunction(()=>globalThis.__threeBlocksSmoke?.stats?.panelVisible===!1,void 0,{timeout:Math.min(o,3e4)}),await e.waitForTimeout(750);let p=await e.evaluate(()=>Number(globalThis.__threeBlocksSmoke?.stats?.textures)||0);await e.waitForTimeout(1100);let b=await e.evaluate(()=>Number(globalThis.__threeBlocksSmoke?.stats?.textures)||0);if(b!==p)throw new Error(`Stats textures advanced after disable (${p} -> ${b}).`);return {...y,statsTextureStopped:!0}}catch(n){return {...X,requested:true,error:`${s}: ${n instanceof Error?n.message:String(n)}`}}}a(ur,"exerciseWorkerRestart");function K(e){return [...new Set(e)].sort((o,t)=>o.localeCompare(t))}a(K,"sortedUnique");function mr(e,o,t){let r=K(e),s=K(o),n=t?K([...r,...s].filter(c=>/MSDF atlases are missing code points:/iu.test(c))):[],l=new Set(n);return {console:r.filter(c=>!l.has(c)),page:s.filter(c=>!l.has(c)),resolved:n}}a(mr,"classifyRecoveredTextErrors");function yr(e){return e.replace(/\u001b\[[0-?]*[ -/]*[@-~]/gu,"")}a(yr,"stripTerminalControl");function fr(e,o,t){let r=e.config.base.startsWith("/")?e.config.base:"/";return new URL(t.replace(/^\/+/,""),`${o}${r.endsWith("/")?r:`${r}/`}`).href}a(fr,"projectUrl");async function Pr(e){let{vite:{createLogger:o,createServer:t}}=await Ee();if(e.forceWebgl===true&&e.unsupportedWorker===true)throw new Error("Browser smoke forceWebgl and unsupportedWorker modes are mutually exclusive.");if(e.unsupportedWorker===true&&e.expectTextGenerationFailure===true)throw new Error("Browser smoke unsupportedWorker and expectTextGenerationFailure modes are mutually exclusive.");let r=await realpath(e.root),s=Pe(e.route),n=V(e.timeoutMs,"Browser smoke timeoutMs",1e3,15*6e4,Be),l=V(e.settleMs,"Browser smoke settleMs",0,1e4,1e3),c={width:V(e.viewport?.width,"Browser smoke viewport width",64,8192,1024),height:V(e.viewport?.height,"Browser smoke viewport height",64,8192,640)},y=_e(e.minimumLuminance,"Browser smoke minimumLuminance",0,255,2),p,b,i,a$1,m=false,u=I(void 0,false),h=[],M=null,H=ce,f={requested:e.hmrModule!==void 0,module:e.hmrModule??null,dispatched:false,acknowledged:false,lifecycleStable:e.hmrModule===void 0,sourceUnchanged:e.hmrModule===void 0,evidenceSource:"public-runtime-node-probe",evidence:ce,restart:X,error:e.hmrModule===void 0?null:"HMR was not reached."},C=false,E=false,q={fatalVisible:false,code:null,detail:null},_={states:[],fallbackObserved:false,recovered:false,visibleElements:0,totalElements:0},v={snapshots:0,textures:0,shaderMode:null,shaders:null,mainPanels:false},$=[],L=0,A=0,P={console:[],page:[]},W,U=process.env.PATH;process.env.PATH=[g.join(r,"node_modules",".bin"),U].filter(Boolean).join(g.delimiter);try{let k=o("silent");k.warn=O=>{$.push(yr(O));},p=await t({root:r,logLevel:"silent",customLogger:k,plugins:[Ye()],optimizeDeps:{force:!0,include:[...tr]},server:{host:"127.0.0.1",port:0,strictPort:!1}}),await p.listen();let x=p.httpServer?.address();if(!x||typeof x=="string")throw new Error("Vite did not expose an ephemeral TCP address.");let R=`http://127.0.0.1:${x.port}`;b=await launchNodeRenderer(),i=await b.newContext({viewport:c}),await i.addInitScript({content:`
|
|
228
|
+
(() => {
|
|
229
|
+
const key = '__three-blocks-text-fallback-states-v1';
|
|
230
|
+
let states = [];
|
|
231
|
+
try { states = JSON.parse( sessionStorage.getItem( key ) || '[]' ); } catch {}
|
|
232
|
+
const probe = globalThis.__threeBlocksTextFallbackProbe = { states };
|
|
233
|
+
const record = value => {
|
|
234
|
+
if ( typeof value !== 'string' || value.length === 0 || probe.states.at( -1 ) === value || probe.states.length >= 32 ) return;
|
|
235
|
+
probe.states.push( value );
|
|
236
|
+
try { sessionStorage.setItem( key, JSON.stringify( probe.states ) ); } catch {}
|
|
237
|
+
};
|
|
238
|
+
const inspect = node => {
|
|
239
|
+
if ( node && node.nodeType === 1 ) record( node.getAttribute( 'data-three-blocks-text-state' ) );
|
|
240
|
+
};
|
|
241
|
+
new MutationObserver( records => {
|
|
242
|
+
for ( const mutation of records ) {
|
|
243
|
+
inspect( mutation.target );
|
|
244
|
+
for ( const node of mutation.addedNodes || [] ) {
|
|
245
|
+
inspect( node );
|
|
246
|
+
if ( node.querySelectorAll ) for ( const child of node.querySelectorAll( '[data-three-blocks-text-state]' ) ) inspect( child );
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
} ).observe( document, { subtree: true, childList: true, attributes: true, attributeFilter: [ 'data-three-blocks-text-state' ] } );
|
|
250
|
+
})();
|
|
251
|
+
`}),e.forceWebgl===!0&&await i.addInitScript(()=>{Object.defineProperty(navigator,"gpu",{configurable:!0,value:void 0});}),e.unsupportedWorker===!0&&await i.addInitScript(()=>{Object.defineProperty(globalThis,"Worker",{configurable:!0,value:void 0});}),a$1=await i.newPage();let F=a$1;if(W=Te(a$1),a$1.on("console",O=>{/WebGPU is not available, running under WebGL2 backend/iu.test(O.text())&&(E=!0);}),await a$1.goto(fr(p,R,s),{waitUntil:"domcontentloaded",timeout:n}),e.unsupportedWorker===!0)C=await ve(async()=>{await de(F,a(async()=>{await F.waitForFunction(()=>globalThis.document.querySelector("#three-blocks-dev-overlay")?.shadowRoot?.querySelector(".dot")?.dataset.tone==="error",void 0,{timeout:Math.min(n,15e3)});},"waitForFailure"),n);},()=>F.evaluate(()=>"gpu"in navigator&&navigator.gpu!==void 0)),q=await Ze(a$1),u=I(await G(a$1),!1);else {let O=a(()=>e.expectTextGenerationFailure===!0?ge(F,n):Q(F,!1,n),"initialReadiness");C=await ve(()=>de(F,O,n),()=>F.evaluate(()=>"gpu"in navigator&&navigator.gpu!==void 0));let T=await ir(a$1,O,n);if(m=T.textEnabled,h=T.codecs,M=T.receipt,H=T.hmrEvidence,e.expectTextGenerationFailure===!0){if(!T.textEnabled)throw new Error("Expected text-generation failure mode requires a text-enabled project.");await ge(a$1,n);let j=performance.now()+Math.min(n,3e4);for(;!$.some(Oe=>/automatic atlas generation failed/iu.test(Oe));){if(performance.now()>=j)throw new Error("Timed out waiting for the automatic text-generation failure warning.");await a$1.waitForTimeout(50);}u=I(await G(a$1),!0);}else if(await Q(a$1,T.textEnabled,n),u=I(await G(a$1),T.textEnabled),T.textEnabled&&u.textReady&&(h=h.map(j=>j.name==="ktx2"?{...j,decoded:!0,evidence:"text-atlas-decoded",blocker:null}:j)),f=await cr(p,a$1,r,e.hmrModule,n,T.textEnabled,H),e.hmrModule!==void 0){let j=await ur(a$1,n,T.textEnabled,T.receipt.shaders.mode);f={...f,restart:j},u=I(await G(a$1),T.textEnabled);}}l>0&&await a$1.waitForTimeout(l),_=await ke(a$1),v=await Z(a$1);let qe=await a$1.screenshot({type:"png"});L=le(qe),A=await ue(a$1);}catch(k){if(a$1!==void 0)try{u=I(await G(a$1),m),_=await ke(a$1),v=await Z(a$1);let x=await a$1.screenshot({type:"png"});L=le(x),A=await ue(a$1);}catch(x){P.page.push(`Failure diagnostics could not be captured: ${x instanceof Error?x.message:String(x)}`);}P.page.push(k instanceof Error?k.message:String(k));}finally{W!==void 0&&(P.console.push(...W.console),P.page.push(...W.page)),await i?.close().catch(R=>{P.page.push(`Browser context cleanup failed: ${R instanceof Error?R.message:String(R)}`);}),await b?.close().catch(R=>{P.page.push(`Browser cleanup failed: ${R instanceof Error?R.message:String(R)}`);});let k=p?.httpServer,x=k?Reflect.get(k,"closeAllConnections"):void 0;k&&typeof x=="function"&&Reflect.apply(x,k,[]),await p?.close().catch(R=>{P.page.push(`Vite cleanup failed: ${R instanceof Error?R.message:String(R)}`);}),U===void 0?delete process.env.PATH:process.env.PATH=U;}let Y=Number(L.toFixed(2)),re=Number(A.toFixed(2)),J=L<=y&&A<=y,B=mr(P.console,P.page,_.recovered),D=B.console,ye=B.page,Me=B.resolved,fe=u.worker&&u.workerReady&&u.assetsReady&&u.compileEnd&&u.textReady&&u.firstFrame,Ce=h.length===3&&h.every(k=>k.state!=="error"),Fe=Object.values(f.evidence).every(Boolean),$e=!f.restart.requested||f.restart.error===null&&[f.restart.appIdentityStable,f.restart.contentIdentityStable,f.restart.canvasReplaced,f.restart.workerIdentityChanged,f.restart.generationAdvanced,f.restart.restartCountAdvanced,f.restart.stateReplayed,f.restart.readinessRestored,f.restart.shaderModeStable,f.restart.statsSnapshotsAdvanced,f.restart.statsTextureTransferred,f.restart.statsTextureStopped].every(Boolean),pe=!f.requested||f.dispatched&&f.acknowledged&&f.lifecycleStable&&f.sourceUnchanged&&Fe&&$e&&f.error===null,he=$.filter(k=>/automatic atlas generation failed/iu.test(k)),Ae=he.reduce((k,x)=>k+(x.match(/three-blocks text generate/gu)?.length??0),0),Ie=e.expectTextGenerationFailure===true&&m&&_.fallbackObserved&&!_.recovered&&_.totalElements>0&&_.visibleElements===_.totalElements&&he.length===1&&Ae===1,Le=e.unsupportedWorker===true&&q.fatalVisible&&q.code==="render-worker-unavailable"&&!u.workerReady&&!u.compileEnd&&!u.firstFrame,We=e.unsupportedWorker===true?"unsupported-worker":e.forceWebgl===true?"WebGL-fallback":"WebGPU-first",je=e.unsupportedWorker===true?"none":fe?e.forceWebgl===true||!C?"WebGL":"WebGPU":"unknown",Ve=u.workerReady&&u.compileEnd&&u.firstFrame,w={schemaVersion:1,command:"browser smoke",execution:"node",passed:e.unsupportedWorker===true?Le:e.expectTextGenerationFailure===true?Ie:fe&&Ce&&pe&&!J&&D.length===0&&ye.length===0,scene:s,lifecycle:u,renderer:{requested:We,active:je,navigatorGpu:C,workerOwned:Ve,fallbackDiagnostic:E},compatibility:{...q,silentMainThreadRenderer:e.unsupportedWorker===true&&(u.compileEnd||u.firstFrame)},receipt:M,textFallback:_,warnings:K($),rendering:{luminance:Y,panelLuminance:re,threshold:y,blackFrame:J},codecs:h,hmr:f,errors:{console:D,page:ye,resolved:Me}};if(w.passed&&e.unsupportedWorker!==true&&e.expectTextGenerationFailure!==true){if(w.receipt===null||w.lifecycle.backend==="unknown"||w.renderer.active!=="WebGPU"&&w.renderer.active!=="WebGL")throw new Error("A successful browser smoke cannot write runtime status without an observed backend and renderer/build receipt.");let k=w.hmr.requested,x=k?pe:null,R={schemaVersion:1,observedAt:new Date().toISOString(),worker:{backend:w.lifecycle.backend,renderer:w.renderer.active,protocolVersion:1},assets:{codecs:w.codecs.map(F=>({name:F.name,available:F.state==="ready",decoded:F.decoded})),resources:0},hmr:{capabilities:{scene:true,component:true,assetManifest:true,workerRestart:true},outcome:{attempted:k,succeeded:x,rollbackPreserved:k?w.hmr.evidence.rollbackPreserved:null,workerRestarted:w.hmr.restart.requested&&w.hmr.restart.workerIdentityChanged}},stats:{snapshots:v.snapshots,textures:v.textures,workerProfiler:v.snapshots>0,mainPanels:v.mainPanels},lifecycle:{state:"first frame",workerReady:w.lifecycle.workerReady,assetsReady:w.lifecycle.assetsReady,compiled:w.lifecycle.compileEnd,firstFrame:w.lifecycle.firstFrame},shaders:{mode:v.shaderMode??w.receipt.shaders.mode,pipelines:w.receipt.shaders.pipelines},...w.receipt.text===void 0?{}:{text:{state:w.receipt.text.state,atlases:w.receipt.text.atlases,glyphs:w.receipt.text.glyphs,requiredGlyphs:w.receipt.text.glyphs}},error:null};await Qe(r,R);}return w}a(Pr,"runBrowserSmoke");function Tr(e){let o=e.lifecycle,t=[`${e.passed?"\u2713":"\u2717"} Browser ${e.scene} \xB7 worker ${o.worker&&o.workerReady?"ready":"failed"} \xB7 assets ${o.assetsReady?"ready":"failed"} \xB7 compile ${o.compileEnd?"ready":"failed"}`,` Renderer ${e.renderer.active} \xB7 ${e.renderer.workerOwned?"worker-owned":e.renderer.requested}`,` Frame ${e.rendering.luminance.toFixed(2)} \xB7 panel ${e.rendering.panelLuminance.toFixed(2)}${e.rendering.blackFrame?" \xB7 black":""}`,` Codecs ${e.codecs.map(r=>`${r.name} ${r.state}${r.decoded?" decoded":""}`).join(" \xB7 ")||"not observed"}`];e.compatibility.fatalVisible&&t.push(` Compatibility ${e.compatibility.detail??"fatal compatibility screen visible"}`),e.textFallback.states.length>0&&t.push(` Text ${e.textFallback.states.join(" \u2192 ")}`),e.hmr.requested&&t.push(` HMR ${e.hmr.acknowledged&&e.hmr.sourceUnchanged&&Object.values(e.hmr.evidence).every(Boolean)?"ready":"failed"} \xB7 ${e.hmr.module??"unknown module"}`),e.hmr.restart.requested&&t.push(` Restart ${e.hmr.restart.error===null&&e.hmr.restart.workerIdentityChanged&&e.hmr.restart.stateReplayed?"ready":"failed"} \xB7 worker/state/stats`);for(let r of e.warnings)t.push(` Warning ${r}`);for(let r of e.errors.console)t.push(` Console ${r}`);for(let r of e.errors.page)t.push(` Page ${r}`);for(let r of e.errors.resolved)t.push(` Recovered ${r}`);e.hmr.error&&t.push(` HMR error ${e.hmr.error}`),e.hmr.restart.error&&t.push(` Restart error ${e.hmr.restart.error}`);for(let r of e.codecs)r.error&&t.push(` ${r.name} error ${r.error}`);return t.join(`
|
|
252
|
+
`)}a(Tr,"formatBrowserSmokeReport");async function pr(e){let{vite:{build:o,preview:t}}=await Ee(),r=await realpath(e.root),s=(e.routes===void 0||e.routes.length===0?["/"]:e.routes).map(Pe),n=V(e.timeoutMs,"Browser preview timeoutMs",1e3,15*6e4,Be),l=V(e.settleMs,"Browser preview settleMs",0,1e4,500),c={width:V(e.viewport?.width,"Browser preview viewport width",64,8192,1024),height:V(e.viewport?.height,"Browser preview viewport height",64,8192,640)},y=_e(e.minimumLuminance,"Browser preview minimumLuminance",0,255,2),p=e.expectShaders??"precompiled",b=e.text===true,i=[],a,m,u=process.env.PATH;process.env.PATH=[g.join(r,"node_modules",".bin"),u].filter(Boolean).join(g.delimiter);try{await o({root:r,logLevel:"warn",...e.buildMode===void 0?{}:{mode:e.buildMode}}),a=await t({root:r,logLevel:"warn",preview:{host:"127.0.0.1",port:0,strictPort:!1,open:!1}});let h=a.httpServer?.address();if(!h||typeof h=="string")throw new Error("Vite preview did not expose an ephemeral TCP address.");let M=a.config.base.startsWith("/")?a.config.base:"/",H=`http://127.0.0.1:${h.port}${M.endsWith("/")?M:`${M}/`}`;m=await launchNodeRenderer();for(let f of s){let C=await m.newContext({viewport:c}),E=await C.newPage(),q=Te(E),_=[],v=I(void 0,b),$=null,L=null,A,P=0,W=0;try{await E.goto(new URL(f.replace(/^\/+/,""),H).href,{waitUntil:"domcontentloaded",timeout:n}),await Q(E,b,n),l>0&&await E.waitForTimeout(l),v=I(await G(E),b),{shaderMode:$,shaders:L}=await Z(E);let B=await E.screenshot({type:"png"});if(P=le(B),W=await ue(E),e.screenshots!==void 0){let D=g.resolve(r,e.screenshots);if(g.relative(r,D).startsWith(".."))throw new Error("Browser preview screenshots must stay inside the project root.");await mkdir(D,{recursive:!0}),A=g.join(D,`${f.replace(/[^a-z0-9]+/giu,"-").replace(/^-|-$/gu,"")||"index"}.png`),await writeFile(A,B);}}catch(B){try{v=I(await G(E),b),$=(await Z(E)).shaderMode;}catch{}_.push(B instanceof Error?B.message:String(B));}finally{await C.close().catch(B=>{_.push(`Browser context cleanup failed: ${B instanceof Error?B.message:String(B)}`);});}let U=K(q.console),Y=K([...q.page,..._]),re=v.worker&&v.workerReady&&v.assetsReady&&v.compileEnd&&v.textReady&&v.firstFrame,J=P<=y&&W<=y;i.push({route:f,passed:re&&!J&&$===p&&U.length===0&&Y.length===0,lifecycle:v,shaderMode:$,...L===null?{}:{shaders:L},...A===void 0?{}:{screenshot:g.relative(r,A).split(g.sep).join("/")},rendering:{luminance:Number(P.toFixed(2)),panelLuminance:Number(W.toFixed(2)),threshold:y,blackFrame:J},errors:{console:U,page:Y}});}}finally{await m?.close().catch(()=>{});let h=a?.httpServer,M=h?Reflect.get(h,"closeAllConnections"):void 0;h&&typeof M=="function"&&Reflect.apply(M,h,[]),await a?.close().catch(()=>{}),u===void 0?delete process.env.PATH:process.env.PATH=u;}return {schemaVersion:1,command:"browser preview",execution:"node",passed:i.length>0&&i.every(h=>h.passed),buildMode:e.buildMode??null,expectShaders:p,routes:i}}a(pr,"runBrowserPreview");async function Mr(e){let o=await realpath(e.root),t={ran:false,passed:true,diagnostics:[]};if(existsSync(g.join(o,"tsconfig.json"))){let n;try{n=createRequire(g.join(o,"package.json")).resolve("typescript/bin/tsc");}catch{}if(n!==void 0){let l=spawnSync(process.execPath,[n,"--noEmit","--pretty","false","-p",o],{cwd:o,encoding:"utf8"});t={ran:true,passed:l.status===0,diagnostics:`${l.stdout}${l.stderr}`.split(`
|
|
253
|
+
`).filter(c=>c.includes("error TS")).slice(0,20)};}}let{loadShaderToolConfig:r}=await import('./shader-config-TOBHWNCD.js'),s=await r(o);try{let n=await pr({root:o,routes:s.scenes.map(l=>l.url),buildMode:"strict",text:s.scenes.some(l=>l.requiresText===!0),viewport:s.viewport,screenshots:".three-blocks/check"});return {schemaVersion:1,command:"check",passed:t.passed&&n.passed,typecheck:t,preview:n}}catch(n){return {schemaVersion:1,command:"check",passed:false,typecheck:t,error:n instanceof Error?n.message:String(n)}}}a(Mr,"runProjectCheck");function Cr(e){let o=a(t=>t?"\u2713":"\u2717","mark");return [`${o(e.typecheck.passed)} types ${e.typecheck.ran?e.typecheck.passed?"clean":e.typecheck.diagnostics.join(`
|
|
254
|
+
`):"not checked (no tsconfig.json or local typescript)"}`,...(e.preview?.routes??[]).map(t=>`${o(t.passed)} ${t.route.padEnd(12)} shaders ${t.shaderMode??"unknown"}${t.shaders===void 0?"":` \xB7 ${t.shaders.injected} injected \xB7 ${t.shaders.live} live`}${t.screenshot===void 0?"":` \xB7 ${t.screenshot}`}${[...t.errors.page,...t.errors.console].map(r=>`
|
|
255
|
+
${r}`).join("")}`),...e.error===void 0?[]:[`\u2717 build ${e.error}`]].join(`
|
|
256
|
+
`)}a(Cr,"formatProjectCheckReport");function Fr(e){let o=[`${e.passed?"\u2713":"\u2717"} Preview production build${e.buildMode===null?"":` \xB7 --mode ${e.buildMode}`} \xB7 expects shaders ${e.expectShaders}`];for(let t of e.routes){let r=t.lifecycle;o.push(` ${t.passed?"\u2713":"\u2717"} ${t.route} \xB7 worker ${r.worker&&r.workerReady?"ready":"failed"} \xB7 compile ${r.compileEnd?"ready":"failed"} \xB7 shaders ${t.shaderMode??"unobserved"} \xB7 frame ${t.rendering.luminance.toFixed(2)}${t.rendering.blackFrame?" \xB7 black":""}`);for(let s of t.errors.console)o.push(` Console ${s}`);for(let s of t.errors.page)o.push(` Page ${s}`);}return o.join(`
|
|
257
|
+
`)}a(Fr,"formatBrowserPreviewReport");export{I as a,le as b,ve as c,tr as d,mr as e,Pr as f,Tr as g,pr as h,Mr as i,Cr as j,Fr as k};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import {b as b$1}from'./chunk-UDMY6S4M.js';import {j as j$1,a as a$1}from'./chunk-ECQE4D2U.js';import {a}from'./chunk-7X4DHW36.js';import {createRequire}from'module';import c from'path';import {isSupportedThreeVersion,THREE_BLOCKS_SUPPORTED_THREE_RANGE,transformThreeWebgpuProviderHooks,transformThreeWebgpuCaptureInstrumentation}from'three-blocks/vite';var s;async function d(){s===void 0&&(s=(async()=>{let e=createRequire(c.join(process.cwd(),"package.json")).resolve("@three-blocks/devtools/browser/shader-capture"),t=c.resolve(c.dirname(e),"../..");return (await j$1(t,e,a$1.metadata,"Shader capture browser runtime")).data.toString("utf8")})());let r=s;try{return await r}catch(e){throw s===r&&(s=void 0),e}}a(d,"loadShaderCaptureRuntimeSource");var T="virtual:three-blocks-shader-capture-client",S="\0three-blocks:shader-capture-client",l="virtual:three-blocks-shader-capture-runtime",b="\0three-blocks:shader-capture-runtime";async function N(){let r=await d(),e=r.replace(/\bexport\{[^{}]*\};?\s*$/u,"");if(e===r)throw new Error("Shader capture browser runtime no longer has the expected final ESM export list.");return e}a(N,"loadShaderCaptureRuntimeScriptSource");function w(r){let e=r.split("?",1)[0];return e===void 0?false:e.split(c.sep).join("/").endsWith("/build/three.webgpu.js")}a(w,"isThreeWebGPUModule");function I(r,e,t={}){if(!isSupportedThreeVersion(e))throw new Error(`The shader provider transform supports Three.js ${THREE_BLOCKS_SUPPORTED_THREE_RANGE}; received "${e}".`);let u=transformThreeWebgpuProviderHooks(r,{threeVersion:e,...t.threeRevision===void 0?{}:{threeRevision:t.threeRevision},id:"three/build/three.webgpu.js"}),a=u.state==="already-applied",i=u.code;return t.instrumentCapture&&(i=transformThreeWebgpuCaptureInstrumentation(i,{...t.captureRuntimeImport===void 0?{}:{runtimeImport:t.captureRuntimeImport},...t.forceWebGL===true?{forceWebGL:true}:{}}).code),{code:i,alreadyPresent:a,captureApplied:t.instrumentCapture===true}}a(I,"applyShaderProviderTransform");var A=/this\.trackTimestamp\s*=\s*\(\s*parameters\.trackTimestamp\s*===\s*true\s*\);/gu,_="Object.defineProperty( this, 'trackTimestamp', { get: () => false, set: () => {} } );";function j(r,e={}){if(!isSupportedThreeVersion(r))throw new Error(`The shader provider transform supports Three.js ${THREE_BLOCKS_SUPPORTED_THREE_RANGE}; received "${r}".`);let t={seen:false,applied:false,alreadyPresent:false};return {plugin:{name:"three-blocks:shader-provider-transform",enforce:"pre",config(){return {optimizeDeps:{exclude:["three","three/webgpu","three/tsl"]},resolve:{dedupe:["three"]}}},resolveId(a){return e.capture&&a===T?S:e.capture&&a===l?b:null},async load(a){return e.capture?a===b?d():a===S?[`export * from '${l}';`,`import { configureThreeBlocksShaderCapture } from '${l}';`,`configureThreeBlocksShaderCapture( ${JSON.stringify({capture:e.capture.capture,backend:e.capture.forceWebGL===true?"webgl":"webgpu",forceLive:e.capture.forceLive,driven:e.capture.driven,settleFrames:e.capture.settleFrames,settleTimeoutMs:e.capture.settleTimeoutMs,visibilityGuard:e.capture.visibilityGuard,captureId:e.capture.captureId,sessionKey:e.capture.sessionKey,token:e.capture.token,readiness:e.capture.readiness??{},transform:b$1})} );`].join(`
|
|
2
|
+
`):null:null},transform(a,i){if(!w(i))return null;t.seen=true,t.id=i;try{let n=I(a,r,{instrumentCapture:e.capture!==void 0,forceWebGL:e.capture?.forceWebGL===!0,...e.capture!==void 0?{captureRuntimeImport:T}:{}}),p=e.disableTimestampQueries===!0?n.code.replace(A,_):n.code;if(e.disableTimestampQueries===!0&&p===n.code)throw new Error("Three.js timestamp tracking anchor drifted; refusing software WebGPU capture.");return t.applied=!0,t.alreadyPresent=n.alreadyPresent,t.captureApplied=n.captureApplied,p===a?null:{code:p,map:null}}catch(n){throw t.error=n instanceof Error?n.message:String(n),n}}},status:t}}a(j,"createShaderProviderTransform");function U(r){if(r.error)throw new Error(r.error);if(!r.seen||!r.applied)throw new Error(`The version-gated shader provider transform was not applied (${r.seen?"module seen":"three/webgpu not seen"}).`)}a(U,"assertShaderProviderTransform");export{d as a,T as b,N as c,w as d,I as e,j as f,U as g};
|
package/dist/cli.js
CHANGED
|
@@ -1,30 +1,31 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {c,b as b$1,h,e,a as a$
|
|
2
|
+
import {c,b as b$1,h,e,a as a$3,f,d}from'./chunk-CMMYXGQ3.js';import {a as a$2}from'./chunk-TK566QET.js';import {g}from'./chunk-75JSWKB4.js';import'./chunk-WNSGAV6N.js';import'./chunk-ECQE4D2U.js';import {a as a$1}from'./chunk-7X4DHW36.js';import a from'process';var i=a.argv.slice(2),se=i.indexOf("--reporter"),_=i.find(e=>e.startsWith("--reporter="))?.slice(11)??(se===-1?void 0:i[se+1]),ae=se!==-1&&(_===void 0||_.startsWith("--"))?'--reporter requires "plain" or "json".':_!==void 0&&_!=="json"&&_!=="plain"?'--reporter must be "plain" or "json".':void 0,b=i.includes("--json")||_==="json",de=new Set(["--reporter","--root","--route","--build-mode","--expect-shaders","--width","--height","--timeout","--settle","--min-luminance","--hmr","--size","--output","--driver","--serve","--base","--url","--runs","--config","--mode","--out","--max-dim","--hdr-max-dim","--quality","--preset"]),ie=[];for(let e=0;e<i.length;e++){let t=i[e];if(t!==void 0){if(t.startsWith("--")){de.has(t)&&e++;continue}ie.push(t);}}var y=ie[0]??"status",C=ie[1];function w(e){let t=i.find(o=>o.startsWith(`${e}=`));if(t!==void 0){let o=t.slice(e.length+1);if(o.length===0)throw new Error(`${e} requires a value.`);return o}let d=i.indexOf(e);if(d===-1)return;let u=i[d+1];if(u===void 0||u.startsWith("--"))throw new Error(`${e} requires a value.`);return u}a$1(w,"optionValue");function ue(e){let t=[];for(let d=0;d<i.length;d++){let u=i[d];if(u!==void 0){if(u.startsWith(`${e}=`)){let o=u.slice(e.length+1);if(o.length===0)throw new Error(`${e} requires a value.`);t.push(o);}else if(u===e){let o=i[d+1];if(o===void 0||o.startsWith("--"))throw new Error(`${e} requires a value.`);t.push(o);}}}return t}a$1(ue,"optionValues");function E(e){let t=w(e);if(t===void 0)return;let d=Number(t);if(!Number.isFinite(d))throw new Error(`${e} must be a finite number.`);return d}a$1(E,"numberOption");async function ce(e){let t=`Shader provider adapter patch:
|
|
3
3
|
${e}
|
|
4
|
-
`;if(
|
|
5
|
-
`:t),
|
|
6
|
-
`));}a(
|
|
7
|
-
`)}a(
|
|
8
|
-
`)}a(
|
|
9
|
-
`),
|
|
10
|
-
`)
|
|
11
|
-
`),
|
|
12
|
-
`),
|
|
13
|
-
`);return}if(y==="
|
|
14
|
-
`)
|
|
15
|
-
|
|
16
|
-
|
|
4
|
+
`;if(a.stderr.write(b?`${JSON.stringify({type:"shader-adapter-diff",diff:e})}
|
|
5
|
+
`:t),i.includes("--yes"))return true;if(!a.stdin.isTTY||!a.stderr.isTTY)throw new Error("Adapter wiring needs consent. Review the diff above, then rerun with --yes; no files were changed.");let{createInterface:d}=await import('readline/promises'),u=d({input:a.stdin,output:a.stderr});try{let o=await u.question("Apply this patch? (y/N) ");return /^y(?:es)?$/iu.test(o.trim())}finally{u.close();}}a$1(ce,"approveAdapterPatch");function M(e){return b?{update(){},stop(){}}:h(e)}a$1(M,"wait");function le(){let e$1=a$1(g=>b$1.accent(g),"c"),t=a$1(g=>b$1.dim(g),"d"),d=c.mark?`${c.mark} `:"",u=[["Inspect",[[`${e$1("status")}`,`project report: shaders, text, browser evidence ${t("\u2014 no browser, no GPU")}`],[`${e$1("check")}`,`types + build + every scene booted in Node ${t("\u2014 with a PNG per scene")}`],[`${e$1("shaders")}`,"verify shader freshness and exit 1 with the exact recovery command"],[`${e$1("shaders status")} ${t("[--check]")}`,`per-scene shader freshness ${t("(--check exits 1 when not fresh)")}`],[`${e$1("text status")}`,"text atlas coverage"],[`${e$1("assets status")}`,"optimized-asset receipt freshness"]]],["Produce",[[`${e$1("shaders capture")} ${t("[--if-stale] [--commit-timing] [--no-assets]")}`,"capture shaders plus a local timing estimate, then optimize public GLB/.hdr assets; during development use the overlay Capture button"],[`${e$1("text generate")} ${t("[--config <path>]")}`,"regenerate MSDF text atlases"],[`${e$1("environment bake")} ${t("[--size 256]")}`,"bake the PMREM room environment to KTX2"],[`${e$1("assets optimize")} ${t("<file|dir\u2026> [--out <dir>] [--quality high]")}`,"meshopt + slot-aware KTX2 for GLB / image / .hdr inputs"]]],["Verify",[[`${e$1("shaders test")}`,"median timing + zero-build + compute + pixel parity gate"],[`${e$1("shaders test --parity-only")}`,"one correctness pair per scene; no timing or published-page soak"],[`${e$1("browser smoke")} ${t("[--route /] [--hmr <module>]")}`,"boot the dev app, verify worker lifecycle + HMR"],[`${e$1("browser preview")} ${t("[--route /]...")}`,"build + serve production, verify precompiled hydration"]]]],o=["",`${d}${b$1.bold("three-blocks devtools")} ${b$1.dim(`v${a$2}`)}`,b$1.dim("WebGPU shader precompilation and verification for Three Blocks projects."),"",`${b$1.bold("Usage")}`,` ${e$1("three-blocks-devtools")} ${t("[command] [options] [--json]")}`];for(let[g,r]of u)o.push("",b$1.bold(g),...e(r,{indent:2,maxWidth:a$3.width-2}));o.push("",b$1.bold("Options"),...e([[t("--json"),"stable machine-readable report on stdout"],[t("--reporter <plain|json>"),"select the stable terminal or CI reporter"],[t("--root <path>"),"project root (defaults to the nearest three-blocks project)"],[t("--backend <webgpu|webgl|both>"),"select shader backend lanes (default: config, then both)"],[t("--runs <n>"),"shader timing captures after warmup (default 5)"],[t("--parity-only"),"skip timing warmup/repeats and the published-page soak"],[t("--commit-timing"),"also write shareable hardware-labelled build timing"],[t("--skip-browser"),"check shader schema and freshness without browser parity"],[t("--driver <vite|static>"),"capture through Vite or an already-built static app"],[t("--serve <path>"),"built application directory for --driver static"],[t("--built"),"with --serve: write the manifests inside that directory, without receipts (a post-build step)"],[t("--base <path>"),"with --built: public path the application was built for (default /)"],[t("--url <url>"),"attach to an already-running transformed application"],[t("--yes"),"apply a previewed framework adapter patch non-interactively"],[t("--out <dir>"),"assets optimize: output directory (default: beside each input)"],[t("--max-dim <px>"),"assets optimize: LDR texture cap (default 2048)"],[t("--quality <default|high>"),"assets optimize: high = UASTC color + higher encoder effort"],[t("--preset <color|normal|data>"),"assets optimize: override the standalone-image preset"],[t("--force"),"assets optimize: re-encode even when cached"]],{indent:2,maxWidth:a$3.width-2}),"",b$1.dim("During development, use the in-page overlay Capture button for one-click recapture."),b$1.dim("`shaders capture` remains the explicit isolated-browser fallback for batch and CI."),""),f(o.join(`
|
|
6
|
+
`));}a$1(le,"help");function pe(e){return e?`${e.render} render \xB7 ${e.compute} compute`:"no coverage"}a$1(pe,"coverageText");function te(e){return e<100?e.toFixed(1):Math.round(e).toString()}a$1(te,"milliseconds");function q(e,t,d$1){return `${e} ${d(t,12)} ${d$1}`}a$1(q,"row");function fe(e$1){if(e$1.skipped)return q(c.tick,"shaders",`fresh ${c.dot} capture skipped ${b$1.dim(`(--if-stale) \xB7 ${e$1.reason}`)}`);let t=Math.max(0,Math.round((e$1.durationMs??0)/1e3)),d=e$1.scenes.length,u=[q(c.tick,"shaders",`captured in ${t} s ${c.dot} wrote ${d} shader scene${d===1?"":"s"}`)];e$1.configuration?.created===true&&u.push(b$1.dim(` created ${e$1.configuration.file} with the default "/" capture route`));for(let g$1 of e$1.scenes)u.push(q(c.tick,g(g$1.scene,g$1.backend),`${pe(g$1.coverage)} ${c.dot} ${b$1.dim(`${g$1.attempts} attempt${g$1.attempts===1?"":"s"}`)}`));let o=e$1.scenes.flatMap(g$1=>{let r=g$1.timing;if(r?.launch===void 0||r.firstRequest===void 0||r.readiness===void 0||r.lastBuild===void 0||r.settled===void 0||r.posted===void 0)return [];let p=a$1((j,l)=>`${te(Math.max(0,l-j))} ms`,"elapsed");return [[g(g$1.scene,g$1.backend),`launch\u2192request ${p(r.launch,r.firstRequest)} ${c.dot} ready ${p(r.firstRequest,r.readiness)} ${c.dot} last build ${p(r.readiness,r.lastBuild)} ${c.dot} settle ${p(r.lastBuild,r.settled)} ${c.dot} post ${p(r.settled,r.posted)}`]]});return o.length>0&&u.push("",b$1.bold("Capture stages"),...e(o,{indent:2,maxWidth:a$3.width-2})),e$1.measurement!==void 0&&u.push(` TSL builds at startup: ${e$1.measurement.beforeBuilds} \u2192 ${e$1.measurement.afterBuilds} ${c.dot} \u2248${te(Math.abs(e$1.measurement.firstFrameDeltaMs))} ms TSL work avoided (single-capture estimate)`),u.push(b$1.dim(" a running dev server reloads on its own; otherwise refresh the page")),u.join(`
|
|
7
|
+
`)}a$1(fe,"formatShaderCapture");function he(e){let t=[q(c.tick,"shaders",`no-GPU ${e.noGpu.state} ${c.dot} browser ${e.browser}`)];e.native&&t.push(q(c.tick,"native raster parity",e.native));for(let d of e.scenes){let u=g(d.scene,d.backend),o=e.timing?.scenes[u],g$1=o===void 0?`${d.coverage.render+d.coverage.compute} TSL build${d.coverage.render+d.coverage.compute===1?"":"s"} skipped`:`${o.builds} TSL build${o.builds===1?"":"s"} skipped ${c.dot} \u2248${te(o.avoidedBuildMs)} ms \xB1 ${te(o.spreadMs)} TSL work avoided ${c.dot} median of ${o.runs} ${c.dot} Latest local capture`,r=o!==void 0&&o.spreadMs>o.avoidedBuildMs*.4?` ${c.dot} ${b$1.warn("noisy measurement \u2014 close other GPU apps and re-run")}`:"";t.push(q(c.tick,u,`${g$1} ${c.dot} ${d.coverage.compute} compute ${c.dot} ${(d.parity.diffRatio*100).toFixed(3)}% pixel diff${r}`));}return t.join(`
|
|
8
|
+
`)}a$1(he,"formatShaderTest");async function me(){if(ae!==void 0)throw new Error(ae);if(y==="help"||y==="--help"||i.includes("--help"))return le();if(y==="version"||i.includes("--version")){f(b?JSON.stringify({version:a$2}):a$2);return}if(y==="check"){let{formatProjectCheckReport:r,runProjectCheck:p}=await import('./browser-smoke-ZHNB3MIO.js'),{findProjectRoot:j}=await import('./status-CJTXLJBV.js'),l=M("typechecking, building, and booting every scene"),f;try{f=await p({root:w("--root")??await j()});}finally{l.stop();}a.stdout.write(`${b?JSON.stringify(f,null,2):r(f)}
|
|
9
|
+
`),f.passed||(a.exitCode=1);return}if(y==="browser"){let{formatBrowserPreviewReport:r,formatBrowserSmokeReport:p,runBrowserPreview:j,runBrowserSmoke:l}=await import('./browser-smoke-ZHNB3MIO.js'),{findProjectRoot:f}=await import('./status-CJTXLJBV.js');if(C==="preview"){let P=w("--root")??await f(),D=ue("--route"),W=w("--build-mode"),U=w("--expect-shaders")??"precompiled";if(U!=="precompiled"&&U!=="live")throw new Error('--expect-shaders must be "precompiled" or "live".');let F=E("--width"),K=E("--height"),B=E("--timeout"),I=E("--settle"),A=E("--min-luminance"),ne=M("building and verifying the production bundle"),n;try{n=await j({root:P,...D.length===0?{}:{routes:D},...W===void 0?{}:{buildMode:W},expectShaders:U,text:i.includes("--text"),...B===void 0?{}:{timeoutMs:B},...I===void 0?{}:{settleMs:I},...A===void 0?{}:{minimumLuminance:A},...F===void 0&&K===void 0?{}:{viewport:{width:F??1024,height:K??640}},headed:i.includes("--headed")});}finally{ne.stop();}a.stdout.write(`${b?JSON.stringify(n,null,2):r(n)}
|
|
10
|
+
`),n.passed||(a.exitCode=1);return}if(C!=="smoke")throw new Error(`Unsupported browser command "${C??""}".`);let v=w("--root")??await f(),m=E("--width"),O=E("--height"),k=w("--route"),T=E("--timeout"),N=E("--settle"),R=E("--min-luminance"),$=w("--hmr");if(i.includes("--webgl")&&i.includes("--unsupported-worker"))throw new Error("--webgl and --unsupported-worker are mutually exclusive.");let x=M(`smoking ${k??"/"} in Node`),z;try{z=await l({root:v,...k===void 0?{}:{route:k},...T===void 0?{}:{timeoutMs:T},...N===void 0?{}:{settleMs:N},...R===void 0?{}:{minimumLuminance:R},...$===void 0?{}:{hmrModule:$},forceWebgl:i.includes("--webgl"),unsupportedWorker:i.includes("--unsupported-worker"),expectTextGenerationFailure:i.includes("--expect-text-generation-failure"),...m===void 0&&O===void 0?{}:{viewport:{width:m??1024,height:O??640}},headed:i.includes("--headed")});}finally{x.stop();}a.stdout.write(`${b?JSON.stringify(z,null,2):p(z)}
|
|
11
|
+
`),z.passed||(a.exitCode=1);return}if(y==="assets"||y==="optimize"){let r=y==="optimize"?"optimize":C??"status",p=ie.slice(y==="optimize"?1:2),{findProjectRoot:j}=await import('./status-CJTXLJBV.js'),l=w("--root")??await j().catch(()=>a.cwd());if(r==="status"){let{formatAssetStatusReport:x,inspectAssets:z}=await import('./asset-optimize-AC3RBHSK.js'),P=await z(l);a.stdout.write(`${b?JSON.stringify(P,null,2):x(P)}
|
|
12
|
+
`),i.includes("--check")&&P.state==="stale"&&(a.exitCode=1);return}if(r!=="optimize")throw new Error(`Unsupported assets command "${r}".`);if(p.length===0)throw new Error("assets optimize needs at least one file or directory (.glb, .png, .jpg, .webp, .hdr).");let f=w("--quality");if(f!==void 0&&f!=="default"&&f!=="high")throw new Error('--quality must be "default" or "high".');let v=w("--preset");if(v!==void 0&&v!=="color"&&v!=="normal"&&v!=="data")throw new Error('--preset must be "color", "normal", or "data".');let m=w("--out"),O=E("--max-dim"),k=E("--hdr-max-dim"),{formatAssetOptimizeReport:T,optimizeAssets:N}=await import('./asset-optimize-AC3RBHSK.js'),R=M("optimizing assets"),$;try{$=await N({root:l,inputs:p,...m===void 0?{}:{outDir:m},...O===void 0?{}:{maxDimension:O},...k===void 0?{}:{hdrMaxDimension:k},...f===void 0?{}:{quality:f},...v===void 0?{}:{preset:v},force:i.includes("--force"),onProgress:a$1(x=>R.update(`optimizing ${b$1.accent(x)}`),"onProgress")});}finally{R.stop();}a.stdout.write(`${b?JSON.stringify($,null,2):T($)}
|
|
13
|
+
`),$.failed.length>0&&(a.exitCode=1);return}if(y==="environment"){if(C!=="bake")throw new Error(`Unsupported environment command "${C??""}".`);let{bakeRoomEnvironment:r,formatEnvironmentBakeReport:p}=await import('./environment-bake-ON5I27N7.js'),{findProjectRoot:j}=await import('./status-CJTXLJBV.js'),l=w("--root")??await j(),f=E("--size"),v=w("--output"),m=E("--timeout"),O=M("baking the room environment on the GPU"),k;try{k=await r({root:l,...f===void 0?{}:{size:f},...v===void 0?{}:{output:v},...m===void 0?{}:{timeoutMs:m},compression:i.includes("--no-zstd")?"none":"zstd",headed:i.includes("--headed")});}finally{O.stop();}a.stdout.write(`${b?JSON.stringify(k,null,2):p(k)}
|
|
14
|
+
`);return}if(y==="shaders"){let{findShaderProjectRoot:r}=await import('./shader-config-TOBHWNCD.js'),p=C??"status";if(!["status","capture","test"].includes(p))throw new Error(`Unsupported shader command "${p}".`);let j=w("--root"),l=await r(j),f$1=w("--driver");if(f$1!==void 0&&f$1!=="vite"&&f$1!=="static")throw new Error('--driver must be "vite" or "static".');let v=f$1,m=w("--serve"),O=w("--url"),k=w("--backend");if(k!==void 0&&k!=="webgpu"&&k!=="webgl"&&k!=="both")throw new Error('--backend must be "webgpu", "webgl", or "both".');let T=k;if(p==="status"){let{inspectShaderMatrix:N}=await import('./shader-workflow-JU5VYBN7.js'),{formatShaderMatrixStatus:R}=await import('./status-CJTXLJBV.js'),$=await N(l,void 0,T);a.stdout.write(`${b?JSON.stringify($,null,2):R($)}
|
|
15
|
+
`),(i.includes("--check")||C===void 0)&&$.state!=="fresh"&&(a.exitCode=1);return}if(p==="capture"&&i.includes("--built")){if(m===void 0)throw new Error("--built needs --serve <built-directory>: the manifests are written inside it.");let{captureBuiltShaders:N}=await import('./shader-workflow-JU5VYBN7.js'),R=w("--base"),$=M("capturing the built application");try{let x=await N({root:l,serve:m,...R===void 0?{}:{base:R},...T===void 0?{}:{backend:T},onSceneStart:a$1((z,P,D)=>$.update(`capturing ${b$1.accent(z)} ${b$1.dim(`(${P+1}/${D})`)}`),"onSceneStart")});$.stop(),a.stdout.write(b?`${JSON.stringify(x,null,2)}
|
|
16
|
+
`:`${q(c.tick,"shaders",`${x.files.length} manifest${x.files.length===1?"":"s"} ${c.dot} ${x.files.join(", ")}`)}
|
|
17
|
+
`);}finally{$.stop();}return}if(p==="capture"){let{captureShaders:N}=await import('./shader-workflow-JU5VYBN7.js'),{applyShaderAutoWire:R,hasRegisterDevtoolsCall:$,inspectShaderAutoWire:x}=await import('./shader-autowire-D2EOG6GF.js'),{buildShaderCaptureProject:z,startNextShaderCaptureServer:P}=await import('./shader-project-runner-NV4GKHDX.js'),{inferShaderCaptureTarget:D}=await import('./shader-config-TOBHWNCD.js'),W=v,U=m,F=O,K,B,I;try{if(W===void 0&&U===void 0&&F===void 0){let n=await x(l);if(!n.configured&&n.plan!==void 0){if(!await ce(n.plan.diff))throw new Error("Adapter wiring was declined; no files were changed.");await R(n.plan);}else if(!n.configured&&n.bundler!=="vite"&&n.bundler!=="unknown")throw new Error(`${n.reason} No files were changed.`);if(n.bundler==="next")B=M("starting the project-local Next.js capture server"),K=await P(l),F=K.url,B.update("capturing shader scenes");else if(n.bundler==="webpack"||n.bundler==="esbuild"||n.bundler==="rollup"){B=M(`building the ${n.bundler} capture target`),await z(l);let S=await D(l);if(S.driverKind!=="static"||S.serve===void 0)throw new Error(`${n.bundler} build completed but no dist/, build/, or out/index.html was found; pass --driver static --serve <directory>.`);W="static",U=S.serve,B.update("capturing shader scenes");}}B??=M("capturing shader scenes"),I=await N({root:l,headed:i.includes("--headed"),ifStale:i.includes("--if-stale"),commitTiming:i.includes("--commit-timing"),...T===void 0?{}:{backend:T},...W===void 0?{}:{driverKind:W},...U===void 0?{}:{serve:U},...F===void 0?{}:{url:F},onSceneStart:a$1((n,S,J)=>B?.update(`capturing ${b$1.accent(n)} ${b$1.dim(`(${S+1}/${J})`)}`),"onSceneStart"),onSceneRetry:a$1((n,S,J,L,G)=>{let X=G instanceof Error&&/timed out/iu.test(G.message),H=`capture attempt ${S}/${J} for "${n}" after ${X?`timeout (${Math.round(L/1e3)} s burned)`:`failure (${G instanceof Error?G.message:String(G)})`}`;a.stderr.write(b?`${JSON.stringify({type:"shader-capture-retry",scene:n,attempt:S,total:J,timeoutMs:L,message:H})}
|
|
18
|
+
`:`${H}
|
|
19
|
+
`);},"onSceneRetry")});}finally{B?.stop(),await K?.close();}let A;if(!i.includes("--no-assets"))try{let{discoverPublicAssets:n,optimizeAssets:S}=await import('./asset-optimize-AC3RBHSK.js'),{loadShaderToolConfig:J}=await import('./shader-config-TOBHWNCD.js'),L=(await J(l)).publicDir??"public",G=await n(l,L);if(G.length>0){let X=M("optimizing project assets");try{A=await S({root:l,inputs:G,onProgress:a$1(H=>X.update(`optimizing ${b$1.accent(H)}`),"onProgress")});}finally{X.stop();}}}catch(n){let S=`Asset optimization skipped: ${n instanceof Error?n.message:String(n)}`;a.stderr.write(b?`${JSON.stringify({type:"asset-optimize-error",message:S})}
|
|
17
20
|
`:`${c.warn} ${S}
|
|
18
|
-
`);}let
|
|
19
|
-
`),!
|
|
20
|
-
`).map(
|
|
21
|
-
`));}if(!await
|
|
22
|
-
`:`${c.warn} ${
|
|
23
|
-
`);}return}if(
|
|
24
|
-
`);return}
|
|
25
|
-
`);}
|
|
26
|
-
`)
|
|
27
|
-
`)
|
|
28
|
-
`),
|
|
29
|
-
`):s.stderr.write(`${c.cross} ${b$1.danger(t)}
|
|
30
|
-
`),s.exitCode=1;});
|
|
21
|
+
`);}let ne=A===void 0?I:{...I,assets:A};if(a.stdout.write(`${b?JSON.stringify(ne,null,2):fe(I)}
|
|
22
|
+
`),!b&&A!==void 0){let{formatAssetOptimizeReport:n}=await import('./asset-optimize-AC3RBHSK.js'),S=A.results.filter(L=>L.cached).length;f(q(A.failed.length>0?c.warn:c.tick,"assets",`${A.results.length} optimized${S>0?` (${S} cached)`:""} ${c.dot} ${b$1.dim("meshopt + KTX2, receipt .three-blocks/assets/meta.json")}`));let J=n(A);J.length>0&&f(J.split(`
|
|
23
|
+
`).map(L=>` ${L}`).join(`
|
|
24
|
+
`));}if(!await $(l)){let n="Add registerDevtools({ renderer }) from three-blocks/devtools so committed shader artifacts hydrate in development and production.";a.stderr.write(b?`${JSON.stringify({type:"shader-runtime-registration",state:"missing",message:n})}
|
|
25
|
+
`:`${c.warn} ${n}
|
|
26
|
+
`);}return}if(p==="test"){let N=w("--mode");if(N!==void 0&&N!=="strict")throw new Error('--mode currently supports only "strict".');let{testShaders:R}=await import('./shader-workflow-JU5VYBN7.js'),$=M("verifying precompiled shaders against the live baseline"),x=E("--runs"),z;try{z=await R({root:l,headed:i.includes("--headed"),skipBrowser:i.includes("--skip-browser"),...v===void 0?{}:{driverKind:v},...m===void 0?{}:{serve:m},...O===void 0?{}:{url:O},...x===void 0?{}:{runs:x},parityOnly:i.includes("--parity-only"),commitTiming:i.includes("--commit-timing"),...T===void 0?{}:{backend:T},onSceneStart:a$1((P,D,W)=>$.update(`verifying ${b$1.accent(P)} ${b$1.dim(`(${D+1}/${W})`)}`),"onSceneStart")});}finally{$.stop();}a.stdout.write(`${b?JSON.stringify(z,null,2):he(z)}
|
|
27
|
+
`);return}}if(y==="text"&&C&&C!=="status"){if(C!=="generate")throw new Error(`Unsupported text command "${C}".`);let{generateTextAtlases:r}=await import('./text-atlas-YYWV7S6F.js'),{findProjectRoot:p}=await import('./status-CJTXLJBV.js'),j=i.indexOf("--config"),l=j===-1?"three-blocks.text.ts":i[j+1];if(l===void 0||l.startsWith("--"))throw new Error("--config requires a project-relative path.");let f$1=await p(),v=M("generating MSDF text atlases"),m;try{m=await r(f$1,l);}finally{v.stop();}if(b)a.stdout.write(`${JSON.stringify(m,null,2)}
|
|
28
|
+
`);else {f(q(c.tick,"text",`${m.glyphs} glyphs ${c.dot} ${m.atlases.length} atlas${m.atlases.length===1?"":"es"} regenerated`));for(let O of m.updatedFiles)f(` ${d(b$1.dim("updated"),12)} ${b$1.dim(O)}`);}return}if(!["status","text"].includes(y))throw new Error(`Unknown command "${y}".`);let{formatThreeBlocksStatus:e,inspectThreeBlocksStatus:t,threeBlocksStatusIsFresh:d$1}=await import('./status-CJTXLJBV.js'),u=await t(),o=(u.text);if(y==="text"&&!o)throw new Error("This project does not enable the text feature.");let g=y==="text"?o:u;a.stdout.write(`${b?JSON.stringify(g,null,2):y==="status"?e(u):JSON.stringify(g,null,2)}
|
|
29
|
+
`),y==="status"&&i.includes("--check")&&!d$1(u)&&(a.exitCode=1);}a$1(me,"main");me().catch(e=>{let t=e instanceof Error?e.message:String(e);b?a.stderr.write(`${JSON.stringify({error:t})}
|
|
30
|
+
`):a.stderr.write(`${c.cross} ${b$1.danger(t)}
|
|
31
|
+
`),a.exitCode=1;});
|