muse/book-reading-clip-lamp

A 60‑mm ESP32‑S3 lamp-head PCB combining USB‑C battery charging/power regulation, OV5640 autofocus camera interfacing, I²S microphone and differential speaker audio, six‑LED boost-driven reading light, buttons, status indicators, and battery monitoring.

Version
0.2.5
License
unset
Stars
0

index.circuit.tsx

PCBPCB preview for index.circuit.tsx
SchematicSchematic preview for index.circuit.tsx
import { replaySavedRoutes } from "./saved-routing"
import type { AutorouterConfig } from "@tscircuit/props"
import { withFunctionalSchematicSheets } from "./schematic-layout"
import React from "react"
import { MBR0540T1G } from "./imports/MBR0540T1G"
import { ESP32S3 } from "./mcu-parts"
import { BQ24074, TPS63021, TPS61165, PowerInductor, LedInductor, PowerSwitch, VbusDetectorFet } from "./power-parts"
import { INMP441Microphone as INMP441, MAX98357Amplifier as MAX98357A } from "./camera-audio-parts"
import { CameraFpcConnector, Camera2V8, Camera1V5, CameraInputBuffer, CameraOutputBuffer, CameraControlTranslator } from "./camera-fpc-parts"
import { AskButton } from "./controls-parts"
import { usbConnectorProps } from "./usb-connector"
import { XL_1608SYGC_06 } from "./imports/XL_1608SYGC_06"
import { XL_1608UOC_06 } from "./imports/XL_1608UOC_06"
import { ReadingLED, UsbESD } from "./indicator-parts"

// Rev B: 60 mm head controller. Top = rear/electronics; bottom = page/LEDs.
// KLT-PAA40-OV5640-1B V1.0 ESP32 autofocus camera on a 24-pin FPC.
// No Muse credentials or finished firmware are included in this hardware design.
const outline = Array.from({length: 96}, (_,i) => ({x:30*Math.cos(i*Math.PI/48),y:30*Math.sin(i*Math.PI/48)}))
const netLinks = (ref:string, pins:Record<string,string>) => Object.entries(pins).map(([pin,net]) =>
  <trace key={`${ref}-${pin}`} from={`${ref}.${pin}`} to={`net.${net}`} schDisplayLabel={net} />)

