Skip to main content
Tutorials

Draw Any Letter With LEDs

Overview

This tutorial shows how to create a reusable LedLetter component. The component takes a capital letter, converts it into a 5 by 7 pixel font, and places one LED for every lit pixel.

The intended usage is:

<LedLetter letter="A" power="net.power" gnd="net.gnd" />

The component below supports capital A through Z, uses small SMD LEDs, and adds one current-limiting resistor for every LED. The PCB layout is generated from simple grid math, and the schematic is automatically spread into readable rows so larger letters do not stack every LED and resistor in one place.

How the layout works

The font is a small Record<string, string[]> where each letter is seven rows tall and five columns wide. Each 1 becomes an LED. Each 0 is left empty.

For every lit pixel, the component calculates the PCB position like this:

const ledPcbX = pcbX + (col - (columns - 1) / 2) * pitch
const ledPcbY = pcbY + ((rows - 1) / 2 - row) * pitch

That keeps the letter centered around pcbX and pcbY, regardless of which letter is selected. Increasing pitch makes the letter larger. Decreasing it makes the LEDs tighter.

Current limiting

Every LED gets its own resistor:

<trace from={power} to={"." + resistorName + " .pos"} />
<trace from={"." + resistorName + " .neg"} to={"." + ledName + " .pos"} />
<trace from={"." + ledName + " .neg"} to={gnd} />

This makes the electrical path:

power -> resistor -> LED -> ground

The default is a 1k resistor and 0603 footprints for both the LED and the resistor. You can switch to 0402 parts when you want a smaller, denser letter:

<LedLetter
letter="K"
power="net.V5"
gnd="net.GND"
ledFootprint="0402"
resistorFootprint="0402"
pitch={2.2}
/>

Reusing the component

Use a different name for every instance so the generated component names stay unique:

<LedLetter name="LEFT_A" letter="A" power="net.V5" gnd="net.GND" pcbX={-12} />
<LedLetter name="RIGHT_Z" letter="Z" power="net.V5" gnd="net.GND" pcbX={12} />

The same font map can be adjusted later if you want a more rounded or condensed style. The placement math does not need to change because it only depends on the row and column of each lit pixel.