@three-blocks/devtools 2.0.0-alpha.238.g8723f0a28ca3 → 3.0.0-alpha.282.g3f938d990c02
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 +63 -37
- package/dist/{browser-smoke-EIKJ6OVK.js → browser-smoke-JHZLPGEB.js} +1 -1
- package/dist/{chunk-GA7PGW2R.js → chunk-3CKEE22B.js} +1 -1
- package/dist/{chunk-OQLHTDDH.js → chunk-AIAYEDXX.js} +1 -1
- package/dist/{chunk-4YRR36JN.js → chunk-FKZT7XLM.js} +18 -18
- package/dist/{chunk-TUIINI6U.js → chunk-L2CZ7RSV.js} +1 -1
- package/dist/{chunk-LUULHXFK.js → chunk-NQIAU3XU.js} +6 -6
- package/dist/chunk-QJFPNM6W.js +2 -0
- package/dist/chunk-YHHGR2AJ.js +80 -0
- package/dist/cli.js +8 -8
- package/dist/{environment-bake-XMRKQJXM.js → environment-bake-BGMGFAVK.js} +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +5 -5
- package/dist/{shader-browser-EYE3UT2U.js → shader-browser-523TEBVA.js} +1 -1
- package/dist/{shader-browser-WF4HNSAV.js → shader-browser-YPBP3WQY.js} +1 -1
- package/dist/shader-capture-server.d.ts +1 -1
- package/dist/shader-capture-server.js +5 -5
- package/dist/{shader-watch-ISNWIAXN.js → shader-watch-XY6A2KGQ.js} +1 -1
- package/dist/shader-workflow-T7W7UHWJ.js +2 -0
- package/dist/{status-D2RF6QTL.js → status-RFA7WAM6.js} +1 -1
- package/dist/transform.js +1 -1
- package/dist/webpack-loader.js +1 -1
- package/package.json +4 -4
- package/dist/chunk-V34C7NIM.js +0 -80
- package/dist/chunk-W6UL2OW7.js +0 -2
- package/dist/shader-workflow-T72N2CLS.js +0 -2
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {b,e as e$2,a as a$4,d as d$2,c as c$2,j as j$2,i as i$2,f as f$2,h as h$1,g as g$1}from'./chunk-
|
|
2
|
+
import {b,e as e$2,a as a$4,d as d$2,c as c$2,j as j$2,i as i$2,f as f$2,h as h$1,g as g$1}from'./chunk-FKZT7XLM.js';import {a as a$3}from'./chunk-ZT6T2W4B.js';import {i,j as j$1,d as d$1,e as e$1,g,b as b$1,l,f as f$1,k as k$1,c as c$3}from'./chunk-NPLE7PPF.js';import {a as a$2,c as c$1}from'./chunk-65VEJRRT.js';import {j,a as a$1,c,d,k,h,e,i as i$1,f}from'./chunk-5L2VS3BN.js';import {a}from'./chunk-HOZDD6PW.js';import {realpath,readdir,readFile,lstat,mkdir,writeFile}from'fs/promises';import Ae from'os';import L from'path';import {SHADER_ADDRESS_SCHEMA_VERSION,SHADER_RECIPE_SCHEMA_VERSION,SHADER_HYDRATION_SCHEMA_VERSION}from'three-blocks/shaders';import {createRequire}from'module';var Ge=[".ts",".tsx",".mts",".cts",".js",".jsx",".mjs",".cjs",".wgsl",".glsl",".vert",".frag",".json",".css"],Je=new Set(Ge),qe=/^(?:three-blocks\.shaders\.json|(?:precompile|three-blocks\.shaders)\.config\.(?:cjs|cts|js|mjs|mts|ts))$/u,Cr=/(?:^|\/)scene\.(?:cjs|cts|js|jsx|mjs|mts|ts|tsx)$/u,jr=/\b(?:export\s+)?(?:async\s+)?function\s+createScene\b|\bcreateScene\s*=\s*(?:async\s*)?\(/u,Dr=/\b(?:[A-Za-z_$][\w$]*\.)*(?:shaders|shaderCache|sceneShaders)\s*\.\s*(?:material|pipeline|compute|container)\s*\(/u,Ar=/\b(import|export)(?!\s*\()\s*(type\b\s*)?(?:[^"'();]*?\bfrom\s*)?["']([^"']+)["']/gu,_r=/\bimport\s*\(\s*["']([^"']+)["']\s*\)/gu,Fr=/\b(?:import|export)(?!\s*\()\s*(?:[^"'();]*?\bfrom\s*)?["']([^"']+)["']|\bimport\s*\(\s*["']([^"']+)["']\s*\)/gu,Nr=/^[0-9A-Za-z][0-9A-Za-z.+_-]{0,127}$/u,Ye=4096,Lr="./shaders";function mr(e,r){let n=L.relative(e,r).split(L.sep).join("/");if(n.length===0||/[\u0000-\u001f\u007f]/u.test(n))throw new Error("Semantic input has an unsafe relative path.");return n}a(mr,"portableRelativePath");function Xe(e,r){try{return new TextDecoder("utf-8",{fatal:!0}).decode(e)}catch{throw new Error(`Shader-relevant source ${JSON.stringify(r)} is not valid UTF-8.`)}}a(Xe,"sourceText");function Qe(e,r){let n="",t="code";for(let i=0;i<e.length;i++){let s=e[i]??"",c=e[i+1]??"";if(t==="code"){if(s==="/"&&c==="/"){n+=" ",t="line-comment",i++;continue}if(s==="/"&&c==="*"){n+=" ",t="block-comment",i++;continue}if(s==="'"||s==='"'||s==="`"){t=s==="'"?"single":s==='"'?"double":"template",n+=r?s:" ";continue}n+=s;continue}if(t==="line-comment"){s===`
|
|
3
3
|
`?(n+=`
|
|
4
4
|
`,t="code"):n+=" ";continue}if(t==="block-comment"){s==="*"&&c==="/"?(n+=" ",t="code",i++):n+=s===`
|
|
5
5
|
`?`
|
|
6
6
|
`:" ";continue}let o=t==="single"?"'":t==="double"?'"':"`";if(s==="\\"&&c.length>0){n+=r?`${s}${c}`:" ",i++;continue}n+=r?s:s===`
|
|
7
7
|
`?`
|
|
8
|
-
`:" ",s===o&&(t="code");}return n}a(Qe,"lexicalSource");function Vr(e){let r=new Set,n=Qe(e,true);for(let t of n.matchAll(Ar))t[2]===void 0&&t[3]!==void 0&&r.add(t[3]);for(let t of n.matchAll(_r))t[1]!==void 0&&r.add(t[1]);return [...r].sort()}a(Vr,"importSpecifiers");function Hr(e){let r=new Set;for(let n of Qe(e,true).matchAll(Fr)){let t=n[1]??n[2];t!==void 0&&r.add(t);}return [...r].sort()}a(Hr,"runtimeSpecifiers");function pr(e){return (e.split(/[?#]/u,1)[0]??e).replaceAll("\\","/")}a(pr,"cleanSpecifier");function Wr(e,r,n){let t=pr(r),i;if(t.startsWith("./")||t.startsWith("../"))i=L.posix.normalize(L.posix.join(L.posix.dirname(e),t));else if(t.startsWith("@/"))i=`src/${t.slice(2)}`;else if(t.startsWith("/src/"))i=t.slice(1);else return;if(i===".three-blocks"||i.startsWith(".three-blocks/"))return;let s=L.posix.extname(i).toLowerCase(),c=new Set([i]);if(s.length===0||!Je.has(s)){for(let o of Ge)c.add(`${i}${o}`);for(let o of Ge)c.add(`${i}/index${o}`);}else if([".js",".mjs",".cjs",".jsx"].includes(s)){let o=i.slice(0,-s.length);for(let m of [".ts",".tsx",".mts",".cts"])c.add(`${o}${m}`);}return [...c].find(o=>n.has(o))}a(Wr,"resolveProjectImport");function Kr(e,r){let n=Qe(r,false);return Cr.test(e)||jr.test(n)||Dr.test(n)}a(Kr,"isShaderRoot");async function Ce(e,r){let n=await realpath(e);if(r!==void 0){let a={},
|
|
9
|
-
`);return c(o)}a(zr,"shaderRuntimeClosure");async function we(e){let[r,n]=await Promise.all([fr(e,"three"),fr(e,"three-blocks")]);return {three:String(r.manifest.version),threeBlocks:String(n.manifest.version),threeBlocksShaderClosure:await zr(n.root,n.manifest)}}a(we,"readInstalledShaderRuntime");var Sr=4096,qr=createRequire(import.meta.url),gr,E=new Proxy({},{get(e,r){return gr??=qr("typescript"),Reflect.get(gr,r)}});function te(e){let r=e;for(;E.isParenthesizedExpression(r)||E.isAsExpression(r)||E.isSatisfiesExpression(r)||E.isNonNullExpression(r);)r=r.expression;return r}a(te,"unwrap");function Gr(e){if(E.isIdentifier(e)||E.isStringLiteral(e)||E.isNumericLiteral(e))return e.text}a(Gr,"propertyName");function ve(e,r){let n=new Map;for(let t of e.properties){if(!E.isPropertyAssignment(t))throw new Error(`${r} may contain only static property assignments.`);let i=Gr(t.name);if(i===void 0||n.has(i))throw new Error(`${r} contains a computed or duplicate property.`);n.set(i,t.initializer);}return n}a(ve,"properties");function be(e,r){if(e===void 0)throw new Error(`${r} is missing.`);let n=te(e);if(!E.isObjectLiteralExpression(n))throw new Error(`${r} must be a static object literal.`);return n}a(be,"objectLiteral");function ke(e,r){if(e===void 0)throw new Error(`${r} is missing.`);let n=te(e);if(!E.isStringLiteral(n)&&!E.isNoSubstitutionTemplateLiteral(n))throw new Error(`${r} must be a string literal.`);return n.text}a(ke,"stringLiteral");function je(e,r){if(e===void 0)throw new Error(`${r} is missing.`);let n=te(e);if(!E.isNumericLiteral(n))throw new Error(`${r} must be a numeric literal.`);return Number(n.text)}a(je,"numericLiteral");function yr(e,r){if(e===void 0)throw new Error(`${r} is missing.`);let n=te(e);if(!E.isArrayLiteralExpression(n))throw new Error(`${r} must be a static array literal.`);return n.elements}a(yr,"arrayLiteral");function Jr(e,r){if(e===void 0)throw new Error(`${r} is missing.`);let n=te(e);if(n.kind===E.SyntaxKind.NullKeyword)return null;if(!E.isNumericLiteral(n))throw new Error(`${r} must be null or a numeric literal.`);return Number(n.text)}a(Jr,"numericOrNullLiteral");function Yr(e){return e.parseDiagnostics??[]}a(Yr,"parseDiagnostics");function wr(e,r,n,t){let i=E.createSourceFile(r,e,E.ScriptTarget.Latest,true,E.ScriptKind.TS),s=Yr(i);if(s.length>0)throw new Error(`Shader manifest is not valid TypeScript: ${E.flattenDiagnosticMessageText(s[0]?.messageText??"parse error"," ")}`);let c=i.statements.filter(E.isExportAssignment).filter(v=>!v.isExportEquals);if(c.length!==1)throw new Error("Shader manifest must contain exactly one default export.");let o=ve(be(c[0]?.expression,"Shader manifest default export"),"Shader manifest"),m=o.get("version");if(m===void 0||!E.isNumericLiteral(te(m))||Number(te(m).getText(i))!==3)throw new Error("Shader manifest version must be the numeric literal 3.");if(ke(o.get("scene"),"Shader manifest scene")!==n)throw new Error(`Shader manifest scene does not match "${n}".`);let l=o.get("runtime"),a$1=(t?.compatibility??(l===void 0?"":ke(ve(be(l,"Shader manifest runtime"),"Shader manifest runtime").get("id"),"Shader manifest runtime id"))).startsWith("three-webgl-");if(t){if(ke(o.get("three"),"Shader manifest Three.js version")!==t.three||ke(o.get("threeBlocks"),"Shader manifest Three Blocks version")!==t.threeBlocks)throw new Error("Shader manifest runtime versions do not match its receipt.");let v=ve(be(o.get("runtime"),"Shader manifest runtime"),"Shader manifest runtime");if(ke(v.get("id"),"Shader manifest runtime id")!==t.compatibility||je(v.get("address"),"Shader manifest address schema")!==t.address||je(v.get("recipe"),"Shader manifest recipe schema")!==t.recipe||je(v.get("hydration"),"Shader manifest hydration schema")!==t.hydration)throw new Error("Shader manifest runtime compatibility schemas do not match its receipt.")}let f=ve(be(o.get("entries"),"Shader manifest entries"),"Shader manifest entries");if(f.size===0&&!a$1||f.size>Sr)throw new Error(`Shader manifest must contain ${a$1?"0":"1"}...${Sr} entries.`);let w=yr(o.get("modules"),"Shader manifest modules").map((v,$)=>{let D=te(v);if(!E.isStringLiteral(D)&&!E.isNoSubstitutionTemplateLiteral(D))throw new Error(`Shader manifest module ${$} must be a shader string literal.`);if(D.text.length===0)throw new Error(`Shader manifest module ${$} is empty.`);return D.text}),O=yr(o.get("states"),"Shader manifest states").map((v,$)=>{let D=ve(be(v,`Shader manifest state ${$}`),`Shader manifest state ${$}`),T=a((q,p)=>{let b=Jr(D.get(q),`Shader manifest state ${$} ${q}`);if(b===null)return false;let x=w[b];if(x===void 0||!a$1&&!x.includes(p))throw new Error(`Shader manifest state ${$} ${q} does not reference a ${p} module.`);return true},"moduleAt"),A=T("vertex","@vertex"),C=T("fragment","@fragment"),H=T("compute","@compute");if(H&&(A||C))throw new Error(`Shader manifest state ${$} mixes render and compute stages.`);if(!H&&!A&&!C)throw new Error(`Shader manifest state ${$} contains no shader stage.`);return {vertex:A,fragment:C,compute:H}}),V={render:0,vertex:0,fragment:0,compute:0};for(let[v,$]of f){if(v.length===0||/[\u0000-\u001f\u007f]/.test(v))throw new Error("Shader manifest contains an invalid entry key.");let D=je($,`Shader manifest entry "${v}"`),T=O[D];if(T===void 0)throw new Error(`Shader manifest entry "${v}" references an absent state.`);(T.vertex||T.fragment)&&(V.render+=1),T.vertex&&(V.vertex+=1),T.fragment&&(V.fragment+=1),T.compute&&(V.compute+=1);}return V}a(wr,"inspectPrecompiledManifest");function Xr(e,r){return e.render===r.render&&e.vertex===r.vertex&&e.fragment===r.fragment&&e.compute===r.compute}a(Xr,"sameCoverage");function Zr(e){let r=e.some(t=>t.state==="invalid")?"invalid":e.some(t=>t.state==="missing")?"missing":e.some(t=>t.state==="stale")?"stale":"fresh",n=e.filter(t=>t.state===r);return {state:r,reason:r==="fresh"?`${e.length} configured shader scene${e.length===1?" is":"s are"} fresh.`:n.map(t=>`${t.scene} (${t.backend}): ${t.reason}`).join("; ")}}a(Zr,"classifyMatrix");function Qr(e,r,n){let t=e.tool;if(!t)return "Shader receipt has no public tool compatibility metadata.";if((t.compatibilities?.[n]??t.compatibility)!==r)return "Shader receipt targets a different runtime compatibility contract.";if(t.transform!==b)return "Shader receipt uses a different provider transform version.";if(t.address!==SHADER_ADDRESS_SCHEMA_VERSION||t.recipe!==SHADER_RECIPE_SCHEMA_VERSION||t.hydration!==SHADER_HYDRATION_SCHEMA_VERSION)return "Shader receipt uses incompatible address, recipe, or hydration schemas."}a(Qr,"exactToolCompatibility");function et(e,r){let n=Object.keys(r).filter(s=>Object.hasOwn(e,s)&&e[s]!==r[s]),t=Object.keys(r).filter(s=>!Object.hasOwn(e,s)),i=Object.keys(e).filter(s=>!Object.hasOwn(r,s));return {...n.length>0?{changedInputs:n}:{},...t.length>0?{addedInputs:t}:{},...i.length>0?{removedInputs:i}:{}}}a(et,"inputChanges");async function De(e=process.cwd(),r,n){let t=await i(e),i$2=await j$1(t),s=d$1(n??i$2.backend),c$2=i$2.scenes.flatMap(l=>e$1(l,s).map(u=>({scene:l,backend:u,key:g(l.key,u)}))),o=L.join(t,b$1),m=a(()=>({schemaVersion:1,root:t,state:"missing",reason:`${b$1}/meta.json is absent.`,scenes:c$2.map(({scene:l,backend:u})=>({scene:l.key,backend:u,state:"missing",reason:"No committed shader receipt."}))}),"missing");if(!await d(o)||!await d(L.join(o,"meta.json")))return m();try{let l=await i$1(t,o,"Shader artifact directory"),u=await j(l,L.join(l,"meta.json"),a$1.receipt,"Shader receipt"),a=c$1(JSON.parse(u.data.toString("utf8"))),f=await e$2(l,u.data),w=r??await we(t),O=new Set(i$2.scenes.flatMap(p=>e$1(p,["webgpu","webgl"]).map(b=>g(p.key,b)))),v=Object.keys(a.scenes).filter(p=>!O.has(p));if(v.length>0)throw new Error(`Shader receipt contains unconfigured scenes: ${v.join(", ")}.`);let $=a.runtime.three!==w.three||a.runtime.threeBlocks!==w.threeBlocks,D=a.runtime.threeBlocksShaderClosure!==w.threeBlocksShaderClosure,T=a.tool?.version!==a$3,A=L.join(t,i$2.publicDir??"public"),C=[];for(let{scene:p,backend:b,key:x}of c$2){let h=a.scenes[x];if(!h){C.push({scene:p.key,backend:b,state:"missing",reason:"Scene/backend is absent from the complete receipt matrix."});continue}let _=a$4(w.three,b),j$1=Qr(a,_,b);if(j$1)throw new Error(`${x}: ${j$1}`);let K=await j(l,L.join(l,h.artifact),a$1.manifest,"Shader manifest");if(c(K.data)!==h.artifactHash)throw new Error(`Shader artifact checksum differs for scene "${p.key}".`);if(h.asset!==void 0&&h.assetHash!==void 0){let F=await j(A,L.join(A,h.asset),a$1.manifest,"Static shader manifest");if(c(F.data)!==h.assetHash)throw new Error(`Static shader manifest checksum differs for scene "${p.key}".`)}if(h.bytes!==void 0&&h.bytes!==K.data.byteLength)throw new Error(`Shader artifact byte count differs for scene "${p.key}".`);let B=wr(K.data.toString("utf8"),K.path,p.key,{three:a.runtime.three,threeBlocks:a.runtime.threeBlocks,compatibility:_,address:SHADER_ADDRESS_SCHEMA_VERSION,recipe:SHADER_RECIPE_SCHEMA_VERSION,hydration:SHADER_HYDRATION_SCHEMA_VERSION});if(!Xr(B,h.coverage))throw new Error(`Shader coverage differs for scene "${p.key}".`);if(b==="webgpu"&&!i$2.allowLiveBuilds&&h.skipped&&h.skipped.render+h.skipped.compute>0)throw new Error(`Scene "${p.key}" contains skipped live builds but allowLiveBuilds is false.`);let S=await Ce(t,p.inputs),k=et(h.inputs,S),y=(k.changedInputs?.length??0)+(k.addedInputs?.length??0)+(k.removedInputs?.length??0),g=$||D||T||y>0,M=f?.scenes[x],R=M===void 0||f===void 0?void 0:{...M,schemaVersion:f.schemaVersion,measuredAt:f.measuredAt,source:f.source,...f.source==="committed-capture"?{adapter:f.adapter,platform:f.platform}:{}};C.push({scene:p.key,backend:b,state:g?"stale":"fresh",reason:$?"Installed runtime versions differ from the receipt.":D?"Installed three-blocks/shaders runtime closure differs from the receipt.":T?`Receipt was generated by @three-blocks/devtools ${a.tool?.version??"unknown"}.`:y>0?`${y} semantic shader input${y===1?"":"s"} changed.`:"Manifest, runtime, schemas, transform, and semantic inputs match.",coverage:B,...!g&&R!==void 0&&R.builds===B.render+B.compute?{timing:R}:{},...k});}let H=Zr(C),q=H.state==="fresh"&&f!==void 0&&C.every(p=>p.timing!==void 0)?f:void 0;return {schemaVersion:1,root:t,...H,scenes:C,runtime:w,receipt:a,...q===void 0?{}:{timing:q}}}catch(l){let u=l instanceof Error?l.message:String(l);return {schemaVersion:1,root:t,state:"invalid",reason:u,scenes:c$2.map(({scene:a,backend:f})=>({scene:a.key,backend:f,state:"invalid",reason:u}))}}}a(De,"inspectShaderMatrix");var xr=".three-blocks/shaders/pending-capture";function nt(e){return (e instanceof Error?`${e.name}: ${e.message}`:String(e)).includes("ShaderHydrationError:")}a(nt,"isShaderHydrationFailure");async function it(e,r,n){if(r.length===0)return;let t=L.join(e,b$1,"meta.json"),i=await readFile(t);if(c(i)!==c(n))throw new Error("Shader receipt changed before failed scenes could be marked for recapture.");let s=c$1(JSON.parse(i.toString("utf8"))),c$2=c(n),o=new Set(r),m=c$1({...s,scenes:Object.fromEntries(Object.entries(s.scenes).map(([l,u])=>[l,o.has(l)?{...u,inputs:{...u.inputs,[xr]:c$2}}:u]))});await f(t,`${d$2(m)}
|
|
10
|
-
`);}a(it,"markShaderScenesForRecapture");function st(e,r){return d$2(e)===d$2(r)}a(st,"equalSnapshot");async function Vt(e={}){let r=e.root?await realpath(e.root):await i(e.start),n=e.config===void 0?await l(r):void 0,t=e.config??n?.config??await j$1(r),i$1=e.runtime??await we(r),s=d$1(e.backend??t.backend),c$1=d$1(t.backend),o=[...new Set([...c$1,...s])],m=[...s].reverse(),l$1=[...f$1(t.scenes,m)],
|
|
8
|
+
`:" ",s===o&&(t="code");}return n}a(Qe,"lexicalSource");function Vr(e){let r=new Set,n=Qe(e,true);for(let t of n.matchAll(Ar))t[2]===void 0&&t[3]!==void 0&&r.add(t[3]);for(let t of n.matchAll(_r))t[1]!==void 0&&r.add(t[1]);return [...r].sort()}a(Vr,"importSpecifiers");function Hr(e){let r=new Set;for(let n of Qe(e,true).matchAll(Fr)){let t=n[1]??n[2];t!==void 0&&r.add(t);}return [...r].sort()}a(Hr,"runtimeSpecifiers");function pr(e){return (e.split(/[?#]/u,1)[0]??e).replaceAll("\\","/")}a(pr,"cleanSpecifier");function Wr(e,r,n){let t=pr(r),i;if(t.startsWith("./")||t.startsWith("../"))i=L.posix.normalize(L.posix.join(L.posix.dirname(e),t));else if(t.startsWith("@/"))i=`src/${t.slice(2)}`;else if(t.startsWith("/src/"))i=t.slice(1);else return;if(i===".three-blocks"||i.startsWith(".three-blocks/"))return;let s=L.posix.extname(i).toLowerCase(),c=new Set([i]);if(s.length===0||!Je.has(s)){for(let o of Ge)c.add(`${i}${o}`);for(let o of Ge)c.add(`${i}/index${o}`);}else if([".js",".mjs",".cjs",".jsx"].includes(s)){let o=i.slice(0,-s.length);for(let m of [".ts",".tsx",".mts",".cts"])c.add(`${o}${m}`);}return [...c].find(o=>n.has(o))}a(Wr,"resolveProjectImport");function Kr(e,r){let n=Qe(r,false);return Cr.test(e)||jr.test(n)||Dr.test(n)}a(Kr,"isShaderRoot");async function Ce(e,r){let n=await realpath(e);if(r!==void 0){let a={},u=0;for(let w of r){let O=await j(n,L.join(n,w),a$1.semanticInput,"Declared shader semantic input");if(u+=O.data.byteLength,u>a$1.semanticTotal)throw new Error("Declared shader semantic inputs exceed the total inspection size limit.");a[w]=c(O.data);}return a}let t=new Map,i=L.join(n,"src");if(await d(i))for(let a of await k(n,i,u=>Je.has(L.extname(u).toLowerCase()))){let u=await j(n,a,a$1.semanticInput,"Shader semantic input");t.set(mr(n,a),u.data);}for(let a of await readdir(n,{withFileTypes:true})){if(!a.isFile()||!qe.test(a.name)&&!Je.has(L.extname(a.name).toLowerCase()))continue;let u=await j(n,L.join(n,a.name),a$1.semanticInput,qe.test(a.name)?"Shader configuration input":"Shader semantic input");t.set(a.name,u.data);}if(t.size>Ye)throw new Error(`Shader input discovery exceeds the ${Ye}-file limit.`);let s=new Set,c$1=new Map;for(let[a,u]of t){if(!a.includes("/")&&qe.test(a)&&s.add(a),!a.startsWith("src/"))continue;let w=Xe(u,a);c$1.set(a,w),Kr(a,w)&&s.add(a);}if(s.size===0)throw new Error("No shader registration or scene source root was found.");let o=new Set,m=[...s].sort();for(;m.length>0;){let a=m.shift();if(a===void 0||o.has(a))continue;let u=t.get(a);if(u===void 0)continue;o.add(a);let w=c$1.get(a)??Xe(u,a);for(let O of Vr(w)){let V=Wr(a,O,t);V!==void 0&&!o.has(V)&&m.push(V);}m.sort();}let l=0,f={};for(let a of [...o].sort()){let u=t.get(a);if(u===void 0)throw new Error(`Shader input ${JSON.stringify(a)} disappeared during inspection.`);if(l+=u.byteLength,l>a$1.semanticTotal)throw new Error("Semantic shader inputs exceed the total inspection size limit.");f[a]=c(u);}return f}a(Ce,"snapshotShaderInputs");function Ze(e){if(typeof e=="string")return e;if(a$2(e))return Ze(e.import)??Ze(e.default)}a(Ze,"conditionalImportTarget");async function fr(e,r){let n=e;for(;;){let t=L.join(n,"node_modules",...r.split("/"),"package.json");if(await d(t)){let s=await h(t,a$1.packageJson,`${r} package.json`),c=JSON.parse(s.data.toString("utf8"));if(!a$2(c)||c.name!==r||typeof c.version!="string"||!Nr.test(c.version))throw new Error(`Installed ${r} package metadata is invalid.`);return {root:L.dirname(s.path),manifest:c}}let i=L.dirname(n);if(i===n)break;n=i;}throw new Error(`Cannot verify the installed ${r} package.`)}a(fr,"findInstalledPackage");async function zr(e$1,r){if(!a$2(r.exports))throw new Error("Installed three-blocks package has no public exports map.");let n=Ze(r.exports[Lr]);if(n===void 0||!n.startsWith("./"))throw new Error("Installed three-blocks shader export has no import target.");let t=await realpath(e$1),i=[L.resolve(t,n)],s=new Map,c$1=0;for(;i.length>0;){let m=i.shift();if(m===void 0)break;let l=await h(m,a$1.semanticInput,"Three Blocks shader runtime module");if(!e(t,l.path)||l.path===t)throw new Error("Three Blocks shader runtime closure escapes its package.");let f=mr(t,l.path);if(s.has(f))continue;if(c$1+=l.data.byteLength,c$1>a$1.semanticTotal)throw new Error("Three Blocks shader runtime closure exceeds the inspection limit.");s.set(f,c(l.data));let a=Xe(l.data,f);for(let u of Hr(a)){let w=pr(u);if(!w.startsWith("./")&&!w.startsWith("../"))continue;let O=L.resolve(L.dirname(l.path),w);if(!e(t,O))throw new Error("Three Blocks shader runtime import escapes its package.");i.push(O);}if(i.sort(),s.size+i.length>Ye)throw new Error("Three Blocks shader runtime closure exceeds the file limit.")}let o=[...s].sort((m,l)=>m[0].localeCompare(l[0])).map(([m,l])=>`${m}\0${l}`).join(`
|
|
9
|
+
`);return c(o)}a(zr,"shaderRuntimeClosure");async function we(e){let[r,n]=await Promise.all([fr(e,"three"),fr(e,"three-blocks")]);return {three:String(r.manifest.version),threeBlocks:String(n.manifest.version),threeBlocksShaderClosure:await zr(n.root,n.manifest)}}a(we,"readInstalledShaderRuntime");var Sr=4096,qr=createRequire(import.meta.url),gr,E=new Proxy({},{get(e,r){return gr??=qr("typescript"),Reflect.get(gr,r)}});function te(e){let r=e;for(;E.isParenthesizedExpression(r)||E.isAsExpression(r)||E.isSatisfiesExpression(r)||E.isNonNullExpression(r);)r=r.expression;return r}a(te,"unwrap");function Gr(e){if(E.isIdentifier(e)||E.isStringLiteral(e)||E.isNumericLiteral(e))return e.text}a(Gr,"propertyName");function ve(e,r){let n=new Map;for(let t of e.properties){if(!E.isPropertyAssignment(t))throw new Error(`${r} may contain only static property assignments.`);let i=Gr(t.name);if(i===void 0||n.has(i))throw new Error(`${r} contains a computed or duplicate property.`);n.set(i,t.initializer);}return n}a(ve,"properties");function be(e,r){if(e===void 0)throw new Error(`${r} is missing.`);let n=te(e);if(!E.isObjectLiteralExpression(n))throw new Error(`${r} must be a static object literal.`);return n}a(be,"objectLiteral");function ke(e,r){if(e===void 0)throw new Error(`${r} is missing.`);let n=te(e);if(!E.isStringLiteral(n)&&!E.isNoSubstitutionTemplateLiteral(n))throw new Error(`${r} must be a string literal.`);return n.text}a(ke,"stringLiteral");function je(e,r){if(e===void 0)throw new Error(`${r} is missing.`);let n=te(e);if(!E.isNumericLiteral(n))throw new Error(`${r} must be a numeric literal.`);return Number(n.text)}a(je,"numericLiteral");function yr(e,r){if(e===void 0)throw new Error(`${r} is missing.`);let n=te(e);if(!E.isArrayLiteralExpression(n))throw new Error(`${r} must be a static array literal.`);return n.elements}a(yr,"arrayLiteral");function Jr(e,r){if(e===void 0)throw new Error(`${r} is missing.`);let n=te(e);if(n.kind===E.SyntaxKind.NullKeyword)return null;if(!E.isNumericLiteral(n))throw new Error(`${r} must be null or a numeric literal.`);return Number(n.text)}a(Jr,"numericOrNullLiteral");function Yr(e){return e.parseDiagnostics??[]}a(Yr,"parseDiagnostics");function wr(e,r,n,t){let i=E.createSourceFile(r,e,E.ScriptTarget.Latest,true,E.ScriptKind.TS),s=Yr(i);if(s.length>0)throw new Error(`Shader manifest is not valid TypeScript: ${E.flattenDiagnosticMessageText(s[0]?.messageText??"parse error"," ")}`);let c=i.statements.filter(E.isExportAssignment).filter(v=>!v.isExportEquals);if(c.length!==1)throw new Error("Shader manifest must contain exactly one default export.");let o=ve(be(c[0]?.expression,"Shader manifest default export"),"Shader manifest"),m=o.get("version");if(m===void 0||!E.isNumericLiteral(te(m))||Number(te(m).getText(i))!==3)throw new Error("Shader manifest version must be the numeric literal 3.");if(ke(o.get("scene"),"Shader manifest scene")!==n)throw new Error(`Shader manifest scene does not match "${n}".`);let l=o.get("runtime"),a$1=(t?.compatibility??(l===void 0?"":ke(ve(be(l,"Shader manifest runtime"),"Shader manifest runtime").get("id"),"Shader manifest runtime id"))).startsWith("three-webgl-");if(t){if(ke(o.get("three"),"Shader manifest Three.js version")!==t.three||ke(o.get("threeBlocks"),"Shader manifest Three Blocks version")!==t.threeBlocks)throw new Error("Shader manifest runtime versions do not match its receipt.");let v=ve(be(o.get("runtime"),"Shader manifest runtime"),"Shader manifest runtime");if(ke(v.get("id"),"Shader manifest runtime id")!==t.compatibility||je(v.get("address"),"Shader manifest address schema")!==t.address||je(v.get("recipe"),"Shader manifest recipe schema")!==t.recipe||je(v.get("hydration"),"Shader manifest hydration schema")!==t.hydration)throw new Error("Shader manifest runtime compatibility schemas do not match its receipt.")}let u=ve(be(o.get("entries"),"Shader manifest entries"),"Shader manifest entries");if(u.size===0&&!a$1||u.size>Sr)throw new Error(`Shader manifest must contain ${a$1?"0":"1"}...${Sr} entries.`);let w=yr(o.get("modules"),"Shader manifest modules").map((v,$)=>{let D=te(v);if(!E.isStringLiteral(D)&&!E.isNoSubstitutionTemplateLiteral(D))throw new Error(`Shader manifest module ${$} must be a shader string literal.`);if(D.text.length===0)throw new Error(`Shader manifest module ${$} is empty.`);return D.text}),O=yr(o.get("states"),"Shader manifest states").map((v,$)=>{let D=ve(be(v,`Shader manifest state ${$}`),`Shader manifest state ${$}`),T=a((q,p)=>{let b=Jr(D.get(q),`Shader manifest state ${$} ${q}`);if(b===null)return false;let x=w[b];if(x===void 0||!a$1&&!x.includes(p))throw new Error(`Shader manifest state ${$} ${q} does not reference a ${p} module.`);return true},"moduleAt"),A=T("vertex","@vertex"),C=T("fragment","@fragment"),H=T("compute","@compute");if(H&&(A||C))throw new Error(`Shader manifest state ${$} mixes render and compute stages.`);if(!H&&!A&&!C)throw new Error(`Shader manifest state ${$} contains no shader stage.`);return {vertex:A,fragment:C,compute:H}}),V={render:0,vertex:0,fragment:0,compute:0};for(let[v,$]of u){if(v.length===0||/[\u0000-\u001f\u007f]/.test(v))throw new Error("Shader manifest contains an invalid entry key.");let D=je($,`Shader manifest entry "${v}"`),T=O[D];if(T===void 0)throw new Error(`Shader manifest entry "${v}" references an absent state.`);(T.vertex||T.fragment)&&(V.render+=1),T.vertex&&(V.vertex+=1),T.fragment&&(V.fragment+=1),T.compute&&(V.compute+=1);}return V}a(wr,"inspectPrecompiledManifest");function Xr(e,r){return e.render===r.render&&e.vertex===r.vertex&&e.fragment===r.fragment&&e.compute===r.compute}a(Xr,"sameCoverage");function Zr(e){let r=e.some(t=>t.state==="invalid")?"invalid":e.some(t=>t.state==="missing")?"missing":e.some(t=>t.state==="stale")?"stale":"fresh",n=e.filter(t=>t.state===r);return {state:r,reason:r==="fresh"?`${e.length} configured shader scene${e.length===1?" is":"s are"} fresh.`:n.map(t=>`${t.scene} (${t.backend}): ${t.reason}`).join("; ")}}a(Zr,"classifyMatrix");function Qr(e,r,n){let t=e.tool;if(!t)return "Shader receipt has no public tool compatibility metadata.";if((t.compatibilities?.[n]??t.compatibility)!==r)return "Shader receipt targets a different runtime compatibility contract.";if(t.transform!==b)return "Shader receipt uses a different provider transform version.";if(t.address!==SHADER_ADDRESS_SCHEMA_VERSION||t.recipe!==SHADER_RECIPE_SCHEMA_VERSION||t.hydration!==SHADER_HYDRATION_SCHEMA_VERSION)return "Shader receipt uses incompatible address, recipe, or hydration schemas."}a(Qr,"exactToolCompatibility");function et(e,r){let n=Object.keys(r).filter(s=>Object.hasOwn(e,s)&&e[s]!==r[s]),t=Object.keys(r).filter(s=>!Object.hasOwn(e,s)),i=Object.keys(e).filter(s=>!Object.hasOwn(r,s));return {...n.length>0?{changedInputs:n}:{},...t.length>0?{addedInputs:t}:{},...i.length>0?{removedInputs:i}:{}}}a(et,"inputChanges");async function De(e=process.cwd(),r,n){let t=await i(e),i$2=await j$1(t),s=d$1(n??i$2.backend),c$2=i$2.scenes.flatMap(l=>e$1(l,s).map(f=>({scene:l,backend:f,key:g(l.key,f)}))),o=L.join(t,b$1),m=a(()=>({schemaVersion:1,root:t,state:"missing",reason:`${b$1}/meta.json is absent.`,scenes:c$2.map(({scene:l,backend:f})=>({scene:l.key,backend:f,state:"missing",reason:"No committed shader receipt."}))}),"missing");if(!await d(o)||!await d(L.join(o,"meta.json")))return m();try{let l=await i$1(t,o,"Shader artifact directory"),f=await j(l,L.join(l,"meta.json"),a$1.receipt,"Shader receipt"),a=c$1(JSON.parse(f.data.toString("utf8"))),u=await e$2(l,f.data),w=r??await we(t),O=new Set(i$2.scenes.flatMap(p=>e$1(p,["webgpu","webgl"]).map(b=>g(p.key,b)))),v=Object.keys(a.scenes).filter(p=>!O.has(p));if(v.length>0)throw new Error(`Shader receipt contains unconfigured scenes: ${v.join(", ")}.`);let $=a.runtime.three!==w.three,D=a.runtime.threeBlocksShaderClosure!==w.threeBlocksShaderClosure,T=a.tool?.version!==a$3,A=L.join(t,i$2.publicDir??"public"),C=[];for(let{scene:p,backend:b,key:x}of c$2){let h=a.scenes[x];if(!h){C.push({scene:p.key,backend:b,state:"missing",reason:"Scene/backend is absent from the complete receipt matrix."});continue}let _=a$4(w.three,b),j$1=Qr(a,_,b);if(j$1)throw new Error(`${x}: ${j$1}`);let K=await j(l,L.join(l,h.artifact),a$1.manifest,"Shader manifest");if(c(K.data)!==h.artifactHash)throw new Error(`Shader artifact checksum differs for scene "${p.key}".`);if(h.asset!==void 0&&h.assetHash!==void 0){let F=await j(A,L.join(A,h.asset),a$1.manifest,"Static shader manifest");if(c(F.data)!==h.assetHash)throw new Error(`Static shader manifest checksum differs for scene "${p.key}".`)}if(h.bytes!==void 0&&h.bytes!==K.data.byteLength)throw new Error(`Shader artifact byte count differs for scene "${p.key}".`);let B=wr(K.data.toString("utf8"),K.path,p.key,{three:a.runtime.three,threeBlocks:a.runtime.threeBlocks,compatibility:_,address:SHADER_ADDRESS_SCHEMA_VERSION,recipe:SHADER_RECIPE_SCHEMA_VERSION,hydration:SHADER_HYDRATION_SCHEMA_VERSION});if(!Xr(B,h.coverage))throw new Error(`Shader coverage differs for scene "${p.key}".`);if(b==="webgpu"&&!i$2.allowLiveBuilds&&h.skipped&&h.skipped.render+h.skipped.compute>0)throw new Error(`Scene "${p.key}" contains skipped live builds but allowLiveBuilds is false.`);let S=await Ce(t,p.inputs),k=et(h.inputs,S),y=(k.changedInputs?.length??0)+(k.addedInputs?.length??0)+(k.removedInputs?.length??0),g=$||D||T||y>0,M=u?.scenes[x],R=M===void 0||u===void 0?void 0:{...M,schemaVersion:u.schemaVersion,measuredAt:u.measuredAt,source:u.source,...u.source==="committed-capture"?{adapter:u.adapter,platform:u.platform}:{}};C.push({scene:p.key,backend:b,state:g?"stale":"fresh",reason:$?"Installed Three.js version differs from the receipt.":D?"Installed three-blocks/shaders runtime closure differs from the receipt.":T?`Receipt was generated by @three-blocks/devtools ${a.tool?.version??"unknown"}.`:y>0?`${y} semantic shader input${y===1?"":"s"} changed.`:"Manifest, runtime, schemas, transform, and semantic inputs match.",coverage:B,...!g&&R!==void 0&&R.builds===B.render+B.compute?{timing:R}:{},...k});}let H=Zr(C),q=H.state==="fresh"&&u!==void 0&&C.every(p=>p.timing!==void 0)?u:void 0;return {schemaVersion:1,root:t,...H,scenes:C,runtime:w,receipt:a,...q===void 0?{}:{timing:q}}}catch(l){let f=l instanceof Error?l.message:String(l);return {schemaVersion:1,root:t,state:"invalid",reason:f,scenes:c$2.map(({scene:a,backend:u})=>({scene:a.key,backend:u,state:"invalid",reason:f}))}}}a(De,"inspectShaderMatrix");var xr=".three-blocks/shaders/pending-capture";function nt(e){return (e instanceof Error?`${e.name}: ${e.message}`:String(e)).includes("ShaderHydrationError:")}a(nt,"isShaderHydrationFailure");async function it(e,r,n){if(r.length===0)return;let t=L.join(e,b$1,"meta.json"),i=await readFile(t);if(c(i)!==c(n))throw new Error("Shader receipt changed before failed scenes could be marked for recapture.");let s=c$1(JSON.parse(i.toString("utf8"))),c$2=c(n),o=new Set(r),m=c$1({...s,scenes:Object.fromEntries(Object.entries(s.scenes).map(([l,f])=>[l,o.has(l)?{...f,inputs:{...f.inputs,[xr]:c$2}}:f]))});await f(t,`${d$2(m)}
|
|
10
|
+
`);}a(it,"markShaderScenesForRecapture");function st(e,r){return d$2(e)===d$2(r)}a(st,"equalSnapshot");async function Vt(e={}){let r=e.root?await realpath(e.root):await i(e.start),n=e.config===void 0?await l(r):void 0,t=e.config??n?.config??await j$1(r),i$1=e.runtime??await we(r),s=d$1(e.backend??t.backend),c$1=d$1(t.backend),o=[...new Set([...c$1,...s])],m=[...s].reverse(),l$1=[...f$1(t.scenes,m)],f,a$1={},u;if(e.ifStale){let S=await De(r,i$1,e.backend??t.backend);if(S.state==="fresh"&&S.scenes.every(k=>k.timing!==void 0))return {schemaVersion:1,root:r,skipped:true,reason:S.reason,scenes:[]};if(S.state!=="invalid"&&S.receipt!==void 0){let k=S.state==="fresh";l$1=l$1.filter(({scene:y,backend:g})=>{let M=S.scenes.find(R=>R.scene===y.key&&R.backend===g);return M?.state!=="fresh"||k&&M.timing===void 0}),f=S.receipt;for(let y of S.scenes){if(y.state!=="fresh"||y.timing===void 0)continue;let{builds:g$1,liveBuildMs:M,precompiledBuildMs:R,avoidedBuildMs:F,runs:W,spreadMs:Ee}=y.timing;a$1[g(y.scene,y.backend)]={builds:g$1,liveBuildMs:M,precompiledBuildMs:R,avoidedBuildMs:F,runs:W,spreadMs:Ee},y.timing.source==="committed-capture"&&y.timing.adapter!==void 0&&y.timing.platform!==void 0&&(u={adapter:y.timing.adapter,platform:y.timing.platform});}}}let w=performance.now(),O=f!==void 0&&(f.runtime.three!==i$1.three||f.runtime.threeBlocksShaderClosure!==i$1.threeBlocksShaderClosure||f.tool?.version!==a$3)?c(d$2({runtime:f.runtime,tool:f.tool})):void 0,V=a(async()=>new Map(await Promise.all(t.scenes.map(async S=>[S.key,await Ce(r,S.inputs)]))),"snapshotInputs"),v=await V(),$=a(async()=>{let S=await V();for(let k of t.scenes){let y=v.get(k.key),g=S.get(k.key);if(y===void 0||g===void 0||!st(y,g))throw new Error(`Semantic shader inputs changed during capture for scene "${k.key}"; the current scene was not committed.`)}},"assertInputsUnchanged"),D=e.driver===void 0,T=e.driver===void 0&&e.driverKind===void 0&&e.serve===void 0&&e.url===void 0?await k$1(r):void 0,A=e.serve??T?.serve,C=e.driverKind??T?.driverKind??(A===void 0?"vite":"static");if(e.url!==void 0&&(e.serve!==void 0||e.driverKind!==void 0))throw new Error("--url cannot be combined with --driver or --serve.");if(C==="vite"&&A!==void 0)throw new Error("--serve requires the static shader driver.");if(C==="static"&&A===void 0&&e.driver===void 0)throw new Error("The static shader driver requires --serve <built-directory>.");let H=e.driver===void 0?await import('./shader-browser-YPBP3WQY.js'):void 0,q=a(()=>e.url!==void 0?H.createAttachedPlaywrightShaderDriver({root:r,runtime:i$1,url:e.url,...e.headed!==void 0?{headed:e.headed}:{}}):C==="static"?H.createStaticPlaywrightShaderDriver({root:r,runtime:i$1,serve:A,...e.headed!==void 0?{headed:e.headed}:{}}):H.createPlaywrightShaderDriver({root:r,runtime:i$1,...e.headed!==void 0?{headed:e.headed}:{}}),"createDriver"),p=new Map,b=a(S=>{if(e.driver!==void 0)return e.driver;let k=p.get(S);return k===void 0&&(k=q(),p.set(S,k)),k},"driverFor"),x=new Map,h=[],_=f!==void 0&&t.scenes.every(S=>e$1(S,o).every(k=>f?.scenes[g(S.key,k)]!==void 0)),j=f,K,B=e.attempts??2;if(!Number.isSafeInteger(B)||B<1||B>5)throw new Error("Shader capture attempts must be an integer in 1...5.");try{for(let[g$1,M]of l$1.entries()){let{scene:R,backend:F,key:W}=M,Ee=b(F);e.onSceneStart?.(W,g$1,l$1.length);let N,Se,se=0;for(;se<B;se++)try{N=c$2(await Ee.capture(R,t,F),{scene:R.key,backend:F,runtime:i$1});let Q=F==="webgl"&&N.skipped.every(G=>G.reason.startsWith("WebGL shader precompilation does not support "));if(N.skipped.length>0&&!t.allowLiveBuilds&&!Q)throw new Error(`Scene "${R.key}" contains ${N.skipped.length} unregistered live shader build${N.skipped.length===1?"":"s"} while allowLiveBuilds is false.`);break}catch(Q){Se=Q,N=void 0,se+1<B&&e.onSceneRetry?.(R.key,se+2,B,t.timeoutMs,Q);}if(!N)throw new Error(`Shader capture "${R.key}" failed after ${B} attempts: ${Se instanceof Error?Se.message:String(Se)}`);if(x.set(W,N),h.push({scene:R.key,backend:F,attempts:se+1,coverage:N.coverage,skipped:N.skipped.length,startupBuilds:N.stats.registeredBuilds,startupBuildMs:N.stats.buildMs,...N.timing===void 0?{}:{timing:N.timing}}),_&&j!==void 0){await $();let Q=new Map(t.scenes.map(G=>{let Fe=e$1(G,o),ae=G.key===R.key?v.get(G.key):Fe.map(J=>j?.scenes[g(G.key,J)]?.inputs).find(J=>J!==void 0);if(ae===void 0)throw new Error(`Shader checkpoint is missing scene "${G.key}".`);return O!==void 0&&!Fe.every(J=>x.has(g(G.key,J)))&&(ae={...ae,[xr]:O}),[G.key,ae]}));K=await j$2({root:r,scenes:t.scenes,backends:o,captures:new Map([[W,N]]),runtime:i$1,inputs:Q,previousReceipt:j,publicDirectory:t.publicDir??"public"}),j=K.receipt;}}await $(),K=await j$2({root:r,scenes:t.scenes,backends:o,captures:x,runtime:i$1,inputs:v,...f===void 0?{}:{previousReceipt:f},publicDirectory:t.publicDir??"public"});let S={...a$1};for(let g$1 of h)S[g(g$1.scene,g$1.backend)]={builds:g$1.coverage.render+g$1.coverage.compute,setupMeasured:!1,liveBuildMs:g$1.startupBuildMs,precompiledBuildMs:0,avoidedBuildMs:g$1.startupBuildMs,runs:1,spreadMs:0};if(e.commitTiming===!0){let g=u??{adapter:x.values().next().value?.provenance?.adapter??"WebGPU adapter",platform:`${Ae.platform()}/${Ae.arch()}`},M=p.values().next().value??e.driver;await i$2(r,S,await(M?.timingEnvironment?.()??g));}else await f$2(r,S);let k=await readFile(L.join(K.directory,"meta.json")),y=await e$2(K.directory,k);return {schemaVersion:1,root:r,skipped:!1,reason:`Wrote ${h.length} shader scene${h.length===1?"":"s"}.`,durationMs:performance.now()-w,scenes:h,measurement:{beforeBuilds:h.reduce((g,M)=>g+M.startupBuilds,0),afterBuilds:0,firstFrameDeltaMs:-h.reduce((g,M)=>g+M.startupBuildMs,0),source:"capture-build-phase"},...n===void 0?{}:{configuration:{created:n.created,file:n.file}},written:K,...y===void 0?{}:{timing:y}}}finally{D&&await Promise.all([...p.values()].map(S=>S.close()));}}a(Vt,"captureShaders");function at(e){return ["workerReady","assetsReady",...e.requiresText?["textReady"]:[],"compileEnd","firstFrame"]}a(at,"requiredReadiness");function Rr(e){if(e.length===0)throw new Error("Cannot take the median of an empty shader timing capture.");let r=[...e].sort((s,c)=>s-c),n=Math.floor(r.length/2),t=r[n];if(t===void 0)throw new Error("Shader timing median is unavailable.");if(r.length%2===1)return t;let i=r[n-1];if(i===void 0)throw new Error("Shader timing median pair is unavailable.");return (i+t)/2}a(Rr,"median");function er(e,r,n,t){if(e.scene!==r.key||e.mode!==n)throw new Error(`Browser observation identity differs for scene "${r.key}".`);if(e.compatibility!==t||e.transform!==b)throw new Error(`Browser observation compatibility differs for scene "${r.key}".`);let i=at(r).filter(s=>e.readiness[s]!==true);if(i.length>0)throw new Error(`Scene "${r.key}" ${n} observation is missing readiness bits: ${i.join(", ")}.`);if(e.errors.length>0)throw new Error(`Scene "${r.key}" ${n} browser errors:
|
|
11
11
|
- ${e.errors.join(`
|
|
12
12
|
- `)}
|
|
13
13
|
${n} demands: ${rr(e.demands)}`)}a(er,"assertObservation");async function ot(e,r,n){if(n===void 0)return new Set;try{let t=JSON.parse(await readFile(L.join(e,r.publicDir??"public",n),"utf8"));return new Set(Object.keys(t.fallbacks??{}))}catch{return new Set}}a(ot,"manifestFallbackKeys");function dt(e,r,n,t,i,s){if(r.render>0&&n.stats.registeredRenderBuilds===0)throw new Error(`Scene "${e.key}" live baseline exercised no registered render pipeline.`);if(r.compute>0&&n.stats.registeredComputeBuilds===0)throw new Error(`Scene "${e.key}" live baseline exercised no registered compute kernel.`);Tr(e,r,t,i,s,n.demands);}a(dt,"assertZeroBuild");function rr(e){return !e||e.length===0?"none recorded":e.map(r=>`${String(r.key??"unregistered")}[${String(r.event)}${r.hit===false?":miss":""}|${String(r.target)}${r.object===void 0?"":`@${String(r.object)}`}]`).join(" ").slice(0,4e3)}a(rr,"describeDemands");function Tr(e,r,n,t,i,s){let c=a(()=>`
|
|
14
14
|
Precompiled demands: ${rr(n.demands)}`+(s===void 0?"":`
|
|
15
|
-
Live demands: ${rr(s)}`),"demandEvidence");if(n.stats.registeredRenderBuilds+n.stats.registeredComputeBuilds>t){let o=n.stats.missedKeys??[];throw new Error(`Scene "${e.key}" injected path performed ${n.stats.registeredRenderBuilds} render and ${n.stats.registeredComputeBuilds} compute registered live builds; capture permits ${t}.`+(o.length>0?` Missed keys: ${o.join(", ")}.`:"")+c())}if(n.stats.buildCalls>t)throw new Error(`Scene "${e.key}" injected path performed ${n.stats.buildCalls} total live NodeBuilder build${n.stats.buildCalls===1?"":"s"}; capture permits ${t} skipped live build${t===1?"":"s"}.`);if(r.render>0&&n.stats.injectedRender===0)throw new Error(`Scene "${e.key}" injected no render entries.`);if(r.compute>0&&n.stats.injectedCompute===0)throw new Error(`Scene "${e.key}" injected no compute entries.`);if(n.stats.missed!==0||n.stats.missedRender!==0||n.stats.missedCompute!==0){let o=n.stats.missedKeys??[],m=o.filter(
|
|
15
|
+
Live demands: ${rr(s)}`),"demandEvidence");if(n.stats.registeredRenderBuilds+n.stats.registeredComputeBuilds>t){let o=n.stats.missedKeys??[];throw new Error(`Scene "${e.key}" injected path performed ${n.stats.registeredRenderBuilds} render and ${n.stats.registeredComputeBuilds} compute registered live builds; capture permits ${t}.`+(o.length>0?` Missed keys: ${o.join(", ")}.`:"")+c())}if(n.stats.buildCalls>t)throw new Error(`Scene "${e.key}" injected path performed ${n.stats.buildCalls} total live NodeBuilder build${n.stats.buildCalls===1?"":"s"}; capture permits ${t} skipped live build${t===1?"":"s"}.`);if(r.render>0&&n.stats.injectedRender===0)throw new Error(`Scene "${e.key}" injected no render entries.`);if(r.compute>0&&n.stats.injectedCompute===0)throw new Error(`Scene "${e.key}" injected no compute entries.`);if(n.stats.missed!==0||n.stats.missedRender!==0||n.stats.missedCompute!==0){let o=n.stats.missedKeys??[],m=o.filter(f=>!i.has(f)),l=o.length>0&&n.stats.missed<=i.size;if(m.length>0||!l)throw new Error(`Scene "${e.key}" injected path reported shader manifest misses.`+(o.length>0?` Missed keys: ${o.join(", ")}.`:"")+(m.length>0&&m.length!==o.length?` Unexpected: ${m.join(", ")}.`:"")+c())}}a(Tr,"assertPrecompiledZeroBuild");async function ct(e,r,n,t,i){let s=L.join(e,c$3);if(await d(s)){let o=await lstat(s);if(o.isSymbolicLink()||!o.isDirectory())throw new Error("Shader parity artifact directory is not a real directory.")}else await mkdir(s,{recursive:true});let c=[`${r}.live.png`,`${r}.precompiled.png`,`${r}.diff.png`];return await Promise.all([n,t,i].map(async(o,m)=>{let l=c[m];if(l===void 0)throw new Error("Parity artifact mapping failed.");let f=L.join(s,l);if(await d(f)){let a=await lstat(f);if(a.isSymbolicLink()||!a.isFile())throw new Error(`Shader parity target is not a regular file: ${l}.`)}await writeFile(f,o,{mode:384});})),c.map(o=>`${c$3}/${o}`)}a(ct,"writeParityFailure");async function Ht(e={}){let r=e.root?await realpath(e.root):await i(e.start),n=e.runtime??await we(r),t=e.config??await j$1(r),i$1=d$1(e.backend??t.backend),s=f$1(t.scenes,[...i$1].reverse()),c=await De(r,n,e.backend??t.backend);if(c.state!=="fresh")throw new Error(`Shader no-GPU validation is ${c.state}: ${c.reason}`);if(e.skipBrowser)return {schemaVersion:1,root:r,noGpu:c,browser:"skipped",scenes:[]};if(e.parityOnly===true&&e.commitTiming===true)throw new Error("Parity-only shader verification cannot commit timing.");let o=e.runs??5;if(!Number.isSafeInteger(o)||o<1||o>100)throw new Error("Shader timing runs must be an integer in 1...100.");let m=await readFile(L.join(r,b$1,"meta.json")),l=c$1(JSON.parse(m.toString("utf8")));if(c.receipt===void 0||d$2(l)!==d$2(c.receipt))throw new Error("Shader receipt changed after no-GPU validation; restart browser parity verification.");let f=e.driver===void 0,a$1=e.driver===void 0&&e.driverKind===void 0&&e.serve===void 0&&e.url===void 0?await k$1(r):void 0,u=e.serve??a$1?.serve,w=e.driverKind??a$1?.driverKind??(u===void 0?"vite":"static");if(e.url!==void 0&&(e.serve!==void 0||e.driverKind!==void 0))throw new Error("--url cannot be combined with --driver or --serve.");if(w==="vite"&&u!==void 0)throw new Error("--serve requires the static shader driver.");if(w==="static"&&u===void 0&&e.driver===void 0)throw new Error("The static shader driver requires --serve <built-directory>.");let O=e.driver===void 0?await import('./shader-browser-YPBP3WQY.js'):void 0,{compareShaderScreenshots:V}=await import('./shader-parity-XPKQQK26.js'),v=a(()=>e.url!==void 0?O.createAttachedPlaywrightShaderDriver({root:r,runtime:n,url:e.url,...e.headed!==void 0?{headed:e.headed}:{}}):w==="static"?O.createStaticPlaywrightShaderDriver({root:r,runtime:n,serve:u,...e.headed!==void 0?{headed:e.headed}:{}}):O.createPlaywrightShaderDriver({root:r,runtime:n,...e.headed!==void 0?{headed:e.headed}:{}}),"createDriver"),$=new Map,D=new Map,T=a((p,b)=>{if(e.driver!==void 0)return e.driver;let x=p.get(b);return x===void 0&&(x=v(),p.set(b,x)),x},"driverFor");await h$1(r,s.map(p=>p.key),m);let A=[],C={},H=[],q=new Set;try{for(let[b,x]of s.entries()){let{scene:h,backend:_,key:j}=x;e.onSceneStart?.(j,b,s.length);let K=c.scenes.find(P=>P.scene===h.key&&P.backend===_);if(!K?.coverage)throw new Error(`Fresh receipt has no coverage for "${j}".`);let B=K.coverage;if(B.render+B.compute===0)continue;let S=a$4(n.three,_),k=c.receipt?.scenes[j]?.skipped,y=(k?.render??0)+(k?.compute??0),g=await ot(r,t,c.receipt?.scenes[j]?.asset),M=a(async P=>{let oe=T($,_),Re=T(D,_),ee=P?"live":"precompiled",$e=P?"precompiled":"live",xe=P?oe:Re,Te=P?Re:oe,ne=await xe.observe(h,ee,t,void 0,_),I=await Te.observe(h,$e,t,ne.frame,_),de=ne.mode==="live"?ne:I,ce=ne.mode==="precompiled"?ne:I;er(de,h,"live",S),er(ce,h,"precompiled",S),dt(h,B,de,ce,y,g);let tr=a(async(Mr,nr,ir)=>{let Y=V(nr,ir,t.parity.channelTolerance,h.maxDiffRatio??t.parity.maxDiffRatio);if(Y.matches)return Y;let Pr=await ct(r,j,nr,ir,Y.diff),Ir=Y.nonBlack?`${Y.differentPixels}/${Y.totalPixels} pixels differ (${(Y.diffRatio*100).toFixed(3)}%).`:`rendered output is black (live=${Y.baselineLuminance.toFixed(4)}, precompiled=${Y.precompiledLuminance.toFixed(4)}).`;throw new Error(`Shader ${Mr} parity failed for scene "${h.key}" at completed frames live=${de.frame}, precompiled=${ce.frame}: ${Ir} Artifacts: ${Pr.join(", ")}`)},"compare");await tr("first frame",de.firstFrameScreenshot,ce.firstFrameScreenshot);let Br=await tr("settled",de.screenshot,ce.screenshot);return {live:de,precompiled:ce,parity:Br}},"observePair"),R,F,W;if(e.parityOnly===!0)try{R=await M(!0);}catch(P){nt(P)&&q.add(j),H.push({scene:j,error:P}),e.onSceneError?.(j,P);continue}else {await M(!0);let P=[];for(let I=0;I<o;I++)P.push(await M(I%2===0));let oe=P[P.length-1];if(oe===void 0)throw new Error(`Shader timing produced no runs for scene "${h.key}".`);if(R=oe,F=await T(D,_).observePublished(h,t,_),er(F,h,"precompiled",S),Tr(h,B,F,y,g),W=h.runtimeMotion?V(F.beforeScreenshot,F.screenshot,t.parity.channelTolerance,1):void 0,W&&W.diffRatio<1e-4)throw new Error(`Published scene "${h.key}" stopped animating during its normal 120-frame soak (changed ${W.differentPixels}/${W.totalPixels} canvas pixels).`);let ee=a(I=>I.stats.buildMs+(I.stats.precompiledSetupMs??0)+(I.stats.hydrationMs??0),"observedNodeBuilderMs"),$e=Rr(P.map(I=>ee(I.live))),xe=Rr(P.map(I=>ee(I.precompiled))),Te=Math.max(0,$e-xe),ne=P.map(I=>Math.max(0,ee(I.live)-ee(I.precompiled)));C[j]={builds:B.render+B.compute,setupMeasured:!0,liveBuildMs:$e,precompiledBuildMs:xe,avoidedBuildMs:Te,runs:o,spreadMs:Math.max(...ne.map(I=>Math.abs(I-Te)))};}let{diff:Ee,...N}=R.parity,{firstFrameScreenshot:Se,screenshot:se,...Q}=R.live,{firstFrameScreenshot:G,screenshot:Fe,...ae}=R.precompiled,J;if(F!==void 0){let{beforeScreenshot:P,firstFrameScreenshot:oe,screenshot:Re,...ee}=F;J=ee;}A.push({scene:h.key,backend:_,coverage:B,live:Q,precompiled:ae,...J===void 0?{}:{published:J},parity:N,...W===void 0?{}:{runtimeMotion:{differentPixels:W.differentPixels,totalPixels:W.totalPixels,diffRatio:W.diffRatio}}}),await g$1(r,[j],m);}if(e.parityOnly===!0){if(await it(r,[...q],m),H.length>0)throw new Error(`Shader parity failed for ${H.length}/${s.length} scene/backend pair(s):
|
|
16
16
|
`+H.map(b=>{let x=b.error instanceof Error?b.error.message:String(b.error);return ` - ${b.scene}: ${x}`}).join(`
|
|
17
|
-
`));return {schemaVersion:1,root:r,noGpu:c,browser:"passed",scenes:A}}if(Object.keys(C).length===0)return {schemaVersion:1,root:r,noGpu:c,browser:"passed",scenes:A};if(e.commitTiming===!0){let b={adapter:i$1.length===1&&i$1[0]==="webgl"?"WebGL adapter":"WebGPU adapter",platform:`${Ae.platform()}/${Ae.arch()}`},h=await(($.values().next().value??e.driver)?.timingEnvironment?.()??b),_=await i$2(r,C,h);return {schemaVersion:1,root:r,noGpu:c,browser:"passed",scenes:A,timing:_.local,committedTiming:_.committed}}let p=await f$2(r,C);return {schemaVersion:1,root:r,noGpu:c,browser:"passed",scenes:A,timing:p}}finally{
|
|
17
|
+
`));return {schemaVersion:1,root:r,noGpu:c,browser:"passed",scenes:A}}if(Object.keys(C).length===0)return {schemaVersion:1,root:r,noGpu:c,browser:"passed",scenes:A};if(e.commitTiming===!0){let b={adapter:i$1.length===1&&i$1[0]==="webgl"?"WebGL adapter":"WebGPU adapter",platform:`${Ae.platform()}/${Ae.arch()}`},h=await(($.values().next().value??e.driver)?.timingEnvironment?.()??b),_=await i$2(r,C,h);return {schemaVersion:1,root:r,noGpu:c,browser:"passed",scenes:A,timing:_.local,committedTiming:_.committed}}let p=await f$2(r,C);return {schemaVersion:1,root:r,noGpu:c,browser:"passed",scenes:A,timing:p}}finally{f&&await Promise.all([...$.values(),...D.values()].map(p=>p.close()));}}a(Ht,"testShaders");export{wr as a,Ce as b,we as c,De as d,Vt as e,Ht as f};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {a}from'./chunk-HOZDD6PW.js';import t from'process';var i=Object.freeze([{id:"three-inspector-invalid-json",pattern:/is not valid JSON/iu},{id:"chromium-webgpu-experimental",pattern:/WebGPU is experimental/iu},{id:"browser-automatic-favicon",pattern:/Failed to load resource:.*404.*\/favicon\.ico/iu}]);function u(r){return i.some(e=>e.pattern.test(r))}a(u,"isDocumentedBrowserNoise");function l(r=t.env,e=t.platform){let o=r.THREE_BLOCKS_WEBGPU_BROWSER_ARGS?.split(/\s+/u).filter(Boolean);if(o&&o.length>0)return o;let s=["--enable-unsafe-webgpu"];return e==="darwin"&&s.push("--enable-gpu","--use-angle=metal"),e==="linux"&&s.push("--enable-features=Vulkan","--disable-vulkan-surface","--ignore-gpu-blocklist","--disable-gpu-driver-bug-workarounds","--disable-gpu-watchdog"),s}a(l,"webgpuBrowserArgs");function p(r=t.env){let e=r.THREE_BLOCKS_WEBGL_BROWSER_ARGS?.split(/\s+/u).filter(Boolean);return e&&e.length>0?e:["--use-angle=swiftshader","--enable-unsafe-swiftshader","--ignore-gpu-blocklist"]}a(p,"webglBrowserArgs");function g(r=false,e=t.env){return r!==true&&e.THREE_BLOCKS_SOFTWARE_WEBGPU!=="1"}a(g,"webgpuBrowserHeadless");export{u as a,l as b,p as c,g as d};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import {d,a as a$1,X,z,Y,B,U,m,l,h,g,S}from'./chunk-3CKEE22B.js';import {a}from'./chunk-EI7MMDWY.js';import x from'process';import {createServer}from'http';import {createRequire}from'module';import {mkdtemp,rm,lstat,realpath}from'fs/promises';import A from'path';import {tmpdir}from'os';import {pathToFileURL}from'url';var Le=Object.freeze([{id:"three-inspector-invalid-json",pattern:/is not valid JSON/iu},{id:"chromium-webgpu-experimental",pattern:/WebGPU is experimental/iu},{id:"browser-automatic-favicon",pattern:/Failed to load resource:.*404.*\/favicon\.ico/iu}]);function Z(n){return Le.some(e=>e.pattern.test(n))}a(Z,"isDocumentedBrowserNoise");function fe(n=x.env,e=x.platform){let t=n.THREE_BLOCKS_WEBGPU_BROWSER_ARGS?.split(/\s+/u).filter(Boolean);if(t&&t.length>0)return t;let r=["--enable-unsafe-webgpu"];return e==="darwin"&&r.push("--enable-gpu","--use-angle=metal"),e==="linux"&&r.push("--enable-features=Vulkan","--disable-vulkan-surface","--ignore-gpu-blocklist","--disable-gpu-driver-bug-workarounds","--disable-gpu-watchdog"),r}a(fe,"webgpuBrowserArgs");function pe(n=x.env){let e=n.THREE_BLOCKS_WEBGL_BROWSER_ARGS?.split(/\s+/u).filter(Boolean);return e&&e.length>0?e:["--use-angle=swiftshader","--enable-unsafe-swiftshader","--ignore-gpu-blocklist"]}a(pe,"webglBrowserArgs");function we(n=false,e=x.env){return n!==true&&e.THREE_BLOCKS_SOFTWARE_WEBGPU!=="1"}a(we,"webgpuBrowserHeadless");var ee="three-blocks.shader-capture.runtime.v1";var Re="/__three-blocks/shaders/capture",K="/__three-blocks/shaders/telemetry",Te="/__three-blocks/shaders/runtime.js",ke="/__three-blocks/shaders/bootstrap.js",Ee="/__three-blocks/shaders/bridge.js",Pe=d.manifest*2,ne=/^[a-z0-9][a-z0-9_-]{0,63}$/u,Ce=64,Be=2e3;async function Ve(){try{return (await import('playwright')).chromium}catch(n){throw new Error('Shader browser work requires the optional "playwright" package. Install it in the project and run `npx playwright install chromium`.',{cause:n})}}a(Ve,"loadChromium");async function We(n){let e;try{e=createRequire(A.join(n,"package.json")).resolve("vite");}catch(r){throw new Error("Shader capture requires Vite in the target project.",{cause:r})}let t=await import(pathToFileURL(e).href);if(typeof t.createServer!="function")throw new Error(`The target project's Vite entry does not export createServer(): ${e}`);return t.createServer}a(We,"loadProjectCreateServer");var ae=class{static{a(this,"CaptureInbox");}#e=new Map;#t=new Map;wait(e,t){let r=this.#t.get(e);if(r!==void 0)return this.#t.delete(e),Promise.resolve(r);if(this.#e.has(e))throw new Error(`A shader capture is already waiting for scene "${e}".`);return new Promise((a,o)=>{let s=setTimeout(()=>{this.#e.delete(e),o(new Error(`Shader capture "${e}" timed out after ${t}ms.`));},t);this.#e.set(e,{resolve:a,reject:o,timer:s});})}receive(e){if(!a$1(e)||typeof e.scene!="string"||!ne.test(e.scene))throw new Error("Capture POST has no safe scene key.");if(!this.#t.has(e.scene)&&!this.#e.has(e.scene)&&this.#t.size>=Ce)throw new Error("Capture POST exceeds the scene inbox limit.");let t=this.#e.get(e.scene);t?(clearTimeout(t.timer),this.#e.delete(e.scene),t.resolve(e)):this.#t.set(e.scene,e);}cancel(e,t){let r=this.#e.get(e);r&&(clearTimeout(r.timer),this.#e.delete(e),r.reject(t));}rejectAll(e){for(let t of this.#e.values())clearTimeout(t.timer),t.reject(e);this.#e.clear(),this.#t.clear();}};async function Je(n,e){let t=await Promise.race([e.then(r=>({kind:"capture",value:r})),n.then(()=>({kind:"navigation"}))]);return t.kind==="capture"?t.value:e}a(Je,"waitForShaderCaptureAcrossNavigation");var se=class{static{a(this,"TelemetryHub");}#e=new Map;#t=new Map;markFirstRequest(e){ne.test(e)&&!this.#t.has(e)&&this.#t.set(e,Date.now());}firstRequest(e){return this.#t.get(e)}receive(e){if(!a$1(e)||typeof e.scene!="string"||!ne.test(e.scene))throw new Error("Shader telemetry has no bounded scene key.");if(!this.#e.has(e.scene)&&this.#e.size>=Ce)throw new Error("Shader telemetry exceeds the scene limit.");this.#e.set(e.scene,e);}read(e){return this.#e.get(e)}clear(e){this.#e.delete(e),this.#t.delete(e);}},Ke=a(async(n,e,t,r,a)=>{let o=0;for(;n.__threeBlocksParityUsesAnimationLoop!==true&&o<e;)await r(),o+=1;if(n.__threeBlocksParityUsesAnimationLoop===true){let s=Number(n.__threeBlocksParityCompletedFrame||0),i=Number(t),d=Number.isSafeInteger(i)&&i>=s?i:s+e;for(n.__threeBlocksParityTargetFrame=d;Number(n.__threeBlocksParityCompletedFrame||0)<d;)await r();}return await a(),Number(n.__threeBlocksParityCompletedFrame||0)},"settleShaderParityFrames");function oe(n,e){return `(() => {
|
|
2
|
+
const root = globalThis;
|
|
3
|
+
const scene = new URL(location.href).searchParams.get('captureId')
|
|
4
|
+
|| 'default';
|
|
5
|
+
const workerCapture = ${JSON.stringify(e??null).replaceAll("<","\\u003c")};
|
|
6
|
+
if (workerCapture) root[Symbol.for('three-blocks.shader-capture.worker-activation.v1')] = { ...workerCapture, scene };
|
|
7
|
+
const randomSeed = (value) => {
|
|
8
|
+
let state = 2166136261;
|
|
9
|
+
for (let index = 0; index < value.length; index++) state = Math.imul(state ^ value.charCodeAt(index), 16777619) >>> 0;
|
|
10
|
+
return state === 0 ? 0x9e3779b9 : state;
|
|
11
|
+
};
|
|
12
|
+
const advanceRandom = (state) => {
|
|
13
|
+
state ^= state << 13;
|
|
14
|
+
state ^= state >>> 17;
|
|
15
|
+
state ^= state << 5;
|
|
16
|
+
return state >>> 0;
|
|
17
|
+
};
|
|
18
|
+
const parityMode = new URL(location.href).searchParams.get('threeBlocksShaderMode');
|
|
19
|
+
if (parityMode === 'live' || parityMode === 'precompiled') {
|
|
20
|
+
root.__threeBlocksParityEpoch = 1700000000000;
|
|
21
|
+
root.__threeBlocksParityTime = 0;
|
|
22
|
+
Date.now = () => root.__threeBlocksParityEpoch + Number(root.__threeBlocksParityTime || 0);
|
|
23
|
+
}
|
|
24
|
+
const randomStreams = new Map();
|
|
25
|
+
Math.random = () => {
|
|
26
|
+
const stackLine = String(new Error().stack || '').split('\\n')[2] || 'unknown';
|
|
27
|
+
const originIndex = stackLine.indexOf(location.origin);
|
|
28
|
+
const callsite = (originIndex >= 0 ? stackLine.slice(0, originIndex) : stackLine).trim() || 'anonymous';
|
|
29
|
+
const next = advanceRandom(randomStreams.get(callsite) ?? randomSeed(scene + '|' + callsite));
|
|
30
|
+
randomStreams.set(callsite, next);
|
|
31
|
+
return next / 4294967296;
|
|
32
|
+
};
|
|
33
|
+
const readiness = { workerReady: false, assetsReady: false, textReady: false, compileEnd: false, firstFrame: false };
|
|
34
|
+
const stats = { buildCalls: 0, renderBuilds: 0, computeBuilds: 0, registeredBuilds: 0, registeredRenderBuilds: 0, registeredComputeBuilds: 0, buildMs: 0, syncBuildMs: 0, asyncBuildElapsedMs: 0, precompiledSetupMs: 0, maxSyncBuildMs: 0, maxPrecompiledSetupMs: 0, hydrationMs: 0, maxHydrationMs: 0, injected: 0, injectedRender: 0, injectedCompute: 0, missed: 0, missedRender: 0, missedCompute: 0, missedKeys: [] };
|
|
35
|
+
const settleParityFrames = ${Ke.toString()};
|
|
36
|
+
const settle = (frames, requestedTarget) => settleParityFrames(
|
|
37
|
+
root,
|
|
38
|
+
frames,
|
|
39
|
+
requestedTarget,
|
|
40
|
+
() => new Promise((resolve) => requestAnimationFrame(resolve)),
|
|
41
|
+
() => new Promise((resolve) => setTimeout(resolve, 100)),
|
|
42
|
+
);
|
|
43
|
+
const bridge = { protocolVersion: 1, compatibility: ${JSON.stringify(n)}, transform: ${B}, readiness, stats, settle };
|
|
44
|
+
root.__threeBlocksShaderTools = bridge;
|
|
45
|
+
requestAnimationFrame(() => requestAnimationFrame(() => { readiness.firstFrame = true; }));
|
|
46
|
+
const poll = async () => {
|
|
47
|
+
try {
|
|
48
|
+
const response = await fetch('/__three-blocks/shaders/telemetry?scene=' + encodeURIComponent(scene), { cache: 'no-store' });
|
|
49
|
+
if (response.status !== 204 && response.ok) {
|
|
50
|
+
const payload = await response.json();
|
|
51
|
+
if (payload.protocolVersion !== 1 || payload.compatibility !== bridge.compatibility || payload.transform !== bridge.transform) throw new Error('incompatible shader telemetry');
|
|
52
|
+
Object.assign(stats, payload.stats);
|
|
53
|
+
if (Array.isArray(payload.demands)) bridge.demands = payload.demands;
|
|
54
|
+
if (typeof payload.demandTotal === 'number') bridge.demandTotal = payload.demandTotal;
|
|
55
|
+
readiness.workerReady = true;
|
|
56
|
+
if (payload.settled === true) {
|
|
57
|
+
readiness.assetsReady = true;
|
|
58
|
+
readiness.textReady = true;
|
|
59
|
+
readiness.compileEnd = true;
|
|
60
|
+
}
|
|
61
|
+
const smoke = root.__threeBlocksSmoke && typeof root.__threeBlocksSmoke === 'object' ? root.__threeBlocksSmoke : { protocolVersion: 1, worker: { offscreenCanvas: true, visible: true }, readiness: {} };
|
|
62
|
+
smoke.readiness = { ...(smoke.readiness || {}), ...readiness };
|
|
63
|
+
root.__threeBlocksSmoke = smoke;
|
|
64
|
+
}
|
|
65
|
+
} catch {}
|
|
66
|
+
setTimeout(poll, 40);
|
|
67
|
+
};
|
|
68
|
+
void poll();
|
|
69
|
+
})();`}a(oe,"publicBridgeScript");function _e(n,e,t,r,a=false){let o=new URL(n.url??"/","http://three-blocks.invalid"),s=o.pathname;if(a&&n.method==="GET"&&/^\/three-blocks\/shaders\/[a-z0-9][a-z0-9_-]{0,63}\.(?:webgpu|webgl)\.json$/u.test(s))return e.statusCode=204,e.end(),true;if(s===K&&n.method==="GET"){let h=o.searchParams.get("scene")??"",S=r.read(h);return S===void 0?(e.statusCode=204,e.end()):(e.statusCode=200,e.setHeader("Content-Type","application/json"),e.end(JSON.stringify(S))),true}let i=s===Re,d=s===K;if(!i&&!d)return false;if(n.method!=="POST")return e.statusCode=405,e.end("POST required"),true;let c=[],w=0,f=false;return n.on("data",h=>{w+=h.byteLength,w>Pe?f=true:c.push(h);}),n.on("end",()=>{if(f){e.statusCode=413,e.end("capture payload too large");return}try{let h=JSON.parse(Buffer.concat(c).toString("utf8"));d?r.receive(h):t.receive(h),e.statusCode=204,e.end();}catch(h){e.statusCode=400,e.end(h instanceof Error?h.message:String(h));}}),true}a(_e,"handleCaptureEndpoint");function qe(n,e,t,r,a){return {name:"three-blocks:shader-capture-endpoint",transformIndexHtml(){return [{tag:"script",children:oe(r,a),injectTo:"head-prepend"}]},configureServer(o){o.middlewares.use((s,i,d)=>{let w=new URL(s.url??"/","http://three-blocks.invalid").searchParams.get("captureId");w!==null&&e.markFirstRequest(w),!_e(s,i,n,e,t)&&d();});}}}a(qe,"captureEndpointPlugin");function ge(n,e,t){let r=new URL(e.url,n);for(let[a,o]of Object.entries(t))r.searchParams.set(a,o);return r.href}a(ge,"browserUrl");function ze(n,e,t){let r=new URL(e.url,n);for(let a of ["capture","precompiled"])r.searchParams.delete(a);return r.searchParams.set("captureId",e.key),r.searchParams.set("threeBlocksShaderCapture","1"),r.searchParams.set("threeBlocksShaderMode","precompiled"),t==="webgl"&&r.searchParams.set("webgl","1"),r.searchParams.set("tbStats","1"),r.href}a(ze,"publishedBrowserUrl");async function O(n){let e;try{await Promise.race([n(),new Promise(t=>{e=setTimeout(t,Be);})]);}catch{}finally{e&&clearTimeout(e);}}a(O,"closeBrowserResource");async function J(n){let e;try{return await Promise.race([n().catch(()=>null),new Promise(t=>{e=setTimeout(()=>t(null),Be);})])}finally{e!==void 0&&clearTimeout(e);}}a(J,"readPageDiagnostic");function te(n){let e=a(()=>{},"resolveFirst"),t=new Promise(s=>{e=s;}),r={console:[],page:[],first:t},a$1=false,o=a(s=>{a$1||(a$1=true,e(new Error(s)));},"report");return n.on("console",s=>{let i=s.type()==="warning"&&/\[three-blocks\/shaders\].*(?:has no entry|manifest miss|hydration)/iu.test(s.text());if(s.type()!=="error"&&!i||Z(s.text()))return;let d=s.location().url,c=d.length>0?`${s.text()} (${d})`:s.text();r.console.push(c),o(`Browser console ${i?"warning":"error"}: ${c}`);}),n.on("pageerror",s=>{if(Z(s.message))return;let i=s.stack||s.message;r.page.push(i),o(`Browser page error: ${i}`);}),n.on("crash",()=>o("Browser page crashed before shader capture completed.")),n.on("close",()=>o("Browser page closed before shader capture completed.")),r}a(te,"collectErrors");function L(n,e,t=false){return typeof n[e]=="boolean"?n[e]:t}a(L,"booleanField");function Ye(n){if(!a$1(n))throw new Error("Browser shader stats are unavailable.");let e=a((t,r=true)=>{let a=n[t];if(typeof a!="number"||!Number.isFinite(a)||a<0||r&&!Number.isSafeInteger(a))throw new Error(`Browser shader stats.${t} is invalid.`);return a},"read");return {buildCalls:e("buildCalls"),renderBuilds:e("renderBuilds"),computeBuilds:e("computeBuilds"),registeredBuilds:e("registeredBuilds"),registeredRenderBuilds:e("registeredRenderBuilds"),registeredComputeBuilds:e("registeredComputeBuilds"),buildMs:e("buildMs",false),syncBuildMs:e("syncBuildMs",false),asyncBuildElapsedMs:e("asyncBuildElapsedMs",false),precompiledSetupMs:e("precompiledSetupMs",false),maxSyncBuildMs:e("maxSyncBuildMs",false),maxPrecompiledSetupMs:e("maxPrecompiledSetupMs",false),hydrationMs:e("hydrationMs",false),maxHydrationMs:e("maxHydrationMs",false),injected:e("injected"),injectedRender:e("injectedRender"),injectedCompute:e("injectedCompute"),missed:e("missed"),missedRender:e("missedRender"),missedCompute:e("missedCompute"),...Array.isArray(n.missedKeys)&&n.missedKeys.every(t=>typeof t=="string")?{missedKeys:n.missedKeys}:{}}}a(Ye,"parseStats");function V(n,e,t,r,a){if(!a$1(n))throw new Error("The page did not expose the public shader devtools bridge.");if(!t&&n.protocolVersion!==1)throw new Error(`Scene "${e.key}" exposed an unsupported shader bridge protocol.`);let o=n.readiness;if(!a$1(o))throw new Error("The shader bridge readiness snapshot is invalid.");let s={workerReady:L(o,"workerReady"),assetsReady:L(o,"assetsReady"),textReady:e.requiresText?L(o,"textReady"):true,compileEnd:L(o,"compileEnd"),firstFrame:L(o,"firstFrame",t)};if(!s.workerReady||!s.assetsReady||!s.textReady||!s.compileEnd)throw new Error(`Scene "${e.key}" did not reach worker/assets/text/compile readiness.`);let i=t?a:n.compatibility,d=t?B:n.transform;if(i!==a||d!==B)throw new Error(`Scene "${e.key}" exposed incompatible shader bridge metadata.`);Y(r);let c=Array.isArray(n.demands)?n.demands.filter(a$1).slice(0,64):void 0;return {compatibility:a,transform:d,readiness:s,stats:Ye(n.stats),...c===void 0?{}:{demands:c}}}a(V,"parseBridge");async function W(n,e){return n.evaluate(t=>{let r=globalThis;if(!t)return r.__threeBlocksShaderTools??null;let a=r.__threeBlocks,o=r.__threeBlocksTslStats;if(!a||typeof a!="object")return null;let s=a;return {readiness:{workerReady:s.workerReady===true,assetsReady:s.loadEnd===true||s.assetsReady===true,textReady:s.textReady===true,compileEnd:s.compileEnd===true,firstFrame:true},stats:o}},e)}a(W,"readBridge");async function xe(n,e){let t=await J(()=>n.evaluate(r=>{let a$1=globalThis,o=a(i=>{let d=a$1;for(let c of i.split(".")){if(d===null||typeof d!="object"&&typeof d!="function")return;d=Reflect.get(d,c);}return d},"resolveGlobal"),s=null;if(r!==null)try{s=JSON.stringify(o(`${r}Diagnostics`))??null;}catch{s=null;}return JSON.stringify({parityCompletedFrame:Number(a$1.__threeBlocksParityCompletedFrame??0),diagnostics:s})},e??null));return t===null?{alive:false,signature:""}:{alive:true,signature:t}}a(xe,"probePageProgress");async function F(n,e,t,r){let a$1=n.evaluate(async c=>{let f=globalThis.__threeBlocksShaderTools;if(f&&typeof f=="object"){let g=Reflect.get(f,"settle");if(typeof g=="function"){let u=await g(c.frames,c.targetFrame);return typeof u=="number"&&Number.isSafeInteger(u)?u:0}}if(!c.legacy||!c.modulePath)throw new Error("The public shader bridge does not provide deterministic settle().");let h=await import(c.modulePath);if(!h.store||typeof h.store!="object")throw new Error("Legacy deterministic store is unavailable.");let S=h.store;return S.recordFrameCount=0,S.recordFrameRate=60,S.recordTotalFrames=c.frames,S.recording=true,await new Promise((g,u)=>{let p=Date.now(),m=a(()=>{if(S.recording===false)return g();if(Date.now()-p>c.timeoutMs)return u(new Error("Legacy deterministic settle timed out."));setTimeout(m,25);},"poll");m();}),0},{frames:t,targetFrame:r,legacy:e.bridge.legacyLab,modulePath:e.bridge.deterministicModule??null,timeoutMs:e.timeoutMs}),o=j(e),s=false,i,d=(async()=>{let c=Date.now(),w=c,f="";for(;;){let h=o-(Date.now()-c);if(h<=0)throw new Error(`Shader parity settle timed out after ${o}ms.`);let S=e.timeoutMs-(Date.now()-w);if(S<=0){let g=await xe(n,e.readiness.global);if(s)throw new Error("Shader parity settle already resolved.");if(g.alive&&g.signature===f)throw new Error(`Shader parity settle timed out after ${e.timeoutMs}ms without progress (hard cap ${o}ms).`);f=g.signature,w=Date.now();continue}if(await new Promise(g=>{i=setTimeout(g,Math.min(S,h,2500));}),s)throw new Error("Shader parity settle already resolved.")}})();try{return await Promise.race([a$1,d])}finally{s=true,i!==void 0&&clearTimeout(i),d.catch(()=>{});}}a(F,"settlePage");async function Se(n,e,t){e.readiness.selector===void 0&&e.readiness.global===void 0||await Promise.race([n.waitForFunction(r=>{let a=globalThis;if(r.selector!==void 0&&a.document?.querySelector(r.selector)==null)return false;if(r.global===void 0)return true;let o=a;for(let d of r.global.split(".")){if((typeof o!="object"||o===null)&&typeof o!="function")return false;o=Reflect.get(o,d);}if(o===true)return true;if(typeof o!="object"||o===null||typeof Reflect.get(o,"then")!="function")return false;let s=a.__threeBlocksReadinessState,i=s instanceof Map?s:new Map;return s instanceof Map||(a.__threeBlocksReadinessState=i),i.has(o)||(i.set(o,false),Promise.resolve(o).then(()=>i.set(o,true),()=>i.set(o,false))),i.get(o)===true},e.readiness,{timeout:j(e)}),t.first.then(r=>Promise.reject(r))]);}a(Se,"waitForConfiguredReadiness");async function be(n){let e=n.locator("canvas"),r=(await e.evaluateAll(a=>a.map((o,s)=>{let i=o.getBoundingClientRect();return {index:s,area:Math.max(0,i.width)*Math.max(0,i.height)}}))).sort((a,o)=>o.area-a.area)[0];if(r===void 0||r.area<=0)throw new Error("Published page has no visible renderer canvas.");return Buffer.from(await e.nth(r.index).screenshot({type:"png"}))}a(be,"primaryCanvasScreenshot");async function re(n,e,t,r,a,o,s){let i=q(r,a,o),d=await U(),c=`(() => {
|
|
70
|
+
const runtime = globalThis[Symbol.for(${JSON.stringify(ee)})];
|
|
71
|
+
if (!runtime || typeof runtime.configureThreeBlocksShaderCapture !== 'function') {
|
|
72
|
+
throw new Error('@three-blocks/devtools attached shader capture runtime is incompatible.');
|
|
73
|
+
}
|
|
74
|
+
runtime.configureThreeBlocksShaderCapture(${JSON.stringify(i).replaceAll("<","\\u003c")});
|
|
75
|
+
})();`;await n.addInitScript({content:`${d}
|
|
76
|
+
${c}`}),await n.addInitScript({content:oe(s,i)}),await n.route("**/*",async w=>{let f=w.request(),h=new URL(f.url()),S=h.pathname;if(f.method()==="GET"&&r!=="precompiled"&&/^\/three-blocks\/shaders\/[a-z0-9][a-z0-9_-]{0,63}\.(?:webgpu|webgl)\.json$/u.test(S)){await w.fulfill({status:204});return}if(S===K&&f.method()==="GET"){let p=t.read(h.searchParams.get("scene")??"");await w.fulfill(p===void 0?{status:204}:{status:200,contentType:"application/json",body:JSON.stringify(p)});return}let g=S===Re,u=S===K;if((g||u)&&f.method()==="POST"){let p=f.postDataBuffer()??Buffer.alloc(0);if(p.byteLength>Pe){await w.fulfill({status:413,body:"capture payload too large"});return}try{let m=JSON.parse(p.toString("utf8"));u?t.receive(m):e.receive(m),await w.fulfill({status:204});}catch(m){await w.fulfill({status:400,body:m instanceof Error?m.message:String(m)});}return}await w.continue();});}a(re,"configureAttachedContext");var Xe=Object.freeze({".avif":"image/avif",".css":"text/css; charset=utf-8",".gif":"image/gif",".html":"text/html; charset=utf-8",".ico":"image/x-icon",".jpeg":"image/jpeg",".jpg":"image/jpeg",".js":"text/javascript; charset=utf-8",".json":"application/json; charset=utf-8",".mjs":"text/javascript; charset=utf-8",".mp4":"video/mp4",".png":"image/png",".svg":"image/svg+xml",".wasm":"application/wasm",".webm":"video/webm",".webp":"image/webp",".woff":"font/woff",".woff2":"font/woff2"});function Qe(n){let e=[`<script src="${Ee}"></script>`,`<script type="module" src="${ke}"></script>`].join(""),t=/<head(?:\s[^>]*)?>/iu.exec(n);return t===null?`${e}${n}`:`${n.slice(0,t.index+t[0].length)}${e}${n.slice(t.index+t[0].length)}`}a(Qe,"injectStaticShaderCaptureHtml");function Ze(n,e,t){let r=q(n,e,t);return [`import { configureThreeBlocksShaderCapture } from ${JSON.stringify(Te)};`,`configureThreeBlocksShaderCapture( ${JSON.stringify(r).replaceAll("<","\\u003c")} );`].join(`
|
|
77
|
+
`)}a(Ze,"staticCaptureBootstrap");var et=5e3;function j(n){return Math.max(n.maxTimeoutMs??n.timeoutMs,n.timeoutMs)}a(j,"configuredHardCapMs");function q(n,e,t){return {capture:n==="capture",backend:t,driven:true,forceLive:n!=="precompiled",settleFrames:e.settleFrames,settleTimeoutMs:e.settleTimeoutMs??3e4,...n==="capture"?{deadlineAt:Date.now()+Math.max(1e3,j(e)-et)}:{},readiness:e.readiness,transform:B}}a(q,"shaderCaptureConfiguration");async function tt(n,e){let t=await m(n,e,s=>/\.(?:c|m)?js$/u.test(s),16384),r=false,a=false,o;for(let s of t){let i=(await l(n,s,d.texture,"Static application JavaScript")).data.toString("utf8");if(i.includes("nodeBuilderStateProvider")&&(r=true),i.includes("three-blocks.shader-capture.runtime.v1")&&(a=true,o??=s),r&&a)break}if(!r||!a)throw new Error("The static build does not contain the Three.js shader capture transform. Run `shaders capture` without an explicit driver or URL to preview adapter wiring and build automatically, or add the manual adapter from the package README and rebuild.");return {seen:true,applied:true,alreadyPresent:false,captureApplied:true,...o===void 0?{}:{id:o}}}a(tt,"inspectStaticCaptureTransform");async function rt(n,e){let t;try{t=decodeURIComponent(e);}catch{return}if(t.includes("\0"))return;let r=t.replace(/^\/+/u,""),a=A.resolve(n,r.length===0?"index.html":r);if(!h(n,a)||a===n||(await g(a)&&(await lstat(a)).isDirectory()&&(a=A.join(a,"index.html")),!await g(a)&&A.extname(a).length===0&&(a=A.join(n,"index.html")),!await g(a)))return;let o=await l(n,a,d.texture,"Static application asset");return {data:o.data,file:o.path}}a(rt,"staticRequestFile");async function nt(n,e,t,r,a,o){let s=await realpath(n.root),i=await realpath(A.resolve(s,n.serve));if(!h(s,i)||i===s)throw new Error("--serve must name a built application directory inside the project root.");let d=await tt(s,i),c=await S(),w=Ze(e,r,t),f=oe(z(n.runtime.three,t),q(e,r,t)),h$1=createServer((g,u)=>{(async()=>{if(_e(g,u,a,o,e!=="precompiled"))return;let p=new URL(g.url??"/","http://three-blocks.invalid");if(g.method!=="GET"&&g.method!=="HEAD"){u.statusCode=405,u.end("GET or HEAD required");return}let m=p.pathname===Te?c:p.pathname===ke?w:p.pathname===Ee?f:void 0;if(m!==void 0){u.statusCode=200,u.setHeader("Content-Type","text/javascript; charset=utf-8"),u.setHeader("Cache-Control","no-store"),u.end(g.method==="HEAD"?void 0:m);return}let y=await rt(i,p.pathname);if(y===void 0){u.statusCode=404,u.end("Not found");return}let v=A.extname(y.file).toLowerCase(),b=v===".html"?Buffer.from(Qe(y.data.toString("utf8"))):y.data;u.statusCode=200,u.setHeader("Content-Type",Xe[v]??"application/octet-stream"),u.setHeader("Content-Length",String(b.byteLength)),u.setHeader("Cache-Control","no-store"),u.end(g.method==="HEAD"?void 0:b);})().catch(p=>{if(u.headersSent)return u.destroy(p instanceof Error?p:void 0);u.statusCode=500,u.end(p instanceof Error?p.message:String(p));});});await new Promise((g,u)=>{h$1.once("error",u),h$1.listen(0,"127.0.0.1",()=>{h$1.off("error",u),g();});});let S$1=h$1.address();if(!S$1||typeof S$1=="string")throw new Error("Static capture server did not expose an ephemeral TCP address.");return {server:h$1,baseUrl:`http://127.0.0.1:${S$1.port}`,transform:d}}a(nt,"startStaticShaderServer");function at(n,e,t){return n===e?true:t&&n!==void 0&&n!=="capture"&&e!=="capture"}a(at,"canReuseShaderBrowserSession");function ve(n){let e=n instanceof Error?n.message:String(n);return e.includes("Execution context was destroyed")&&e.includes("navigation")||/^launch: Timeout \d+ms exceeded\./u.test(e)}a(ve,"isRetryableShaderObservationNavigation");var $=class{static{a(this,"PlaywrightShaderDriver");}#e;#t=new ae;#n=new se;#h;#m;#o;#i;#r;#a;#f;#l;#p;#w;#u=0;#c;constructor(e){this.#e=e;}#d(){return this.#h?.status??this.#m??{seen:false,applied:false,alreadyPresent:false}}async#y(e,t){if(this.#r?.isConnected()===true)return;this.#r=void 0;let r=await Ve();this.#c??=await mkdtemp(A.join(tmpdir(),"three-blocks-shader-cache-")),this.#r=await r.launch({headless:t==="webgl"?this.#e.headed!==true:we(this.#e.headed===true),args:[...t==="webgl"?pe():fe(),`--disk-cache-dir=${this.#c}`],timeout:e.timeoutMs}),this.#u=0;}async#s(e,t,r){let a;try{return await Promise.race([r(),new Promise((o,s)=>{a=setTimeout(()=>s(new Error(`launch: Timeout ${t.timeoutMs}ms exceeded.`)),t.timeoutMs);})])}catch(o){throw this.#r===e&&(this.#r=void 0),await O(()=>e.close()),o}finally{a!==void 0&&clearTimeout(a);}}async#g(e,t,r){let a=this.#o!==void 0||this.#i!==void 0||this.#e.url!==void 0&&this.#a!==void 0,o=this.#p===t&&(this.#i!==void 0?this.#l===e:at(this.#l,e,r.bridge.legacyLab));if(a&&o){this.#l=e,await this.#y(r,t);return}if(a&&await this.close(),this.#l=e,this.#p=t,this.#e.url!==void 0){let s=new URL(this.#e.url);if(!["http:","https:"].includes(s.protocol)||s.username||s.password||s.hash)throw new Error("Attached shader URL must be an HTTP(S) URL without credentials or a fragment.");this.#a=s.href,this.#m={seen:true,applied:true,alreadyPresent:false,captureApplied:true,id:"attached-application"},await this.#y(r,t);return}if(this.#e.serve!==void 0)try{let s=await nt({root:this.#e.root,runtime:this.#e.runtime,serve:this.#e.serve,...this.#e.headed===void 0?{}:{headed:this.#e.headed}},e,t,r,this.#t,this.#n);this.#i=s.server,this.#m=s.transform,this.#a=s.baseUrl,await this.#y(r,t);return}catch(s){throw await this.close(),s}this.#h=X(this.#e.runtime.three,{disableTimestampQueries:x.env.THREE_BLOCKS_SOFTWARE_WEBGPU==="1",...r.bridge.legacyLab?{}:{capture:{capture:e==="capture",driven:true,forceLive:e!=="precompiled",forceWebGL:t==="webgl",settleFrames:r.settleFrames,settleTimeoutMs:r.settleTimeoutMs??3e4,readiness:r.readiness}}}),this.#f={THREE_BLOCKS_SHADER_TOOL:x.env.THREE_BLOCKS_SHADER_TOOL,THREE_BLOCKS_PRECOMPILE_CAPTURE_SERVER:x.env.THREE_BLOCKS_PRECOMPILE_CAPTURE_SERVER},x.env.THREE_BLOCKS_SHADER_TOOL="1",x.env.THREE_BLOCKS_PRECOMPILE_CAPTURE_SERVER="1";try{let s=await We(this.#e.root);this.#o=await s({root:this.#e.root,logLevel:"error",plugins:[this.#h.plugin,qe(this.#t,this.#n,e!=="precompiled",z(this.#e.runtime.three,t),q(e,r,t))],server:{host:"127.0.0.1",port:0}}),await this.#o.listen();let i=this.#o.httpServer?.address();if(!i||typeof i=="string")throw new Error("Vite did not expose an ephemeral TCP address.");this.#a=`http://127.0.0.1:${i.port}`,await this.#y(r,t);}catch(s){throw await this.close(),s}}async capture(e,t,r="webgpu"){let a$2=Date.now();if(await this.#g("capture",r,t),!this.#r||!this.#a)throw new Error("Shader browser driver did not start.");let o=this.#r,s=await this.#s(o,t,()=>o.newContext({viewport:t.viewport}));this.#e.url!==void 0&&await this.#s(o,t,()=>re(s,this.#t,this.#n,"capture",t,r,z(this.#e.runtime.three,r)));let i=await this.#s(o,t,()=>s.newPage()),d=te(i);this.#n.clear(e.key);let c=j(t),w=this.#t.wait(e.key,c),f=false;c>t.timeoutMs?(async()=>{let m=Math.min(5e3,Math.max(1e3,Math.round(t.timeoutMs/8))),y=Date.now(),v="",b="";for(;!f;){if(await new Promise(k=>setTimeout(k,m)),f)return;let T=this.#n.read(e.key),B=T===void 0?"":JSON.stringify(T);if(B!==v){v=B,y=Date.now();continue}if(Date.now()-y<t.timeoutMs)continue;let E=await xe(i,t.readiness.global);if(f)return;if(!E.alive||E.signature!==b){b=E.signature,y=Date.now();continue}this.#t.cancel(e.key,new Error(`Shader capture "${e.key}" timed out after ${t.timeoutMs}ms without progress (hard cap ${c}ms).`));return}})().catch(()=>{}):void 0;let S=Promise.race([w,d.first.then(m=>Promise.reject(m))]),g=a(()=>{},"resolveDisconnected"),u=new Promise(m=>{g=m;}),p=a(()=>g(new Error("Shader capture browser disconnected before posting a manifest.")),"onDisconnected");o.on("disconnected",p);try{let m=i.goto(ge(this.#a,e,{threeBlocksShaderCapture:"1",capture:"1",captureId:e.key,captureFrames:String(Math.max(4,t.settleFrames)),settleFrames:String(t.settleFrames),...r==="webgl"?{webgl:"1"}:{}}),{waitUntil:"domcontentloaded",timeout:t.timeoutMs}),y=await Je(m,Promise.race([S,u.then(b=>Promise.reject(b))]));Y(this.#d());let v=[...d.page,...d.console];if(v.length>0)throw new Error(`Capture browser errors:
|
|
78
|
+
- ${v.join(`
|
|
79
|
+
- `)}`);return a$1(y)?{...y,timing:{...a$1(y.timing)?y.timing:{},launch:a$2,...this.#n.firstRequest(e.key)===void 0?{}:{firstRequest:this.#n.firstRequest(e.key)},posted:Date.now()}}:y}catch(m){let y=m instanceof Error?m:new Error(String(m));this.#t.cancel(e.key,y),await w.catch(()=>{});let v=this.#n.read(e.key);if(y.message.includes("timed out")){let b=await J(()=>i.evaluate(E=>{let k=globalThis,N=k.__threeBlocksShaderTools,Me=N&&typeof N=="object"?N:void 0,Oe=k.document,M=Reflect.get(k,Symbol.for("three-blocks.shader-capture.cache-value.v1")),I=k.location,Ae=I!==null&&typeof I=="object"&&typeof Reflect.get(I,"href")=="string"?String(Reflect.get(I,"href")):"http://three-blocks.invalid/",je=new URL(Ae).searchParams.get("captureId")??"default",ie=M!==null&&typeof M=="object"&&typeof Reflect.get(M,"registrations")=="function"?Reflect.apply(Reflect.get(M,"registrations"),M,[je]):void 0,de=a(R=>{let _=k;for(let De of R.split(".")){if(_===null||typeof _!="object"&&typeof _!="function")return;_=Reflect.get(_,De);}return _},"resolveGlobal"),le=null,z=null;if(E!==null){let R=de(E);le=R===true||R===false?R:R===void 0?"absent":R!==null&&typeof R.then=="function"?"promise":typeof R;try{let _=JSON.stringify(de(`${E}Diagnostics`));z=typeof _=="string"?_.slice(0,2048):null;}catch{z=null;}}return {documentReadyState:Oe?.readyState??null,parityTargetFrame:Number(k.__threeBlocksParityTargetFrame??0),parityCompletedFrame:Number(k.__threeBlocksParityCompletedFrame??0),readiness:Me?.readiness??null,readinessGlobal:le,readinessDiagnostics:z,captureCache:M!==null&&typeof M=="object"?{activeScene:Reflect.get(M,"activeScene")??null,registrations:Array.isArray(ie)?ie.slice(0,16).map(R=>R!==null&&typeof R=="object"?{key:Reflect.get(R,"key")??null,kind:Reflect.get(R,"kind")??null}:null):null}:null,threeRuntimeResources:performance.getEntriesByType("resource").map(R=>R.name).filter(R=>R.includes("three.webgpu"))}},t.readiness.global??null)),T=t.readiness.global!==void 0&&b!==null&&b.readinessGlobal!==true,B=b===null?"Capture page did not answer diagnostics before the deadline; its main thread was blocked or gone. ":T?`Application readiness "${t.readiness.global}" never completed (state: ${JSON.stringify(b.readinessGlobal)}${b.readinessDiagnostics===null?"":`, diagnostics: ${b.readinessDiagnostics}`}). `:"";throw new Error(`${B}${y.message} Last capture state for "${e.key}": ${JSON.stringify({page:b,telemetry:v??null,transform:this.#d()})}`)}throw y}finally{f=true,o.off("disconnected",p),await O(()=>s.close()),this.#u++,(!o.isConnected()||this.#u>=(t.browserRelaunchScenes??8))&&(this.#r===o&&(this.#r=void 0),await O(()=>o.close()),this.#u=0);}}async observe(e,t,r,a,o="webgpu"){for(let s=0;s<2;s++)try{return await this.#S(e,o,t,r,a)}catch(i){if(s===0&&ve(i))continue;throw i}throw new Error(`Shader observation retry was exhausted for scene "${e.key}".`)}async#S(e,t,r,a,o){if(await this.#g(r,t,a),!this.#r||!this.#a)throw new Error("Shader browser driver did not start.");let s=this.#r,i=await this.#s(s,a,()=>s.newContext({viewport:a.viewport}));this.#e.url!==void 0&&await this.#s(s,a,()=>re(i,this.#t,this.#n,r,a,t,z(this.#e.runtime.three,t)));let d=await this.#s(s,a,()=>i.newPage()),c=te(d);this.#n.clear(e.key);try{await d.goto(ge(this.#a,e,{threeBlocksShaderCapture:"1",threeBlocksShaderMode:r,captureId:e.key,...r==="live"?{precompiled:"0"}:{},...t==="webgl"?{webgl:"1"}:{}}),{waitUntil:"domcontentloaded",timeout:a.timeoutMs}),await Promise.race([d.waitForFunction(a.bridge.legacyLab?"globalThis.__threeBlocks?.compileEnd === true":"globalThis.__threeBlocksShaderTools?.readiness?.compileEnd === true",void 0,{timeout:j(a)}),c.first.then(u=>Promise.reject(u))]),V(await W(d,a.bridge.legacyLab),e,a.bridge.legacyLab,this.#d(),z(this.#e.runtime.three,t)),await Se(d,a,c),await Promise.race([d.waitForFunction(a.bridge.legacyLab?"true":"globalThis.__threeBlocksShaderTools?.readiness?.firstFrame === true",void 0,{timeout:j(a)}),c.first.then(u=>Promise.reject(u))]),await F(d,a,1);let w=Buffer.from(await d.screenshot({type:"png",timeout:a.timeoutMs})),f=e.parityFrames??a.parity.frames,h=await F(d,a,f,o),S=Buffer.from(await d.screenshot({type:"png",timeout:a.timeoutMs}));e.parityFrames!==void 0&&f<a.parity.frames&&await F(d,a,a.parity.frames-f);let g=V(await W(d,a.bridge.legacyLab),e,a.bridge.legacyLab,this.#d(),z(this.#e.runtime.three,t));return this.#w===void 0&&(this.#w=await d.evaluate(async u=>{if(u==="webgl"){let E=Reflect.get(globalThis,"document").querySelector("canvas")?.getContext("webgl2"),k=E?.getExtension("WEBGL_debug_renderer_info");return {adapter:E&&k?String(E.getParameter(k.UNMASKED_RENDERER_WEBGL)):"WebGL adapter",platform:navigator.platform||navigator.userAgent}}let p=Reflect.get(navigator,"gpu"),m=typeof p=="object"&&p!==null?Reflect.get(p,"requestAdapter"):void 0,y=typeof m=="function"?await Reflect.apply(m,p,[]):void 0,v=typeof y=="object"&&y!==null?Reflect.get(y,"info"):void 0,b=["description","device","architecture","vendor"].flatMap(T=>{let B=typeof v=="object"&&v!==null?Reflect.get(v,T):void 0;return typeof B=="string"&&B.length>0?[B]:[]});return {adapter:[...new Set(b)].join(" \xB7 ")||"WebGPU adapter",platform:navigator.platform||navigator.userAgent}},t)),{scene:e.key,mode:r,...g,frame:h,firstFrameScreenshot:w,screenshot:S,errors:[...c.page,...c.console]}}catch(w){let f=w instanceof Error?w:new Error(String(w));if(/(?:timed?\s*out|timeout)/iu.test(f.message)){let u=this.#n.read(e.key),p=await J(()=>d.evaluate(()=>{let m=globalThis,y=m.__threeBlocksShaderTools,v=y&&typeof y=="object"?y:void 0;return {documentReadyState:m.document?.readyState??null,parityTargetFrame:Number(m.__threeBlocksParityTargetFrame??0),parityCompletedFrame:Number(m.__threeBlocksParityCompletedFrame??0),readiness:v?.readiness??null,threeRuntimeResources:performance.getEntriesByType("resource").map(T=>T.name).filter(T=>T.includes("three.webgpu"))}}));throw new Error(`${f.message} Last ${r} state for "${e.key}": ${JSON.stringify({page:p,telemetry:u??null})}`)}let h=this.#n.read(e.key),g=(a$1(h)&&Array.isArray(h.demands)&&h.demands.length>0?JSON.stringify(h.demands).slice(0,6e3):void 0)??await J(()=>d.evaluate(u=>{let p=globalThis,m=Reflect.get(p,Symbol.for(u)),y=m!==null&&typeof m=="object"?Reflect.get(m,"readThreeBlocksShaderDemands"):void 0,v=typeof y=="function"?Reflect.apply(y,m,[]):void 0,b=p.__threeBlocksShaderTools,T=Array.isArray(v)&&v.length>0?v:b&&typeof b=="object"?Reflect.get(b,"demands"):void 0;return Array.isArray(T)&&T.length>0?JSON.stringify(T).slice(0,6e3):null},ee));throw typeof g=="string"?new Error(`${f.message}
|
|
80
|
+
${r} demands: ${g}`):f}finally{await O(()=>i.close());}}async observePublished(e,t,r="webgpu"){for(let a=0;a<2;a++)try{return await this.#b(e,r,t)}catch(o){if(a===0&&ve(o))continue;throw o}throw new Error(`Published shader observation retry was exhausted for scene "${e.key}".`)}async#b(e,t,r){if(await this.#g("precompiled",t,r),!this.#r||!this.#a)throw new Error("Shader browser driver did not start.");let a=this.#r,o=await this.#s(a,r,()=>a.newContext({viewport:r.viewport}));this.#e.url!==void 0&&await this.#s(a,r,()=>re(o,this.#t,this.#n,"precompiled",r,t,z(this.#e.runtime.three,t)));let s=await this.#s(a,r,()=>o.newPage()),i=te(s);this.#n.clear(e.key);try{await s.goto(ze(this.#a,e,t),{waitUntil:"domcontentloaded",timeout:r.timeoutMs}),await Promise.race([s.waitForFunction(r.bridge.legacyLab?"globalThis.__threeBlocks?.compileEnd === true":"globalThis.__threeBlocksShaderTools?.readiness?.compileEnd === true",void 0,{timeout:j(r)}),i.first.then(h=>Promise.reject(h))]),await Se(s,r,i),V(await W(s,r.bridge.legacyLab),e,r.bridge.legacyLab,this.#d(),z(this.#e.runtime.three,t)),await F(s,r,2);let d=await be(s),c=await F(s,r,120),w=await be(s),f=V(await W(s,r.bridge.legacyLab),e,r.bridge.legacyLab,this.#d(),z(this.#e.runtime.three,t));return {scene:e.key,mode:"precompiled",...f,frame:c,firstFrameScreenshot:d,beforeScreenshot:d,screenshot:w,errors:[...i.page,...i.console]}}finally{await O(()=>o.close());}}timingEnvironment(){return this.#w??{adapter:this.#p==="webgl"?"WebGL adapter":"WebGPU adapter",platform:`${x.platform}/${x.arch}`}}async close(){this.#t.rejectAll(new Error("Shader browser driver closed.")),this.#r&&await O(()=>this.#r?.close()??Promise.resolve());let e=this.#o?.httpServer,t=e?Reflect.get(e,"closeAllConnections"):void 0;if(e&&typeof t=="function"&&Reflect.apply(t,e,[]),this.#o&&await O(()=>this.#o?.close()??Promise.resolve()),this.#i){let r=this.#i;r.closeAllConnections(),await O(()=>new Promise(a=>{r.close(()=>a());}));}if(this.#r=void 0,this.#o=void 0,this.#i=void 0,this.#a=void 0,this.#h=void 0,this.#m=void 0,this.#l=void 0,this.#p=void 0,this.#w=void 0,this.#u=0,this.#c!==void 0&&(await rm(this.#c,{recursive:true,force:true}),this.#c=void 0),this.#f){for(let[r,a]of Object.entries(this.#f))a===void 0?delete x.env[r]:x.env[r]=a;this.#f=void 0;}}};function Tt(n){return new $(n)}a(Tt,"createPlaywrightShaderDriver");function kt(n){return new $(n)}a(kt,"createStaticPlaywrightShaderDriver");function Et(n){return new $(n)}a(Et,"createAttachedPlaywrightShaderDriver");export{Le as a,Z as b,fe as c,we as d,Je as e,Ke as f,oe as g,at as h,ve as i,Tt as j,kt as k,Et as l};
|
package/dist/cli.js
CHANGED
|
@@ -5,20 +5,20 @@ ${e}
|
|
|
5
5
|
`:t),r.includes("--yes"))return true;if(!o.stdin.isTTY||!o.stderr.isTTY)throw new Error("Adapter wiring needs consent. Review the diff above, then rerun with --yes; no files were changed.");let{createInterface:i}=await import('readline/promises'),n=i({input:o.stdin,output:o.stderr});try{let u=await n.question("Apply this patch? (y/N) ");return /^y(?:es)?$/iu.test(u.trim())}finally{n.close();}}a(pe,"approveAdapterPatch");function W(e){return g?{update(){},stop(){}}:h(e)}a(W,"wait");function fe(){let e$1=a(f=>b$1.accent(f),"c"),t=a(f=>b$1.dim(f),"d"),i=c.mark?`${c.mark} `:"",n=[["Inspect",[[`${e$1("status")}`,`project report: shaders, text, browser evidence ${t("\u2014 no browser, no GPU")}`],[`${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"]]],["Produce",[[`${e$1("shaders capture")} ${t("[--if-stale] [--commit-timing] [--driver static --serve dist]")}`,"capture shaders plus a local timing estimate; during development use the overlay Capture button"],[`${e$1("shaders watch")} ${t("[--debounce <ms>]")}`,"recapture automatically while you work"],[`${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"]]],["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"]]]],u=["",`${i}${b$1.bold("three-blocks devtools")} ${b$1.dim(`v${a$1}`)}`,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[f,a]of n)u.push("",b$1.bold(f),...e(a,{indent:2,maxWidth:a$2.width-2}));u.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("--headed"),"show the automation browser window"],[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("--url <url>"),"attach to an already-running transformed application"],[t("--yes"),"apply a previewed framework adapter patch non-interactively"]],{indent:2,maxWidth:a$2.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(u.join(`
|
|
6
6
|
`));}a(fe,"help");function he(e){return e?`${e.render} render \xB7 ${e.compute} compute`:"no coverage"}a(he,"coverageText");function Z(e){return e<100?e.toFixed(1):Math.round(e).toString()}a(Z,"milliseconds");function q(e,t,i){return `${e} ${d(t,12)} ${i}`}a(q,"row");function de(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)),i=e$1.scenes.length,n=[q(c.tick,"shaders",`captured in ${t} s ${c.dot} wrote ${i} shader scene${i===1?"":"s"}`)];e$1.configuration?.created===true&&n.push(b$1.dim(` created ${e$1.configuration.file} with the default "/" capture route`));for(let f of e$1.scenes)n.push(q(c.tick,f.scene,`${he(f.coverage)} ${c.dot} ${b$1.dim(`${f.attempts} attempt${f.attempts===1?"":"s"}`)}`));let u=e$1.scenes.flatMap(f=>{let a$1=f.timing;if(a$1?.launch===void 0||a$1.firstRequest===void 0||a$1.readiness===void 0||a$1.lastBuild===void 0||a$1.settled===void 0||a$1.posted===void 0)return [];let m=a((O,l)=>`${Z(Math.max(0,l-O))} ms`,"elapsed");return [[f.scene,`launch\u2192request ${m(a$1.launch,a$1.firstRequest)} ${c.dot} ready ${m(a$1.firstRequest,a$1.readiness)} ${c.dot} last build ${m(a$1.readiness,a$1.lastBuild)} ${c.dot} settle ${m(a$1.lastBuild,a$1.settled)} ${c.dot} post ${m(a$1.settled,a$1.posted)}`]]});return u.length>0&&n.push("",b$1.bold("Capture stages"),...e(u,{indent:2,maxWidth:a$2.width-2})),e$1.measurement!==void 0&&n.push(` TSL builds at startup: ${e$1.measurement.beforeBuilds} \u2192 ${e$1.measurement.afterBuilds} ${c.dot} \u2248${Z(Math.abs(e$1.measurement.firstFrameDeltaMs))} ms TSL work avoided (single-capture estimate)`),n.push(b$1.dim(" a running dev server reloads on its own; otherwise refresh the page")),n.join(`
|
|
7
7
|
`)}a(de,"formatShaderCapture");function me(e){let t=[q(c.tick,"shaders",`no-GPU ${e.noGpu.state} ${c.dot} browser ${e.browser}`)];for(let i of e.scenes){let n=e.timing?.scenes[i.scene],u=n===void 0?`${i.coverage.render+i.coverage.compute} TSL build${i.coverage.render+i.coverage.compute===1?"":"s"} skipped`:`${n.builds} TSL build${n.builds===1?"":"s"} skipped ${c.dot} \u2248${Z(n.avoidedBuildMs)} ms \xB1 ${Z(n.spreadMs)} TSL work avoided ${c.dot} median of ${n.runs} ${c.dot} Latest local capture`,f=n!==void 0&&n.spreadMs>n.avoidedBuildMs*.4?` ${c.dot} ${b$1.warn("noisy measurement \u2014 close other GPU apps and re-run")}`:"";t.push(q(c.tick,i.scene,`${u} ${c.dot} ${i.coverage.compute} compute ${c.dot} ${(i.parity.diffRatio*100).toFixed(3)}% pixel diff${f}`));}return t.join(`
|
|
8
|
-
`)}a(me,"formatShaderTest");async function we(){if(ae!==void 0)throw new Error(ae);if(y==="help"||y==="--help"||r.includes("--help"))return fe();if(y==="version"||r.includes("--version")){f(g?JSON.stringify({version:a$1}):a$1);return}if(y==="browser"){let{formatBrowserPreviewReport:a,formatBrowserSmokeReport:m,runBrowserPreview:O,runBrowserSmoke:l}=await import('./browser-smoke-
|
|
8
|
+
`)}a(me,"formatShaderTest");async function we(){if(ae!==void 0)throw new Error(ae);if(y==="help"||y==="--help"||r.includes("--help"))return fe();if(y==="version"||r.includes("--version")){f(g?JSON.stringify({version:a$1}):a$1);return}if(y==="browser"){let{formatBrowserPreviewReport:a,formatBrowserSmokeReport:m,runBrowserPreview:O,runBrowserSmoke:l}=await import('./browser-smoke-JHZLPGEB.js'),{findProjectRoot:k}=await import('./status-RFA7WAM6.js');if(R==="preview"){let P=$("--root")??await k(),M=le("--route"),B=$("--build-mode"),T=$("--expect-shaders")??"precompiled";if(T!=="precompiled"&&T!=="live")throw new Error('--expect-shaders must be "precompiled" or "live".');let I=b("--width"),D=b("--height"),j=b("--timeout"),J=b("--settle"),A=b("--min-luminance"),V=W("building and verifying the production bundle"),E;try{E=await O({root:P,...M.length===0?{}:{routes:M},...B===void 0?{}:{buildMode:B},expectShaders:T,text:r.includes("--text"),...j===void 0?{}:{timeoutMs:j},...J===void 0?{}:{settleMs:J},...A===void 0?{}:{minimumLuminance:A},...I===void 0&&D===void 0?{}:{viewport:{width:I??1024,height:D??640}},headed:r.includes("--headed")});}finally{V.stop();}o.stdout.write(`${g?JSON.stringify(E,null,2):a(E)}
|
|
9
9
|
`),E.passed||(o.exitCode=1);return}if(R!=="smoke")throw new Error(`Unsupported browser command "${R??""}".`);let S=$("--root")??await k(),h=b("--width"),x=b("--height"),v=$("--route"),N=b("--timeout"),L=b("--settle"),_=b("--min-luminance"),U=$("--hmr");if(r.includes("--webgl")&&r.includes("--unsupported-worker"))throw new Error("--webgl and --unsupported-worker are mutually exclusive.");let K=W(`smoking ${v??"/"} in a real browser`),w;try{w=await l({root:S,...v===void 0?{}:{route:v},...N===void 0?{}:{timeoutMs:N},...L===void 0?{}:{settleMs:L},..._===void 0?{}:{minimumLuminance:_},...U===void 0?{}:{hmrModule:U},forceWebgl:r.includes("--webgl"),unsupportedWorker:r.includes("--unsupported-worker"),expectTextGenerationFailure:r.includes("--expect-text-generation-failure"),...h===void 0&&x===void 0?{}:{viewport:{width:h??1024,height:x??640}},headed:r.includes("--headed")});}finally{K.stop();}o.stdout.write(`${g?JSON.stringify(w,null,2):m(w)}
|
|
10
|
-
`),w.passed||(o.exitCode=1);return}if(y==="environment"){if(R!=="bake")throw new Error(`Unsupported environment command "${R??""}".`);let{bakeRoomEnvironment:a,formatEnvironmentBakeReport:m}=await import('./environment-bake-
|
|
11
|
-
`);return}if(y==="shaders"){let{findShaderProjectRoot:a$1}=await import('./shader-config-EOFU5D3Y.js'),m=R??"status";if(!["status","capture","test","watch"].includes(m))throw new Error(`Unsupported shader command "${m}".`);let O=$("--root"),l=await a$1(O),k=$("--driver");if(k!==void 0&&k!=="vite"&&k!=="static")throw new Error('--driver must be "vite" or "static".');let S=k,h=$("--serve"),x=$("--url"),v=$("--backend");if(v!==void 0&&v!=="webgpu"&&v!=="webgl"&&v!=="both")throw new Error('--backend must be "webgpu", "webgl", or "both".');let N=v;if(m==="status"){let{inspectShaderMatrix:w}=await import('./shader-workflow-
|
|
12
|
-
`),(r.includes("--check")||R===void 0)&&M.state!=="fresh"&&(o.exitCode=1);return}if(m==="capture"){let{captureShaders:w}=await import('./shader-workflow-
|
|
10
|
+
`),w.passed||(o.exitCode=1);return}if(y==="environment"){if(R!=="bake")throw new Error(`Unsupported environment command "${R??""}".`);let{bakeRoomEnvironment:a,formatEnvironmentBakeReport:m}=await import('./environment-bake-BGMGFAVK.js'),{findProjectRoot:O}=await import('./status-RFA7WAM6.js'),l=$("--root")??await O(),k=b("--size"),S=$("--output"),h=b("--timeout"),x=W("baking the room environment on the GPU"),v;try{v=await a({root:l,...k===void 0?{}:{size:k},...S===void 0?{}:{output:S},...h===void 0?{}:{timeoutMs:h},compression:r.includes("--no-zstd")?"none":"zstd",headed:r.includes("--headed")});}finally{x.stop();}o.stdout.write(`${g?JSON.stringify(v,null,2):m(v)}
|
|
11
|
+
`);return}if(y==="shaders"){let{findShaderProjectRoot:a$1}=await import('./shader-config-EOFU5D3Y.js'),m=R??"status";if(!["status","capture","test","watch"].includes(m))throw new Error(`Unsupported shader command "${m}".`);let O=$("--root"),l=await a$1(O),k=$("--driver");if(k!==void 0&&k!=="vite"&&k!=="static")throw new Error('--driver must be "vite" or "static".');let S=k,h=$("--serve"),x=$("--url"),v=$("--backend");if(v!==void 0&&v!=="webgpu"&&v!=="webgl"&&v!=="both")throw new Error('--backend must be "webgpu", "webgl", or "both".');let N=v;if(m==="status"){let{inspectShaderMatrix:w}=await import('./shader-workflow-T7W7UHWJ.js'),{formatShaderMatrixStatus:P}=await import('./status-RFA7WAM6.js'),M=await w(l,void 0,N);o.stdout.write(`${g?JSON.stringify(M,null,2):P(M)}
|
|
12
|
+
`),(r.includes("--check")||R===void 0)&&M.state!=="fresh"&&(o.exitCode=1);return}if(m==="capture"){let{captureShaders:w}=await import('./shader-workflow-T7W7UHWJ.js'),{applyShaderAutoWire:P,hasRegisterDevtoolsCall:M,inspectShaderAutoWire:B}=await import('./shader-autowire-SPE5DM2X.js'),{buildShaderCaptureProject:T,startNextShaderCaptureServer:I}=await import('./shader-project-runner-S2AID2RJ.js'),{inferShaderCaptureTarget:D}=await import('./shader-config-EOFU5D3Y.js'),j=S,J=h,A=x,V,E,ee;try{if(j===void 0&&J===void 0&&A===void 0){let c=await B(l);if(!c.configured&&c.plan!==void 0){if(!await pe(c.plan.diff))throw new Error("Adapter wiring was declined; no files were changed.");await P(c.plan);}else if(!c.configured&&c.bundler!=="vite"&&c.bundler!=="unknown")throw new Error(`${c.reason} No files were changed.`);if(c.bundler==="next")E=W("starting the project-local Next.js capture server"),V=await I(l),A=V.url,E.update("capturing shader scenes");else if(c.bundler==="webpack"||c.bundler==="esbuild"||c.bundler==="rollup"){E=W(`building the ${c.bundler} capture target`),await T(l);let C=await D(l);if(C.driverKind!=="static"||C.serve===void 0)throw new Error(`${c.bundler} build completed but no dist/, build/, or out/index.html was found; pass --driver static --serve <directory>.`);j="static",J=C.serve,E.update("capturing shader scenes");}}E??=W("capturing shader scenes"),ee=await w({root:l,headed:r.includes("--headed"),ifStale:r.includes("--if-stale"),commitTiming:r.includes("--commit-timing"),...N===void 0?{}:{backend:N},...j===void 0?{}:{driverKind:j},...J===void 0?{}:{serve:J},...A===void 0?{}:{url:A},onSceneStart:a((c,C,H)=>E?.update(`capturing ${b$1.accent(c)} ${b$1.dim(`(${C+1}/${H})`)}`),"onSceneStart"),onSceneRetry:a((c,C,H,ie,z)=>{let ue=z instanceof Error&&/timed out/iu.test(z.message),se=`capture attempt ${C}/${H} for "${c}" after ${ue?`timeout (${Math.round(ie/1e3)} s burned)`:`failure (${z instanceof Error?z.message:String(z)})`}`;o.stderr.write(g?`${JSON.stringify({type:"shader-capture-retry",scene:c,attempt:C,total:H,timeoutMs:ie,message:se})}
|
|
13
13
|
`:`${se}
|
|
14
14
|
`);},"onSceneRetry")});}finally{E?.stop(),await V?.close();}if(o.stdout.write(`${g?JSON.stringify(ee,null,2):de(ee)}
|
|
15
15
|
`),!await M(l)){let c$1="Add registerDevtools({ renderer }) from three-blocks/devtools so committed shader artifacts hydrate in development and production.";o.stderr.write(g?`${JSON.stringify({type:"shader-runtime-registration",state:"missing",message:c$1})}
|
|
16
16
|
`:`${c.warn} ${c$1}
|
|
17
|
-
`);}return}if(m==="test"){let w=$("--mode");if(w!==void 0&&w!=="strict")throw new Error('--mode currently supports only "strict".');let{testShaders:P}=await import('./shader-workflow-
|
|
18
|
-
`);return}let L=b("--debounce"),{watchShaders:_}=await import('./shader-watch-
|
|
17
|
+
`);}return}if(m==="test"){let w=$("--mode");if(w!==void 0&&w!=="strict")throw new Error('--mode currently supports only "strict".');let{testShaders:P}=await import('./shader-workflow-T7W7UHWJ.js'),M=W("verifying precompiled shaders against the live baseline"),B=b("--runs"),T;try{T=await P({root:l,headed:r.includes("--headed"),skipBrowser:r.includes("--skip-browser"),...S===void 0?{}:{driverKind:S},...h===void 0?{}:{serve:h},...x===void 0?{}:{url:x},...B===void 0?{}:{runs:B},parityOnly:r.includes("--parity-only"),commitTiming:r.includes("--commit-timing"),...N===void 0?{}:{backend:N},onSceneStart:a((I,D,j)=>M.update(`verifying ${b$1.accent(I)} ${b$1.dim(`(${D+1}/${j})`)}`),"onSceneStart")});}finally{M.stop();}o.stdout.write(`${g?JSON.stringify(T,null,2):me(T)}
|
|
18
|
+
`);return}let L=b("--debounce"),{watchShaders:_}=await import('./shader-watch-XY6A2KGQ.js'),U=new AbortController;o.once("SIGINT",()=>U.abort()),o.once("SIGTERM",()=>U.abort());let K=await _({root:l,headed:r.includes("--headed"),...S===void 0?{}:{driverKind:S},...h===void 0?{}:{serve:h},...x===void 0?{}:{url:x},...L===void 0?{}:{debounceMs:L},signal:U.signal,onResult(w){o.stdout.write(`${g?JSON.stringify(w):de(w)}
|
|
19
19
|
`);},onError(w){o.stderr.write(`${g?JSON.stringify({error:w.message}):`${c.cross} ${b$1.danger(w.message)}`}
|
|
20
|
-
`);}});g||f(q(c.ring,"watching",b$1.dim(K.root))),await K.done;return}if(y==="text"&&R&&R!=="status"){if(R!=="generate")throw new Error(`Unsupported text command "${R}".`);let{generateTextAtlases:a}=await import('./text-atlas-WRYJT3E7.js'),{findProjectRoot:m}=await import('./status-
|
|
21
|
-
`);else {f(q(c.tick,"text",`${h.glyphs} glyphs ${c.dot} ${h.atlases.length} atlas${h.atlases.length===1?"":"es"} regenerated`));for(let x of h.updatedFiles)f(` ${d(b$1.dim("updated"),12)} ${b$1.dim(x)}`);}return}if(!["status","text"].includes(y))throw new Error(`Unknown command "${y}".`);let{formatThreeBlocksStatus:e,inspectThreeBlocksStatus:t,threeBlocksStatusIsFresh:i}=await import('./status-
|
|
20
|
+
`);}});g||f(q(c.ring,"watching",b$1.dim(K.root))),await K.done;return}if(y==="text"&&R&&R!=="status"){if(R!=="generate")throw new Error(`Unsupported text command "${R}".`);let{generateTextAtlases:a}=await import('./text-atlas-WRYJT3E7.js'),{findProjectRoot:m}=await import('./status-RFA7WAM6.js'),O=r.indexOf("--config"),l=O===-1?"three-blocks.text.ts":r[O+1];if(l===void 0||l.startsWith("--"))throw new Error("--config requires a project-relative path.");let k=await m(),S=W("generating MSDF text atlases"),h;try{h=await a(k,l);}finally{S.stop();}if(g)o.stdout.write(`${JSON.stringify(h,null,2)}
|
|
21
|
+
`);else {f(q(c.tick,"text",`${h.glyphs} glyphs ${c.dot} ${h.atlases.length} atlas${h.atlases.length===1?"":"es"} regenerated`));for(let x of h.updatedFiles)f(` ${d(b$1.dim("updated"),12)} ${b$1.dim(x)}`);}return}if(!["status","text"].includes(y))throw new Error(`Unknown command "${y}".`);let{formatThreeBlocksStatus:e,inspectThreeBlocksStatus:t,threeBlocksStatusIsFresh:i}=await import('./status-RFA7WAM6.js'),n=await t(),u=(n.text);if(y==="text"&&!u)throw new Error("This project does not enable the text feature.");let f$1=y==="text"?u:n;o.stdout.write(`${g?JSON.stringify(f$1,null,2):y==="status"?e(n):JSON.stringify(f$1,null,2)}
|
|
22
22
|
`),y==="status"&&r.includes("--check")&&!i(n)&&(o.exitCode=1);}a(we,"main");we().catch(e=>{let t=e instanceof Error?e.message:String(e);g?o.stderr.write(`${JSON.stringify({error:t})}
|
|
23
23
|
`):o.stderr.write(`${c.cross} ${b$1.danger(t)}
|
|
24
24
|
`),o.exitCode=1;});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {b,d,a as a$2}from'./chunk-W6UL2OW7.js';import {a as a$1,c,d as d$1,h,e}from'./chunk-5L2VS3BN.js';import {a}from'./chunk-HOZDD6PW.js';import {randomUUID}from'crypto';import {mkdir,lstat,realpath,writeFile,rename,rm,readFile}from'fs/promises';import p from'path';import {fileURLToPath}from'url';import F from'zlib';import {VK_FORMAT_R16G16B16A16_SFLOAT,KHR_SUPERCOMPRESSION_NONE,read,KHR_SUPERCOMPRESSION_ZSTD,write}from'ktx-parse';var N="/__three-blocks/devtools/environment-bake",Q="/__three-blocks/devtools/environment-bake/upload",T="virtual:three-blocks-devtools/environment-bake.ts",O=`\0${T}`,q=`/@id/__x00__${T}`,ee="src/assets/environment/room-environment.pmrem.ktx2",_=128*1024*1024,te=1;async function re(){try{let[e,r]=await Promise.all([import('playwright'),import('vite')]);return {chromium:e.chromium,createServer:r.createServer}}catch(e){throw new Error('Environment baking requires the optional "playwright" and "vite" packages. Install both in the project and run `npx playwright install chromium`.',{cause:e})}}a(re,"loadEnvironmentBakeBrowserTools");function j(e,r,t,n,o){let d=e??o;if(!Number.isSafeInteger(d)||d<t||d>n)throw new Error(`${r} must be an integer in ${t}...${n}.`);return d}a(j,"boundedInteger");function V(e){let r=j(e,"Environment cube size",16,1024,256);if((r&r-1)!==0)throw new Error("Environment cube size must be a power of two.");return r}a(V,"validateEnvironmentCubeSize");function ne(){return F}a(ne,"zstdFunctions");function oe(e){if(!/^[0-9A-Za-z][0-9A-Za-z.+_-]{0,63}$/u.test(e))throw new Error("Browser reported an invalid Three.js revision.");return e}a(oe,"boundedThreeRevision");function ie(e){if(e.vkFormat!==VK_FORMAT_R16G16B16A16_SFLOAT)throw new Error("RoomEnvironment bake must be RGBA16F KTX2.");if(e.typeSize!==2)throw new Error("RoomEnvironment RGBA16F KTX2 must use a two-byte component type.");if(e.supercompressionScheme!==KHR_SUPERCOMPRESSION_NONE)throw new Error("Browser RoomEnvironment KTX2 must be uncompressed before deterministic encoding.");if(!Number.isSafeInteger(e.pixelWidth)||e.pixelWidth<=0||e.pixelWidth>8192||!Number.isSafeInteger(e.pixelHeight)||e.pixelHeight<=0||e.pixelHeight>8192||e.pixelDepth!==0||e.layerCount!==0||e.faceCount!==1||e.levels.length!==1||e.levels[0]===void 0)throw new Error("RoomEnvironment KTX2 has invalid CubeUV dimensions or topology.");let r=e.pixelWidth*e.pixelHeight*8;if(!Number.isSafeInteger(r)||r>_)throw new Error("RoomEnvironment KTX2 decoded payload exceeds the safety limit.");let t=e.levels[0],n=r+e.pixelHeight*256;if(t.levelData.byteLength<r||t.levelData.byteLength>n||t.levelData.byteLength%8!==0||t.uncompressedByteLength!==t.levelData.byteLength)throw new Error(`RoomEnvironment KTX2 level byte count ${t.levelData.byteLength} is outside the bounded RGBA16F CubeUV layout.`);return e.levels.map(o=>new Uint8Array(o.levelData))}a(ie,"validateRawContainer");function ae(e,r){return e.byteLength===r.byteLength&&Buffer.from(e).equals(Buffer.from(r))}a(ae,"sameBytes");function se(e,r){let t=V(r.cubeSize),n=oe(r.threeRevision);if(e.byteLength===0||e.byteLength>a$1.texture)throw new Error("RoomEnvironment KTX2 input exceeds the bounded texture size.");let o=read(e),d=ie(o),m=r.compression??"zstd",c$1=ne(),f=F.constants.ZSTD_c_compressionLevel;if(m==="zstd"&&(c$1.zstdCompressSync===void 0||c$1.zstdDecompressSync===void 0||f===void 0))throw new Error("This Node.js runtime does not provide deterministic Zstandard support; use --no-zstd explicitly to opt out.");if(o.supercompressionScheme=m==="zstd"?KHR_SUPERCOMPRESSION_ZSTD:KHR_SUPERCOMPRESSION_NONE,o.levelCount=d.length,o.levels=d.map(a=>{let l=m==="zstd"?c$1.zstdCompressSync?.(a,{params:{[f]:19}}):void 0;return {levelData:l===void 0?a:new Uint8Array(l.buffer,l.byteOffset,l.byteLength),uncompressedByteLength:a.byteLength}}),m==="zstd")for(let a of o.dataFormatDescriptor)a.bytesPlane=[0,0,0,0,0,0,0,0];o.keyValue={KTXorientation:"rd",KTXwriter:`three-blocks RoomEnvironment \xB7 three r${n}`};let u=write(o,{keepWriter:true});if(u.byteLength===0||u.byteLength>a$1.texture)throw new Error("Encoded RoomEnvironment KTX2 exceeds the bounded texture size.");let i=read(u);if(i.vkFormat!==VK_FORMAT_R16G16B16A16_SFLOAT||i.pixelWidth!==o.pixelWidth||i.pixelHeight!==o.pixelHeight||i.supercompressionScheme!==o.supercompressionScheme||i.keyValue.KTXorientation!=="rd"||i.levels.length!==d.length)throw new Error("RoomEnvironment KTX2 header failed round-trip validation.");for(let a=0;a<i.levels.length;a+=1){let l=i.levels[a],g=d[a];if(l===void 0||g===void 0)throw new Error(`RoomEnvironment KTX2 level ${a} is missing after round-trip.`);let R=m==="zstd"?c$1.zstdDecompressSync?.(l.levelData):l.levelData;if(R===void 0||l.uncompressedByteLength!==g.byteLength||!ae(R,g))throw new Error(`RoomEnvironment KTX2 level ${a} failed byte-for-byte round-trip validation.`)}let h=d.reduce((a,l)=>a+l.byteLength,0);return {bytes:u,metadata:{compression:m,cubeSize:t,format:"RGBA16F CubeUVReflectionMapping",height:i.pixelHeight,rawBytes:h,sha256:c(u),three:n,version:te,width:i.pixelWidth}}}a(se,"encodeRoomEnvironmentKtx2");var S=class{static{a(this,"BakeInbox");}promise;#t=a(()=>{},"#resolve");#r=a(()=>{},"#reject");#e=false;constructor(){this.promise=new Promise((r,t)=>{this.#t=r,this.#r=t;});}receive(r){return this.#e?false:(this.#e=true,this.#t(r),true)}reject(r){this.#e||(this.#e=true,this.#r(r));}};function ue(e){if(e.url!==void 0)try{return new URL(e.url,"http://three-blocks.invalid").pathname}catch{return}}a(ue,"requestPath");function y(e,r,t=""){e.statusCode=r,e.setHeader("Content-Type",t.startsWith("<!")?"text/html; charset=utf-8":"text/plain; charset=utf-8"),e.setHeader("Cache-Control","no-store"),e.end(t);}a(y,"respond");function de(e,r){return {name:"three-blocks:environment-bake",enforce:"post",resolveId(t){return t===T?O:void 0},load(t){return t===O?r:void 0},configureServer(t){t.middlewares.use((n,o,d)=>{let m=ue(n);if(m===N&&(n.method==="GET"||n.method==="HEAD")){let a=n.method==="HEAD"?"":`<!doctype html><html lang="en"><head><meta charset="utf-8"><title>Three Blocks environment bake</title></head><body><canvas id="three-blocks-environment-baker" width="1" height="1"></canvas><script type="module" src="${q}"></script></body></html>`;y(o,200,a);return}if(m!==Q)return d();if(n.method!=="POST"){y(o,405,"POST required");return}let c=n.headers["content-type"];if(typeof c!="string"||!c.toLowerCase().startsWith("image/ktx2")){y(o,415,"image/ktx2 required");return}let f=Number(n.headers["content-length"]??0);if(Number.isFinite(f)&&f>_){y(o,413,"Bake payload exceeds 128 MiB");return}let u=[],i=0,h=false;n.on("data",a=>{i+=a.byteLength,i>_?h=true:u.push(a);}),n.on("error",a=>e.reject(a)),n.on("end",()=>{if(h){y(o,413,"Bake payload exceeds 128 MiB"),e.reject(new Error("RoomEnvironment bake upload exceeded 128 MiB."));return}let a=n.headers["x-three-revision"];if(typeof a!="string"){y(o,400,"x-three-revision required"),e.reject(new Error("RoomEnvironment upload omitted the Three.js revision."));return}let l=e.receive({bytes:new Uint8Array(Buffer.concat(u)),threeRevision:a});y(o,l?204:409,l?"":"Bake upload already received");});});}}}a(de,"bakePlugin");async function me(){let e=p.dirname(fileURLToPath(import.meta.url)),r=[p.join(e,"browser","environment-bake.js"),p.join(e,"browser","environment-bake.ts")];for(let t of r)if(await d$1(t))return (await h(t,a$1.semanticInput,"Environment bake browser entry")).data.toString("utf8");throw new Error("The separately built environment bake browser entry is missing.")}a(me,"browserEntrySource");function ce(e){return new Promise((r,t)=>{e.on("pageerror",n=>{a$2(n.message)||t(n);}),e.on("console",n=>{n.type()==="error"&&!a$2(n.text())&&t(new Error(n.text()));});})}a(ce,"pageFailure");async function le(e,r){await e.waitForFunction(()=>globalThis.__THREE_BLOCKS_ROOM_ENVIRONMENT_BAKE__!==void 0,void 0,{timeout:Math.min(r,3e4)});let t=await e.evaluate(()=>globalThis.__THREE_BLOCKS_ROOM_ENVIRONMENT_BAKE__);if(!t||typeof t!="object"||Reflect.get(t,"ok")!==true){let n=t&&typeof t=="object"?Reflect.get(t,"error"):void 0;throw new Error(typeof n=="string"?n:"Browser RoomEnvironment bake did not report success.")}}a(le,"readBrowserBakeResult");var pe=a(async e=>{let{chromium:r,createServer:t}=await re(),n=new S,o,d$1,m,c,f=false;try{let u=await me();o=await t({root:e.root,configFile:!1,logLevel:"silent",optimizeDeps:{noDiscovery:!0},plugins:[de(n,u)],server:{host:"127.0.0.1",port:0,strictPort:!1}}),await o.listen();let i=o.httpServer?.address();if(!i||typeof i=="string")throw new Error("Environment bake Vite server has no ephemeral TCP address.");d$1=await r.launch({headless:d(e.headed),args:[...b()]}),m=await d$1.newContext({viewport:{width:320,height:240}});let h=await m.newPage(),a=ce(h),l=new Promise((R,H)=>{c=setTimeout(()=>H(new Error(`RoomEnvironment bake timed out after ${e.timeoutMs}ms.`)),e.timeoutMs),c.unref();});await h.goto(`http://127.0.0.1:${i.port}${N}?size=${e.size}`,{waitUntil:"domcontentloaded",timeout:Math.min(e.timeoutMs,3e4)});let g=await Promise.race([n.promise,a,l]);return await le(h,e.timeoutMs),g}catch(u){throw f=true,n.reject(u instanceof Error?u:new Error(String(u))),await n.promise.catch(()=>{}),u}finally{c&&clearTimeout(c);let u=[];if(await m?.close().catch(i=>u.push(`context: ${i instanceof Error?i.message:String(i)}`)),await d$1?.close().catch(i=>u.push(`browser: ${i instanceof Error?i.message:String(i)}`)),await o?.close().catch(i=>u.push(`Vite: ${i instanceof Error?i.message:String(i)}`)),!f&&u.length>0)throw new Error(`RoomEnvironment cleanup failed (${u.join("; ")}).`)}},"captureRoomEnvironment");function fe(e$1,r){let t=r??ee;if(p.isAbsolute(t)||t.length===0||t.length>2048||/[\u0000-\u001f\u007f]/u.test(t)||!t.endsWith(".ktx2"))throw new Error("Environment output must be a bounded project-relative .ktx2 path.");let n=p.resolve(e$1,t);if(!e(e$1,n)||n===e$1)throw new Error("Environment output escapes the project root.");return {asset:n,metadata:`${n.slice(0,-5)}.json`}}a(fe,"outputPaths");async function he(e$1,r){let t=p.relative(e$1,r);if(t==="")return;let n=e$1;for(let d of t.split(p.sep)){n=p.join(n,d),await d$1(n)||await mkdir(n);let m=await lstat(n);if(m.isSymbolicLink()||!m.isDirectory())throw new Error(`Environment output parent is not a real directory: ${n}.`)}let o=await realpath(r);if(!e(e$1,o))throw new Error("Environment output parent resolves outside the project root.")}a(he,"ensureSafeParent");async function M(e){if(!await d$1(e))return;let r=await lstat(e);if(r.isSymbolicLink()||!r.isFile())throw new Error(`Environment output target must be a regular file: ${e}.`)}a(M,"validateOutputTarget");async function ve(e,r,t,n){await Promise.all([M(e),M(t)]);let o=`${process.pid}-${randomUUID()}`,d=p.join(p.dirname(e),`.${p.basename(e)}.${o}.tmp`),m=p.join(p.dirname(t),`.${p.basename(t)}.${o}.tmp`),c=`${d}.backup`,f=`${m}.backup`,u=false,i=false,h=false,a=false;try{await Promise.all([writeFile(d,r,{flag:"wx"}),writeFile(m,n,{encoding:"utf8",flag:"wx"})]),await d$1(e)&&(await rename(e,c),u=!0),await d$1(t)&&(await rename(t,f),i=!0),await rename(d,e),h=!0,await rename(m,t),a=!0,await Promise.all([rm(c,{force:!0}),rm(f,{force:!0})]);}catch(l){throw a&&await rm(t,{force:true}),h&&await rm(e,{force:true}),i&&await rename(f,t),u&&await rename(c,e),l}finally{await Promise.all([rm(d,{force:true}),rm(m,{force:true}),rm(c,{force:true}),rm(f,{force:true})]);}}a(ve,"writeAtomicPair");function U(e,r){return p.relative(e,r).split(p.sep).join("/")}a(U,"portableRelative");async function _e(e){let r=await realpath(e.root),t=V(e.size??256),n=j(e.timeoutMs,"Environment bake timeoutMs",1e3,15*6e4,24e4),o=fe(r,e.output);await he(r,p.dirname(o.asset));let m=await(e.capture??pe)({root:r,size:t,timeoutMs:n,headed:e.headed===true}),c$1=se(m.bytes,{cubeSize:t,threeRevision:m.threeRevision,compression:e.compression??"zstd"}),f=`${JSON.stringify(c$1.metadata,null,2)}
|
|
2
|
+
import {b,d,a as a$2}from'./chunk-QJFPNM6W.js';import {a as a$1,c,d as d$1,h,e}from'./chunk-5L2VS3BN.js';import {a}from'./chunk-HOZDD6PW.js';import {randomUUID}from'crypto';import {mkdir,lstat,realpath,writeFile,rename,rm,readFile}from'fs/promises';import p from'path';import {fileURLToPath}from'url';import F from'zlib';import {VK_FORMAT_R16G16B16A16_SFLOAT,KHR_SUPERCOMPRESSION_NONE,read,KHR_SUPERCOMPRESSION_ZSTD,write}from'ktx-parse';var N="/__three-blocks/devtools/environment-bake",Q="/__three-blocks/devtools/environment-bake/upload",T="virtual:three-blocks-devtools/environment-bake.ts",O=`\0${T}`,q=`/@id/__x00__${T}`,ee="src/assets/environment/room-environment.pmrem.ktx2",_=128*1024*1024,te=1;async function re(){try{let[e,r]=await Promise.all([import('playwright'),import('vite')]);return {chromium:e.chromium,createServer:r.createServer}}catch(e){throw new Error('Environment baking requires the optional "playwright" and "vite" packages. Install both in the project and run `npx playwright install chromium`.',{cause:e})}}a(re,"loadEnvironmentBakeBrowserTools");function j(e,r,t,n,o){let d=e??o;if(!Number.isSafeInteger(d)||d<t||d>n)throw new Error(`${r} must be an integer in ${t}...${n}.`);return d}a(j,"boundedInteger");function V(e){let r=j(e,"Environment cube size",16,1024,256);if((r&r-1)!==0)throw new Error("Environment cube size must be a power of two.");return r}a(V,"validateEnvironmentCubeSize");function ne(){return F}a(ne,"zstdFunctions");function oe(e){if(!/^[0-9A-Za-z][0-9A-Za-z.+_-]{0,63}$/u.test(e))throw new Error("Browser reported an invalid Three.js revision.");return e}a(oe,"boundedThreeRevision");function ie(e){if(e.vkFormat!==VK_FORMAT_R16G16B16A16_SFLOAT)throw new Error("RoomEnvironment bake must be RGBA16F KTX2.");if(e.typeSize!==2)throw new Error("RoomEnvironment RGBA16F KTX2 must use a two-byte component type.");if(e.supercompressionScheme!==KHR_SUPERCOMPRESSION_NONE)throw new Error("Browser RoomEnvironment KTX2 must be uncompressed before deterministic encoding.");if(!Number.isSafeInteger(e.pixelWidth)||e.pixelWidth<=0||e.pixelWidth>8192||!Number.isSafeInteger(e.pixelHeight)||e.pixelHeight<=0||e.pixelHeight>8192||e.pixelDepth!==0||e.layerCount!==0||e.faceCount!==1||e.levels.length!==1||e.levels[0]===void 0)throw new Error("RoomEnvironment KTX2 has invalid CubeUV dimensions or topology.");let r=e.pixelWidth*e.pixelHeight*8;if(!Number.isSafeInteger(r)||r>_)throw new Error("RoomEnvironment KTX2 decoded payload exceeds the safety limit.");let t=e.levels[0],n=r+e.pixelHeight*256;if(t.levelData.byteLength<r||t.levelData.byteLength>n||t.levelData.byteLength%8!==0||t.uncompressedByteLength!==t.levelData.byteLength)throw new Error(`RoomEnvironment KTX2 level byte count ${t.levelData.byteLength} is outside the bounded RGBA16F CubeUV layout.`);return e.levels.map(o=>new Uint8Array(o.levelData))}a(ie,"validateRawContainer");function ae(e,r){return e.byteLength===r.byteLength&&Buffer.from(e).equals(Buffer.from(r))}a(ae,"sameBytes");function se(e,r){let t=V(r.cubeSize),n=oe(r.threeRevision);if(e.byteLength===0||e.byteLength>a$1.texture)throw new Error("RoomEnvironment KTX2 input exceeds the bounded texture size.");let o=read(e),d=ie(o),m=r.compression??"zstd",c$1=ne(),f=F.constants.ZSTD_c_compressionLevel;if(m==="zstd"&&(c$1.zstdCompressSync===void 0||c$1.zstdDecompressSync===void 0||f===void 0))throw new Error("This Node.js runtime does not provide deterministic Zstandard support; use --no-zstd explicitly to opt out.");if(o.supercompressionScheme=m==="zstd"?KHR_SUPERCOMPRESSION_ZSTD:KHR_SUPERCOMPRESSION_NONE,o.levelCount=d.length,o.levels=d.map(a=>{let l=m==="zstd"?c$1.zstdCompressSync?.(a,{params:{[f]:19}}):void 0;return {levelData:l===void 0?a:new Uint8Array(l.buffer,l.byteOffset,l.byteLength),uncompressedByteLength:a.byteLength}}),m==="zstd")for(let a of o.dataFormatDescriptor)a.bytesPlane=[0,0,0,0,0,0,0,0];o.keyValue={KTXorientation:"rd",KTXwriter:`three-blocks RoomEnvironment \xB7 three r${n}`};let u=write(o,{keepWriter:true});if(u.byteLength===0||u.byteLength>a$1.texture)throw new Error("Encoded RoomEnvironment KTX2 exceeds the bounded texture size.");let i=read(u);if(i.vkFormat!==VK_FORMAT_R16G16B16A16_SFLOAT||i.pixelWidth!==o.pixelWidth||i.pixelHeight!==o.pixelHeight||i.supercompressionScheme!==o.supercompressionScheme||i.keyValue.KTXorientation!=="rd"||i.levels.length!==d.length)throw new Error("RoomEnvironment KTX2 header failed round-trip validation.");for(let a=0;a<i.levels.length;a+=1){let l=i.levels[a],g=d[a];if(l===void 0||g===void 0)throw new Error(`RoomEnvironment KTX2 level ${a} is missing after round-trip.`);let R=m==="zstd"?c$1.zstdDecompressSync?.(l.levelData):l.levelData;if(R===void 0||l.uncompressedByteLength!==g.byteLength||!ae(R,g))throw new Error(`RoomEnvironment KTX2 level ${a} failed byte-for-byte round-trip validation.`)}let h=d.reduce((a,l)=>a+l.byteLength,0);return {bytes:u,metadata:{compression:m,cubeSize:t,format:"RGBA16F CubeUVReflectionMapping",height:i.pixelHeight,rawBytes:h,sha256:c(u),three:n,version:te,width:i.pixelWidth}}}a(se,"encodeRoomEnvironmentKtx2");var S=class{static{a(this,"BakeInbox");}promise;#t=a(()=>{},"#resolve");#r=a(()=>{},"#reject");#e=false;constructor(){this.promise=new Promise((r,t)=>{this.#t=r,this.#r=t;});}receive(r){return this.#e?false:(this.#e=true,this.#t(r),true)}reject(r){this.#e||(this.#e=true,this.#r(r));}};function ue(e){if(e.url!==void 0)try{return new URL(e.url,"http://three-blocks.invalid").pathname}catch{return}}a(ue,"requestPath");function y(e,r,t=""){e.statusCode=r,e.setHeader("Content-Type",t.startsWith("<!")?"text/html; charset=utf-8":"text/plain; charset=utf-8"),e.setHeader("Cache-Control","no-store"),e.end(t);}a(y,"respond");function de(e,r){return {name:"three-blocks:environment-bake",enforce:"post",resolveId(t){return t===T?O:void 0},load(t){return t===O?r:void 0},configureServer(t){t.middlewares.use((n,o,d)=>{let m=ue(n);if(m===N&&(n.method==="GET"||n.method==="HEAD")){let a=n.method==="HEAD"?"":`<!doctype html><html lang="en"><head><meta charset="utf-8"><title>Three Blocks environment bake</title></head><body><canvas id="three-blocks-environment-baker" width="1" height="1"></canvas><script type="module" src="${q}"></script></body></html>`;y(o,200,a);return}if(m!==Q)return d();if(n.method!=="POST"){y(o,405,"POST required");return}let c=n.headers["content-type"];if(typeof c!="string"||!c.toLowerCase().startsWith("image/ktx2")){y(o,415,"image/ktx2 required");return}let f=Number(n.headers["content-length"]??0);if(Number.isFinite(f)&&f>_){y(o,413,"Bake payload exceeds 128 MiB");return}let u=[],i=0,h=false;n.on("data",a=>{i+=a.byteLength,i>_?h=true:u.push(a);}),n.on("error",a=>e.reject(a)),n.on("end",()=>{if(h){y(o,413,"Bake payload exceeds 128 MiB"),e.reject(new Error("RoomEnvironment bake upload exceeded 128 MiB."));return}let a=n.headers["x-three-revision"];if(typeof a!="string"){y(o,400,"x-three-revision required"),e.reject(new Error("RoomEnvironment upload omitted the Three.js revision."));return}let l=e.receive({bytes:new Uint8Array(Buffer.concat(u)),threeRevision:a});y(o,l?204:409,l?"":"Bake upload already received");});});}}}a(de,"bakePlugin");async function me(){let e=p.dirname(fileURLToPath(import.meta.url)),r=[p.join(e,"browser","environment-bake.js"),p.join(e,"browser","environment-bake.ts")];for(let t of r)if(await d$1(t))return (await h(t,a$1.semanticInput,"Environment bake browser entry")).data.toString("utf8");throw new Error("The separately built environment bake browser entry is missing.")}a(me,"browserEntrySource");function ce(e){return new Promise((r,t)=>{e.on("pageerror",n=>{a$2(n.message)||t(n);}),e.on("console",n=>{n.type()==="error"&&!a$2(n.text())&&t(new Error(n.text()));});})}a(ce,"pageFailure");async function le(e,r){await e.waitForFunction(()=>globalThis.__THREE_BLOCKS_ROOM_ENVIRONMENT_BAKE__!==void 0,void 0,{timeout:Math.min(r,3e4)});let t=await e.evaluate(()=>globalThis.__THREE_BLOCKS_ROOM_ENVIRONMENT_BAKE__);if(!t||typeof t!="object"||Reflect.get(t,"ok")!==true){let n=t&&typeof t=="object"?Reflect.get(t,"error"):void 0;throw new Error(typeof n=="string"?n:"Browser RoomEnvironment bake did not report success.")}}a(le,"readBrowserBakeResult");var pe=a(async e=>{let{chromium:r,createServer:t}=await re(),n=new S,o,d$1,m,c,f=false;try{let u=await me();o=await t({root:e.root,configFile:!1,logLevel:"silent",optimizeDeps:{noDiscovery:!0},plugins:[de(n,u)],server:{host:"127.0.0.1",port:0,strictPort:!1}}),await o.listen();let i=o.httpServer?.address();if(!i||typeof i=="string")throw new Error("Environment bake Vite server has no ephemeral TCP address.");d$1=await r.launch({headless:d(e.headed),args:[...b()]}),m=await d$1.newContext({viewport:{width:320,height:240}});let h=await m.newPage(),a=ce(h),l=new Promise((R,H)=>{c=setTimeout(()=>H(new Error(`RoomEnvironment bake timed out after ${e.timeoutMs}ms.`)),e.timeoutMs),c.unref();});await h.goto(`http://127.0.0.1:${i.port}${N}?size=${e.size}`,{waitUntil:"domcontentloaded",timeout:Math.min(e.timeoutMs,3e4)});let g=await Promise.race([n.promise,a,l]);return await le(h,e.timeoutMs),g}catch(u){throw f=true,n.reject(u instanceof Error?u:new Error(String(u))),await n.promise.catch(()=>{}),u}finally{c&&clearTimeout(c);let u=[];if(await m?.close().catch(i=>u.push(`context: ${i instanceof Error?i.message:String(i)}`)),await d$1?.close().catch(i=>u.push(`browser: ${i instanceof Error?i.message:String(i)}`)),await o?.close().catch(i=>u.push(`Vite: ${i instanceof Error?i.message:String(i)}`)),!f&&u.length>0)throw new Error(`RoomEnvironment cleanup failed (${u.join("; ")}).`)}},"captureRoomEnvironment");function fe(e$1,r){let t=r??ee;if(p.isAbsolute(t)||t.length===0||t.length>2048||/[\u0000-\u001f\u007f]/u.test(t)||!t.endsWith(".ktx2"))throw new Error("Environment output must be a bounded project-relative .ktx2 path.");let n=p.resolve(e$1,t);if(!e(e$1,n)||n===e$1)throw new Error("Environment output escapes the project root.");return {asset:n,metadata:`${n.slice(0,-5)}.json`}}a(fe,"outputPaths");async function he(e$1,r){let t=p.relative(e$1,r);if(t==="")return;let n=e$1;for(let d of t.split(p.sep)){n=p.join(n,d),await d$1(n)||await mkdir(n);let m=await lstat(n);if(m.isSymbolicLink()||!m.isDirectory())throw new Error(`Environment output parent is not a real directory: ${n}.`)}let o=await realpath(r);if(!e(e$1,o))throw new Error("Environment output parent resolves outside the project root.")}a(he,"ensureSafeParent");async function M(e){if(!await d$1(e))return;let r=await lstat(e);if(r.isSymbolicLink()||!r.isFile())throw new Error(`Environment output target must be a regular file: ${e}.`)}a(M,"validateOutputTarget");async function ve(e,r,t,n){await Promise.all([M(e),M(t)]);let o=`${process.pid}-${randomUUID()}`,d=p.join(p.dirname(e),`.${p.basename(e)}.${o}.tmp`),m=p.join(p.dirname(t),`.${p.basename(t)}.${o}.tmp`),c=`${d}.backup`,f=`${m}.backup`,u=false,i=false,h=false,a=false;try{await Promise.all([writeFile(d,r,{flag:"wx"}),writeFile(m,n,{encoding:"utf8",flag:"wx"})]),await d$1(e)&&(await rename(e,c),u=!0),await d$1(t)&&(await rename(t,f),i=!0),await rename(d,e),h=!0,await rename(m,t),a=!0,await Promise.all([rm(c,{force:!0}),rm(f,{force:!0})]);}catch(l){throw a&&await rm(t,{force:true}),h&&await rm(e,{force:true}),i&&await rename(f,t),u&&await rename(c,e),l}finally{await Promise.all([rm(d,{force:true}),rm(m,{force:true}),rm(c,{force:true}),rm(f,{force:true})]);}}a(ve,"writeAtomicPair");function U(e,r){return p.relative(e,r).split(p.sep).join("/")}a(U,"portableRelative");async function _e(e){let r=await realpath(e.root),t=V(e.size??256),n=j(e.timeoutMs,"Environment bake timeoutMs",1e3,15*6e4,24e4),o=fe(r,e.output);await he(r,p.dirname(o.asset));let m=await(e.capture??pe)({root:r,size:t,timeoutMs:n,headed:e.headed===true}),c$1=se(m.bytes,{cubeSize:t,threeRevision:m.threeRevision,compression:e.compression??"zstd"}),f=`${JSON.stringify(c$1.metadata,null,2)}
|
|
3
3
|
`;await ve(o.asset,c$1.bytes,o.metadata,f);let u=await readFile(o.asset);if(c(u)!==c$1.metadata.sha256)throw new Error("Committed RoomEnvironment checksum does not match metadata.");return {schemaVersion:1,command:"environment bake",output:U(r,o.asset),metadataOutput:U(r,o.metadata),bytes:c$1.bytes.byteLength,metadata:c$1.metadata}}a(_e,"bakeRoomEnvironment");function ye(e){if(e<1e3)return `${e} B`;let r=e/1e3;return `${r>=100?Math.round(r):r.toFixed(1)} kB`}a(ye,"formatBytes");function Se(e){return [`\u2713 Environment ${e.metadata.width}\xD7${e.metadata.height} \xB7 CubeUV ${e.metadata.cubeSize}px \xB7 RGBA16F ${e.metadata.compression}`,` Output ${e.output} \xB7 ${ye(e.bytes)}`,` Checksum ${e.metadata.sha256}`].join(`
|
|
4
4
|
`)}a(Se,"formatEnvironmentBakeReport");export{_e as bakeRoomEnvironment,pe as captureRoomEnvironment,se as encodeRoomEnvironmentKtx2,Se as formatEnvironmentBakeReport,V as validateEnvironmentCubeSize};
|
package/dist/index.d.ts
CHANGED
|
@@ -263,7 +263,7 @@ declare function ensureShaderToolConfig(root: string): Promise<EnsuredShaderTool
|
|
|
263
263
|
/** Published devtools protocol/package version. Kept dependency-free for instant CLI startup. */
|
|
264
264
|
declare const SHADER_DEVTOOLS_VERSION: "0.1.0";
|
|
265
265
|
|
|
266
|
-
declare const SHADER_PROVIDER_TRANSFORM_VERSION:
|
|
266
|
+
declare const SHADER_PROVIDER_TRANSFORM_VERSION: 62;
|
|
267
267
|
declare const SHADER_LOCAL_TIMING_FILE: "timing.local.json";
|
|
268
268
|
declare const SHADER_COMMITTED_TIMING_FILE: "timing.json";
|
|
269
269
|
declare const SHADER_PARITY_EVIDENCE_FILE: "parity.json";
|
|
@@ -923,6 +923,9 @@ declare const DOCUMENTED_BROWSER_NOISE: readonly [{
|
|
|
923
923
|
}, {
|
|
924
924
|
readonly id: "chromium-webgpu-experimental";
|
|
925
925
|
readonly pattern: RegExp;
|
|
926
|
+
}, {
|
|
927
|
+
readonly id: "browser-automatic-favicon";
|
|
928
|
+
readonly pattern: RegExp;
|
|
926
929
|
}];
|
|
927
930
|
declare function isDocumentedBrowserNoise(message: string): boolean;
|
|
928
931
|
/** Chromium launch flags used by public WebGPU tools. */
|