Luminary Geometry: LED Period-Tracking Lunar Calendar

This project manifested at the time of the overturning of the U.S. Supreme Court’s Roe v. Wade decision in June 2022. As the news spread like wildfire, menstruating people worldwide were quickly advised to delete their period-tracking data from private apps and devices, to hide their period data from their doctors, and even their partners, to avoid future incrimination around the right to abortion.
Shocked and angry, I needed an outlet, and what better outlet than making?
Islamic Geometry
A month or so before the news hit, I had taken an online Islamic geometry course by Samira Mian. Soon after, I began experimenting with the patterns in code (p5js). The code got me thinking about translating the patterns into hardware, and I proposed this idea to arturo182. Inspired by Jason Coon’s LED CycloHex patterns, we attempted an LED Islamic geometry-inspired circuit board. We chose the ten-pointed star from a pattern book I found in my late grandfather’s dusty library on my last visit to India.

The 10-pointed star was an easy pattern to replicate and tessellate with digital software. Arturo182 designed the entire circuit board from scratch in KiCad. It incorporated addressable surface-mount LEDs — 10 for each star unit in a 6×5 grid (30 units = 250 LEDs, because some LEDs overlap by the nature of the geometric pattern). We consulted each other on the look and feel of the board: purple solder mask, white silkscreen, and gold for the traditional art of Islamic illumination. At the time, we aimed to experiment with NeoPixel libraries and play with LED animations. We wanted to have fun and make a pretty board, but had no idea about the new direction the project would take.

Soon the most beautiful Islamic geometry-inspired circuit board was in our hands. We hooked it up to Solder Party’s RP2040 Stamp Round Carrier and used CircuitPython to program it. But I was far from satisfied with the blinky LED animation trains, which I thought took the focus away from the timeless artform on the circuit board. I wanted to make it appear delicate, drawing attention to the art.

