Overview
Turn every step into a burst of light with these interactive light-up children's animal slippers. A force-sensitive resistor tucked inside the insole detects steps, and instantly triggers animations across addressable NeoPixel LEDs, glowing in your favorite colors. As you walk, the slippers respond in real time—adding a playful, responsive layer of light to every step. Comfortable, customizable, and full of personality, this project brings wearable tech right to your child's feet.
This guide uses a Feather PropMaker RP2040 board, and we've included sample CircuitPython code to get you up and running. Customize the code to make the colors and animations exactly what you want them to be, and let your animal spirit shine through.
For two slippers you'll want to order two controllers, two resistors, two switches and two batteries. 1 meter (39 inches) of NeoPixels was enough to surround both of the little tyke slippers I made.
Additional Tools & Materials
- Animal Slippers! I ordered these - the eyes light up already for extra punch
- Needle & thread
- Seam ripper
- Soldering iron & accessories
- Hot glue gun
Page last edited April 22, 2026
Text editor powered by tinymce.
CircuitPython
CircuitPython is a derivative of MicroPython designed to simplify experimentation and education on low-cost microcontrollers. It makes it easier than ever to get prototyping by requiring no upfront desktop software downloads. Simply copy and edit files on the CIRCUITPY drive to iterate.
CircuitPython Quickstart
Follow this step-by-step to quickly get CircuitPython running on your board.
Click the link above to download the latest CircuitPython UF2 file.
Save it wherever is convenient for you.
To enter the bootloader, hold down the BOOT/BOOTSEL button (highlighted in red above), and while continuing to hold it (don't let go!), press and release the reset button (highlighted in red or blue above). Continue to hold the BOOT/BOOTSEL button until the RPI-RP2 drive appears!
If the drive does not appear, release all the buttons, and then repeat the process above.
You can also start with your board unplugged from USB, press and hold the BOOTSEL button (highlighted in red above), continue to hold it while plugging it into USB, and wait for the drive to appear before releasing the button.
A lot of people end up using charge-only USB cables and it is very frustrating! Make sure you have a USB cable you know is good for data sync.
You will see a new disk drive appear called RPI-RP2.
Drag the adafruit_circuitpython_etc.uf2 file to RPI-RP2.
The RPI-RP2 drive will disappear and a new disk drive called CIRCUITPY will appear.
That's it, you're done! :)
Safe Mode
You want to edit your code.py or modify the files on your CIRCUITPY drive, but find that you can't. Perhaps your board has gotten into a state where CIRCUITPY is read-only. You may have turned off the CIRCUITPY drive altogether. Whatever the reason, safe mode can help.
Safe mode in CircuitPython does not run any user code on startup, and disables auto-reload. This means a few things. First, safe mode bypasses any code in boot.py (where you can set CIRCUITPY read-only or turn it off completely). Second, it does not run the code in code.py. And finally, it does not automatically soft-reload when data is written to the CIRCUITPY drive.
Therefore, whatever you may have done to put your board in a non-interactive state, safe mode gives you the opportunity to correct it without losing all of the data on the CIRCUITPY drive.
To enter safe mode when using CircuitPython, plug in your board or hit reset (highlighted in red above). Immediately after the board starts up or resets, it waits 1000ms. On some boards, the onboard status LED (highlighted in green above) will blink yellow during that time. If you press reset during that 1000ms, the board will start up in safe mode. It can be difficult to react to the yellow LED, so you may want to think of it simply as a slow double click of the reset button. (Remember, a fast double click of reset enters the bootloader.)
In Safe Mode
If you successfully enter safe mode on CircuitPython, the LED will intermittently blink yellow three times.
If you connect to the serial console, you'll find the following message.
Auto-reload is off. Running in safe mode! Not running saved code. CircuitPython is in safe mode because you pressed the reset button during boot. Press again to exit safe mode. Press any key to enter the REPL. Use CTRL-D to reload.
You can now edit the contents of the CIRCUITPY drive. Remember, your code will not run until you press the reset button, or unplug and plug in your board, to get out of safe mode.
Flash Resetting UF2
If your board ever gets into a really weird state and CIRCUITPY doesn't show up as a disk drive after installing CircuitPython, try loading this 'nuke' UF2 to RPI-RP2. which will do a 'deep clean' on your Flash Memory. You will lose all the files on the board, but at least you'll be able to revive it! After loading this UF2, follow the steps above to re-install CircuitPython.
Page last edited April 22, 2026
Text editor powered by tinymce.
Code the Slippers
Once you've finished setting up your RP2040 Prop-Maker Feather with CircuitPython, you can access the code and necessary libraries by downloading the Project Bundle.
To do this, click on the Download Project Bundle button in the window below. It will download to your computer as a zipped folder.
# SPDX-FileCopyrightText: 2026 Erin St Blaine for Adafruit Industries
#
# SPDX-License-Identifier: MIT
import time
import board
import digitalio
import neopixel
# =========================================================
# Ripple Footstep Lights with Color Cycling
# Pylint-friendly version
#
# What this project does:
# - Reads an FSR on pin A0
# - Triggers a ripple of light from the center of the strip
# - Changes color on each new press
# - If pressed again while running:
# - the timer extends
# - the color changes immediately
# - the ripple restarts from the center
# =========================================================
# -----------------------------
# USER SETTINGS
# -----------------------------
NUM_PIXELS = 20
ACTIVE_SECONDS = 3.0
PIXEL_BRIGHTNESS = 0.3
# Lower = faster ripple, higher = slower ripple
RIPPLE_DELAY = 0.05
# Lower = shorter trail, higher = longer trail
TRAIL_FADE = 0.6
# End fade settings
FADE_DELAY = 0.03
FADE_STEPS = 20
# Color cycle: white -> pink -> purple -> blue
COLOR_SEQUENCE = [
(255, 255, 255), # white
(255, 100, 180), # pink
(180, 0, 255), # purple
(0, 120, 255), # blue
]
print("boot")
# -----------------------------
# SENSOR SETUP
# -----------------------------
# FSR wired between A0 and GND.
# With internal pull-up enabled:
# - unpressed = True
# - pressed = False
motion = digitalio.DigitalInOut(board.A0)
motion.direction = digitalio.Direction.INPUT
motion.pull = digitalio.Pull.UP
print("motion ready")
# -----------------------------
# EXTERNAL POWER SETUP
# -----------------------------
# The Prop-Maker Feather needs EXTERNAL_POWER enabled
# to power the external NeoPixel terminal.
external_power = digitalio.DigitalInOut(board.EXTERNAL_POWER)
external_power.direction = digitalio.Direction.OUTPUT
external_power.value = True
print("external power enabled")
# -----------------------------
# NEOPIXEL SETUP
# -----------------------------
pixels = neopixel.NeoPixel(
board.EXTERNAL_NEOPIXELS,
NUM_PIXELS,
brightness=PIXEL_BRIGHTNESS,
auto_write=False
)
print("pixels ready")
# -----------------------------
# HELPER FUNCTIONS
# -----------------------------
def clear():
"""Turn all pixels off."""
pixels.fill((0, 0, 0))
pixels.show()
def dim_rgb(rgb_value, factor):
"""Return a dimmed version of an RGB color tuple."""
return (
int(rgb_value[0] * factor),
int(rgb_value[1] * factor),
int(rgb_value[2] * factor),
)
def get_next_color(sequence_index):
"""
Advance to the next color in the sequence.
Returns:
tuple: (new_index, new_rgb)
"""
new_index = (sequence_index + 1) % len(COLOR_SEQUENCE)
return new_index, COLOR_SEQUENCE[new_index]
def ripple_frame(center_pixel, radius, ripple_rgb):
"""
Draw one frame of the ripple animation.
center_pixel: where the ripple starts
radius: how far the wave has expanded
ripple_rgb: current ripple color
"""
for pixel_index in range(NUM_PIXELS):
distance = abs(pixel_index - center_pixel)
# Bright wave front
if distance == radius:
pixels[pixel_index] = ripple_rgb
# Optional thicker wave front:
# Uncomment these two lines and comment out the line above
# if abs(distance - radius) <= 1:
# pixels[pixel_index] = ripple_rgb
# Fade the trail behind the wave
elif distance < radius:
red, green, blue = pixels[pixel_index]
pixels[pixel_index] = (
int(red * TRAIL_FADE),
int(green * TRAIL_FADE),
int(blue * TRAIL_FADE),
)
# Pixels ahead of the wave stay off
else:
pixels[pixel_index] = (0, 0, 0)
pixels.show()
def ripple_for(seconds, start_rgb, starting_index):
"""
Run the ripple animation for a set amount of time.
If the sensor is pressed again while the animation is running:
- extend the timer
- change to the next color
- restart the ripple from the center
Returns:
int: updated color sequence index
"""
center_pixel = NUM_PIXELS // 2
active_rgb = start_rgb
sequence_index = starting_index
end_time = time.monotonic() + seconds
was_pressed = False
radius = 0
while time.monotonic() < end_time:
is_pressed = not motion.value
# Detect a new press during the active animation
if is_pressed and not was_pressed:
sequence_index, active_rgb = get_next_color(sequence_index)
print("extended, new color:", active_rgb)
end_time = time.monotonic() + seconds
radius = 0
ripple_frame(center_pixel, radius, active_rgb)
radius += 1
if radius > NUM_PIXELS:
radius = 0
time.sleep(RIPPLE_DELAY)
was_pressed = is_pressed
return sequence_index
def fade_out():
"""Fade the current pixels smoothly to black."""
current_pixels = [pixels[pixel_index] for pixel_index in range(NUM_PIXELS)]
for step in range(FADE_STEPS, -1, -1):
factor = step / FADE_STEPS
for pixel_index in range(NUM_PIXELS):
pixels[pixel_index] = dim_rgb(current_pixels[pixel_index], factor)
pixels.show()
time.sleep(FADE_DELAY)
clear()
# -----------------------------
# STARTUP FLASH
# -----------------------------
startup_colors = [
(255, 0, 0),
(0, 255, 0),
(0, 0, 255),
]
for startup_rgb in startup_colors:
pixels.fill(startup_rgb)
pixels.show()
time.sleep(0.2)
clear()
print("starting loop")
# -----------------------------
# MAIN LOOP
# -----------------------------
last_state = motion.value
current_sequence_index = -1
while True:
current_state = motion.value
if current_state != last_state:
print("changed:", current_state)
# Trigger on press: True -> False
if not current_state:
print("TRIGGERED")
current_sequence_index, trigger_rgb = get_next_color(
current_sequence_index
)
print("color:", trigger_rgb)
current_sequence_index = ripple_for(
ACTIVE_SECONDS,
trigger_rgb,
current_sequence_index
)
fade_out()
last_state = current_state
time.sleep(0.01)
Upload the Code and Libraries to the RP2040 Prop-Maker Feather
After downloading the Project Bundle, plug your RP2040 Prop-Maker Feather into the computer's USB port with a known good USB data+power cable. You should see a new flash drive appear in the computer's File Explorer or Finder (depending on your operating system) called CIRCUITPY. Unzip the folder and copy the following items to the RP2040 Prop-Maker Feather's CIRCUITPY drive.
- lib folder
- code.py
Your RP2040 Prop-Maker Feather CIRCUITPY drive should look like this after copying the lib folder, and the code.py file.
Customizing the Ripple Slippers Code
This code is designed so you can change the overall look and feel of the effect without needing to rewrite the animation logic. Most of the creative control lives near the top of the file in the settings section.
The easiest ways to personalize the effect are:
-
ACTIVE_SECONDSfor effect length -
PIXEL_BRIGHTNESSfor brightness -
RIPPLE_DELAYfor ripple speed -
TRAIL_FADEfor trail softness -
COLOR_SEQUENCEfor your custom palette
These few settings let you completely change the mood of the animation without needing to dig into the full code logic.
# -----------------------------
# USER SETTINGS
# -----------------------------
NUM_PIXELS = 20
ACTIVE_SECONDS = 3.0
PIXEL_BRIGHTNESS = 0.3
# Lower = faster ripple, higher = slower ripple
RIPPLE_DELAY = 0.05
# Lower = shorter trail, higher = longer trail
TRAIL_FADE = 0.6
# End fade settings
FADE_DELAY = 0.03
FADE_STEPS = 20
# Color cycle: white -> pink -> purple -> blue
COLOR_SEQUENCE = [
(255, 255, 255), # white
(255, 100, 180), # pink
(180, 0, 255), # purple
(0, 120, 255), # blue
]
Effect length
This value controls how long the ripple effect runs after each step.
The code is also set up so that if the sensor is triggered again while the animation is still running, the timer extends and the ripple restarts.
Brightness
This controls the overall LED brightness. A lower value saves battery and creates a softer glow, or a higher value makes more "pop".
Ripple Speed and Trail Length.
Change RIPPLE_DELAY to adjust how quickly the ripple moves out from the center, and change TRAIL_FADE to adjust the fade rate.
Final fade-out
At the end of each run, the animation fades gently to black. FADE_DELAY and FADE_STEPS control that fade.
Colors
Each color is written as:
(red, green, blue)
with values from 0 to 255. Change the hex colors to your favorites. Here's a color picker on Google.
Page last edited April 22, 2026
Text editor powered by tinymce.
Wiring Diagram
The NeoPixel strip attaches to the screw terminal as shown:
- +5v to +5v
- G to G
- DI to NEO
The force sensitive resistor gets connected into G and A0 - either side can go to either pin.
Plug your inline switch into the JST connector on the board, and plug the battery into the other end of the switch.
Page last edited April 22, 2026
Text editor powered by tinymce.
Electronics Assembly
Figure out how many pixels you need to wrap around the slippers. Mine fit 16 pixels each. Cut two lengths of LED strip to this length.
Cut the connector off the IN end of your NeoPixel strip. Usually this is the female connector, but verify you've got the correct end by looking for arrows on the strip itself -- they should be pointing away from the end you're working with.
Extend the red, black, and white wires by a few inches by soldering on a short length of wire to each. Cover the connections with heat shrink.
For the second slipper, solder these three wires directly to the copper pads on the strip: red to +, white to DI, and black to G.
If you need more help with this, check out our How to Solder NeoPixels guide.
The trickiest part of this project is preparing the force sensitive resistor (FSR). These little leads are delicate and hard to solder, and it's easy to accidentally melt the plastic so take your time.
Tin both pads with a blob of solder. Cut a couple of 2-3" long wires and tin the ends of each as well. Put the wire in place and gently melt the solder on the pad and the wire at the same time, then hold it very still until the solder solidifies for a firm connection. Cover the connections with heat shrink or electrical tape to protect them from pulling out.
Solder the two wires into the holes marked G and A0. Insert the wires from the NeoPixel strip into the screw terminal as shown: red to +5v, black to G, and white to NEO.
Plug the switch into the JST connector on the Feather, and plug the battery into the other side of the switch. Flick the switch to "on" and the LEDs should light up with a quick red, green, blue "startup" sequence.
Tap on the force sensitive resistor (FSR) and the LED strip will light up with a ripple effect in the colors you chose in the code.
Troubleshooting
If your strip isn't lighting up, here are a few things to try:
- Check that the pins you soldered to match the pins in the code. The FSR should be connected to G and A0, and the LED strip should be in the three rightmost screw terminals reading red, black, white from left to right.
- Be sure your battery is charged. Try plugging the battery directly into the JST port without the switch in between and make sure you get a status light on your board. If not, try powering from the USB port to see if you get different behavior.
- Try re-uploading the code. Check the serial monitor in your code editor to see if you're getting errors. ChatGPT or Claude can be helpful with debugging any errors you see.
- If you get a startup flash of red, green, blue but then nothing when you tap the sensor, then the sensor is likely the problem. Check to be sure you haven't bridged the pads with solder and that the plastic didn't get melted or the lines get broken. These things are super delicate!
- Be sure the wire connections into the screw terminal are secure.
Page last edited April 22, 2026
Text editor powered by tinymce.
Slipper Assembly
Use a thread ripper to open the back seam of the slippers. Go a couple inches along the sole seam on both sides. Pull out the foam insole.
Slip the LEDs into the sole, making sure the lights are facing outwards. Push the foam insole back in to hold them in place. I found it helpful to trim the foam just a little bit to make room for the pixel strip. Try to get the strip in there evenly, so the middle LED is placed right at the front of the slipper.
This is a little harder than it sounds. Turn the lights on once you have everything in place to make sure your LED strip is in there smoothly with no bumps or twists.
Slide the Feather into the right side of the slipper with the USB port facing the back (we need to be able to access it for battery charging), and the screw terminal facing outwards away from the feet. That terminal could make these slippers pretty uncomfortable if it's facing in and rubbing on tiny ankles.
Slip the FSR underneath the fabric lining and above the insole and secure it with a dab of hot glue when it's in striking range of little feet.
Slide the battery in on the left side, and slide in any extra wire from the switch. I found it easier to push the switch wire in first and slide the battery in afterwards.
Keep the switch out and accessible. Sew up the back seam and the sole side seams with a needle & strong thread -- I used heavy duty thread since these will probably take some abuse.
Use hot glue to secure the switch to the back of the slippers where it can be easily reached and pushed by little fingers.
Feel around for the USB port on the Feather. Use your thread ripper to cut a small hole in the fabric that will admit a USB cable for charging the batteries.
Test them out to be sure they are working, and get ready for light-up fun!
Page last edited April 22, 2026
Text editor powered by tinymce.