main
John Lauer Three revisions with per-experiment write-ups, inline 3D viewers, sources, fab files, open-science scorecard 091a7c9 12d ago
import { Molecule } from "@tsci/adom-inc.molecule"
import { UsbCReceptacle } from "./UsbCReceptacle"

// "STEVEN" desk nameplate molecule, 5 x 7 dot-matrix edition.
// USB-C powered from the EAST (right) edge, one white 0603 LED per lit pixel,
// each with its own 470 ohm resistor (~4.3 mA, keeps the whole board under the 500 mA a USB-C source gives without negotiation). Four corner machine pins fixture it into
// the Adom workcell.
//
// Every part is an Adom Basic Part (wiki.adom.inc/adom/adom-basic-parts):
//   LED    IN-S63BT5UW        white 0603, Inolux
//   R      CR0402-FX-4700GLF  470 ohm 1% 0402, Bourns
//   R_CC   CR0402-FX-4701GLF  4.7 kohm 1% 0402, Bourns  (USB-C Rd)
//   C_BULK CL21A106KOQNNNG    10 uF X5R 0805, Samsung
//   C_HF   0402B104J160CT     100 nF X7R 0402, Walsin
//   J1     TYPE-C-31-M-12     LCSC C165948 (wrapper copied verbatim from the adom-usbc guide)

// 5x7 font. 1 = LED. Row 0 is the top row. Five columns, not three, so N gets
// a real diagonal: a 3-wide N degenerates into a blob that reads as H.
const FONT: Record<string, string[]> = {
  S: ["01111", "10000", "10000", "01110", "00001", "00001", "11110"],
  T: ["11111", "00100", "00100", "00100", "00100", "00100", "00100"],
  E: ["11111", "10000", "10000", "11110", "10000", "10000", "11111"],
  V: ["10001", "10001", "10001", "10001", "10001", "01010", "00100"],
  // The diagonal walks column 1 to 2 to 3 down the glyph.
  N: ["10001", "11001", "11001", "10101", "10011", "10011", "10001"],
  L: ["10000", "10000", "10000", "10000", "10000", "10000", "11111"],
  A: ["00100", "01010", "10001", "10001", "11111", "10001", "10001"],
  I: ["11111", "00100", "00100", "00100", "00100", "00100", "11111"],
}

const TEXT = "STEVEN"

const COLS = 5
const ROWS = 7
const PITCH = 3.0
const LETTER_GAP = 3.0
const LETTER_W = COLS * PITCH
const TEXT_WIDTH = TEXT.length * LETTER_W + (TEXT.length - 1) * LETTER_GAP

// Board: text + a left margin + ~20 mm reserved on the east edge for the
// USB-C receptacle, its CC resistors and decoupling.
const BOARD_W = Math.ceil((TEXT_WIDTH + 30) / 2) * 2
const BOARD_H = 44
const TEXT_LEFT_X = -BOARD_W / 2 + 8
const TEXT_CENTER_Y = 1

// adom-usbc guide: W/2 - 4 for a nominal-size molecule. This one is ABSOLUTE
// sized, so the real edge is 1 mm further out (W/2 + 0.2 wing, measured); W/2 - 5
// lands the guide reference numbers: overhang 2.3, hole gap 1.8, pad gap 7.0.
const USB_X = BOARD_W / 2 - 5
const PARTS_X = USB_X - 9

const R_OFFSET = 1.6   // resistor sits this far below its LED

type Pixel = { x: number; y: number; idx: number }
const PIXELS: Pixel[] = (() => {
  const out: Pixel[] = []
  let idx = 0
  for (let li = 0; li < TEXT.length; li++) {
    const g = FONT[TEXT[li]]
    const x0 = TEXT_LEFT_X + li * (LETTER_W + LETTER_GAP)
    for (let row = 0; row < ROWS; row++)
      for (let col = 0; col < COLS; col++) {
        if (g[row][col] !== "1") continue
        out.push({ x: x0 + col * PITCH + PITCH / 2, y: TEXT_CENTER_Y + (3 - row) * PITCH, idx: idx++ })
      }
  }
  return out
})()
const N = PIXELS.length

// Schematic: every symbol gets explicit coordinates. Placing SOME parts turns
// tscircuit's auto-layout off for the rest, so it is all or nothing.
const SCH_COLS = 10
const schSlot = (i: number) => ({ x: -40 + (i % SCH_COLS) * 8, y: 40 - Math.floor(i / SCH_COLS) * 3 })

