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/routed-overlay.ts

import { readFileSync } from "node:fs"
import { createHash } from "node:crypto"
import type { AnyCircuitElement } from "circuit-json"
import copper from "../design/routed-copper.json"

export function addVerifiedCopper(json: AnyCircuitElement[]) {
  const inputHash=createHash("sha256").update(readFileSync("docs/routing-input.json")).digest("hex")
  if (inputHash!==copper.input_sha256) throw new Error("Wiring or placement changed: native routes need to be updated and checked.")
  const cadHash=createHash("sha256").update(readFileSync("hardware/MuseVoiceRemote.kicad_pcb")).digest("hex")
  if (cadHash!==copper.cad_sha256) throw new Error("Native CAD changed without an updated DRC/route snapshot.")
  const nets=json.filter(e=>e.type==="source_net")
  const traces=json.filter(e=>e.type==="source_trace")
  const board=json.find(e=>e.type==="pcb_board")!
  const sourceFor=(name:string)=>{
    const net=nets.find(n=>n.name===name)
    const trace=traces.find(t=>net && t.connected_source_net_ids?.includes(net.source_net_id))
    if (!trace) throw new Error(`No tscircuit source net for native copper ${name}`)
    return trace.source_trace_id
  }
  for (const [i,t] of copper.tracks.entries()) json.push({ type:"pcb_trace",pcb_trace_id:`native_trace_${i}`,
    source_trace_id:sourceFor(t.net),subcircuit_id:board.subcircuit_id,
    route:[t.start,t.end].map(([x,y])=>({ route_type:"wire",x,y,width:t.width,layer:t.layer })) } as AnyCircuitElement)
  for (const [i,v] of copper.vias.entries()) json.push({ type:"pcb_via",pcb_via_id:`native_via_${i}`,
    source_trace_id:sourceFor(v.net),subcircuit_id:board.subcircuit_id,
    x:v.at[0],y:v.at[1],outer_diameter:v.outerDiameter,hole_diameter:v.holeDiameter,
    from_layer:"top",to_layer:"bottom",layers:["top","inner1","inner2","bottom"] } as AnyCircuitElement)
  // Retain the actual filled native geometry, including every clearance hole.
  // A rectangular approximation would short foreign pads and tracks.
  const pours=(copper as typeof copper & {pours?:{
    net:string;layer:string;brep_shape:{outer_ring:{vertices:{x:number;y:number}[]};inner_rings:{vertices:{x:number;y:number}[]}[]}
  }[]}).pours ?? []
  for(const [i,p] of pours.entries()) {
    const net=nets.find(n=>n.name===p.net)
    if(!net)throw new Error(`No source net for native plane ${p.net}`)
    json.push({type:"pcb_copper_pour",pcb_copper_pour_id:`native_pour_${i}`,
      source_net_id:net.source_net_id,subcircuit_id:board.subcircuit_id,
      layer:p.layer,covered_with_solder_mask:true,shape:"brep",brep_shape:p.brep_shape} as AnyCircuitElement)
  }
  return copper
}