molecule
Steven's Nameplate: three revisions
Public Made by Adomby adom
A USB-C desk nameplate for Steven Moss (Astera Institute), built three ways and published as open experiments: a 3x5 LED board, a 5x7 LED board, and a laser-ablated silkscreen plate. Source, fab files, negative results, reproduce steps.
main
John Lauer
Three revisions with per-experiment write-ups, inline 3D viewers, sources, fab files, open-science scorecard
091a7c9
12d ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
import { Molecule, ValidateContacts } from "@tsci/adom-inc.molecule"
import { MachineContactMedium } from "@tsci/adom-inc.library"
import { UsbCReceptacle } from "./UsbCReceptacle"
// 3×5 pixel font — [col, row] pairs for each lit LED (row 0 = top)
const FONT: Record<string, [number, number][]> = {
S: [[0,0],[1,0],[2,0],[0,1],[0,2],[1,2],[2,2],[2,3],[0,4],[1,4],[2,4]],
T: [[0,0],[1,0],[2,0],[1,1],[1,2],[1,3],[1,4]],
E: [[0,0],[1,0],[2,0],[0,1],[0,2],[1,2],[0,3],[0,4],[1,4],[2,4]],
V: [[0,0],[2,0],[0,1],[2,1],[0,2],[2,2],[0,3],[2,3],[1,4]],
N: [[0,0],[2,0],[0,1],[1,1],[2,1],[0,2],[2,2],[0,3],[2,3],[0,4],[2,4]],
}
const WORD = "STEVEN"
const GRID = 3.5 // mm between LED centers
const LETTER_GAP = 4 // mm gap between letters
const LETTER_W = 2 * GRID
type Led = { x: number; y: number }
const leds: Led[] = []
let cursor = 0
for (const ch of WORD) {
for (const [col, row] of FONT[ch]) {
leds.push({ x: cursor + col * GRID, y: -row * GRID })
}
cursor += LETTER_W + LETTER_GAP
}
const textWidth = cursor - LETTER_GAP // 62 mm for STEVEN
const xOff = -(textWidth / 2) // centred on a 96-wide board → −31 … +31
const yOff = 7 // center vertically: rows at y = 7, 3.5, 0, -3.5, -7
const N = leds.length // 58
// Nominal board width. USB-C sits at W/2 − 4 per the adom-usbc guide.
const W = 96
export default () => (
<Molecule
type="4pin"
size="96x24"
pinType="MachinePinMediumStandard"
wing="nominal"
roundEdges={true}
>
{/* ── Silkscreen ── */}
<silkscreentext text="STEVEN" fontSize={1.3}
pcbX={xOff + textWidth / 2} pcbY={-10} layer="top" />
<silkscreentext text="NAME IN LIGHTS" fontSize={0.5}
pcbX={xOff + textWidth / 2} pcbY={-11.3} layer="top" />
<silkscreentext layer="bottom" text="STEVEN'S NAMEPLATE" fontSize={1.0} pcbX={0} pcbY={3} />
<silkscreentext layer="bottom" text={`USB-C powered · ${N} white LEDs`} fontSize={0.5} pcbX={0} pcbY={1.5} />
<silkscreentext layer="bottom" text="v1.0 · 2026" fontSize={0.5} pcbX={0} pcbY={0} />
{/* ── 4 corner machine contacts for workcell scaffold (2 mm grid) ── */}
<ValidateContacts>
<MachineContactMedium name="MC_VCC1" pcbX={-40} pcbY={8} />
<MachineContactMedium name="MC_GND1" pcbX={-40} pcbY={-8} />
<MachineContactMedium name="MC_VCC2" pcbX={36} pcbY={8} />
<MachineContactMedium name="MC_GND2" pcbX={36} pcbY={-8} />
</ValidateContacts>
<silkscreentext text="VCC" fontSize={0.4} pcbX={-40} pcbY={6.5} layer="top" />
<silkscreentext text="GND" fontSize={0.4} pcbX={-40} pcbY={-6.5} layer="top" />
<silkscreentext text="VCC" fontSize={0.4} pcbX={36} pcbY={6.5} layer="top" />
<silkscreentext text="GND" fontSize={0.4} pcbX={36} pcbY={-6.5} layer="top" />
{/* ── USB-C power input (east edge) — pcbX = nominal/2 − 4 = 44 ── */}
<UsbCReceptacle name="J1" pcbX={W / 2 - 4} pcbY={0} mount="east" />
{/* CC pulldowns. Spec is Rd = 5.1k ±10% (4.59k–5.61k). Adom stocks no
5.1k in any package (see adom-basic-parts), so use the stocked 4.7k
0402 — comfortably inside the window, unlike 5.6k which sits on the
upper limit. */}
<resistor name="R_CC1" resistance="4.7k" footprint="0402" pcbX={37} pcbY={2} />
<resistor name="R_CC2" resistance="4.7k" footprint="0402" pcbX={37} pcbY={-2} />
<capacitor name="C_BYP" capacitance="100nF" footprint="0402" pcbX={40} pcbY={5} />
{/* ── 58 white 0603 LEDs spelling STEVEN (3×5 pixel grid, 3 mm pitch) ── */}
{leds.map((pos, i) => (
<led key={`D${i + 1}`} name={`D${i + 1}`} color="white" footprint="0603"
pcbX={xOff + pos.x} pcbY={yOff + pos.y} />
))}
{/* ── 58 × 220 Ω current-limiting resistors (one per LED), 1.6 mm below each
LED and rotated 180° so pin2 sits directly under the anode. 1.6 mm (not
1.5/1.75/1.9) is the offset the autorouter fully connects — the others
each leave one bottom-layer trace ending under a top pad with no via;
see scripts/check-connectivity.py. ── */}
{leds.map((pos, i) => (
<resistor key={`R${i + 1}`} name={`R${i + 1}`} resistance="220" footprint="0402"
pcbX={xOff + pos.x} pcbY={yOff + pos.y - 1.6} pcbRotation={180} />
))}
{/* ── Nets ── */}
<net name="VBUS" />
<net name="GND" />
{/* Machine contacts → power rails (scaffold can power the board too) */}
<trace from="MC_VCC1.pin1" to="net.VBUS" />
<trace from="MC_VCC2.pin1" to="net.VBUS" />
<trace from="MC_GND1.pin1" to="net.GND" />
<trace from="MC_GND2.pin1" to="net.GND" />
{/* USB-C → power rails */}
<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" />
{/* CC pulldowns — required for a charger to supply power */}
<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" />
{/* Bypass cap */}
<trace from="C_BYP.pin1" to="net.VBUS" />
<trace from="C_BYP.pin2" to="net.GND" />
{/* LED wiring: VBUS → resistor → LED anode, cathode → GND */}
{leds.map((_, i) => (
<trace key={`vr${i}`} from={`R${i + 1}.pin1`} to="net.VBUS" />
))}
{leds.map((_, i) => (
<trace key={`rd${i}`} from={`R${i + 1}.pin2`} to={`D${i + 1}.anode`} />
))}
{leds.map((_, i) => (
<trace key={`dg${i}`} from={`D${i + 1}.cathode`} to="net.GND" />
))}
</Molecule>
)