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()}