AnasSarkiz/muse-voice-remote
Muse Voice Remote — bare ESP32-S3R8, 155 TOP JLCPCB parts with real supplier CAD, native 3D assembly and GLB exports. Revised 17 mm case allocation; 0.30 mm via drill /0.45 mm pad. Checked prototype PCB; mechanical, RF and MUSE qualification pending.
- Version
- 1.3.2
- License
- unset
- Stars
- 0
scripts/check-assembly-viewer.mjs
import {chromium} from "playwright"
import assert from "node:assert/strict"
import {writeFile,mkdir} from "node:fs/promises"
import {readFile} from "node:fs/promises"
import {createHash} from "node:crypto"
// Start `npm run dev` first. This check exercises actual WebGL loads and controls.
const browser=await chromium.launch({executablePath:process.env.CHROMIUM_PATH||"/usr/bin/chromium",headless:true,
args:["--no-sandbox","--use-gl=angle","--use-angle=swiftshader","--enable-unsafe-swiftshader"]})
const page=await browser.newPage({viewport:{width:1500,height:1050}})
const errors=[]
page.on("pageerror",e=>errors.push(e.message))
page.on("response",r=>{if(r.status()>=400&&!r.url().endsWith("favicon.ico"))errors.push(`${r.status()} ${r.url()}`)})
try{
await page.goto(process.env.ASSEMBLY_URL||"http://127.0.0.1:8080/assembly/",{waitUntil:"networkidle"})
await page.waitForFunction(()=>window.museAssembly?.ready,null,{timeout:60000})
const initial=await page.evaluate(()=>window.museAssembly)
assert.equal(initial.supplierMeshes,155)
assert.equal(initial.assetTransport,"sha256-verified-byte-parts")
assert.equal(initial.envelopes,6)
assert.equal(initial.parts.filter(p=>p.name.startsWith("ENV_")&&p.visible).length,6)
assert.deepEqual(initial.geometryBounds.map(x=>Math.round(x*100)/100),[72,17,53.5])
await mkdir("dist/assembly/previews",{recursive:true})
await page.screenshot({path:"dist/assembly/previews/assembled.png"})
await page.getByRole("button",{name:"Exploded",exact:true}).click()
const exploded=await page.evaluate(()=>window.museAssembly)
assert.equal(exploded.mode,"exploded")
const battery=p=>p.parts.find(e=>e.name==="ENV_BATTERY_UNSELECTED")
assert.equal(battery(exploded).position[1]-battery(initial).position[1],17)
await page.screenshot({path:"dist/assembly/previews/exploded.png"})
await page.getByRole("button",{name:"Populated PCB",exact:true}).click()
const pcb=await page.evaluate(()=>window.museAssembly)
assert.ok(pcb.parts.filter(p=>p.name.startsWith("ENV_")).every(p=>!p.visible))
assert.ok(pcb.parts.filter(p=>!p.name.startsWith("ENV_")).every(p=>p.visible))
await page.screenshot({path:"dist/assembly/previews/populated-pcb.png"})
await page.getByRole("button",{name:"Assembled",exact:true}).click()
await page.getByLabel("Mechanical envelopes",{exact:true}).uncheck()
assert.equal(await page.evaluate(()=>window.museAssembly.parts.filter(p=>p.name.startsWith("ENV_")&&p.visible).length),0)
await page.getByLabel("Mechanical envelopes",{exact:true}).check()
await page.getByRole("button",{name:"Battery · maximum envelope, unselected",exact:true}).click()
assert.match(await page.locator("#selection").textContent(),/Battery/)
for(const name of ["TOP / components","Front / LCD","Isometric","Reset view"])
await page.getByRole("button",{name,exact:true}).click()
if(process.env.CHECK_ASSEMBLY_DOWNLOAD==="1"){
const pending=page.waitForEvent("download")
await page.getByRole("button",{name:"Download assembly ZIP",exact:true}).click()
const saved=await pending
assert.equal(saved.suggestedFilename(),"MuseVoiceRemote-3d-assembly.zip")
const bytes=await readFile(await saved.path())
const expected=JSON.parse(await readFile("dist/assembly-bundle-assets.json","utf8")).assets["MuseVoiceRemote-3d-assembly.zip"]
assert.equal(bytes.length,expected.bytes)
assert.equal(createHash("sha256").update(bytes).digest("hex"),expected.sha256)
}
assert.deepEqual(errors,[])
const proof={status:"passed",supplier_models_loaded:155,rendered_mesh_primitives:initial.meshCount,
geometry_bounds_mm:initial.geometryBounds,checks:["WebGL/GLB loaded","assembled envelopes","exploded offsets","PCB-only visibility",
"envelope toggle","part inspection","camera controls","SHA-256 verified GLB byte parts",
...(process.env.CHECK_ASSEMBLY_DOWNLOAD==="1"?["SHA-256 verified reconstructed ZIP download"]:[])],page_errors:errors}
await writeFile("docs/assembly-browser-verification.json",JSON.stringify(proof,null,2)+"\n")
console.log(JSON.stringify(proof,null,2))
}finally{await browser.close()}