@three-blocks/devtools 11.0.0 → 11.1.0-alpha.394.gd927ae9c8e86

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.
Files changed (77) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/NOTICE +26 -0
  3. package/README.md +117 -170
  4. package/dist/asset-optimize-YJGWKD4Y.js +1 -0
  5. package/dist/asset-transforms-ZVZ4RD4L.js +11 -0
  6. package/dist/browser/shader-capture.js +2 -2
  7. package/dist/browser-smoke-4MYMHKWB.js +1 -0
  8. package/dist/chunk-4SVF5BRM.js +2 -0
  9. package/dist/chunk-7X4DHW36.js +1 -0
  10. package/dist/chunk-BBODS5RH.js +5 -0
  11. package/dist/{chunk-IILE5RBI.js → chunk-CMMYXGQ3.js} +1 -2
  12. package/dist/chunk-DCLDEPPB.js +253 -0
  13. package/dist/{chunk-5L2VS3BN.js → chunk-ECQE4D2U.js} +1 -2
  14. package/dist/chunk-IWQV456Z.js +3 -0
  15. package/dist/chunk-LSH64HEU.js +80 -0
  16. package/dist/{chunk-X5OFYHIY.js → chunk-MIJXPQPM.js} +2 -3
  17. package/dist/chunk-NDIPQLTU.js +16 -0
  18. package/dist/{chunk-NPLE7PPF.js → chunk-NJITVI23.js} +1 -2
  19. package/dist/chunk-O5FU2ASS.js +16 -0
  20. package/dist/chunk-QQKHDH26.js +1 -0
  21. package/dist/chunk-S5LI2C2H.js +5 -0
  22. package/dist/chunk-SBUKHO24.js +1 -0
  23. package/dist/chunk-TK566QET.js +1 -0
  24. package/dist/{chunk-65VEJRRT.js → chunk-WNSGAV6N.js} +1 -2
  25. package/dist/chunk-ZG3LO3VB.js +1 -0
  26. package/dist/{chunk-UDUICSME.js → chunk-ZTHZE36A.js} +1 -1
  27. package/dist/cli.d.ts +1 -0
  28. package/dist/cli.js +26 -26
  29. package/dist/environment-bake-ON5I27N7.js +1 -0
  30. package/dist/index.d.ts +24 -12
  31. package/dist/index.js +1 -279
  32. package/dist/{shader-autowire-SPE5DM2X.js → shader-autowire-D2EOG6GF.js} +1 -2
  33. package/dist/shader-browser-6ICBHK3S.js +1 -0
  34. package/dist/shader-capture-server.d.ts +1 -1
  35. package/dist/shader-capture-server.js +1 -1
  36. package/dist/{shader-config-EOFU5D3Y.js → shader-config-AKZEKIRB.js} +1 -2
  37. package/dist/{shader-parity-QXJWR6OZ.js → shader-parity-7DEPQEDI.js} +1 -1
  38. package/dist/{shader-project-runner-S2AID2RJ.js → shader-project-runner-NV4GKHDX.js} +1 -2
  39. package/dist/shader-watch-JBUA4LP5.js +1 -0
  40. package/dist/shader-workflow-5EHHR32D.js +1 -0
  41. package/dist/status-GDVSLQWV.js +1 -0
  42. package/dist/text-atlas-YYWV7S6F.js +1 -0
  43. package/dist/transform.cjs +1 -1
  44. package/dist/transform.js +1 -1
  45. package/dist/webpack-loader.cjs +1 -1
  46. package/dist/webpack-loader.js +1 -1
  47. package/node/index.d.mts +70 -0
  48. package/node/index.mjs +407 -0
  49. package/node/ipc.mjs +31 -0
  50. package/node/layout.mjs +546 -0
  51. package/node/loader.mjs +103 -0
  52. package/node/media.mjs +454 -0
  53. package/node/recording.mjs +67 -0
  54. package/node/worker.mjs +1314 -0
  55. package/package.json +27 -11
  56. package/dist/asset-optimize-GG72JCOX.js +0 -6
  57. package/dist/browser-smoke-KFF7XV7F.js +0 -254
  58. package/dist/chunk-45AVKQQK.js +0 -80
  59. package/dist/chunk-5FT6AZD6.js +0 -82
  60. package/dist/chunk-7N6TU4JG.js +0 -17
  61. package/dist/chunk-EI7MMDWY.js +0 -1
  62. package/dist/chunk-HOZDD6PW.js +0 -2
  63. package/dist/chunk-LKXY5YU2.js +0 -17
  64. package/dist/chunk-MIUIIPS4.js +0 -1
  65. package/dist/chunk-NF4RFSUJ.js +0 -18
  66. package/dist/chunk-QJFPNM6W.js +0 -2
  67. package/dist/chunk-ZT6T2W4B.js +0 -2
  68. package/dist/chunk-ZZLAZ7GJ.js +0 -6
  69. package/dist/environment-bake-BGMGFAVK.js +0 -4
  70. package/dist/shader-browser-H5CB2ZQX.js +0 -2
  71. package/dist/shader-browser-UXXR6QI2.js +0 -1
  72. package/dist/shader-parity-XPKQQK26.js +0 -2
  73. package/dist/shader-watch-EORZ2SEC.js +0 -2
  74. package/dist/shader-workflow-7NQFDQI5.js +0 -2
  75. package/dist/status-PTBB4SW2.js +0 -2
  76. package/dist/text-atlas-UORTLOQJ.js +0 -2
  77. /package/dist/{chunk-TRHSN2DJ.cjs → chunk-LMLJIVNY.cjs} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@three-blocks/devtools",
3
- "version": "11.0.0",
3
+ "version": "11.1.0-alpha.394.gd927ae9c8e86",
4
4
  "description": "Three Blocks devtools command engine for npx three-blocks; the runtime lives in three-blocks/devtools and the Vite plugin",
5
5
  "keywords": [
6
6
  "three",
@@ -20,6 +20,10 @@
20
20
  "three-blocks-devtools": "./dist/cli.js"
21
21
  },
22
22
  "exports": {
23
+ "./node": {
24
+ "types": "./node/index.d.mts",
25
+ "import": "./node/index.mjs"
26
+ },
23
27
  ".": {
24
28
  "types": "./dist/index.d.ts",
25
29
  "import": "./dist/index.js"
@@ -46,6 +50,7 @@
46
50
  },
47
51
  "files": [
48
52
  "dist",
53
+ "node",
49
54
  "fonts/OFL-1.1.txt",
50
55
  "README.md",
51
56
  "CHANGELOG.md",
@@ -64,30 +69,41 @@
64
69
  "build": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\" && tsup --config tsup.config.ts",
65
70
  "typecheck": "tsc --noEmit && tsc -p tsconfig.browser.json --noEmit",
66
71
  "test": "vitest run",
72
+ "test:node": "node tests/node-renderer.check.mjs && node tests/node-renderer-ipc.check.mjs && bun tests/node-renderer-ipc.check.mjs && node tests/node-dom.check.mjs",
67
73
  "test:vite-adoption": "bun run --cwd ../three-blocks build && bun run build && THREE_BLOCKS_GPU_TEST=1 vitest run tests/shader-browser.integration.test.ts",
68
74
  "test:package": "bun run build && node scripts/check-package-fitness.mjs && npx --yes publint@0.3.21 --strict --level warning --pack npm",
69
75
  "prepublishOnly": "bun run build"
70
76
  },
71
77
  "dependencies": {
78
+ "@ungap/structured-clone": "1.3.2",
79
+ "@cwasm/jpeg-turbo": "0.1.3",
72
80
  "@gltf-transform/core": "4.4.2",
73
81
  "@gltf-transform/extensions": "4.4.2",
74
- "@gltf-transform/functions": "4.4.2",
82
+ "@napi-rs/canvas": "1.0.9",
83
+ "@napi-rs/webcodecs": "1.4.1",
84
+ "@onirenaud/node-webgl": "0.2.0",
85
+ "css.escape": "1.5.1",
86
+ "css-what": "6.2.2",
75
87
  "ktx-parse": "1.1.0",
76
88
  "ktx2-encoder": "0.6.0",
89
+ "lightningcss": "1.32.0",
90
+ "linkedom": "0.18.12",
77
91
  "meshoptimizer": "1.2.0",
78
92
  "msdf-bmfont-xml": "npm:@pixi/msdf-bmfont-xml@3.0.0",
79
93
  "opentype.js": "1.3.4",
80
94
  "pngjs": "7.0.0",
81
- "sharp": "0.35.3",
82
95
  "subset-font": "2.5.0",
83
- "typescript": "^5.9.3"
96
+ "tough-cookie": "6.0.2",
97
+ "typescript": "^5.9.3",
98
+ "webgpu": "0.4.0",
99
+ "yoga-layout": "3.2.1"
84
100
  },
85
101
  "devDependencies": {
102
+ "@gltf-transform/functions": "4.4.2",
86
103
  "@types/node": "^22.10.0",
87
104
  "@types/three": "0.185.0",
88
105
  "create-vite": "9.1.1",
89
- "playwright": "^1.61.1",
90
- "three-blocks": "0.12.0",
106
+ "three-blocks": "0.12.1-alpha.394.gd927ae9c8e86",
91
107
  "tsup": "^8.0.0",
92
108
  "vite": "^7.2.2",
93
109
  "vitest": "^4.1.8"
@@ -96,17 +112,17 @@
96
112
  "node": ">=22.12.0"
97
113
  },
98
114
  "peerDependencies": {
99
- "playwright": "^1.61.1",
100
115
  "three": ">=0.185.0",
101
- "three-blocks": ">=0.12.0 <0.13.0",
116
+ "three-blocks": "0.12.1-alpha.394.gd927ae9c8e86",
102
117
  "vite": ">=7.2.2 <9.0.0"
103
118
  },
104
119
  "peerDependenciesMeta": {
105
- "playwright": {
106
- "optional": true
107
- },
108
120
  "vite": {
109
121
  "optional": true
110
122
  }
123
+ },
124
+ "threeBlocks": {
125
+ "channel": "alpha",
126
+ "site": "https://preprod.threejs-blocks.com"
111
127
  }
112
128
  }
