So we’re singing from the same page, let’s lay out some eye terminology…

The technical term for the “white” of the eye is the sclera.

The iris is the muscle that contracts to adjust the size of the pupil in response to light.

The upper and lower eyelids are involved in blinking.

This program’s eye graphics are stored flat and unrolled, like a map projection. The horizontal (X) axis works like the longitude, or angle around the eye, while the vertical (Y) axis is the latitude. The images are wrapped around the pupil in a clockwise direction.

There are two images (or texture maps) associated with the eyes…one for the iris, another for the sclera.

The iris is what we think of as the “color” of the eye and is most often what you’ll want to edit. Sometimes you just need to edit the hue & saturation in a program like Photoshop, or you can make something totally custom if you’re after a particular look.

The sclera is the “white” of the eye…which really isn’t that white at all. There’s veins and blotches and gross stuff!

Image Storage

The texture maps are stored as 24-bit BMP images…nobody’s favorite, but easy for microcontrollers to handle. (This is also sometimes called “Windows Bitmap” format, though plenty of non-Windows software can read and write these images…and not to be confused with “X BitMap” or “Portable Bitmap Format,” different animals.)

Textures are loaded from drive into RAM, downsampled to 16-bit color (what the displays natively use) and then written to the chip’s internal flash memory (different from the flash filesystem). Although the code places no strict limit on image dimensions, RAM and flash are both finite resources, and this limits to how large these textures can be…both individually and in total.

No single image can exceed available RAM, or about 160 kilobytes. The total of all images must fit within flash, or about 360 kilobytes. These figures might change a bit in the future, so try to leave yourself some overhead.

Use the following formula to determine the space needed for an image:

width in pixels × height in pixels × 2 bytes

For example, a 500 × 150 pixel texture would consume 500 × 150 × 2 = 150,000 bytes. This fits in RAM just fine, and takes up a bit less than half of the flash space.

You don’t have to texture-map both the iris and sclera if you don’t want to…on the Configurable Settings page we explain how to use solid colors for either or both. Also shown there…it’s possible to assign independent textures to the left and right eyes. When both eyes are sharing the same texture, the code will place only one instance in flash, saving space.

To make the re-use of textures less obvious, the “seam” where a texture map wraps around is normally at the 12 o’clock position for the right eye and 6 o’clock for the left eye. The Configurable Settings page shows how to change this.

Eye textures can be any size (RAM permitting), on either axis…even down to a single pixel. When wrapping small images around the whole eye, nearest-neighbor sampling (no interpolation) is used. This can be exploited to create stylized blocky or grid designs…no need to waste space on a big image when just a few pixels will do.

Too-large images may exceed available space, while too-small images may exhibit visible jaggies (unless you’re aiming for that effect as described above). The ideal size can be calculated based on the circumference of the iris or the whole eye…

The iris and overall eye size are configurable (shown on following page)…but for example, let’s assume you’ve got an iris with a 60 pixel radius (120 pixel diameter) and the eyeball has a 125 pixel radius (250 pixel diameter)…both of these are the defaults.

Multiply the iris and/or eye diameters by Pi (3.14) to get the ideal width in pixels for the iris and sclera images.

For example: iris with 120 pixel diameter. 120 px × 3.14 = 377 pixels wide. You can use that, or round up or down a smidge to a round number if you like (e.g. 360 or 380 pixels).

Sclera image width for 250 pixel diameter eye: 250 × 3.14 = 785 pixels wide…but again, OK to round up or down a little…use 800 pixels wide if you like, unless really pressed for space.

The ideal image heights are a bit different. First, although the code can load any size image, it won’t actually benefit above 128 pixels on the vertical axis, it’s just wasted space. For the iris, use its radius (60 pixels in the case described above) or even a little less, since the pupil is always open a bit. For the sclera…try 200 minus the iris radius, keeping in mind the 128 pixel recommended maximum (e.g. with a 60 pixel iris, 140 is our target, then cap it at 128). But…with an 800 pixel wide sclera as described above…800 × 128 × 2 = 204 kilobytes…quite a bit over the 160K RAM limit! Whittle down one or both axes, whatever you think can best handle less resolution, until you find a size that fits. Once in motion, and at a reasonable viewing distance, minor “jaggies” aren’t that noticeable.

Photoshop users: the eye code maps textures differently than Photoshop’s “Polar Coordinates” filter. Ours wraps clockwise, with the top of the image becoming the outer circumference, while Photoshop wraps counterclockwise, with the bottom becoming the outer circumference. If using Photoshop to create or preview textures, simply rotate the rectangular image 180° before applying a rectangular-to-polar filter, or after a polar-to-rectangular filter.


The eyelids have stricter requirements. There are always two files (one each for the upper and lower eyelids) both 240 × 240 pixels exactly, both 1-bit BMP images (NOT 24-bit like the texture maps!).

The white area — which should span the entire 240 pixel width — represents the extent of vertical motion, the “open-most” and “closed-most” range. The eyes won’t hold the open-most position all the time when idle…the upper eyelid “tracks” the moving pupil, because that’s how eyes work.

A good set of eyelid images will overlap by a few pixels, so the eye makes a good solid blink.

This particular set of eyelids is slightly asymmetrical to approximate the eye’s caruncle* — that triangular bit by the tear duct. The shape is mirrored between the two eyes. But it is super 100% okay to make symmetrical eyelids if you prefer…a simple “football shape”…that usually looks better on a single-eye board like the HalloWing M4. For some of the eye designs we’ll offer both.

* Which itself is a vestigial remnant of the nictitating membrane, the “third eyelid” that reptiles have. How cool is that!?

The eyelid images as shown above are for the right eye. That is…the monster’s right eye, meaning the eye on the left when looking at the M4SK.

This guide was first published on Aug 20, 2019. It was last updated on Jun 19, 2024.

This page (Preparing Graphics) was last updated on Mar 08, 2024.

Text editor powered by tinymce.