export default () => (
  <Molecule
    type="4pin"
    size={`${BOARD_W}x${BOARD_H} absolute`}
    pinType="MachinePinMediumStandard"
    wing="nominal"
    roundEdges={true}
  >
    <silkscreentext text="S T E V E N" fontSize={1.3} pcbX={TEXT_LEFT_X + TEXT_WIDTH / 2} pcbY={17} layer="top" />
    <silkscreentext text="Steven Moss * Astera Institute" fontSize={0.6} pcbX={TEXT_LEFT_X + TEXT_WIDTH / 2} pcbY={15.4} layer="top" />
    <silkscreentext text="ADOM * FORT WORTH TEXAS" fontSize={0.5} pcbX={TEXT_LEFT_X + TEXT_WIDTH / 2} pcbY={-15} layer="top" />
    <silkscreentext text="5V IN" fontSize={0.8} pcbX={PARTS_X + 2} pcbY={13.5} layer="top" />
    <silkscreentext text="USB-C >>" fontSize={0.55} pcbX={PARTS_X + 2} pcbY={12.2} layer="top" />

    <silkscreentext layer="bottom" text="STEVEN NAMEPLATE v2" fontSize={1.4} pcbX={0} pcbY={10} />
    <silkscreentext layer="bottom" text={`${N} white 0603 LEDs * 5x7 dot matrix * one 470R per LED`} fontSize={0.55} pcbX={0} pcbY={7.5} />
    <silkscreentext layer="bottom" text="Plug any USB-C phone charger into the RIGHT edge" fontSize={0.55} pcbX={0} pcbY={6} />
    <silkscreentext layer="bottom" text="Designed by AI with adom-tsci * wiki.adom.inc/adom/steven-led-nameplate" fontSize={0.5} pcbX={0} pcbY={3.5} />
    <silkscreentext layer="bottom" text="Adom Industries * Fort Worth, Texas * 2026" fontSize={0.5} pcbX={0} pcbY={2} />

    <UsbCReceptacle name="J1" pcbX={USB_X} pcbY={0} mount="east" schX={-30} schY={-12} />
    <resistor name="R_CC1" resistance="4.7k" footprint="0402" manufacturerPartNumber="CR0402-FX-4701GLF" pcbX={PARTS_X} pcbY={6} schX={-14} schY={-9} />
    <resistor name="R_CC2" resistance="4.7k" footprint="0402" manufacturerPartNumber="CR0402-FX-4701GLF" pcbX={PARTS_X} pcbY={-6} schX={-14} schY={-15} />
    <capacitor name="C_BULK" capacitance="10uF" footprint="0805" manufacturerPartNumber="CL21A106KOQNNNG" pcbX={PARTS_X} pcbY={0} schX={-4} schY={-12} />
    <capacitor name="C_HF" capacitance="100nF" footprint="0402" manufacturerPartNumber="0402B104J160CT" pcbX={PARTS_X + 3.5} pcbY={0} schX={2} schY={-12} />

    <net name="VBUS" />
    <net name="GND" />
    <trace from="J1.VBUS1" to="net.VBUS" />
    <trace from="J1.VBUS2" to="net.VBUS" />
    <trace from="J1.GND1" to="net.GND" />
    <trace from="J1.GND2" to="net.GND" />
    <trace from="R_CC1.pin1" to="J1.CC1" />
    <trace from="R_CC1.pin2" to="net.GND" />
    <trace from="R_CC2.pin1" to="J1.CC2" />
    <trace from="R_CC2.pin2" to="net.GND" />
    <trace from="C_BULK.pin1" to="net.VBUS" />
    <trace from="C_BULK.pin2" to="net.GND" />
    <trace from="C_HF.pin1" to="net.VBUS" />
    <trace from="C_HF.pin2" to="net.GND" />

    {PIXELS.map((p) => (
      <resistor key={`R${p.idx}`} name={`R${p.idx + 1}`} resistance="470" footprint="0402"
        manufacturerPartNumber="CR0402-FX-4700GLF" pcbX={p.x} pcbY={p.y - R_OFFSET} pcbRotation={180}
        schX={schSlot(p.idx).x} schY={schSlot(p.idx).y} />
    ))}
    {PIXELS.map((p) => (
      <led key={`D${p.idx}`} name={`D${p.idx + 1}`} color="white" footprint="0603"
        manufacturerPartNumber="IN-S63BT5UW" pcbX={p.x} pcbY={p.y}
        schX={schSlot(p.idx).x + 3} schY={schSlot(p.idx).y} />
    ))}
    {PIXELS.map((p) => <trace key={`tv${p.idx}`} from={`R${p.idx + 1}.pin1`} to="net.VBUS" />)}
    {PIXELS.map((p) => <trace key={`tr${p.idx}`} from={`R${p.idx + 1}.pin2`} to={`D${p.idx + 1}.anode`} />)}
    {PIXELS.map((p) => <trace key={`tg${p.idx}`} from={`D${p.idx + 1}.cathode`} to="net.GND" />)}
  </Molecule>
)