abse/smartwatch-flex-top-only

Three-panel flex smartwatch with two parallel R3.9 bends, all components flat-top, low-profile JST connector harnesses, split heartbeat optical windows and screw-retained PCB mounting. Modeled 39 × 50.5 × 14.5mm prototype; 100% routing, zero native DRC and shorts. Hardware qualification pending.

Version
0.2.20
License
unset
Stars
0

scripts/audit-clearance.mjs

import fs from 'node:fs'
import {createHash} from 'node:crypto'
import {copperModel,SpatialCopper,intentionalCoilLeadContact} from './copper-model.mjs'
import {gap} from './copper-geometry.mjs'
const [cachePath,sourcePath='dist/extract-routing/circuit.json',output='reports/clearance-audit.json']=process.argv.slice(2)
const cache=JSON.parse(fs.readFileSync(cachePath)),source=JSON.parse(fs.readFileSync(sourcePath)),shapes=copperModel(cache,source),index=new SpatialCopper(shapes),seen=new Set(),failures=[]
let minimum=Infinity
for(const s of shapes)for(const o of index.near(s,.2)){
 if(o===s||intentionalCoilLeadContact(s,o)||s.net===o.net||!s.layers.some(l=>o.layers.includes(l)))continue
 const key=[s.id,o.id].sort().join('|');if(seen.has(key))continue;seen.add(key)
 const d=gap(s,o);minimum=Math.min(minimum,d)
 if(d<.127-1e-6)failures.push({a:s.id,b:o.id,netA:s.net,netB:o.net,layer:s.layers.filter(l=>o.layers.includes(l)),gapMM:d})
}
const report={checkedAt:new Date().toISOString(),cachePath,cacheSha256:createHash('sha256').update(fs.readFileSync(cachePath)).digest('hex'),sourcePath,shapeCount:shapes.length,minimumDifferentNetGapMM:minimum,minRequiredGapMM:.127,failures,limitations:'Checks actual pad shapes, trace capsules and all four through-via annuli. Generated copper pours, board-edge, drill geometry and whole-net continuity are checked separately.'}
fs.writeFileSync(output,JSON.stringify(report,null,2)+'\n')
console.log(`${shapes.length} copper primitives: ${failures.length} different-net clearance failures; minimum ${minimum.toFixed(6)} mm.`)
if(failures.length)process.exitCode=1