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",
  }
}