Skip to main content
Tutorials

Draw Any Letter with LEDs

Overview

In this tutorial you will build a PCB that spells out a letter using individual LEDs. Each LED is placed along the actual stroke of the character — not a blocky pixel grid — because we sample points directly from the vector paths in @tscircuit/alphabet.

The result is a compact, reusable LedLetter component that accepts any A–Z letter and produces a layout-ready circuit with resistors, LEDs, and traces already wired up.

How it works

1. Vector paths instead of a pixel grid

The @tscircuit/alphabet library stores each character as an SVG path made of M (move-to) and L (line-to) commands in a normalised [0, 1] coordinate space. We parse those commands into line segments, then walk along every segment and place a LED at regular intervals.

SVG path string
└─ parseSvgPath() → [ { x1, y1, x2, y2 }, … ]
└─ sampleSegments(spacing) → [ { x, y }, … ]
└─ <led> at (pcbX, pcbY)

Because we follow the actual stroke geometry the LEDs hug the curves of the letter rather than approximating them with a blocky bitmap.

2. Coordinate mapping

The glyph coordinates sit in roughly x: [0.02, 0.58], y: [0.26, 0.96]. We subtract the glyph centre (cx=0.3, cy=0.61) and multiply by size (in mm) to get PCB coordinates centred at (0, 0). The Y axis is also flipped because SVG measures downward while PCB coordinates measure upward.

pcbX = (glyph.x - 0.30) × size
pcbY = -(glyph.y - 0.61) × size

3. Per-LED circuit

Each sample point gets a current-limiting resistor in series with an LED, both connected between the power net and ground:

net.VBUS → Rᵢ → LEDᵢ → net.GND

The default resistance of 150 Ω is safe for a 3.3 V supply. Adjust it with the resistance prop if you use a different voltage or LED colour.

Component API

<LedLetter
letter="A" // any uppercase A–Z
power="net.VBUS" // power net name
gnd="net.GND" // ground net name
size={20} // PCB extent in mm (default 20)
ledSpacing={0.12} // spacing between LEDs in glyph units (default 0.12)
resistance={150} // current-limiting resistor value in Ω (default 150)
/>

Switch the preview to PCB view in the panel above to see the letter shape, or to Schematic to inspect the wiring.

Extending to multiple letters

Wrap several LedLetter components in a <group> and offset each one horizontally to spell a word:

export default () => (
<board width="100mm" height="35mm">
<SmdUsbC
name="USBC"
connections={{ GND1: "net.GND", GND2: "net.GND", VBUS1: "net.VBUS", VBUS2: "net.VBUS" }}
pcbY={-13}
/>
<group pcbX={-30}>
<LedLetter letter="H" power="net.VBUS" gnd="net.GND" size={18} />
</group>
<group pcbX={0}>
<LedLetter letter="I" power="net.VBUS" gnd="net.GND" size={18} />
</group>
</board>
)

Each letter is self-contained: its own resistors, LEDs, and traces are generated automatically.


/claim tscircuit/docs-old#50