Eyebrows
If you could keep only one feature on a robot face, keep the eyebrows. They carry more emotional
information per pixel than the eyes and the mouth combined, and this lab builds them out of
poly() so they can bend instead of just tilting.
Why a Polygon Instead of a Line
A straight diagonal line reads as an eyebrow, barely. A four-point polygon with a bend in the middle reads as an eyebrow that belongs to somebody. The curve is what does it.
1 2 | |
Every number is an offset from the eyebrow's anchor point, in signed shorts, so negative offsets are allowed — which is what lets the shape be written around a center rather than from a corner. Read the two arrays side by side and you will see the second is the first with its x-values negated. That is the mirror image, written by hand.
The Cost of a Filled Brow
shapes.poly() fills a shape by drawing one horizontal run per row it covers. A brow this size is about a dozen rows — a dozen runs down the wire, which is cheap. Open lib/shapes.py and read the scanline fill if you have not yet.
Sample Program Code
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 45 46 47 48 49 50 51 52 53 | |
Here's what that program draws on the display:

Look at how much attitude those two shapes add compared with the flat lines in Your First Face. Same eyes, same mouth, completely different character.
The Eyebrow Vocabulary
Almost every emotion in this kit is reachable by changing two things about the brows: their tilt and their lift.
| Brow position | Reads as |
|---|---|
| Inner ends angled down toward the nose | Angry, determined |
| Inner ends angled up | Sad, worried, pleading |
| Both raised high and flat | Surprised |
| Both low and flat | Bored, skeptical |
| One up, one down | Doubtful — the single most useful mismatched face |
One Number, Opposite Mood
Flip the sign on the second number of each array — the -12 — and the brows arch the other way. One character in the file, and my whole face changes what it is saying.
Things to Try
- Flip the arch, as in the tip above, and describe the new expression in one word before you look at anything else.
- Draw the brows with
NO_FILL. An outlined brow is a thin wire frame — on a screen this size it reads as a scratch, not a brow. That is why every stroke in this kit gets thickened. - Give the two brows different shapes by editing one array. A face with mismatched brows reads as skeptical, and it takes exactly one changed number to get there.
- Move the anchor. Change
EYE_Y - 44toEYE_Y - 30so the brows sit closer to the eyes. A low brow crowds the eye and reads as intensity; a high one reads as openness.
References
- Drawing Polygons — the scanline fill that makes a curved brow possible
- Drawing Lines — the straight-line eyebrow, and the rule about which way to tilt
- The Emotion Table — where brow tilt and lift become two columns of data