muse/esp32-eink-display
A 55×46 mm two-layer ESP32-S3 e-paper controller board with USB‑C power/programming, buck regulation, FPC display connector, UC8179-style boost/charge-pump circuitry, ESD protection, controls, and routed passive components.
- Version
- 1.3.4
- License
- unset
- Stars
- 0
routing.ts
import { AutoroutingPipelineSolver, type SimpleRouteJson } from "@tscircuit/capacity-autorouter"
// The installed built-in pipeline routes the board. A final geometry cleanup
// separates distinct-net vias that its output places just under copper clearance.
// Attached wire vertices move with each via; the normal board DRC checks the result.
export async function createMuseRouter(input: SimpleRouteJson) {
const solver = new AutoroutingPipelineSolver(input)
const output = () => {
const traces = solver.getOutputSimplifiedPcbTraces()
const vias: {x:number,y:number,net:string}[] = []
for (const t of traces) for (const p of t.route) {
if (p.route_type !== "via") continue
if (!vias.some(v=>v.net===t.connection_name && Math.hypot(v.x-p.x,v.y-p.y)<1e-8))
vias.push({x:p.x,y:p.y,net:t.connection_name})
}
const minimum = (input.minViaPadDiameter ?? 0.5) +
(input.minTraceToPadEdgeClearance ?? 0.15) + 0.01
let moved = 0
for (let i=0;i<vias.length;i++) for (let j=i+1;j<vias.length;j++) {
const a=vias[i],b=vias[j]
if (a.net===b.net) continue
const distance=Math.hypot(b.x-a.x,b.y-a.y)
if (distance>=minimum || distance<1e-8) continue
const dx=(b.x-a.x)*(minimum-distance)/distance
const dy=(b.y-a.y)*(minimum-distance)/distance
for (const t of traces) if(t.connection_name===b.net) for(const p of t.route)
if("x" in p && Math.hypot(p.x-b.x,p.y-b.y)<1e-8) {p.x+=dx;p.y+=dy}
b.x+=dx;b.y+=dy;moved++
}
console.log(`Muse routing: adjusted ${moved} via clearance(s); physical vias 0.3/0.5 mm`)
return traces
}
const handlers = new Map<string, ((event: unknown) => void)[]>()
const emit = (name: string, event: unknown) => handlers.get(name)?.forEach(fn => fn(event))
let stopped = false
let running = false
return {
input,
get isRouting() {return running},
stop() {stopped = true; running = false},
solveSync() {solver.solve(); return output()},
on(name: string, fn: (event: unknown) => void) {
handlers.set(name, [...(handlers.get(name) ?? []), fn])
},
start() {
running = true
const tick = () => {
if (stopped) return
try {
for (let i=0; i<1000 && !solver.solved && !solver.failed; i++) solver.step()
if (solver.failed) {emit("error", {error: new Error(solver.error ?? "Routing failed")}); return}
if (solver.solved) {emit("complete", {traces: output()}); return}
setTimeout(tick, 0)
} catch(error) {emit("error", {error})}
}
setTimeout(tick, 0)
},
}
}
