pixalynx/pixal-nfc-card

This code defines React components representing specific electronic hardware components—namely, a 100-ohm SMD resistor, a surface-mount LED, and a chip with labeled pins—each modeled with detailed footprints, 3D CAD models, and manufacturer part information for PCB design.

Version
1.1.0
License
unset
Stars
0

index.circuit.tsx

PCBPCB preview for index.circuit.tsx
SchematicSchematic preview for index.circuit.tsx
import { Fragment } from "react"
import { ST25TN01K_AFH5 } from "./imports/ST25TN01K_AFH5"
import { arc, dashPolyline, roundedRectPolyline } from "./lib/artwork"
import { coilPath } from "./lib/coil"
import { estimateInductance } from "./lib/inductance"
import { CARD, COIL, LEAD_WIDTH, PARTS, TERMINAL } from "./lib/layout"

// Front print -- edit before ordering
const OWNER = "PIXALYNX"
const TAGLINE = "NFC CARD"

const coil = coilPath(COIL)
const outerEnd = coil[0]
const innerEnd = coil[coil.length - 1]
const coilMicrohenries = (estimateInductance(coil, COIL.width) * 1e6).toFixed(2)

// The coil is a DC short between its terminals. Core honours this for every
// component, but InductorProps does not declare it yet.
const coilTerminalsBonded = { internallyConnectedPins: [["pin1", "pin2"]] }

const coilCopperMargin = Math.max(COIL.width, TERMINAL.outerDiameter) / 2 + 0.25
const courtyard = [
  { x: COIL.left - coilCopperMargin, y: COIL.bottom - coilCopperMargin },
  { x: COIL.right + coilCopperMargin, y: COIL.bottom - coilCopperMargin },
  { x: COIL.right + coilCopperMargin, y: COIL.top + coilCopperMargin },
  { x: COIL.left - coilCopperMargin, y: COIL.top + coilCopperMargin },
  { x: COIL.left - coilCopperMargin, y: COIL.bottom - coilCopperMargin },
]

// Front artwork: dashed tap zone just outside the coil, contactless icon, owner block on the right
const zone = { cx: (COIL.left + COIL.right) / 2, w: COIL.right - COIL.left + 2, h: COIL.top - COIL.bottom + 2 }
const zoneDashes = dashPolyline(roundedRectPolyline(zone.cx, 0, zone.w, zone.h, 4), 1, 0.8)
const icon = { x: zone.cx - 3, y: 7 }
const iconArcs = [2.2, 3.9, 5.6].map((r) => arc(icon.x, icon.y, r, -48, 48))
const iconDot = arc(icon.x, icon.y, 0.3, 0, 360, 12)
const textX = 28

export default () => (
  <board
    title="pixal-nfc-card"
    width={`${CARD.width}mm`}
    height={`${CARD.height}mm`}
    borderRadius={`${CARD.cornerRadius}mm`}
    thickness={`${CARD.thickness}mm`}
    layers={2}
    solderMaskColor="black"
    silkscreenColor="white"
  >
    <schematicsheet name="NFC" displayName="Passive NFC — revision B" sheetWidth={60} sheetHeight={40}>
    <keepout shape="rect" pcbX={zone.cx} pcbY={0} width={49} height={47} layers={["top", "bottom"]} excludeRefs={[".L1"]} />
    <ST25TN01K_AFH5 name="U1" pcbX={PARTS.U1.x} pcbY={PARTS.U1.y} pcbRotation={PARTS.U1.rot} schX={0} schY={0} />
    {/*
      The PCB antenna. Its copper lives in the footprint so the schematic shows a
      plain inductor between the two antenna nets; the terminals are plated holes
      that carry the coil (bottom) up to the leads (top).
    */}
    <inductor
      name="L1"
      inductance={`${coilMicrohenries}uH`}
      doNotPlace
      {...coilTerminalsBonded}
      pcbX={0}
      pcbY={0}
      schX={-3.2}
      schY={-1.2}
      schOrientation="horizontal"
      footprint={
        <footprint>
          <platedhole
            portHints={["pin1"]}
            shape="circle"
            outerDiameter={`${TERMINAL.outerDiameter}mm`}
            holeDiameter={`${TERMINAL.holeDiameter}mm`}
            pcbX={outerEnd.x}
            pcbY={outerEnd.y}
          />
          <platedhole
            portHints={["pin2"]}
            shape="circle"
            outerDiameter={`${TERMINAL.outerDiameter}mm`}
            holeDiameter={`${TERMINAL.holeDiameter}mm`}
            pcbX={innerEnd.x}
            pcbY={innerEnd.y}
          />
          <pcbtrace
            layer="bottom"
            thickness={`${COIL.width}mm`}
            route={coil.map((p) => ({ route_type: "wire", x: p.x, y: p.y, width: COIL.width, layer: "bottom" }))}
          />
          <courtyardoutline outline={courtyard} />
        </footprint>
      }
    />

    {/* Only the two differential feeds enter the antenna keepout. Release audits
        enforce these exceptions geometrically, including turn-to-turn spacing. */}
    <trace name="ANT_A" schDisplayLabel="ANT_A" from=".L1 > .pin2" to=".U1 > .AC0"
      thickness={LEAD_WIDTH} pcbPath={[
        { x: 11.7, y: 3 }, { x: 11.7, y: 1.1 }, { x: 12.3, y: 0.5 },
      ]} />
    <trace name="ANT_B" schDisplayLabel="ANT_B" from=".L1 > .pin1" to=".U1 > .AC1"
      thickness={LEAD_WIDTH} pcbPath={[
        { x: 11.7, y: -3 }, { x: 11.7, y: -1.1 }, { x: 12.3, y: -0.5 },
      ]} />

    {zoneDashes.map((route, i) => (
      <Fragment key={`zone-${i}`}>
        <silkscreenpath route={route} strokeWidth="0.3mm" />
      </Fragment>
    ))}
    {iconArcs.map((route, i) => (
      <Fragment key={`icon-${i}`}>
        <silkscreenpath route={route} strokeWidth="0.55mm" />
      </Fragment>
    ))}
    <silkscreenpath route={iconDot} strokeWidth="0.6mm" />
    <silkscreentext text="TAP HERE" fontSize="3.2mm" anchorAlignment="center" pcbX={zone.cx} pcbY={-2.5} />
    <silkscreentext text="HOLD PHONE HERE" fontSize="1.7mm" anchorAlignment="center" pcbX={zone.cx} pcbY={-6.5} />

    <silkscreentext text={OWNER} fontSize="3.2mm" anchorAlignment="center" pcbX={textX} pcbY={15} />
    <silkscreentext text={TAGLINE} fontSize="1.8mm" anchorAlignment="center" pcbX={textX} pcbY={10.5} />
    <silkscreenpath route={[{ x: 17, y: 8 }, { x: 40, y: 8 }]} strokeWidth="0.2mm" />
    <silkscreentext text="TAP TO OPEN" fontSize="1.7mm" anchorAlignment="center" pcbX={textX} pcbY={5} />
    <silkscreentext text="MY PAGE" fontSize="1.7mm" anchorAlignment="center" pcbX={textX} pcbY={2} />
    <silkscreentext text="U1" fontSize="1.7mm" anchorAlignment="center" pcbX={13.5} pcbY={-3.5} />
    <silkscreentext text="13.56 MHz" fontSize="1.7mm" anchorAlignment="center" pcbX={textX} pcbY={-19} />
    <silkscreentext text="REV B / NFC" fontSize="1.7mm" anchorAlignment="center" pcbX={textX} pcbY={-22} />
    </schematicsheet>
  </board>
)