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/preserve-jlcpcb-cad.ts
type SupplierCad = {
model_obj_url?: string
model_step_url?: string
rotation?: { z?: number }
}
// The upstream generator drops CAD when its URL probe fails. A failed download
// does not mean the supplier has no model: retain the original model references.
export function preserveSupplierCad(tsx: string, cad: SupplierCad | undefined) {
if (!cad?.model_obj_url || !cad.model_step_url) {
throw new Error("JLCPCB import has no supplier OBJ/STEP references; do not silently publish missing CAD.")
}
if (tsx.includes("cadModel=")) {
if (!tsx.includes(cad.model_obj_url) || !tsx.includes(cad.model_step_url)) {
throw new Error("Generated CAD does not retain both original supplier model references.")
}
return { tsx, placement: "existing supplier CAD references and placement preserved" }
}
const marker = /([ \t]*)\{\.\.\.(?:restProps|props)\}/
if (!marker.test(tsx)) throw new Error("Cannot attach CAD to generated component props.")
const model = {
objUrl: cad.model_obj_url,
stepUrl: cad.model_step_url,
pcbRotationOffset: cad.rotation?.z ?? 0,
}
// Without downloaded model bounds, use viewer bounds alignment. Do not copy
// inferred dimensions or fabricated Z offsets from the footprint fallback.
return {
tsx: tsx.replace(marker, (match, indent: string) =>
`${indent}cadModel={${JSON.stringify(model, null, 2)}}\n${match}`),
placement: "supplier links and rotation retained; downloaded model bounds unverified",
}
}