Drawing Lines
A straight line is the cheapest way to put emotion on a screen. Tilt two short lines above a pair of eyes and your robot goes from calm to furious — no curves, no fills, no extra memory. The framebuffer gives you three line commands, and picking the right one matters more than you might expect.
Three Ways to Draw a Line
The general line() command can draw any line at all, so you might wonder why the other two exist. The answer is speed: horizontal and vertical lines are so common that MicroPython includes shortcuts that skip the angle math entirely.
1 2 3 | |
Notice that the three commands take different arguments. hline() and vline() start at a point and take a length — how many pixels to run. line() takes two full points and connects them.
| Command | Arguments | Use it for |
|---|---|---|
hline(x, y, w, c) |
start point plus a width | Flat mouths, dividers, box tops and bottoms |
vline(x, y, h, c) |
start point plus a height | Narrow eyes, box sides, tally marks |
line(x1, y1, x2, y2, c) |
two end points | Angled eyebrows, zigzag mouths, anything diagonal |
Reach for hline and vline When You Can
hline(0, 20, 128, 1) and line(0, 20, 127, 20, 1) draw the same row of dots, but the first one is faster. In an animation loop running 30 times a second, those savings add up.
Sample Program Code
This program draws two things at once. On the left, a box built from two hline() calls and two vline() calls, with an X of general line() calls inside it. On the right, an angry face made from nothing but lines.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | |
Here's what that program draws on the display:

The Eyebrow Rule
That face on the right is five lines and it still reads as angry. The reason is entirely in the eyebrows: both of them slope down toward the nose. The left brow runs from (68, 12) down to (86, 22), and the right one mirrors it.
Remember that y grows downward on this display, so a larger y means lower on the screen. The inner ends of both eyebrows have the larger y values, which puts them closer to the nose and closer to the mouth.
Flip those numbers and the whole feeling flips with them:
| Inner ends of the eyebrows | Reads as |
|---|---|
| Lower than the outer ends | Angry, focused, determined |
| Higher than the outer ends | Sad, worried, pleading |
| Level with the outer ends | Neutral, calm, idle |
Diagonal Lines Look Chunky, and That's Normal
Your diagonals will come out as little stair steps, because a pixel can only sit on the grid — it can't land halfway between two rows. Every screen does this. Step back a foot and the stairs vanish.
Watch the Off-by-One
Here is the mistake that catches almost everyone. hline(0, 20, 128, 1) draws 128 pixels starting at column 0, so it covers columns 0 through 127 — exactly the full width of the display. Write hline(0, 20, 129, 1) and that last pixel has nowhere to go.
The same logic applies to line(), but with a twist: line() takes end points, not lengths. To span the full width you write line(0, 20, 127, 20, 1), using 127 rather than 128, because the rightmost column is numbered 127.
Challenge
- Change the two eyebrow lines so the face reads as sad instead of angry.
- Rebuild the box on the left using only
line()calls. Does it look any different? - Draw a frowning mouth from two
line()calls that meet in the middle. - Animate a single
hline()moving down the screen to make a scanning effect, clearing withfill(0)between frames.