Many Moons
Meanwhile, my obsession with Islamic geometry grew, and I learned all sorts of interesting meanings and symbolisms embodied in the artform — symmetry, unity, harmony, and balance. By drawing connections to symmetrical natural cycles sacred to many cultures and practices, I landed on experimenting with moon phases on the board. Arturo182 helped manually program each unit of 10 LEDs using a coded array to reflect four phases of the moon (first-quarter, full moon, third-quarter, new moon). A total grid of 30 ten-pointed stars allowed us to visualize the board as a monthly moon phase calendar! Another silver lining was learning that lunar months alternate between 29 and 30 days, so we could ignore months with 31 days.
We initially chose white (#FFFFFF) for the LEDs representing the moon phases (the new moon was on a dimmer setting to indicate a fresh start). The board looked beautiful, but it still felt scant. It needed something more.

With the overturning of Roe v. Wade, it didn’t take me long to imagine my monthly period tracking data alongside the moon phase calendar. This is when the project came together. I manually programmed the LEDs to reflect the two natural cycles in delectable twilight colors: #330019 (deep rose) for period tracking, #190033 (dark purple) for half and full moon phases, and #0F000F (dark magenta-purple) for the new moon. For this, I used an online tool that includes an RBG color picker and converts a chosen color to a hex code. I experimented with a bunch of twilight hues on the LEDs before I came to a final decision. It made sense to bring more beauty to these natural cycles and to see them together — a way to push back against the misogyny surrounding our female bodies.
Project Steps
CircuitPython Code
The project code is rather short. Download code.py from the GitHub repo. Start by importing the board library for pin information and the neopixel library for controlling the LEDs:
import board import neopixel
Then define the pixel pin on the board to control all 250 LEDs. If you’re not using the 2040 Stamp Round Carrier, ensure that you have the right pixel pin for your board. Define the number of NeoPixels:
pixel_pin = board.GP11 num_pixels = 250
Next, write an array for a total of 30 star units (moons) of 10 LEDs each. Make sure to get the numbers right — remember, some LEDs overlap!
moons = [ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [10, 6, 7, 11, 12, 13, 14, 15, 16, 17], [18, 14, 15, 19, 20, 21, 22, 23, 24, 25], [26, 22, 23, 27, 28, 29, 30, 31, 32, 33], [34, 30, 31, 35, 36, 37, 38, 39, 40, 41], [42, 38, 39, 43, 44, 45, 46, 47, 48, 49], [50, 51, 52, 53, 54, 55, 56, 57, 58, 59], [60, 56, 57, 61, 62, 63, 64, 65, 66, 67], [68, 64, 65, 69, 70, 71, 72, 73, 74, 75], [76, 72, 73, 77, 78, 79, 80, 81, 82, 83], [84, 80, 81, 85, 86, 87, 88, 89, 90, 91], [92, 88, 89, 93, 94, 95, 96, 97, 98, 99], [100, 101, 102, 103, 104, 105, 106, 107, 108, 109], [110, 106, 107, 111, 112, 113, 114, 115, 116, 117], [118, 114, 115, 119, 120, 121, 122, 123, 124, 125], [126, 122, 123, 127, 128, 129, 130, 131, 132, 133], [134, 130, 131, 135, 136, 137, 138, 139, 140, 141], [142, 138, 139, 143, 144, 145, 146, 147, 148, 149], [150, 151, 152, 153, 154, 155, 156, 157, 158, 159], [160, 156, 157, 161, 162, 163, 164, 165, 166, 167], [168, 164, 165, 169, 170, 171, 172, 173, 174, 175], [176, 172, 173, 177, 178, 179, 180, 181, 182, 183], [184, 180, 181, 185, 186, 187, 188, 189, 190, 191], [192, 188, 189, 193, 194, 195, 196, 197, 198, 199], [200, 201, 202, 203, 204, 205, 206, 207, 208, 209], [210, 196, 197, 211, 212, 213, 214, 215, 216, 217], [218, 214, 215, 219, 220, 221, 222, 223, 224, 225], [226, 222, 223, 227, 228, 229, 230, 231, 232, 233], [234, 230, 231, 235, 236, 237, 238, 239, 240, 241], [242, 238, 239, 243, 244, 245, 246, 247, 248, 249] ]
Then define how the LEDs correspond with the moon phases and the period days. We define four moon phases in this project — full moon (10 LEDs), first-quarter (6 LEDs), third-quarter (6 LEDs), and the new moon (10 LEDs, second color). The period day is drawn the same as the full/new moon but we define it separately so we can later assign the right color to it.
def show_fullmoon(moon, color): for i in range(10): pixels[moons[moon][i]] = color def show_firstquarter(moon, color): for i in range(5): pixels[moons[moon][i]] = color pixels[moons[moon][9]] = color def show_thirdquarter(moon, color): for i in range(4, 10): pixels[moons[moon][i]] = color def show_newmoon(moon, color): for i in range(10): pixels[moons[moon][i]] = color def period(moon, color): for i in range(10): pixels[moons[moon][i]] = color
The following is most important part of the code because it’s where you edit the moon phases and period days for every calendar month. For example, in the code below, period days fall between the third and seventh day of the month (i.e., define period units 2, 3, 4, 5, 6), full moon on the eighth day, and so on. Moon phase information can be found on a website like timeanddate.com.
period(2, 0x330019) period(3, 0x330019) period(4, 0x330019) period(5, 0x330019) period(6, 0x330019) show_fullmoon(7, 0x190033) show_firstquarter(15, 0x190033) show_newmoon(22, 0x0F000F) show_thirdquarter(29, 0x190033)
Conclusion
Seeing my period days overlap with the moon phases gave me a feeling for when my next cycle will arrive. Despite being a manual process of updating the board each month, I feel more empowered to visualize my cycle, locally and privately, rather than hide it from those who wish to take control of female bodies and their data.
Photography by arturo182.
This article appeared in Make: Vol. 86.
Leave a Reply