hrithik18k/punck-tscircuit-recreation

A four-layer Eurorack drum/sampler controller PCB built around an STM32H743, dual QSPI flash, PCM5100 stereo DAC, TL074 analog audio circuitry, input clamps, 12V-to-3.3V power regulation, MIDI/USB/SWD connectors, controls, LEDs, and trigger/audio I/O.

Version
1.0.3
License
unset
Stars
0

scripts/generate-index.ts

import fs from 'node:fs'
const d=JSON.parse(fs.readFileSync('native/components.json','utf8'))
const sheetFor=(p:any)=>p.section==='Passives'?(p.name.startsWith('C')?'Capacitors':'Resistors'):p.section
const sheets=[...new Set(d.parts.map(sheetFor))]
const attr=(k:string,v:any)=>v===undefined?'':` ${k}={${JSON.stringify(v)}}`
const lines=[`import { punckRouter } from './native/punck-router.browser.js'`,`import data from './native/components.json'`,`import { ExactFootprint } from './native/ExactFootprint'`,``, `// Original hardware: https://github.com/dchwebb/Punck (Hardware_v1_1).`, `// Native schematic and fresh autorouting. Run build:native for the two validated via repairs.`, `const footprints = Object.fromEntries(data.parts.map(part => [part.name, part]))`,``, `export default function Punck() {`, `  return <board width={91.2} height={100} thickness={1.59} layers={4}`, `    autorouter={{algorithmFn:punckRouter,allowViaInPad:false}} minViaEdgeToPadEdgeClearance={0.4} minTraceWidth={0.15}>`]
for(const [i,s] of sheets.entries())lines.push(`    <schematicsheet name={${JSON.stringify(s)}} displayName={${JSON.stringify(s.replaceAll('_',' '))}} sheetIndex={${i}} />`)
for(const s of d.sections)lines.push(`    <schematicsection${attr('name','section_'+s)}${attr('displayName',s.replaceAll('_',' '))} />`)
const nets=[...new Set(d.parts.flatMap((p:any)=>p.pins.filter((v:any)=>v.net&&!v.nc).map((v:any)=>v.net)))]
for(const n of nets)lines.push(`    <net${attr('name',n)} />`)
for(const p of d.parts){
 const common={name:p.name,pcbX:p.x,pcbY:p.y,pcbRotation:['C24','R16','C26','C23'].includes(p.name)?180:0,layer:p.layer,schX:p.schX,schY:p.schY,schRotation:p.schRotation??0,schSectionName:'section_'+p.section,schSheetName:sheetFor(p)}
 let type='chip',props:any={...common}
 if(p.ftype==='simple_resistor'&&p.pins.length===2){type='resistor';props.resistance=p.value.replace(/^(\d+)([kmunp])(\d+)$/,'$1.$3$2')}
 else if(p.ftype==='simple_capacitor'&&p.pins.length===2){type='capacitor';props.capacitance=p.value.replace(/^(\d+)([kmunp])(\d+)$/,'$1.$3$2');if(['C1','C34','C20'].includes(p.name))props.schOrientation='vertical'}
 else {const half=Math.ceil(p.pins.length/2);Object.assign(props,{manufacturerPartNumber:p.value,pinLabels:Object.fromEntries(p.pins.map((v:any)=>[v.selector,[v.label.replace(/\+/g,'_PLUS').replace(/-/g,'_MINUS').replace(/[^a-zA-Z0-9_]/g,'_')]])),pinAttributes:Object.fromEntries(p.pins.filter((v:any)=>v.nc).map((v:any)=>[v.selector,{doNotConnect:true}])),schWidth:p.schWidth??(p.pins.length>20?9:4),schHeight:p.verticalPins?1:(half+1)*.2,schPinArrangement:p.verticalPins?{topSide:{direction:'left-to-right',pins:[p.verticalPins[0]]},bottomSide:{direction:'left-to-right',pins:[p.verticalPins[1]]}}:{leftSide:{direction:'top-to-bottom',pins:p.pins.slice(0,half).map((v:any)=>v.selector)},rightSide:{direction:'top-to-bottom',pins:p.pins.slice(half).map((v:any)=>v.selector)}}})}
 lines.push(`\n    <${type}${Object.entries(props).map(([k,v])=>attr(k,v)).join('')}\n      footprint={<ExactFootprint part={footprints[${JSON.stringify(p.name)}]} />} />`)
}
lines.push('\n    {/* Named connections drive both the schematic and PCB routing. */}')
for(const p of d.parts)for(const v of p.pins.filter((v:any)=>v.net&&!v.nc))lines.push(`    <netlabel${attr('connection',`.${p.name} > .${v.selector}`)}${attr('net',v.net)}${attr('schSheetName',sheetFor(p))} />`)
lines.push('  </board>','}','')
fs.writeFileSync('index.circuit.tsx',lines.join('\n'))