@@ -1,6 +0,0 @@
1
- #!/usr/bin/env node
2
- import {d}from'./chunk-7N6TU4JG.js';import'./chunk-ZT6T2W4B.js';import'./chunk-NPLE7PPF.js';import'./chunk-65VEJRRT.js';import {b,a as a$1,c,h,d as d$1,f}from'./chunk-5L2VS3BN.js';import {a}from'./chunk-HOZDD6PW.js';import {readFile,lstat,readdir,realpath,mkdir}from'fs/promises';import i from'path';import {read,KHR_DF_PRIMARIES_BT709,write}from'ktx-parse';var U=2,ie="ktx2-encoder@0.6.0",ae=i.join(".three-blocks","assets"),ue=i.join(ae,"meta.json"),we=i.join(ae,"cache"),Te=256*1024*1024,Ae=64*1024*1024,ee=115e5,te=64,Ee=163,Re=166,ve=167,Se=1000066e3,de=1,le=2,$e=/baseColor|emissive|diffuse|sheenColor|specularColor/u,Me=/normal/iu,Oe=/(?:^|[_\-.])(?:normal|nrm|nor)(?:[_\-.]|map|$)/iu,_e=/(?:rough|metal|orm\b|occlusion|ambient|[_\-.]ao(?:[_\-.]|$)|height|disp|thick|mask)/iu;function Ie(t){return t.some(e=>Me.test(e))?"normal":t.some(e=>$e.test(e))||t.length===0?"color":"data"}a(Ie,"presetForTextureSlots");function De(t){let e=i.basename(t);return Oe.test(e)?"normal":_e.test(e)?"data":"color"}a(De,"presetForImageName");function V(t){let e=i.extname(t).toLowerCase();return e===".glb"?"glb":e===".png"||e===".jpg"||e===".jpeg"||e===".webp"?"image":e===".hdr"?"hdr":null}a(V,"assetKindFor");function P(t,e){let r=i.relative(t,e);return (r!==""&&!r.startsWith("..")&&!i.isAbsolute(r)?r:e).split(i.sep).join("/")}a(P,"portable");var X;function ce(){return X??=Promise.all([import('ktx2-encoder'),import('sharp')]).then(([t,e])=>({encodeToKTX2:t.encodeToKTX2,sharp:e.default})),X}a(ce,"loadEncoderTools");function me(t,e){let r=e.quality==="high";return t==="hdr"?{mode:"uastc-hdr",options:{isHDR:true,imageType:"hdr",isUASTC:true,isYFlip:true,generateMipmap:true,needSupercompression:true,hdrQualityLevel:r?2:1}}:t==="color"&&!r?{mode:"etc1s",options:{isUASTC:false,qualityLevel:160,compressionLevel:2,isPerceptual:true,isSRGB:true,generateMipmap:true}}:{mode:"uastc",options:{isUASTC:true,uastcLDRQualityLevel:r?2:1,enableRDO:true,rdoQualityLevel:1,generateMipmap:true,needSupercompression:true,isPerceptual:t==="color",isSRGB:t==="color",isNormalMap:t==="normal"}}}a(me,"encoderOptionsFor");function Le(t,e){let r=read(t),s=r.dataFormatDescriptor[0];if(s===void 0)return t;let n=e==="color"?le:de;return s.transferFunction===n&&(e!=="color"||s.colorPrimaries===KHR_DF_PRIMARIES_BT709)?t:(s.transferFunction=n,e==="color"&&(s.colorPrimaries=KHR_DF_PRIMARIES_BT709),write(r,{keepWriter:true}))}a(Le,"normalizeDfdTransfer");function he(t,e,r,s){let n=read(t),o=n.dataFormatDescriptor[0];if(o===void 0)throw new Error(`${s} produced a KTX2 container without a data format descriptor.`);if(e==="hdr"){if(n.vkFormat!==Se||o.colorModel!==ve)throw new Error(`${s} is not a UASTC HDR container (vkFormat ${n.vkFormat}, color model ${o.colorModel}).`)}else {let c=r==="etc1s"?Ee:Re;if(n.vkFormat!==0||o.colorModel!==c)throw new Error(`${s} is not a ${r} container (vkFormat ${n.vkFormat}, color model ${o.colorModel}).`)}let a=e==="color",u=o.transferFunction;if(a&&u!==le)throw new Error(`${s} must carry the sRGB transfer function; found ${u}.`);if(!a&&u!==de)throw new Error(`${s} must carry the linear transfer function; found ${u}.`);if(Math.max(n.pixelWidth,n.pixelHeight)>=8&&n.levels.length<2)throw new Error(`${s} is missing its mip chain.`);return {width:n.pixelWidth,height:n.pixelHeight,levels:n.levels.length}}a(he,"verifyKtx2");async function ye(t,e,r,s){let{encodeToKTX2:n,sharp:o}=await ce(),a$1=r.maxDimension,{mode:u,options:c}=me(e,r),d=performance.now(),m=false,p=Le(await n(t,{...c,imageDecoder:a(async $=>{let E=o($),M=await E.metadata(),O=M.width??0,b=M.height??0;if(O<1||b<1)throw new Error(`${s} has no decodable dimensions.`);let y=Math.min(1,a$1/Math.max(O,b));O*y*b*y>ee&&(y=Math.sqrt(ee/(O*b)));let x=y<1,w=x?Math.max(4,Math.floor(O*y/4)*4):O,I=x?Math.max(4,Math.floor(b*y/4)*4):b,_=x?E.resize(w,I,{fit:"fill",kernel:"lanczos3"}):E,{data:h,info:v}=await _.ensureAlpha().raw().toBuffer({resolveWithObject:true});for(let S=3;S<h.byteLength;S+=4)if(h[S]!==255){m=true;break}return {data:new Uint8Array(h.buffer,h.byteOffset,h.byteLength),width:v.width,height:v.height}},"decode")}),e),{width:f,height:R,levels:g}=he(p,e,u,s);return {bytes:p,width:f,height:R,levels:g,hasAlpha:m,mode:u,durationMs:performance.now()-d}}a(ye,"encodeLdrTexture");function Be(t,e){let r=new TextDecoder("latin1").decode(t.subarray(0,Math.min(t.byteLength,4096))),s=/-Y\s+(\d+)\s+\+X\s+(\d+)/u.exec(r);if(s?.[1]===void 0||s[2]===void 0)throw new Error(`${e} is not a supported Radiance .hdr file (missing "-Y <h> +X <w>" resolution).`);return {width:Number(s[2]),height:Number(s[1])}}a(Be,"hdrDimensions");async function ke(t,e,r){let s=Be(t,r);if(Math.max(s.width,s.height)>e.hdrMaxDimension)throw new Error(`${r} is ${s.width}x${s.height}, above the ${e.hdrMaxDimension}px HDR cap; resize the source (HDR resize is not supported yet).`);let{encodeToKTX2:n}=await ce(),{mode:o,options:a}=me("hdr",e),u=performance.now(),c=await n(t,a),{width:d,height:m,levels:A}=he(c,"hdr",o,r);return {bytes:c,width:d,height:m,levels:A,hasAlpha:false,mode:o,durationMs:performance.now()-u}}a(ke,"encodeHdrTexture");function pe(t,e,r,s){let n=0,o=t,a=e;for(let u=0;u<r;u+=1)n+=o*a*s,o=Math.max(1,o>>1),a=Math.max(1,a>>1);return n}a(pe,"uncompressedMipBytes");function q(t,e,r,s){let n=0,o=t,a=e;for(let u=0;u<r;u+=1)n+=Math.ceil(o/4)*Math.ceil(a/4)*s,o=Math.max(1,o>>1),a=Math.max(1,a>>1);return n}a(q,"compressedMipBytes");function fe(t,e){return t==="etc1s"&&!e?8:16}a(fe,"transcodedBlockBytes");async function Fe(t,e,r){let s=r.preset??De(e),n=`Image ${JSON.stringify(i.basename(e))}`,o=await ye(t,s,r,n),a=[`preset ${s} (${r.preset===null?"from filename":"explicit"})`];return s!=="color"&&a.push("linear DFD: consumers must treat this texture as non-color data"),a.push("compressed textures never flip: sample with glTF-style (flipY=false) UVs"),{bytes:o.bytes,metadata:{vramBytesIn:pe(o.width,o.height,o.levels,4),vramBytesOut:q(o.width,o.height,o.levels,fe(o.mode,o.hasAlpha)),textures:[{name:i.basename(e),slots:[],preset:s,mode:o.mode,width:o.width,height:o.height,bytesIn:t.byteLength,bytesOut:o.bytes.byteLength,durationMs:Math.round(o.durationMs)}],notes:a}}}a(Fe,"buildImageAsset");async function Pe(t,e,r){let s=`Environment ${JSON.stringify(i.basename(e))}`,n=await ke(t,r,s);return {bytes:n.bytes,metadata:{vramBytesIn:n.width*n.height*8,vramBytesOut:q(n.width,n.height,n.levels,16),textures:[{name:i.basename(e),slots:["equirectangular"],preset:"hdr",mode:n.mode,width:n.width,height:n.height,bytesIn:t.byteLength,bytesOut:n.bytes.byteLength,durationMs:Math.round(n.durationMs)}],notes:["BC6H on BC-capable devices; transcodes to RGBA16F elsewhere"]}}}a(Pe,"buildHdrAsset");async function Ne(t,e,r,s){let[{Logger:n,NodeIO:o},{ALL_EXTENSIONS:a,KHRTextureBasisu:u},{dedup:c,listTextureSlots:d,meshopt:m,prune:A,weld:p},{MeshoptDecoder:f,MeshoptEncoder:R}]=await Promise.all([import('@gltf-transform/core'),import('@gltf-transform/extensions'),import('@gltf-transform/functions'),import('meshoptimizer')]);await R.ready,await f.ready;let g=new o().registerExtensions(a).registerDependencies({"meshopt.encoder":R,"meshopt.decoder":f}),$=`GLB ${JSON.stringify(i.basename(e))}`;g.setLogger(new n(n.Verbosity.SILENT));let E=await g.readBinary(t);E.setLogger(new n(n.Verbosity.SILENT));let M=E.getRoot().listTextures();if(M.length>0&&M.every(h=>h.getMimeType()==="image/ktx2")&&E.getRoot().listExtensionsUsed().some(h=>h.extensionName==="EXT_meshopt_compression"))return {bytes:t,metadata:{vramBytesIn:0,vramBytesOut:0,textures:[],notes:["already optimized (KTX2 + meshopt); copied unchanged"]}};s?.("optimizing geometry"),await E.transform(c(),A({keepAttributes:true,keepExtras:true,keepSolidTextures:true}),p(),m({encoder:R,level:"medium"}));let b=[],y=[],x=0,w=0,I=0;for(let h of M){let v=h.getName()||h.getURI()||`texture-${b.length}`,S=h.getImage(),k=h.getMimeType();if(S===null||S.byteLength===0)continue;if(k==="image/ktx2"){y.push(`${v}: already KTX2, kept`);continue}if(!/^image\/(?:png|jpeg|webp)$/u.test(k)){y.push(`${v}: unsupported ${k}, kept`);continue}let z=h.getSize();if(z!==null&&Math.max(z[0],z[1])<te){y.push(`${v}: below ${te}px, kept`);continue}let W=d(h),j=Ie(W);s?.(`encoding ${v} (${j})`);let T=await ye(new Uint8Array(S),j,r,`${$} texture ${JSON.stringify(v)}`);h.setImage(T.bytes).setMimeType("image/ktx2");let G=h.getURI();G!==""&&h.setURI(G.replace(/\.(?:png|jpe?g|webp)$/iu,".ktx2")),I+=1,x+=pe(T.width,T.height,T.levels,4),w+=q(T.width,T.height,T.levels,fe(T.mode,T.hasAlpha)),b.push({name:v,slots:W,preset:j,mode:T.mode,width:T.width,height:T.height,bytesIn:S.byteLength,bytesOut:T.bytes.byteLength,durationMs:Math.round(T.durationMs)});}I>0&&E.createExtension(u).setRequired(true);let _=await g.writeBinary(E);return await g.readBinary(_),I>0&&y.push("requires a KTX2-wired loader (three-blocks/assets or GLTFLoader.setKTX2Loader)"),{bytes:_,metadata:{vramBytesIn:x,vramBytesOut:w,textures:b,notes:y}}}a(Ne,"buildGlbAsset");function Ce(t,e,r){let s=i.basename(t,i.extname(t));if(e==="glb"){let n=r===null?i.join(i.dirname(t),`${s}.tb.glb`):i.join(r,`${s}.glb`);if(i.resolve(n)===i.resolve(t))throw new Error(`Output would overwrite the input: ${JSON.stringify(t)}. Pass a different output directory.`);return n}return i.join(r??i.dirname(t),`${s}.ktx2`)}a(Ce,"outputPathFor");async function ge(t){let e={schemaVersion:U,tool:{name:"three-blocks-devtools",assetOptimizeVersion:U,encoder:ie},assets:{}},r;try{r=await readFile(t,"utf8");}catch(s){if(b(s)==="ENOENT")return e;throw s}if(r.length>a$1.receipt)return e;try{let s=JSON.parse(r);if(typeof s!="object"||s===null)return e;let n=s;return n.schemaVersion!==U||typeof n.assets!="object"||n.assets===null?e:{...e,assets:{...n.assets}}}catch{return e}}a(ge,"readReceipt");async function Ue(t){let e=[];for(let r of t){let s=i.resolve(r);if((await lstat(s)).isDirectory()){let o=[s],a=0;for(;o.length>0;){let u=o.shift();if(u===void 0)break;let c=(await readdir(u,{withFileTypes:true})).sort((d,m)=>d.name.localeCompare(m.name));for(let d of c){if(a+=1,a>8192)throw new Error("Input directory expansion exceeds the 8192-entry limit.");if(d.isSymbolicLink()||d.name.startsWith("."))continue;let m=i.join(u,d.name);if(d.isDirectory()){d.name!=="three-blocks"&&o.push(m);continue}d.isFile()&&!d.name.endsWith(".tb.glb")&&V(d.name)!==null&&e.push(m);}}}else e.push(s);}if(e.length===0)throw new Error("No optimizable inputs found (.glb, .png, .jpg, .webp, .hdr).");return e}a(Ue,"expandInputs");async function Ve(t){let e=await realpath(t.root),r={maxDimension:re(t.maxDimension,2048),hdrMaxDimension:re(t.hdrMaxDimension,4096),quality:t.quality??"default",preset:t.preset??null},s=t.outDir===void 0?null:i.resolve(e,t.outDir);s!==null&&await mkdir(s,{recursive:true});let n=i.join(e,we),o=i.join(e,ue),a$2=c(d({version:U,encoder:ie,...r})),u=await Ue(t.inputs),c$1=[],d$2=[],m=await ge(o);for(let[A,p]of u.entries()){let f$1=V(p);try{if(f$1===null)throw new Error(`Unsupported asset type ${JSON.stringify(i.extname(p))}; expected .glb, .png, .jpg, .webp, or .hdr (EXR sources are not supported yet \u2014 convert environments to .hdr).`);t.onProgress?.(`${i.basename(p)} (${A+1}/${u.length})`);let R=f$1==="glb"?Te:f$1==="hdr"?Ae:a$1.texture,g=await h(p,R,"Asset input"),$=g.path,E=c(g.data),M=c(`${E}\0${a$2}`),O=f$1==="glb"?"glb":"ktx2",b=i.join(n,`${M}.${O}`),y=i.join(n,`${M}.json`),x,w,I=!1;if(t.force!==!0&&await d$1(b)&&await d$1(y))x=(await h(b,R,"Cached asset")).data,w=JSON.parse((await h(y,a$1.metadata,"Cached asset metadata")).data.toString("utf8")),I=!0;else {let v=a(k=>t.onProgress?.(`${i.basename(p)}: ${k}`),"progress"),S=f$1==="glb"?await Ne(g.data,$,r,v):f$1==="hdr"?await Pe(g.data,$,r):await Fe(g.data,$,r);x=S.bytes,w=S.metadata,await f(b,x),await f(y,`${JSON.stringify(w,null," ")}
3
- `);}let _=Ce($,f$1,s);await mkdir(i.dirname(_),{recursive:!0}),await f(_,x);let h$1=c(x);m.assets[P(e,$)]={kind:f$1,inputSha256:E,output:P(e,_),outputSha256:h$1,settingsSha256:a$2,bytesIn:g.data.byteLength,bytesOut:x.byteLength,vramBytesIn:w.vramBytesIn,vramBytesOut:w.vramBytesOut},c$1.push({input:P(e,$),output:P(e,_),kind:f$1,cached:I,bytesIn:g.data.byteLength,bytesOut:x.byteLength,vramBytesIn:w.vramBytesIn,vramBytesOut:w.vramBytesOut,textures:w.textures,notes:w.notes});}catch(R){d$2.push({input:P(e,p),error:R instanceof Error?R.message:String(R)});}}return c$1.length>0&&await f(o,`${JSON.stringify(m,null," ")}
4
- `),{schemaVersion:1,command:"assets optimize",root:e,results:c$1,failed:d$2,bytesIn:c$1.reduce((A,p)=>A+p.bytesIn,0),bytesOut:c$1.reduce((A,p)=>A+p.bytesOut,0)}}a(Ve,"optimizeAssets");function re(t,e){if(t===void 0)return e;if(!Number.isInteger(t)||t<64||t>16384)throw new Error("Texture dimension caps must be integers between 64 and 16384.");return t}a(re,"boundedDimension");function D(t){if(t<1e3)return `${t} B`;if(t<1e6){let r=t/1e3;return `${r>=100?Math.round(r):r.toFixed(1)} kB`}let e=t/1e6;return `${e>=100?Math.round(e):e.toFixed(2)} MB`}a(D,"formatBytes");function ne(t,e){if(t===0)return "";let r=Math.round((e-t)/t*100);return r===0?"":` (${r>0?"+":""}${r}%)`}a(ne,"percentDelta");function qe(t){let e=[];for(let r of t.results){let s=r.cached?" \xB7 cached":"";e.push(`${r.input} -> ${r.output}`),e.push(` ${D(r.bytesIn)} -> ${D(r.bytesOut)}${ne(r.bytesIn,r.bytesOut)}${s}`),r.vramBytesOut>0&&e.push(` VRAM \u2248 ${D(r.vramBytesIn)} -> ${D(r.vramBytesOut)}`);for(let n of r.textures){let o=n.slots.length>0?` [${n.slots.join(", ")}]`:"";e.push(` ${n.name}${o} ${n.preset}/${n.mode} ${n.width}x${n.height} ${D(n.bytesIn)} -> ${D(n.bytesOut)}`);}for(let n of r.notes)e.push(` note: ${n}`);}for(let r of t.failed)e.push(`failed ${r.input}: ${r.error}`);return t.results.length>1&&e.push(`total ${D(t.bytesIn)} -> ${D(t.bytesOut)}${ne(t.bytesIn,t.bytesOut)}`),e.join(`
5
- `)}a(qe,"formatAssetOptimizeReport");async function We(t,e){let r=await realpath(t),s=i.resolve(r,e);if(!await d$1(s))return [];let n=[],o=[s],a=0;for(;o.length>0;){let u=o.shift();if(u===void 0)break;let c=(await readdir(u,{withFileTypes:true})).sort((d,m)=>d.name.localeCompare(m.name));for(let d of c){if(a+=1,a>8192)throw new Error("Public asset discovery exceeds the 8192-entry limit.");if(d.isSymbolicLink()||d.name.startsWith("."))continue;let m=i.join(u,d.name);if(d.isDirectory()){if(u===s&&d.name==="three-blocks")continue;o.push(m);continue}if(!d.isFile()||d.name.endsWith(".tb.glb"))continue;let A=V(d.name);(A==="glb"||A==="hdr")&&n.push(m);}}return n.sort()}a(We,"discoverPublicAssets");async function Ge(t){let e=await realpath(t),r=await ge(i.join(e,ue)),s=[];for(let[n,o]of Object.entries(r.assets).sort(([a],[u])=>a.localeCompare(u))){let a=i.resolve(e,n),u=i.resolve(e,o.output),c$1="fresh";if(!await d$1(a))c$1="missing-input";else if(!await d$1(u))c$1="missing-output";else {let[d,m]=await Promise.all([readFile(a),readFile(u)]);(c(d)!==o.inputSha256||c(m)!==o.outputSha256)&&(c$1="stale");}s.push({input:n,output:o.output,kind:o.kind,state:c$1});}return {schemaVersion:1,command:"assets status",root:e,state:s.length===0?"empty":s.every(n=>n.state==="fresh")?"fresh":"stale",entries:s}}a(Ge,"inspectAssets");function Je(t){if(t.state==="empty")return "No optimized assets recorded. Run `assets optimize <file|directory>` first.";let e=t.entries.map(r=>`${r.state==="fresh"?"fresh ":r.state.padEnd(14)} ${r.input} -> ${r.output}`);return t.state==="stale"&&e.push("Some assets moved or changed; re-run `assets optimize` on the stale inputs."),e.join(`
6
- `)}a(Je,"formatAssetStatusReport");function Ye(){X=void 0;}a(Ye,"resetAssetOptimizeToolsForTests");export{U as ASSET_OPTIMIZE_VERSION,ae as ASSET_RECEIPT_DIRECTORY,ue as ASSET_RECEIPT_FILE,We as discoverPublicAssets,qe as formatAssetOptimizeReport,Je as formatAssetStatusReport,Ge as inspectAssets,Ve as optimizeAssets,De as presetForImageName,Ie as presetForTextureSlots,Ye as resetAssetOptimizeToolsForTests};
@@ -1,254 +0,0 @@
1
- #!/usr/bin/env node
2
- import {b,a as a$3}from'./chunk-ZZLAZ7GJ.js';import'./chunk-IILE5RBI.js';import'./chunk-X5OFYHIY.js';import'./chunk-LKXY5YU2.js';import'./chunk-5FT6AZD6.js';import'./chunk-7N6TU4JG.js';import {a as a$2,b as b$1,d}from'./chunk-QJFPNM6W.js';import'./chunk-ZT6T2W4B.js';import'./chunk-NPLE7PPF.js';import {a as a$1}from'./chunk-65VEJRRT.js';import {j,a as a$4,c}from'./chunk-5L2VS3BN.js';import {a}from'./chunk-HOZDD6PW.js';import {randomUUID}from'crypto';import {mkdir,realpath,writeFile,rename,rm}from'fs/promises';import F from'path';import {PNG}from'pngjs';var ye="virtual:three-blocks-devtools/browser-smoke",ve=`\0${ye}`,Ke=`/@id/__x00__${ye}`,Be=9e4;async function Ee(){try{let[e,r]=await Promise.all([import('playwright'),import('vite')]);return {chromium:e.chromium,vite:r}}catch(e){throw new Error('Browser smoke and preview require the optional "playwright" and "vite" packages. Install both in the project and run `npx playwright install chromium`.',{cause:e})}}a(Ee,"loadBrowserSmokeTools");function V(e,r,o,t,n){let a=e??n;if(!Number.isSafeInteger(a)||a<o||a>t)throw new Error(`${r} must be an integer in ${o}...${t}.`);return a}a(V,"boundedInteger");function _e(e,r,o,t,n){let a=e??n;if(!Number.isFinite(a)||a<o||a>t)throw new Error(`${r} must be a finite number in ${o}...${t}.`);return a}a(_e,"boundedRatio");function Pe(e){let r=e??"/";if(r.length===0||r.length>2048||/[\u0000-\u001f\u007f]/u.test(r))throw new Error("Browser smoke route must be a bounded project URL.");let o=new URL(r,"http://three-blocks.invalid/");if(o.origin!=="http://three-blocks.invalid"||o.hash.length>0)throw new Error("Browser smoke route must stay within the project and have no fragment.");return `${o.pathname}${o.search}`}a(Pe,"safeRoute");function N(e,r){return e[r]===true}a(N,"booleanField");function $(e,r){if(!a$1(e)||!a$1(e.value))return {source:"missing",backend:"unknown",worker:false,workerReady:false,assetsReady:false,compileEnd:false,textEnabled:r,textReady:!r,firstFrame:false};let o=e.value,t=e.source==="public";if(t&&o.protocolVersion!==1)return {source:"public",backend:"unknown",worker:false,workerReady:false,assetsReady:false,compileEnd:false,textEnabled:r,textReady:!r,firstFrame:false};let n=a$1(o.readiness)?o.readiness:o,a=o.worker,d=t&&a$1(a)?a.offscreenCanvas===true&&a.visible===true:a===true;return {source:t?"public":"legacy",backend:t&&a$1(a)?a.offscreenCanvas===true?"OffscreenCanvas":"MainThread":a===true?"OffscreenCanvas":"unknown",worker:d,workerReady:N(n,"workerReady"),assetsReady:N(n,"assetsReady")||N(n,"loadEnd"),compileEnd:N(n,"compileEnd"),textEnabled:r,textReady:!r||N(n,"textReady"),firstFrame:N(n,"firstFrame")}}a($,"parseBrowserSmokeLifecycle");function ie(e){let r=PNG.sync.read(e),o=Math.floor(r.width*.25),t=Math.floor(r.width*.75),n=Math.floor(r.height*.25),a=Math.floor(r.height*.75),d=0,c=0;for(let f=n;f<a;f+=2)for(let p=o;p<t;p+=2){let h=(f*r.width+p)*4,l=r.data[h],i=r.data[h+1],s=r.data[h+2];l===void 0||i===void 0||s===void 0||(d+=Math.max(l,i,s),c+=1);}return c===0?0:d/c}a(ie,"screenshotLuminance");function Je(){return `
3
- import * as THREE from 'three/webgpu';
4
- import { createAssetLoaderRegistry, createAssetManager, createThreeAssetAdapters, defineAssets } from 'three-blocks/assets';
5
- import { SceneHotReloader } from 'three-blocks/hmr';
6
- import { createShaderCache } from 'three-blocks/shaders';
7
- import { createStatsWorker } from 'three-blocks/stats';
8
- import { threeBlocksBuildReceipt, threeBlocksConfig, loadThreeBlocksMeshoptDecoder } from 'three-blocks/vite/config';
9
-
10
- const root = globalThis;
11
- const hmr = root.__threeBlocksSmokeProbe ??= { before: 0, after: 0 };
12
- if ( import.meta.hot ) {
13
- import.meta.hot.on( 'vite:beforeUpdate', () => { hmr.before += 1; } );
14
- import.meta.hot.on( 'vite:afterUpdate', () => { hmr.after += 1; } );
15
- import.meta.hot.accept();
16
- }
17
-
18
- async function externalCodec( name, config, pathKey ) {
19
- if ( config === false ) return { name, state: 'disabled', routes: [], decoded: false, evidence: 'delivery', blocker: null, error: null };
20
- const routes = [];
21
- try {
22
- for ( const file of config.files ) {
23
- const route = config[ pathKey ] + file;
24
- const response = await fetch( new URL( route, location.origin ), { cache: 'no-store' } );
25
- const body = await response.arrayBuffer();
26
- if ( ! response.ok ) throw new Error( route + ' returned HTTP ' + response.status );
27
- if ( body.byteLength === 0 ) throw new Error( route + ' returned an empty body' );
28
- routes.push( { route: new URL( route, location.origin ).pathname, bytes: body.byteLength, contentType: response.headers.get( 'content-type' ) ?? '' } );
29
- }
30
- return {
31
- name,
32
- state: 'ready',
33
- routes,
34
- decoded: false,
35
- evidence: 'delivery',
36
- blocker: null,
37
- error: null,
38
- };
39
- } catch ( error ) {
40
- return { name, state: 'error', routes, decoded: false, evidence: 'delivery', blocker: null, error: error instanceof Error ? error.message : String( error ) };
41
- }
42
- }
43
-
44
- async function meshoptCodec() {
45
- if ( threeBlocksConfig.codecs.meshopt === false ) return { name: 'meshopt', state: 'disabled', routes: [], decoded: false, evidence: 'decoder-ready', blocker: null, error: null };
46
- try {
47
- const decoder = await loadThreeBlocksMeshoptDecoder();
48
- await decoder.ready;
49
- if ( decoder.supported !== true ) throw new Error( 'Meshopt decoder reports supported=false' );
50
- return {
51
- name: 'meshopt',
52
- state: 'ready',
53
- routes: [],
54
- decoded: false,
55
- evidence: 'decoder-ready',
56
- blocker: null,
57
- error: null,
58
- };
59
- } catch ( error ) {
60
- return { name: 'meshopt', state: 'error', routes: [], decoded: false, evidence: 'decoder-ready', blocker: null, error: error instanceof Error ? error.message : String( error ) };
61
- }
62
- }
63
-
64
- async function decodeCodecFixtures() {
65
- const fixtureRoot = '/__three-blocks-codec-fixtures';
66
- const available = await fetch( fixtureRoot + '/Box.gltf', { cache: 'no-store' } ).then( async response => {
67
- if ( ! response.ok ) return false;
68
- try {
69
- const value = JSON.parse( await response.text() );
70
- return Array.isArray( value?.extensionsUsed ) && value.extensionsUsed.includes( 'KHR_draco_mesh_compression' );
71
- } catch {
72
- return false;
73
- }
74
- }, () => false );
75
- if ( ! available ) return null;
76
- const canvas = document.createElement( 'canvas' );
77
- canvas.width = 4;
78
- canvas.height = 4;
79
- const renderer = new THREE.WebGPURenderer( { canvas, antialias: false } );
80
- let runtime;
81
- let manager;
82
- try {
83
- await renderer.init();
84
- runtime = createThreeAssetAdapters( {
85
- renderer,
86
- codecs: threeBlocksConfig.codecs,
87
- loadMeshopt: loadThreeBlocksMeshoptDecoder,
88
- } );
89
- manager = createAssetManager( runtime.registry );
90
- const load = async ( name, definition, validate ) => {
91
- try {
92
- const lease = await manager.lease( defineAssets( { fixture: definition } ) );
93
- try {
94
- if ( ! validate( lease.assets.fixture ) ) throw new Error( name + ' returned the wrong decoded object.' );
95
- return { ok: true, error: null };
96
- } finally {
97
- lease.release();
98
- }
99
- } catch ( error ) {
100
- return { ok: false, error: error instanceof Error ? error.message : String( error ) };
101
- }
102
- };
103
- return {
104
- draco: await load( 'Draco', { type: 'gltf', url: fixtureRoot + '/Box.gltf' }, value => value?.scene?.isObject3D === true ),
105
- meshopt: await load( 'Meshopt', { type: 'gltf', url: fixtureRoot + '/Meshopt.gltf' }, value => value?.scene?.isObject3D === true ),
106
- ktx2: await load( 'KTX2', { type: 'ktx2', url: fixtureRoot + '/geist.msdf.ktx2' }, value => value?.isTexture === true ),
107
- };
108
- } finally {
109
- await manager?.shutdown();
110
- await runtime?.dispose();
111
- renderer.dispose();
112
- }
113
- }
114
-
115
- async function proveHotRuntime() {
116
- const sharedAsset = { id: 'shared-browser-smoke-asset' };
117
- let disposedAssets = 0;
118
- const registry = createAssetLoaderRegistry( {
119
- json: {
120
- type: 'json',
121
- load: async () => sharedAsset,
122
- dispose: () => { disposedAssets += 1; },
123
- },
124
- } );
125
- const manager = createAssetManager( registry );
126
- const manifest = { shared: { type: 'json', url: '/__three-blocks-smoke-shared.json' } };
127
- const createScene = async ( name ) => {
128
- const scope = manager.createScope();
129
- const assets = await scope.load( manifest );
130
- return {
131
- name,
132
- asset: assets.shared,
133
- hot: { state: 0 },
134
- dispose() { scope.dispose(); },
135
- };
136
- };
137
- const first = await createScene( 'first' );
138
- first.hot.state = 37;
139
- let now = 0;
140
- const pushed = [];
141
- const profiler = {
142
- init() {}, begin() {}, end() {}, update() {}, dispose() {},
143
- getData: () => ( { fps: 60, cpu: 1, gpu: 2, gpuCompute: 3 } ),
144
- };
145
- const stats = createStatsWorker( {
146
- sampleRate: 4,
147
- now: () => now,
148
- publish: ( value ) => pushed.push( value ),
149
- createProfiler: async () => profiler,
150
- } );
151
- await stats.init( {} );
152
- stats.beginFrame();
153
- stats.endFrame();
154
- const stableStats = stats;
155
- const reloader = new SceneHotReloader( first, {
156
- context: { manager, stats },
157
- compile: ( candidate ) => {
158
- if ( candidate.name === 'failed' ) throw new Error( 'intentional browser-smoke compile failure' );
159
- },
160
- } );
161
- const replaced = await reloader.replace( () => createScene( 'second' ) );
162
- now = 300;
163
- stats.beginFrame();
164
- stats.endFrame();
165
- const cacheAfterCommit = manager.cacheSnapshot();
166
- const committed = reloader.current;
167
- let rollbackPhase = null;
168
- try {
169
- await reloader.replace( () => createScene( 'failed' ) );
170
- } catch ( error ) {
171
- rollbackPhase = error && typeof error === 'object' ? error.phase : null;
172
- }
173
- const cacheAfterRollback = manager.cacheSnapshot();
174
- const shaderCache = createShaderCache( 'browser-smoke' );
175
- const firstMaterial = {};
176
- const firstRegistration = shaderCache.forScene( 'browser-smoke' ).material( 'browser-smoke/material', firstMaterial );
177
- const nextMaterial = {};
178
- const nextRegistration = shaderCache.forScene( 'browser-smoke', { replaceExisting: true } )
179
- .material( 'browser-smoke/material', nextMaterial );
180
- firstRegistration.dispose();
181
- const invalidation = shaderCache.invalidationFor( 'browser-smoke/material', 'browser-smoke' );
182
- const shaderReplacementActive = shaderCache.registration( 'browser-smoke/material', 'browser-smoke' )?.target === nextMaterial;
183
- nextRegistration.dispose();
184
- const result = {
185
- sceneIdentityReplaced: replaced.previous === first && replaced.current === committed && committed !== first,
186
- stateRestored: committed.hot.state === 37,
187
- assetIdentityPreserved: first.asset === committed.asset && committed.asset === sharedAsset,
188
- assetReferencesPreserved: cacheAfterCommit.length === 1 && cacheAfterCommit[ 0 ]?.references === 1 && disposedAssets === 0,
189
- statsIdentityPreserved: stats === stableStats,
190
- statsSequenceAdvanced: pushed.length === 2 && pushed[ 0 ]?.sequence === 0 && pushed[ 1 ]?.sequence === 1,
191
- shaderInvalidated: shaderReplacementActive && invalidation?.key === 'browser-smoke/material' && /replaced during HMR/.test( invalidation.reason ),
192
- rollbackPreserved: rollbackPhase === 'compile' && reloader.current === committed && cacheAfterRollback.length === 1 && cacheAfterRollback[ 0 ]?.references === 1,
193
- };
194
- committed.dispose();
195
- stats.dispose();
196
- await manager.shutdown();
197
- return result;
198
- }
199
-
200
- export async function probe() {
201
- const codecs = [
202
- await externalCodec( 'draco', threeBlocksConfig.codecs.draco, 'decoderPath' ),
203
- await externalCodec( 'ktx2', threeBlocksConfig.codecs.ktx2, 'transcoderPath' ),
204
- await meshoptCodec(),
205
- ];
206
- const decoded = await decodeCodecFixtures();
207
- if ( decoded ) {
208
- for ( const codec of codecs ) {
209
- const result = decoded[ codec.name ];
210
- if ( result?.ok ) {
211
- codec.decoded = true;
212
- codec.evidence = 'asset-manager-decoded';
213
- codec.blocker = null;
214
- } else if ( result ) {
215
- codec.state = 'error';
216
- codec.error = result.error;
217
- }
218
- }
219
- }
220
- return {
221
- textEnabled: threeBlocksConfig.text.enabled,
222
- receipt: threeBlocksBuildReceipt,
223
- hmrEvidence: await proveHotRuntime(),
224
- codecs,
225
- };
226
- }
227
- `}a(Je,"browserProbeSource");function Xe(){return {name:"three-blocks:browser-smoke-probe",enforce:"post",resolveId(e){return e===ye?ve:void 0},load(e){return e===ve?Je():void 0}}}a(Xe,"browserProbePlugin");function Te(e){let r={console:[],page:[]};return e.on("console",o=>{o.type()!=="error"||a$2(o.text())||r.console.push(o.text());}),e.on("pageerror",o=>{a$2(o.message)||r.page.push(o.message);}),r}a(Te,"collectPageErrors");async function U(e){return e.evaluate(()=>{let r=globalThis,o=r.__threeBlocksSmoke;if(o!==void 0)return {source:"public",value:o};let t=r.__threeBlocksBrowserTools;if(t&&typeof t=="object"){let n=Reflect.get(t,"smoke");if(n!==void 0)return {source:"public",value:n}}return {source:r.__threeBlocks===void 0?"missing":"legacy",value:r.__threeBlocks??null}})}a(U,"readBridge");async function Ye(e){return e.evaluate(()=>{let r=globalThis,o=r.document.querySelector("[data-tb-fatal-code]"),t=o?.getAttribute("data-tb-fatal-code")??"",n=(o?.title||o?.textContent||"")?.replace(/^three-blocks — error:\s*/u,"").replace(/^Uncaught(?:\s+Error)?:\s*/u,"").trim()??"";return {fatalVisible:o!==null&&/^[a-z][a-z0-9-]{0,63}$/u.test(t)&&r.getComputedStyle(o).display!=="none"&&r.getComputedStyle(o).visibility!=="hidden",code:t.length>0?t:null,detail:n.length>0?n:null}})}a(Ye,"readCompatibilityFailure");async function xe(e){return e.evaluate(()=>{let r=globalThis,o=r.__threeBlocksTextFallbackProbe?.states,t=Array.isArray(o)?o.filter(c=>typeof c=="string").slice(0,32):[],n=t.indexOf("fallback"),a=t.lastIndexOf("ready"),d=[...r.document.querySelectorAll("[data-canvas-text]")];return {states:t,fallbackObserved:n>=0,recovered:n>=0&&a>n,visibleElements:d.filter(c=>c.getAttribute("data-canvas-text-fallback")!=="false").length,totalElements:d.length}})}a(xe,"readTextFallbackEvidence");async function Y(e){return e.evaluate(()=>{let r=globalThis,o=r.__threeBlocksSmoke?.diagnostics?.shaderMode;return {snapshots:Math.max(0,Number(r.__threeBlocksSmoke?.stats?.snapshots)||0),textures:Math.max(0,Number(r.__threeBlocksSmoke?.stats?.textures)||0),shaderMode:o==="precompiled"||o==="live"?o:null,mainPanels:r.document.querySelector("[data-three-blocks-stats-mode]")!==null}})}a(Y,"readBrowserRuntimeObservation");async function Ze(e,r){let o=Buffer.from(`${JSON.stringify(r,null,2)}
228
- `,"utf8");if(o.byteLength>b)throw new Error(`Runtime status receipt exceeds ${b} bytes.`);let t=F.join(e,...a$3.split("/")),n=F.dirname(t);await mkdir(n,{recursive:true});let a=await realpath(n),d=F.relative(e,a);if(d.startsWith("..")||F.isAbsolute(d))throw new Error("Runtime status receipt directory escapes the project root.");let c=F.join(a,`.status.${process.pid}.${randomUUID()}.tmp`);try{await writeFile(c,o,{flag:"wx",mode:384}),await rename(c,t);}finally{await rm(c,{force:true});}}a(Ze,"writeRuntimeStatusReceipt");async function Z(e,r,o){await e.waitForFunction(t=>{let n=globalThis,a=n.__threeBlocksSmoke,d=a!==void 0;if(a===void 0){let l=n.__threeBlocksBrowserTools;l&&typeof l=="object"&&(a=Reflect.get(l,"smoke")),d=a!==void 0;}if(a===void 0&&(a=n.__threeBlocks),!a||typeof a!="object")return false;let c=a;if(d&&c.protocolVersion!==1)return false;let f=c.readiness&&typeof c.readiness=="object"?c.readiness:c,p=c.worker;return (d&&p&&typeof p=="object"?Reflect.get(p,"offscreenCanvas")===true&&Reflect.get(p,"visible")===true:p===true)&&f.workerReady===true&&(f.assetsReady===true||f.loadEnd===true)&&f.compileEnd===true&&f.firstFrame===true&&(!t||f.textReady===true)},r,{timeout:o});}a(Z,"waitForLifecycle");async function Se(e,r){await e.waitForFunction(()=>{let t=[...globalThis.document.querySelectorAll("[data-canvas-text]")];return t.length>0&&t.every(n=>n.getAttribute("data-canvas-text-fallback")==="true")},void 0,{timeout:Math.min(r,3e4)});}a(Se,"waitForTextFallback");async function de(e,r,o){await r();let t=250,n=performance.now()+Math.min(o,5e3),a$1=performance.now(),d=a(()=>{a$1=performance.now();},"navigated");e.on("framenavigated",d);try{for(;performance.now()-a$1<t;){if(performance.now()>=n)throw new Error("Timed out waiting for startup navigation to settle.");await e.waitForTimeout(25);}}finally{e.off("framenavigated",d);}await r();}a(de,"waitForStableReadiness");async function Re(e,r){return await e(),r()}a(Re,"readAfterInitialReadiness");function Qe(e,r,o){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 ${r} route ${o} is invalid.`);let t=e.route.endsWith(".wasm")?"application/wasm":"javascript";if(!e.contentType.includes(t))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(Qe,"parseCodecRoute");function G(e,r,o){if(typeof e!="string"||!r.includes(e))throw new Error(`${o} is invalid.`);return e}a(G,"literal");function le(e,r){if(!Number.isSafeInteger(e)||Number(e)<0)throw new Error(`${r} is invalid.`);return Number(e)}a(le,"nonnegativeInteger");function er(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 r=e.text;if(r!==void 0&&(!a$1(r)||!["ready","generating","fallback","missing","invalid"].includes(String(r.state))))throw new Error("Browser build receipt text state is invalid.");return {schemaVersion:2,renderer:{owner:"worker",api:"WebGPU",fallback:"WebGL"},assets:{draco:G(e.assets.draco,["ready","disabled"],"Browser build receipt Draco state"),ktx2:G(e.assets.ktx2,["ready","disabled"],"Browser build receipt KTX2 state"),meshopt:G(e.assets.meshopt,["lazy","disabled"],"Browser build receipt Meshopt state")},shaders:{state:G(e.shaders.state,["fresh","stale","invalid","missing"],"Browser build receipt shader state"),mode:G(e.shaders.mode,["precompiled","live"],"Browser build receipt shader mode"),pipelines:le(e.shaders.pipelines,"Browser build receipt shader pipeline count")},...r===void 0?{}:{text:{state:G(r.state,["ready","generating","fallback","missing","invalid"],"Browser build receipt text state"),atlases:le(r.atlases,"Browser build receipt text atlas count"),glyphs:le(r.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(er,"parseBuildReceipt");var ce=Object.freeze({sceneIdentityReplaced:false,stateRestored:false,assetIdentityPreserved:false,assetReferencesPreserved:false,statsIdentityPreserved:false,statsSequenceAdvanced:false,shaderInvalidated:false,rollbackPreserved:false}),J=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}),rr=Object.freeze(["three-blocks/assets","three-blocks/hmr","three-blocks/runtime","three-blocks/shaders","three-blocks/stats","three-blocks/text","three-blocks/worker"]);function tr(e){if(!a$1(e))throw new Error("Browser HMR evidence is invalid.");let r={...ce};for(let o of Object.keys(r)){if(e[o]!==true)throw new Error(`Browser HMR evidence ${o} did not pass.`);r[o]=true;}return r}a(tr,"parseHmrEvidence");function or(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 r=["draco","ktx2","meshopt"],o=e.codecs.map((t,n)=>{let a=r[n];if(a===void 0||!a$1(t)||t.name!==a||!["ready","disabled","error"].includes(String(t.state))||!Array.isArray(t.routes)||t.error!==null&&typeof t.error!="string")throw new Error(`Browser codec probe entry ${n} is invalid.`);let d=t.state,c=t.routes.map((p,h)=>Qe(p,a,h)),f=G(t.evidence,["delivery","decoder-ready","text-atlas-decoded","asset-manager-decoded"],`Browser codec ${a} evidence`);if(typeof t.decoded!="boolean"||t.blocker!==null&&typeof t.blocker!="string")throw new Error(`Browser codec ${a} decode evidence is invalid.`);if(d==="ready"&&a!=="meshopt"&&c.length===0)throw new Error(`Browser codec ${a} exposed no routes.`);if(d==="error"&&(typeof t.error!="string"||t.error.length===0||t.error.length>8192))throw new Error(`Browser codec ${a} has an invalid error.`);return {name:a,state:d,routes:c,decoded:t.decoded,evidence:f,blocker:typeof t.blocker=="string"?t.blocker:null,error:typeof t.error=="string"?t.error:null}});return {textEnabled:e.textEnabled,codecs:o,receipt:er(e.receipt),hmrEvidence:tr(e.hmrEvidence)}}a(or,"parseCodecProbe");async function nr(e){let r=await e.evaluate(async o=>{let t=await import(o);if(typeof t.probe!="function")throw new Error("Browser smoke probe module has no probe() export.");return await t.probe()},Ke);return or(r)}a(nr,"probeCodecs");function ar(e){return e instanceof Error&&/execution context was destroyed|most likely because of a navigation/iu.test(e.message)}a(ar,"isNavigationRace");async function sr(e,r,o){for(let t=0;t<3;t++)try{return await nr(e)}catch(n){if(!ar(n)||t===2)throw n;await de(e,r,o);}throw new Error("Browser codec probe did not complete.")}a(sr,"probeCodecsAfterNavigation");async function ue(e){return e.evaluate(()=>{let r=globalThis,o=0;for(let t of r.document.querySelectorAll("canvas")){if(t.width<=0||t.height<=0)continue;let n=null;try{n=t.getContext("2d");}catch{continue}if(n)try{let a=n.getImageData(0,0,t.width,t.height).data,d=0,c=0;for(let f=0;f+2<a.length;f+=4)d+=Math.max(a[f]??0,a[f+1]??0,a[f+2]??0),c+=1;c>0&&(o=Math.max(o,d/c));}catch{}}return o})}a(ue,"panelLuminance");function lr(e){return e.split(F.sep).join("/")}a(lr,"portablePath");async function ir(e){return e.evaluate(()=>{let o=globalThis.__threeBlocksSmokeProbe;if(!o||typeof o!="object")return 0;let t=Reflect.get(o,"after");return typeof t=="number"&&Number.isSafeInteger(t)?t:0})}a(ir,"hmrEventCount");async function dr(e,r,o,t,n,a,d){if(t===void 0)return {requested:false,module:null,dispatched:false,acknowledged:false,lifecycleStable:true,sourceUnchanged:true,evidenceSource:"public-runtime-browser-probe",evidence:d,restart:J,error:null};let c$1=lr(t),f=false,p=false,h=false,l=false;try{let i=await j(o,F.join(o,t),a$4.semanticInput,"HMR scene module"),s=c(i.data),w=e.moduleGraph.getModulesByFile(i.path);if(!w||w.size===0)throw new Error(`HMR scene module ${JSON.stringify(c$1)} is not in Vite's module graph.`);let m=await ir(r);e.watcher.emit("change",i.path),f=!0,await r.waitForFunction(T=>{let y=globalThis.__threeBlocksSmokeProbe;return !!(y&&typeof y=="object"&&Number(Reflect.get(y,"after"))>T)},m,{timeout:Math.min(n,3e4)}),p=!0,await Z(r,a,Math.min(n,3e4)),h=!0;let g=await j(o,i.path,a$4.semanticInput,"HMR scene module");if(l=c(g.data)===s,!l)throw new Error("HMR scene source changed during the smoke run.");return {requested:!0,module:c$1,dispatched:f,acknowledged:p,lifecycleStable:h,sourceUnchanged:l,evidenceSource:"public-runtime-browser-probe",evidence:d,restart:J,error:null}}catch(i){return {requested:true,module:c$1,dispatched:f,acknowledged:p,lifecycleStable:h,sourceUnchanged:l,evidenceSource:"public-runtime-browser-probe",evidence:d,restart:J,error:i instanceof Error?i.message:String(i)}}}a(dr,"exerciseHmr");async function cr(e,r,o,t){let n="stats-baseline";try{let a=await e.evaluate(()=>{let l=globalThis;return new URL(l.location.href).searchParams.get("tbStats")==="1"});a&&(n="stats-query-boot",await e.waitForFunction(()=>globalThis.__threeBlocksSmoke?.stats?.panelVisible===!0,void 0,{timeout:Math.min(r,3e4)}));let d=await e.evaluate(()=>{let l=globalThis;return {panelVisible:l.__threeBlocksSmoke?.stats?.panelVisible,textures:Number(l.__threeBlocksSmoke?.stats?.textures)||0,panelAttached:l.document.querySelector("[data-three-blocks-stats-mode]")!==null}});if(!a&&(d.panelVisible!==!1||d.textures!==0||d.panelAttached))throw new Error("Generated stats panel is not default-off before browser-smoke activation.");n="stats-enable",await e.evaluate(async()=>{let i=globalThis.__threeBlocksSmoke?.stats;if(!i||typeof i.setPanelVisible!="function"||typeof i.setPanelMode!="function")throw new Error("Generated stats panel controls are unavailable.");if(await Reflect.apply(i.setPanelVisible,i,[!0])!==!0)throw new Error("Generated stats panel could not be enabled.");if(await Reflect.apply(i.setPanelMode,i,["expanded"])!==!0)throw new Error("Generated stats panel could not be expanded.")}),n="stats-expanded",await e.waitForFunction(()=>{let l=globalThis;return l.__threeBlocksSmoke?.stats?.panelVisible===!0&&l.document.querySelector('[data-three-blocks-stats-mode="expanded"]')!==null},void 0,{timeout:Math.min(r,3e4)}),n="stats-initial-texture",await e.waitForFunction(l=>Number(globalThis.__threeBlocksSmoke?.stats?.textures)>l,d.textures,{timeout:Math.min(r,3e4)}),n="snapshot";let c=await e.evaluate(()=>{let l=globalThis,i=l.__threeBlocksSmoke,s=l.document.querySelector("#app"),w=l.document.querySelector("#scene"),m=l.document.querySelector("main")??s;if(!i||typeof i.restartWorker!="function"||!s||!w||!m||typeof i.diagnostics?.workerId!="string")throw new Error("Generated worker restart diagnostics are unavailable.");return l.__threeBlocksWorkerRestartProbe={app:s,content:m,canvas:w},{workerId:i.diagnostics.workerId,generation:i.worker.generation,restartCount:i.restart.count,snapshots:i.stats.snapshots,textures:i.stats.textures}});n="restart-call",await e.evaluate(async()=>{let l=globalThis,i=l.__threeBlocksSmoke?.restartWorker;if(typeof i!="function")throw new Error("Generated restartWorker() is unavailable.");await Reflect.apply(i,l.__threeBlocksSmoke,["browser smoke worker restart"]);}),n="restart-readiness",await e.waitForFunction(l=>{let s=globalThis.__threeBlocksSmoke,w=s?.readiness;return typeof s?.diagnostics?.workerId=="string"&&s.diagnostics.workerId!==l.workerId&&Number(s.worker?.generation)>l.generation&&s.restart?.stateReplayed===!0&&w?.workerReady===!0&&w.assetsReady===!0&&w.compileEnd===!0&&w.firstFrame===!0&&(!l.textEnabled||w.textReady===!0)},{workerId:c.workerId,generation:c.generation,textEnabled:o},{timeout:Math.min(r,45e3)}),n="stats-snapshot",await e.waitForFunction(l=>Number(globalThis.__threeBlocksSmoke?.stats?.snapshots)>l,c.snapshots,{timeout:Math.min(r,3e4)}),n="stats-texture",await e.waitForFunction(l=>Number(globalThis.__threeBlocksSmoke?.stats?.textures)>l,c.textures,{timeout:Math.min(r,3e4)});let f=await e.evaluate(l=>{let i=globalThis,s=i.__threeBlocksSmoke,w=i.__threeBlocksWorkerRestartProbe,m=s?.readiness;if(!s||!w||!m)throw new Error("Generated restart evidence disappeared.");return {requested:!0,appIdentityStable:w.app===i.document.querySelector("#app"),contentIdentityStable:w.content===(i.document.querySelector("main")??i.document.querySelector("#app")),canvasReplaced:s.restart.canvasReplaced&&w.canvas!==i.document.querySelector("#scene"),workerIdentityChanged:typeof s.diagnostics?.workerId=="string"&&s.diagnostics.workerId!==l.workerId,generationAdvanced:s.worker.generation===l.generation+1,restartCountAdvanced:s.restart.count===l.restartCount+1,stateReplayed:s.restart.stateReplayed&&s.restart.lastReason==="browser smoke worker restart",readinessRestored:m.workerReady===!0&&m.assetsReady===!0&&m.compileEnd===!0&&m.firstFrame===!0&&(!l.textEnabled||m.textReady===!0),shaderModeStable:s.diagnostics?.shaderMode===l.expectedShaderMode,statsSnapshotsAdvanced:s.stats.snapshots>l.snapshots,statsTextureTransferred:s.stats.textures>l.textures,statsTextureStopped:!1,error:null}},{...c,textEnabled:o,expectedShaderMode:t});n="stats-disable",await e.evaluate(async()=>{let i=globalThis.__threeBlocksSmoke?.stats;if(!i||typeof i.setPanelVisible!="function")throw new Error("Generated stats visibility control disappeared before disable.");if(await Reflect.apply(i.setPanelVisible,i,[!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(r,3e4)}),await e.waitForTimeout(750);let p=await e.evaluate(()=>Number(globalThis.__threeBlocksSmoke?.stats?.textures)||0);await e.waitForTimeout(1100);let h=await e.evaluate(()=>Number(globalThis.__threeBlocksSmoke?.stats?.textures)||0);if(h!==p)throw new Error(`Stats textures advanced after disable (${p} -> ${h}).`);return {...f,statsTextureStopped:!0}}catch(a){return {...J,requested:true,error:`${n}: ${a instanceof Error?a.message:String(a)}`}}}a(cr,"exerciseWorkerRestart");function D(e){return [...new Set(e)].sort((r,o)=>r.localeCompare(o))}a(D,"sortedUnique");function ur(e,r,o){let t=D(e),n=D(r),a=o?D([...t,...n].filter(c=>/MSDF atlases are missing code points:/iu.test(c))):[],d=new Set(a);return {console:t.filter(c=>!d.has(c)),page:n.filter(c=>!d.has(c)),resolved:a}}a(ur,"classifyRecoveredTextErrors");function mr(e){return e.replace(/\u001b\[[0-?]*[ -/]*[@-~]/gu,"")}a(mr,"stripTerminalControl");function yr(e,r,o){let t=e.config.base.startsWith("/")?e.config.base:"/";return new URL(o.replace(/^\/+/,""),`${r}${t.endsWith("/")?t:`${t}/`}`).href}a(yr,"projectUrl");async function xr(e){let{chromium:r,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 n=await realpath(e.root),a$1=Pe(e.route),d$1=V(e.timeoutMs,"Browser smoke timeoutMs",1e3,15*6e4,Be),c=V(e.settleMs,"Browser smoke settleMs",0,1e4,1e3),f={width:V(e.viewport?.width,"Browser smoke viewport width",64,8192,1024),height:V(e.viewport?.height,"Browser smoke viewport height",64,8192,640)},p=_e(e.minimumLuminance,"Browser smoke minimumLuminance",0,255,2),h,l,i,s,w=false,m=$(void 0,false),g=[],T=null,z=ce,y={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-browser-probe",evidence:ce,restart:J,error:e.hmrModule===void 0?null:"HMR was not reached."},q=false,B=false,O={fatalVisible:false,code:null,detail:null},E={states:[],fallbackObserved:false,recovered:false,visibleElements:0,totalElements:0},v={snapshots:0,textures:0,shaderMode:null,mainPanels:false},A=[],I=0,L=0,P={console:[],page:[]},j,K=process.env.PATH;process.env.PATH=[F.join(n,"node_modules",".bin"),K].filter(Boolean).join(F.delimiter);try{let k=o("silent");k.warn=H=>{A.push(mr(H));},h=await t({root:n,logLevel:"silent",customLogger:k,plugins:[Xe()],optimizeDeps:{force:!0,include:[...rr]},server:{host:"127.0.0.1",port:0,strictPort:!1}}),await h.listen();let x=h.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}`;l=await r.launch({headless:d(e.headed===!0),args:[...b$1()]}),i=await l.newContext({viewport:f}),await i.addInitScript({content:`
229
- (() => {
230
- const key = '__three-blocks-text-fallback-states-v1';
231
- let states = [];
232
- try { states = JSON.parse( sessionStorage.getItem( key ) || '[]' ); } catch {}
233
- const probe = globalThis.__threeBlocksTextFallbackProbe = { states };
234
- const record = value => {
235
- if ( typeof value !== 'string' || value.length === 0 || probe.states.at( -1 ) === value || probe.states.length >= 32 ) return;
236
- probe.states.push( value );
237
- try { sessionStorage.setItem( key, JSON.stringify( probe.states ) ); } catch {}
238
- };
239
- const inspect = node => {
240
- if ( node && node.nodeType === 1 ) record( node.getAttribute( 'data-three-blocks-text-state' ) );
241
- };
242
- new MutationObserver( records => {
243
- for ( const mutation of records ) {
244
- inspect( mutation.target );
245
- for ( const node of mutation.addedNodes || [] ) {
246
- inspect( node );
247
- if ( node.querySelectorAll ) for ( const child of node.querySelectorAll( '[data-three-blocks-text-state]' ) ) inspect( child );
248
- }
249
- }
250
- } ).observe( document, { subtree: true, childList: true, attributes: true, attributeFilter: [ 'data-three-blocks-text-state' ] } );
251
- })();
252
- `}),e.forceWebgl===!0&&await i.addInitScript(()=>{Object.defineProperty(Navigator.prototype,"gpu",{configurable:!0,value:void 0});}),e.unsupportedWorker===!0&&await i.addInitScript(()=>{Object.defineProperty(globalThis,"Worker",{configurable:!0,value:void 0});}),s=await i.newPage();let C=s;if(j=Te(s),s.on("console",H=>{/WebGPU is not available, running under WebGL2 backend/iu.test(H.text())&&(B=!0);}),await s.goto(yr(h,R,a$1),{waitUntil:"domcontentloaded",timeout:d$1}),e.unsupportedWorker===!0)q=await Re(async()=>{await de(C,a(async()=>{await C.waitForFunction(()=>globalThis.document.querySelector("#three-blocks-dev-overlay")?.shadowRoot?.querySelector(".dot")?.dataset.tone==="error",void 0,{timeout:Math.min(d$1,15e3)});},"waitForFailure"),d$1);},()=>C.evaluate(()=>"gpu"in navigator&&navigator.gpu!==void 0)),O=await Ye(s),m=$(await U(s),!1);else {let H=a(()=>e.expectTextGenerationFailure===!0?Se(C,d$1):Z(C,!1,d$1),"initialReadiness");q=await Re(()=>de(C,H,d$1),()=>C.evaluate(()=>"gpu"in navigator&&navigator.gpu!==void 0));let _=await sr(s,H,d$1);if(w=_.textEnabled,g=_.codecs,T=_.receipt,z=_.hmrEvidence,e.expectTextGenerationFailure===!0){if(!_.textEnabled)throw new Error("Expected text-generation failure mode requires a text-enabled project.");await Se(s,d$1);let W=performance.now()+Math.min(d$1,3e4);for(;!A.some(je=>/automatic atlas generation failed/iu.test(je));){if(performance.now()>=W)throw new Error("Timed out waiting for the automatic text-generation failure warning.");await s.waitForTimeout(50);}m=$(await U(s),!0);}else if(await Z(s,_.textEnabled,d$1),m=$(await U(s),_.textEnabled),_.textEnabled&&m.textReady&&(g=g.map(W=>W.name==="ktx2"?{...W,decoded:!0,evidence:"text-atlas-decoded",blocker:null}:W)),y=await dr(h,s,n,e.hmrModule,d$1,_.textEnabled,z),e.hmrModule!==void 0){let W=await cr(s,d$1,_.textEnabled,_.receipt.shaders.mode);y={...y,restart:W},m=$(await U(s),_.textEnabled);}}c>0&&await s.waitForTimeout(c),E=await xe(s),v=await Y(s);let Oe=await s.screenshot({type:"png"});I=ie(Oe),L=await ue(s);}catch(k){if(s!==void 0)try{m=$(await U(s),w),E=await xe(s),v=await Y(s);let x=await s.screenshot({type:"png"});I=ie(x),L=await ue(s);}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{j!==void 0&&(P.console.push(...j.console),P.page.push(...j.page)),await i?.close().catch(R=>{P.page.push(`Browser context cleanup failed: ${R instanceof Error?R.message:String(R)}`);}),await l?.close().catch(R=>{P.page.push(`Browser cleanup failed: ${R instanceof Error?R.message:String(R)}`);});let k=h?.httpServer,x=k?Reflect.get(k,"closeAllConnections"):void 0;k&&typeof x=="function"&&Reflect.apply(x,k,[]),await h?.close().catch(R=>{P.page.push(`Vite cleanup failed: ${R instanceof Error?R.message:String(R)}`);}),K===void 0?delete process.env.PATH:process.env.PATH=K;}let X=Number(I.toFixed(2)),M=Number(L.toFixed(2)),fe=I<=p&&L<=p,Q=ur(P.console,P.page,E.recovered),pe=Q.console,we=Q.page,Me=Q.resolved,he=m.worker&&m.workerReady&&m.assetsReady&&m.compileEnd&&m.textReady&&m.firstFrame,Ce=g.length===3&&g.every(k=>k.state!=="error"),Fe=Object.values(y.evidence).every(Boolean),Ae=!y.restart.requested||y.restart.error===null&&[y.restart.appIdentityStable,y.restart.contentIdentityStable,y.restart.canvasReplaced,y.restart.workerIdentityChanged,y.restart.generationAdvanced,y.restart.restartCountAdvanced,y.restart.stateReplayed,y.restart.readinessRestored,y.restart.shaderModeStable,y.restart.statsSnapshotsAdvanced,y.restart.statsTextureTransferred,y.restart.statsTextureStopped].every(Boolean),be=!y.requested||y.dispatched&&y.acknowledged&&y.lifecycleStable&&y.sourceUnchanged&&Fe&&Ae&&y.error===null,ke=A.filter(k=>/automatic atlas generation failed/iu.test(k)),$e=ke.reduce((k,x)=>k+(x.match(/three-blocks text generate/gu)?.length??0),0),Ie=e.expectTextGenerationFailure===true&&w&&E.fallbackObserved&&!E.recovered&&E.totalElements>0&&E.visibleElements===E.totalElements&&ke.length===1&&$e===1,Le=e.unsupportedWorker===true&&O.fatalVisible&&O.code==="render-worker-unavailable"&&!m.workerReady&&!m.compileEnd&&!m.firstFrame,We=e.unsupportedWorker===true?"unsupported-worker":e.forceWebgl===true?"WebGL-fallback":"WebGPU-first",Ve=e.unsupportedWorker===true?"none":he?e.forceWebgl===true||!q?"WebGL":"WebGPU":"unknown",qe=m.workerReady&&m.compileEnd&&m.firstFrame,b={schemaVersion:1,command:"browser smoke",passed:e.unsupportedWorker===true?Le:e.expectTextGenerationFailure===true?Ie:he&&Ce&&be&&!fe&&pe.length===0&&we.length===0,scene:a$1,lifecycle:m,renderer:{requested:We,active:Ve,navigatorGpu:q,workerOwned:qe,fallbackDiagnostic:B},compatibility:{...O,silentMainThreadRenderer:e.unsupportedWorker===true&&(m.compileEnd||m.firstFrame)},receipt:T,textFallback:E,warnings:D(A),rendering:{luminance:X,panelLuminance:M,threshold:p,blackFrame:fe},codecs:g,hmr:y,errors:{console:pe,page:we,resolved:Me}};if(b.passed&&e.unsupportedWorker!==true&&e.expectTextGenerationFailure!==true){if(b.receipt===null||b.lifecycle.backend==="unknown"||b.renderer.active!=="WebGPU"&&b.renderer.active!=="WebGL")throw new Error("A successful browser smoke cannot write runtime status without an observed backend and renderer/build receipt.");let k=b.hmr.requested,x=k?be:null,R={schemaVersion:1,observedAt:new Date().toISOString(),worker:{backend:b.lifecycle.backend,renderer:b.renderer.active,protocolVersion:1},assets:{codecs:b.codecs.map(C=>({name:C.name,available:C.state==="ready",decoded:C.decoded})),resources:0},hmr:{capabilities:{scene:true,component:true,assetManifest:true,workerRestart:true},outcome:{attempted:k,succeeded:x,rollbackPreserved:k?b.hmr.evidence.rollbackPreserved:null,workerRestarted:b.hmr.restart.requested&&b.hmr.restart.workerIdentityChanged}},stats:{snapshots:v.snapshots,textures:v.textures,workerProfiler:v.snapshots>0,mainPanels:v.mainPanels},lifecycle:{state:"first frame",workerReady:b.lifecycle.workerReady,assetsReady:b.lifecycle.assetsReady,compiled:b.lifecycle.compileEnd,firstFrame:b.lifecycle.firstFrame},shaders:{mode:v.shaderMode??b.receipt.shaders.mode,pipelines:b.receipt.shaders.pipelines},...b.receipt.text===void 0?{}:{text:{state:b.receipt.text.state,atlases:b.receipt.text.atlases,glyphs:b.receipt.text.glyphs,requiredGlyphs:b.receipt.text.glyphs}},error:null};await Ze(n,R);}return b}a(xr,"runBrowserSmoke");function Sr(e){let r=e.lifecycle,o=[`${e.passed?"\u2713":"\u2717"} Browser ${e.scene} \xB7 worker ${r.worker&&r.workerReady?"ready":"failed"} \xB7 assets ${r.assetsReady?"ready":"failed"} \xB7 compile ${r.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(t=>`${t.name} ${t.state}${t.decoded?" decoded":""}`).join(" \xB7 ")||"not observed"}`];e.compatibility.fatalVisible&&o.push(` Compatibility ${e.compatibility.detail??"fatal compatibility screen visible"}`),e.textFallback.states.length>0&&o.push(` Text ${e.textFallback.states.join(" \u2192 ")}`),e.hmr.requested&&o.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&&o.push(` Restart ${e.hmr.restart.error===null&&e.hmr.restart.workerIdentityChanged&&e.hmr.restart.stateReplayed?"ready":"failed"} \xB7 worker/state/stats`);for(let t of e.warnings)o.push(` Warning ${t}`);for(let t of e.errors.console)o.push(` Console ${t}`);for(let t of e.errors.page)o.push(` Page ${t}`);for(let t of e.errors.resolved)o.push(` Recovered ${t}`);e.hmr.error&&o.push(` HMR error ${e.hmr.error}`),e.hmr.restart.error&&o.push(` Restart error ${e.hmr.restart.error}`);for(let t of e.codecs)t.error&&o.push(` ${t.name} error ${t.error}`);return o.join(`
253
- `)}a(Sr,"formatBrowserSmokeReport");async function Rr(e){let{chromium:r,vite:{build:o,preview:t}}=await Ee(),n=await realpath(e.root),a=(e.routes===void 0||e.routes.length===0?["/"]:e.routes).map(Pe),d$1=V(e.timeoutMs,"Browser preview timeoutMs",1e3,15*6e4,Be),c=V(e.settleMs,"Browser preview settleMs",0,1e4,500),f={width:V(e.viewport?.width,"Browser preview viewport width",64,8192,1024),height:V(e.viewport?.height,"Browser preview viewport height",64,8192,640)},p=_e(e.minimumLuminance,"Browser preview minimumLuminance",0,255,2),h=e.expectShaders??"precompiled",l=e.text===true,i=[],s,w,m=process.env.PATH;process.env.PATH=[F.join(n,"node_modules",".bin"),m].filter(Boolean).join(F.delimiter);try{await o({root:n,logLevel:"warn",...e.buildMode===void 0?{}:{mode:e.buildMode}}),s=await t({root:n,logLevel:"warn",preview:{host:"127.0.0.1",port:0,strictPort:!1,open:!1}});let g=s.httpServer?.address();if(!g||typeof g=="string")throw new Error("Vite preview did not expose an ephemeral TCP address.");let T=s.config.base.startsWith("/")?s.config.base:"/",z=`http://127.0.0.1:${g.port}${T.endsWith("/")?T:`${T}/`}`;w=await r.launch({headless:d(e.headed===!0),args:[...b$1()]});for(let y of a){let q=await w.newContext({viewport:f}),B=await q.newPage(),O=Te(B),E=[],v=$(void 0,l),A=null,I=0,L=0;try{await B.goto(new URL(y.replace(/^\/+/,""),z).href,{waitUntil:"domcontentloaded",timeout:d$1}),await Z(B,l,d$1),c>0&&await B.waitForTimeout(c),v=$(await U(B),l),A=(await Y(B)).shaderMode;let M=await B.screenshot({type:"png"});I=ie(M),L=await ue(B);}catch(M){try{v=$(await U(B),l),A=(await Y(B)).shaderMode;}catch{}E.push(M instanceof Error?M.message:String(M));}finally{await q.close().catch(M=>{E.push(`Browser context cleanup failed: ${M instanceof Error?M.message:String(M)}`);});}let P=D(O.console),j=D([...O.page,...E]),K=v.worker&&v.workerReady&&v.assetsReady&&v.compileEnd&&v.textReady&&v.firstFrame,X=I<=p&&L<=p;i.push({route:y,passed:K&&!X&&A===h&&P.length===0&&j.length===0,lifecycle:v,shaderMode:A,rendering:{luminance:Number(I.toFixed(2)),panelLuminance:Number(L.toFixed(2)),threshold:p,blackFrame:X},errors:{console:P,page:j}});}}finally{await w?.close().catch(()=>{});let g=s?.httpServer,T=g?Reflect.get(g,"closeAllConnections"):void 0;g&&typeof T=="function"&&Reflect.apply(T,g,[]),await s?.close().catch(()=>{}),m===void 0?delete process.env.PATH:process.env.PATH=m;}return {schemaVersion:1,command:"browser preview",passed:i.length>0&&i.every(g=>g.passed),buildMode:e.buildMode??null,expectShaders:h,routes:i}}a(Rr,"runBrowserPreview");function Br(e){let r=[`${e.passed?"\u2713":"\u2717"} Preview production build${e.buildMode===null?"":` \xB7 --mode ${e.buildMode}`} \xB7 expects shaders ${e.expectShaders}`];for(let o of e.routes){let t=o.lifecycle;r.push(` ${o.passed?"\u2713":"\u2717"} ${o.route} \xB7 worker ${t.worker&&t.workerReady?"ready":"failed"} \xB7 compile ${t.compileEnd?"ready":"failed"} \xB7 shaders ${o.shaderMode??"unobserved"} \xB7 frame ${o.rendering.luminance.toFixed(2)}${o.rendering.blackFrame?" \xB7 black":""}`);for(let n of o.errors.console)r.push(` Console ${n}`);for(let n of o.errors.page)r.push(` Page ${n}`);}return r.join(`
254
- `)}a(Br,"formatBrowserPreviewReport");export{rr as BROWSER_SMOKE_OPTIMIZE_DEPENDENCIES,ur as classifyRecoveredTextErrors,Br as formatBrowserPreviewReport,Sr as formatBrowserSmokeReport,$ as parseBrowserSmokeLifecycle,Re as readAfterInitialReadiness,Rr as runBrowserPreview,xr as runBrowserSmoke,ie as screenshotLuminance};