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/package-assembly.ts
import JSZip from "jszip"
import { readFile, writeFile, readdir } from "node:fs/promises"
import { createHash } from "node:crypto"
import { writeAssetChunks } from "./chunk-assets"
const proof=JSON.parse(await readFile("docs/assembly-browser-verification.json","utf8"))
if(proof.status!=="passed")throw new Error("Browser verification must pass before packaging")
const zip=new JSZip()
const options={date:new Date("1980-01-01T00:00:00Z"),createFolders:false}
async function add(path:string,name:string){zip.file(name,await readFile(path),options)}
async function scan(directory:string){
for(const e of (await readdir(directory,{withFileTypes:true})).sort((a,b)=>a.name.localeCompare(b.name))){
const path=`${directory}/${e.name}`
if(e.isDirectory())await scan(path)
else if(!path.endsWith(".glb") && !(directory==="dist/assembly/lib"&&["OrbitControls.js","GLTFLoader.js","BufferGeometryUtils.js"].includes(e.name)))
await add(path,path.slice("dist/".length))
}
}
await scan("dist/assembly")
for(const name of ["review.html","circuit.json","pcb-top.svg","pcb-top.png","schematic.svg","bom.csv","placement.json",
"MuseVoiceRemote.kicad_pcb","MuseVoiceRemote.kicad_pro","native-drc.txt","diagnostics.json"])
await add(`dist/${name}`,name)
await add("manufacturing/MuseVoiceRemote-fabrication-v1.3.1.zip","manufacturing/MuseVoiceRemote-fabrication-v1.3.1.zip")
await add("docs/3d-assembly.md","README.md")
await add("docs/assembly-browser-verification.json","assembly/browser-verification.json")
const bytes=await zip.generateAsync({type:"nodebuffer",compression:"DEFLATE",compressionOptions:{level:9}})
await JSZip.loadAsync(bytes,{checkCRC32:true})
const file="dist/MuseVoiceRemote-3d-assembly.zip"
await writeFile(file,bytes)
await writeAssetChunks([file],"dist/assembly-bundle-assets.json")
const report={file,bytes:bytes.length,sha256:createHash("sha256").update(bytes).digest("hex"),browser_verification:"passed",
usage:"Use the viewer's Download assembly ZIP button, unzip and serve locally. GLB files use exact SHA-256-verified byte parts to respect the registry upload limit. Run python3 assembly/reassemble-assets.py assembly/assets.json to recover the original GLBs for a desktop viewer."}
await writeFile("docs/assembly-bundle.json",JSON.stringify(report,null,2)+"\n")
console.log(JSON.stringify(report,null,2))