type Passive = [string,string,string,string,number,number,string,number,number,number?]
// reference, value, net1, net2, PCB x/y, schematic section, schematic x/y, rotation
const resistors:Passive[] = [
 ["R1","5.1k","CC1","GND",-20,-4,"USB",-30,8,90],
 ["R2","5.1k","CC2","GND",-24,-7.5,"USB",-25,8,90],
 ["R3","22","USB_DP_CONN","USB_DP",-15.3,2,"USB",-30,4],
 ["R4","22","USB_DM_CONN","USB_DM",-16,4,"USB",-25,4],
 ["R5","1.78k","ISET","GND",-20,-13,"Charger",-31,-13],
 ["R6","1.62k","ILIM","GND",-16.5,-13,"Charger",-26,-13],
 ["R7","46.4k","TMR","GND",-13,-13,"Charger",-21,-13],
 ["R8","100k","USB_500MA","GND",-23.5,-13,"Charger",-16,-13],
 ["R9","10k","EN","V3V3",-12,10,"MCU",-6,13,90],
 ["R10","10k","BOOT","V3V3",12,10,"MCU",0,13,90],
 ["R11","10k","STRAP45","GND",10,0,"MCU",6,13],
 ["R12","10k","STRAP46","GND",7,0,"MCU",12,13],
 ["R13","10k","USB_SUSPEND","GND",4,0,"MCU",18,13],
 ["R14","100k","AMP_SD","GND",13,-11.5,"Audio",25,-11],
 ["R15","100k","MIC_DATA","GND",22,-4.4,"Audio",30,-11,90],
 ["R16","100k","LED_PWM","GND",12,7,"Light",25,14],
 ["R17","13.3","LED_SENSE","GND",19,3,"Light",30,14],
 ["R18","10k","ASK","V3V3",-11,-20,"Controls",-6,-26],
 ["R19","10k","LIGHT_KEY","V3V3",11,-20,"Controls",0,-26],
 ["R20","470k","VBAT","BAT_ADC",15,1,"Controls",6,-26],
 ["R21","470k","BAT_ADC","GND",15,-1,"Controls",12,-26],
 ["R22","1k","STATUS_A","GND",13,16,"Controls",18,-26,180],
 ["R24","2k","AMP_EN","AMP_SD",10,-9,"Audio",35,-11],
 ["R23","1k","SYS","CHG_LED_A",-24,-15,"Charger",-11,-13,180],
]
resistors.push(
 ["R25","100k","SYS_EN","GND",0,-10,"Regulator",-10,-30],
 ["R26","10k","VBUS","VBUS_GATE",-18,5.5,"USB",-30,-1],
 ["R27","100k","VBUS_GATE","GND",-18,12,"USB",-25,-1],
 ["R28","47k","V3V3","VBUS_DRAIN",-16,15,"USB",-20,-1,180],
 ["R29","2k","VBUS_DRAIN","VBUS_N",-14,5.5,"USB",-15,-1],
)
const capacitors:Passive[] = [
 ["C1","4.7uF","VBUS","GND",-17,-5.5,"Charger",-31,-17],
 ["C2","10uF","VBAT","GND",-21.3,-8,"Charger",-26,-17],
 ["C3","22uF","SYS","GND",-13,-8,"Charger",-21,-17],
 ["C4","10uF","SYS","GND",-4,-4,"Regulator",-31,-34],
 ["C5","10uF","SYS","GND",-4.8,-7,"Regulator",-26,-34],
 ["C6","100nF","SYS","GND",-8,-0.5,"Regulator",-21,-34],
 ["C7","22uF","V3V3","GND",-12.3,-3.5,"Regulator",-16,-34],
 ["C8","22uF","V3V3","GND",-15.85,-3.5,"Regulator",-11,-34],
 ["C9","22uF","V3V3","GND",-12,-0.5,"Regulator",-6,-34],
 ["C10","10uF","V3V3","GND",-12,18,"MCU",-6,17],
 ["C11","100nF","V3V3","GND",-12,16,"MCU",0,17],
 ["C12","1uF","EN","GND",-12,13,"MCU",6,17],
 
 
 ["C15","10uF","SYS","GND",18,-8,"Audio",25,-15],
 ["C16","100nF","SYS","GND",18,-6,"Audio",30,-15],
 ["C17","100nF","V3V3","GND",23,4.9,"Audio",35,-15],
 ["C18","4.7uF","SYS","GND",12,4,"Light",25,18],
 ["C19","220nF","LED_COMP","GND",20,5.5,"Light",30,18],
 ["C20","1uF","LED_ANODE","GND",24,12.5,"Light",35,18],
 ["C21","100nF","BAT_ADC","GND",17.5,-3,"Controls",12,-30],
]

const cameraResistors:Passive[] = [
 ["R30","100k","CAM_XCLK","GND",11,-15,"Camera",-13,-10],
 ["R31","100k","CAM_RESET","GND",13,-16.5,"Camera",-8,-10],
 ["R32","10k","CAM_PWDN","V3V3",14,-18,"Camera",-3,-10],
 ["R33","33","FPC_XCLK_DRV","FPC_XCLK",11,-7,"Camera",-10,-5],
]
const cameraCapacitors:Passive[] = [
 ["C13","10uF","V3V3","GND",-17.5,12,"CameraPower",-12,-3],
 ["C14","100nF","CAM2V8","GND",0,-17,"CameraPower",-5.4,-7],
 ["C22","4.7uF","CAM2V8","GND",-10.5,12,"CameraPower",-7.8,-7],
 ["C23","1uF","V3V3","GND",-10.5,16,"CameraPower",-9,-3],
 ["C24","4.7uF","CAM1V5","GND",-3.5,16,"CameraPower",8,-3],
 ["C25","100nF","CAM1V5","GND",-2.5,-17,"CameraPower",11,-3],
 ["C26","4.7uF","CAM2V8","GND",8,-16.5,"CameraPower",-3,-7],
 ["C27","100nF","V3V3","GND",-17.6,4,"Camera",-4.8,-13],
 ["C28","100nF","V3V3","GND",17.6,4,"Camera",-2.4,-13],
 ["C29","100nF","CAM2V8","GND",21,-12.5,"Camera",4,-13],
 ["C30","100nF","CAM2V8","GND",-18.5,-10,"Camera",7,-13],
 ["C31","100nF","V3V3","GND",-17,-13,"Camera",0,-13],
]

export default function LampHead({ routeAlgorithm = replaySavedRoutes }: { routeAlgorithm?: AutorouterConfig["algorithmFn"] } = {}) {
 return withFunctionalSchematicSheets(<board title="Lamp Clip - Head PCB Rev B" width={60} height={60} outline={outline}
   layers={4} thickness={1.6} allowBlindAndBuriedVias={false} isViaInPadAllowed doubleSidedAssembly solderMaskColor="black" silkscreenColor="white"
   minTraceWidth={0.15} minBoardEdgeClearance={0.3} minViaEdgeToPadEdgeClearance={0.15} minViaHoleDiameter={0.3} minViaPadDiameter={0.45}
   autorouter={{local:true,traceClearance:0.15,algorithmFn:routeAlgorithm}} pcbStyle={{silkscreenFontSize:0.7}}>
  <net name="GND" isGroundNet nominalTraceWidth={0.3}/>
  {["VBUS","VBAT","SYS","V3V3","CAM2V8","CAM1V5"].map(n=><net name={n} isPowerNet nominalTraceWidth={0.4}/>)}

  {["BUCK_L1","BUCK_L2"].map(n=><net name={n} isPowerNet nominalTraceWidth={0.8}/>)}
  {["SPK_P","SPK_N","LED_SW"].map(n=><net name={n} isPowerNet nominalTraceWidth={0.4}/>)}
  <connector standard="usb_c" {...usbConnectorProps} name="J1" pcbX={-25.1} pcbY={0} pcbRotation={270} allowOffBoard
   schSectionName="USB" schX={-31} schY={15} />
  {netLinks("J1",{VBUS1:"VBUS",VBUS2:"VBUS",GND1:"GND",GND2:"GND",SHELL1:"GND",SHELL2:"GND",SHELL3:"GND",SHELL4:"GND",CC1:"CC1",CC2:"CC2",DP1:"USB_DP_CONN",DP2:"USB_DP_CONN",DM1:"USB_DM_CONN",DM2:"USB_DM_CONN"})}
  <UsbESD name="U7" pcbX={-19} pcbY={0} schSectionName="USB" schX={-20} schY={15}/>
  {netLinks("U7",{pin1:"USB_DP_CONN",pin2:"GND",pin3:"USB_DM_CONN",pin4:"USB_DM_CONN",pin5:"VBUS",pin6:"USB_DP_CONN"})}

  <VbusDetectorFet name="Q1" pcbX={-18} pcbY={8.5} pcbRotation={180} schSectionName="USB" schX={-16} schY={8}/>
  {netLinks("Q1",{pin1:"VBUS_GATE",pin2:"GND",pin3:"VBUS_DRAIN"})}
  <PowerSwitch name="SW3" pcbX={-22.5} pcbY={10.5} pcbRotation={270} schSectionName="Regulator" schX={-30} schY={-26}/>
  {netLinks("SW3",{pin1:"SYS",pin2:"SYS_EN",pin3:"GND"})}
  <ESP32S3 name="U1" pcbX={0} pcbY={12} schSectionName="MCU" schX={5} schY={4} schWidth={2.8} schHeight={4.2}/>
  {netLinks("U1",{pin1:"GND",pin2:"V3V3",pin3:"EN",pin4:"I2S_BCLK",pin5:"I2S_WS",pin6:"SPK_DATA",pin7:"MIC_DATA",pin8:"CAM_D0",pin9:"CAM_D3",pin10:"CAM_D1",pin11:"CAM_D2",pin12:"AMP_EN",pin13:"USB_DM",pin14:"USB_DP",pin15:"USB_SUSPEND",pin16:"STRAP46",pin17:"LED_PWM",pin18:"CAM_XCLK",pin19:"CAM_D6",pin20:"CAM_D5",pin21:"CAM_PCLK",pin22:"CAM_D4",pin23:"USB_500MA",pin24:"CAM_HREF",pin25:"CAM_D7",pin26:"STRAP45",pin27:"BOOT",pin31:"CAM_VSYNC",pin32:"CAM_SCL",pin33:"CAM_SDA",pin34:"CAM_RESET",pin35:"CAM_PWDN",pin36:"ASK",pin37:"VBUS_N",pin38:"LIGHT_KEY",pin39:"BAT_ADC",pin40:"GND",pin41:"GND"})}

  <BQ24074 name="U2" pcbX={-17} pcbY={-9.5} schSectionName="Charger" schX={-22} schY={-6} schHeight={1.8}/>
  {netLinks("U2",{pin1:"NTC",pin2:"VBAT",pin3:"VBAT",pin4:"GND",pin5:"USB_SUSPEND",pin6:"USB_500MA",pin8:"GND",pin9:"CHG_N",pin10:"SYS",pin11:"SYS",pin12:"ILIM",pin13:"VBUS",pin14:"TMR",pin16:"ISET",pin17:"GND"})}
  <TPS63021 name="U3" pcbX={-8} pcbY={-4} pcbRotation={270} schSectionName="Regulator" schX={-21} schY={-26} schHeight={1.6}/>
  {netLinks("U3",{pin1:"SYS",pin2:"GND",pin3:"V3V3",pin4:"V3V3",pin5:"V3V3",pin6:"BUCK_L2",pin7:"BUCK_L2",pin8:"BUCK_L1",pin9:"BUCK_L1",pin10:"SYS",pin11:"SYS",pin12:"SYS_EN",pin13:"GND",pin15:"GND"})}
  <PowerInductor name="L1" pcbX={-8} pcbY={-9} pcbRotation={180} schSectionName="Regulator" schX={-12} schY={-25}/>
  {netLinks("L1",{pin1:"BUCK_L1",pin2:"BUCK_L2"})}

  <CameraFpcConnector name="J2" pcbX={0} pcbY={-12} layer="bottom" schSectionName="Camera" schX={-12} schY={3} schWidth={2.6} schHeight={3}/>
  {netLinks("J2",{pin2:"GND",pin3:"FPC_SDA",pin4:"CAM2V8",pin5:"FPC_SCL",pin6:"FPC_RESET",pin7:"FPC_VSYNC",pin8:"FPC_PWDN",pin9:"FPC_HREF",pin10:"CAM1V5",pin11:"CAM2V8",pin12:"FPC_D7",pin13:"FPC_XCLK",pin14:"FPC_D6",pin15:"GND",pin16:"FPC_D5",pin17:"FPC_PCLK",pin18:"FPC_D4",pin19:"FPC_D0",pin20:"FPC_D3",pin21:"FPC_D1",pin22:"FPC_D2",pin24:"CAM2V8",pin25:"GND",pin26:"GND"})}
  <Camera2V8 name="U8" pcbX={-14} pcbY={12} layer="bottom" schSectionName="CameraPower" schX={-8} schY={4}/>
  {netLinks("U8",{pin1:"V3V3",pin2:"GND",pin3:"V3V3",pin5:"CAM2V8"})}
  <Camera1V5 name="U9" pcbX={-7} pcbY={16} layer="bottom" schSectionName="CameraPower" schX={8} schY={4}/>
  {netLinks("U9",{pin1:"V3V3",pin2:"GND",pin3:"CAM2V8",pin5:"CAM1V5"})}
  <CameraInputBuffer name="U10" pcbX={-13} pcbY={0} layer="bottom" schSectionName="Camera" schX={0} schY={3} schWidth={2} schHeight={2.2}/>
  {netLinks("U10",{pin1:"CAM_PWDN",pin2:"FPC_D0",pin18:"CAM_D0",pin4:"FPC_D1",pin16:"CAM_D1",pin6:"FPC_D2",pin14:"CAM_D2",pin8:"FPC_D3",pin12:"CAM_D3",pin11:"FPC_D4",pin9:"CAM_D4",pin13:"FPC_D5",pin7:"CAM_D5",pin15:"FPC_D6",pin5:"CAM_D6",pin17:"FPC_D7",pin3:"CAM_D7",pin19:"CAM_PWDN",pin10:"GND",pin20:"V3V3"})}
  <CameraInputBuffer name="U11" pcbX={13} pcbY={0} layer="bottom" schSectionName="Camera" schX={10} schY={3} schWidth={2} schHeight={2.2} noConnect={["pin12","pin9","pin7","pin5","pin3"]}/>
  {netLinks("U11",{pin1:"CAM_PWDN",pin2:"FPC_PCLK",pin18:"CAM_PCLK",pin4:"FPC_VSYNC",pin16:"CAM_VSYNC",pin6:"FPC_HREF",pin14:"CAM_HREF",pin8:"GND",pin11:"GND",pin13:"GND",pin15:"GND",pin17:"GND",pin19:"V3V3",pin10:"GND",pin20:"V3V3"})}
  <CameraOutputBuffer name="U12" pcbX={17} pcbY={-12.5} layer="bottom" schSectionName="Camera" schX={-2} schY={-5} schWidth={1.7} schHeight={1.6} noConnect={["pin11"]}/>
  {netLinks("U12",{pin1:"GND",pin2:"CAM_XCLK",pin3:"FPC_XCLK_DRV",pin4:"GND",pin5:"CAM_RESET",pin6:"FPC_RESET",pin7:"GND",pin8:"FPC_PWDN",pin9:"CAM_PWDN",pin10:"GND",pin12:"GND",pin13:"CAM2V8",pin14:"CAM2V8"})}
  <CameraControlTranslator name="U13" pcbX={-14} pcbY={-10} layer="bottom" schSectionName="Camera" schX={10} schY={-5} schWidth={1.5} schHeight={1.2}/>
  {netLinks("U13",{pin1:"CAM_SCL",pin2:"GND",pin3:"CAM2V8",pin4:"FPC_SCL",pin5:"FPC_SDA",pin6:"FPC_RESET",pin7:"V3V3",pin8:"CAM_SDA"})}
  {/* Camera-side rails and signal conditioning stay on the page-facing side. */}
  {cameraResistors.map(([ref,value,a,b,x,y,section,sx,sy,rot])=><React.Fragment key={ref}>
   <resistor name={ref} resistance={value} footprint="0402" pcbX={x} pcbY={y} pcbRotation={rot??0} layer="bottom" schSectionName={section} schX={sx} schY={sy} schRotation={ref==="R32"?90:ref==="R33"?0:-90}/>
   {netLinks(ref,{pin1:a,pin2:b})}
  </React.Fragment>)}
  {cameraCapacitors.map(([ref,value,a,b,x,y,section,sx,sy])=><React.Fragment key={ref}>
   <capacitor name={ref} capacitance={value} maxVoltageRating="10V" footprint={value==="100nF"?"0402":"0603"} pcbX={x} pcbY={y} pcbRotation={ref==="C26"?180:0} layer="bottom" schSectionName={section} schX={sx} schY={sy} schRotation={-90}/>
   {netLinks(ref,{pin1:a,pin2:b})}
  </React.Fragment>)}

  <INMP441 name="U4" pcbX={22} pcbY={0} pcbRotation={180} schSectionName="Audio" schX={32} schY={-4} schHeight={1}/>
  {netLinks("U4",{pin1:"I2S_BCLK",pin2:"MIC_DATA",pin3:"I2S_WS",pin4:"GND",pin5:"GND",pin6:"GND",pin7:"V3V3",pin8:"V3V3",pin9:"GND"})}
  <MAX98357A name="U5" pcbX={14} pcbY={-8} schSectionName="Audio" schX={24} schY={-4} schHeight={1.8}/>
  {netLinks("U5",{pin1:"SPK_DATA",pin3:"GND",pin4:"AMP_SD",pin7:"SYS",pin8:"SYS",pin9:"SPK_P",pin10:"SPK_N",pin11:"GND",pin14:"I2S_WS",pin15:"GND",pin16:"I2S_BCLK",pin17:"GND"})}

  <TPS61165 name="U6" pcbX={16} pcbY={7} pcbRotation={0} schSectionName="Light" schX={27} schY={7}/>
  {netLinks("U6",{pin1:"SYS",pin2:"LED_PWM",pin3:"LED_SW",pin4:"GND",pin5:"LED_COMP",pin6:"LED_SENSE"})}
  <LedInductor name="L2" pcbX={18} pcbY={12} schSectionName="Light" schX={34} schY={8}/>
  {netLinks("L2",{pin1:"SYS",pin2:"LED_SW"})}
  <MBR0540T1G name="D1" pcbX={21.7} pcbY={7.7} pcbRotation={180}
   schSectionName="Light" schX={34} schY={4}/>
  {netLinks("D1",{anode:"LED_SW",cathode:"LED_ANODE"})}
  {Array.from({length:6},(_,i)=>{
   const a=i*Math.PI/3; const ref=`LED${i+1}`
   return <React.Fragment key={ref}>
    <ReadingLED name={ref} pcbX={25*Math.cos(a)} pcbY={25*Math.sin(a)} pcbRotation={i*60} layer="bottom"
      schSectionName="Light" schX={24+(i%3)*5} schY={25+Math.floor(i/3)*3}/>
    {netLinks(ref,{pin1:i===5?"LED_SENSE":`LED_LINK_${i+1}`,pin2:i===0?"LED_ANODE":`LED_LINK_${i}`})}
   </React.Fragment>
  })}

  <connector name="J3" manufacturerPartNumber="SOLDER_HARNESS_6P_2.54" pcbX={0} pcbY={-20.5}
   schSectionName="Charger" schX={-11} schY={-6}
   pinLabels={{pin1:"BAT_P",pin2:"BAT_N",pin3:"NTC",pin4:"NTC_RETURN",pin5:"SPK_P",pin6:"SPK_N"}}
   footprint={<footprint insertionDirection="from_above">
    {Array.from({length:6},(_,i)=><platedhole portHints={[`pin${i+1}`]} pcbX={(i-2.5)*2.54} pcbY={0} shape="circle" holeDiameter={1} outerDiameter={1.8}/>)}
   </footprint>}/>
  {netLinks("J3",{pin1:"VBAT",pin2:"GND",pin3:"NTC",pin4:"GND",pin5:"SPK_P",pin6:"SPK_N"})}

  {[{name:"SW1",net:"ASK",x:-8,sx:-6},{name:"SW2",net:"LIGHT_KEY",x:8,sx:0}].map(b=><React.Fragment key={b.name}>
   <AskButton name={b.name} pcbX={b.x} pcbY={-24.5} schSectionName="Controls" schX={b.sx} schY={-21}/>
   {netLinks(b.name,{pin1:b.net,pin2:"GND"})}
  </React.Fragment>)}
  <XL_1608SYGC_06 name="LED7" color="green" pcbRotation={180} pcbX={13} pcbY={19} schSectionName="Controls" schX={18} schY={-21} schRotation={-90}/>
  {netLinks("LED7",{anode:"V3V3",cathode:"STATUS_A"})}
  <XL_1608UOC_06 name="LED8" color="orange" pcbRotation={180} pcbX={-24} pcbY={-10} schSectionName="Charger" schX={-11} schY={-17}/>
  {netLinks("LED8",{anode:"CHG_LED_A",cathode:"CHG_N"})}

  {resistors.map(([name,value,a,b,x,y,section,sx,sy,rotation])=><React.Fragment key={name}>
   <resistor name={name} resistance={value} footprint="0603" pcbX={x} pcbY={y} pcbRotation={rotation??0}
    schSectionName={section} schX={sx} schY={sy} schRotation={b==="V3V3"?90:(a==="USB_DP_CONN"||a==="USB_DM_CONN"||a==="AMP_EN")?0:-90}/> 
   {netLinks(name,{pin1:a,pin2:b})}
  </React.Fragment>)}
  {capacitors.map(([name,value,a,b,x,y,section,sx,sy])=><React.Fragment key={name}>
   <capacitor name={name} capacitance={value} footprint={value==="22uF"||name==="C20"?"0805":"0603"}
    maxVoltageRating={name==="C20"?"50V":"10V"} pcbX={x} pcbY={y} pcbRotation={name==="C8"?180:["C3","C4","C5","C20"].includes(name)?90:0} schSectionName={section} schX={sx} schY={sy} schRotation={-90}/>
   {netLinks(name,{pin1:a,pin2:b})}
  </React.Fragment>)}
  {["GND","V3V3","SYS","BOOT","EN","VBUS_N"].map((net,i)=><React.Fragment key={`TP${i+1}`}>
   <testpoint name={`TP${i+1}`} footprintVariant="pad" padDiameter={1.2} pcbX={-15+i*2.5} pcbY={24-(i<2?2:0)}
    schSectionName="Controls" schX={-6+i*4.8} schY={-35}/>
   {netLinks(`TP${i+1}`,{pin1:net})}
  </React.Fragment>)}
  {[-1,1].flatMap(x=>[-1,1].map(y=><hole name={`H${x+1}${y+1}`} pcbX={x*(y>0?20:21)} pcbY={y>0?19:-16} diameter={2.2}/>))}
  {/* Interior ground pours provide short returns; final stackup/USB impedance must be agreed with the fabricator. */}
  <copperpour connectsTo="net.GND" layer="inner1" clearance={0.2} boardEdgeMargin={0.4}/>
  <copperpour connectsTo="net.GND" layer="inner2" clearance={0.2} boardEdgeMargin={0.4}/>
  {/* Grounded exposed-pad vias. Filled/capped processing or stencil review required. */}
  {[[-16.8,-9.5],[-7.8,-4],[14.2,-8],[-4.5,13.325]].map(([x,y],i)=><via name={`VG${i+1}`} connectsTo="net.GND" pcbX={x} pcbY={y} fromLayer="top" toLayer="bottom" holeDiameter={0.3} outerDiameter={0.45}/>)}
  {/* Explicit short links associate each thermal pad with its plane via. pcbPath points are relative to the source component. */}
  <trace name="EP_GND_1" from="U2.pin17" to="VG1.top" thickness={0.3} pcbPath={[{x:0,y:0},{x:0.2,y:0}]}/>
  <trace name="EP_GND_2" from="U3.pin15" to="VG2.top" thickness={0.3} pcbPath={[{x:0,y:0},{x:0.2,y:0}]}/>
  <trace name="EP_GND_3" from="U5.pin17" to="VG3.top" thickness={0.3} pcbPath={[{x:0.000127,y:-0.000127},{x:0.2,y:0}]}/>
  <silkscreentext text="LAMP CLIP / HEAD B" pcbX={0} pcbY={26} fontSize={1}/>
  <silkscreentext text="BAT+  GND  NTC  GND  SPK+  SPK-" pcbX={0} pcbY={-18.5} fontSize={0.65}/>
  <silkscreentext text="ASK" pcbX={-8} pcbY={-28.2} fontSize={0.75}/>
  <silkscreentext text="LIGHT" pcbX={8} pcbY={-28.2} fontSize={0.75}/>
  <silkscreenrect pcbX={0} pcbY={3.5} width={9} height={9} layer="bottom" strokeWidth={0.15}/>
  <silkscreentext text="OV5640 AF / ALIGN LENS" pcbX={0} pcbY={10} layer="bottom" fontSize={0.8}/>
 </board>)
}