The Pocket Galaxy is a small, 3d printed infinity mirror using NeoPixel leds & see-through acrylic mirrors. It makes a fun desk accessory, and a LiPoly battery and charger keep it blinking on the go.

By illuminating the interior of the mirrored frame, the light is reflected 'infinitely' into the distance, creating a black hole-like effect. 


Links to these products can also be found on the right sidebar!

NOTE: We sell all of the compenents needed for this project EXCEPT the see-through mirrored acrylic. If you have access to a laser cutter you can buy a sheet and cut, otherwise, two 2 1/8" x 2 1/8" cuts can be bought here for $10.

You'll also need a soldering iron, some krazy glue and a 3d Printer. This particular Pocket Galaxy was printed on a Printrbot Simple Metal.

Prerequisite Guides

It'd be best to take a look over these guides and get familiar with these components! 

The Pocket Galaxy prints in 3 pieces, with about a 2.5 hour print time.




190°c (PLA)

.2 layer height

1 perimeter

5% infill

no supports

All files can print simultaneously on a 6x6x6 Printrbot Simple Metal bed

The two end pieces will house the electronics and mirrored acrylic, and the NeoPixel strips will be glued into the middle ring.

Cut the Neopixel strip down to 12 LEDs and remove the silicone casing. Using the middle piece as a reference, bend the Neopixel strip into a square so that each side sits nice and flush. It may take a few attempts, but the better it sits the better it'll look in the end. 


Quick note: any wires used in this project should be on the thinner gauge side and stranded since at the end we'll need to pack it all inside the case. I cut and stripped our breadboard jumper wires.


Feed 3 wires through the slot of the middle piece and solder to the strip. The wire should be cut to just a bit over the length of one side of the print.


Now would be a good time to test the strip. If it passes, super glue each side down until it is all in place! Set that piece aside while we prep the rest of the components.


In order to fit the LiPo charger in the case, the JST connector will need to be removed, and the battery soldered directly to the contacts. 


Carefully clip the two sides on the open end of the JST, then the two longer leads on the backside. At this point the plastic should fall right off. Remove the remaining metal pieces with a soldering iron.


Position the PocketG_Bottom so that the opening for the USB is on the lower left. Place the LiPo battery in the top part, and cut the JST connector off so that the wires reach to the next side, rounding the corner.  


Then solder it to the +/- pads where the JST used to be. Be careful not to let the wires short! 


Also at this point, cut the trace between the two switch points so an on/off switch can be added :)

After cutting those traces, place the components back in the case as pictured and measure out the length of wire needed to get to the switch. The Trinket slides into the slots with a cut out to access the USB port.


Bend the leads on the switch 90° so it'll fit on its ledge above the Trinket, and solder to the LiPoly backpack. 

Almost there!!






Place all of the components together inside the PocketG_bottom and measure out the remaining wires.


Remove the components from the case and solder together the remaining wires:

Trinket GPIO #2 ----> NeoPixel Data Input
Trinket 5V ----------> NeoPixel 5V
Trinket GND --------> NeoPixel GND
Trinket GND --------> LiPoly Backpack GND
Trinket BAT+ --------> LiPoly Backpack BAT
Trinket 5V ----------> LiPoly Backpack 5V

It should look something like this!:

Place the mirrored acrylic into the case, and place each component in. The Trinket and switch have designated spots, whereas the Lipo battery and LiPoly backpack sit freely in the top and right (respectively) within the hollow frame. Clean the acrylic thoroughly to remove any dust/fingerprints. They'll be pretty obvious once it's lit up.


In order to slide the Trinket into place, you may have to cut down the exposed excess wire/solder on the underside so it sits as flush as possible.


When all the components are in, make sure the wires all fit around the corners so they don't interfere with it closing. Take the top half and slip it on over the rest of the assembly. The pieces will press fit together with a little force.

Now we're ready to put some code on there!

Once the case is put together, the reset button to upload on the Trinket is inaccessible. Fortunately it enters the bootloader for a short period of time whenever it is powered over USB. So, once the code is ready, plug it in and hit upload! 

I adapted the StrandTest code from the NeoPixel library to only run the rainbow pattern (and slightly faster), but any LED patterns can be used! Here's mine below:

#include <Adafruit_NeoPixel.h>

#define PIN 2

// Parameter 1 = number of pixels in strip
// Parameter 2 = Arduino pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
//   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
//   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
//   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
//   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
Adafruit_NeoPixel strip = Adafruit_NeoPixel(12, PIN, NEO_GRB + NEO_KHZ800);

// IMPORTANT: To reduce NeoPixel burnout risk, add 1000 uF capacitor across
// pixel power leads, add 300 - 500 Ohm resistor on first pixel's data input
// and minimize distance between Arduino and first pixel.  Avoid connecting
// on a live circuit...if you must, connect GND first.

void setup() {
  strip.begin();; // Initialize all pixels to 'off'

void loop() {

void rainbow(uint8_t wait) {
  uint16_t i, j;

  for(j=0; j<256; j++) {
    for(i=0; i<strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel((i+j) & 255));
// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
  WheelPos = 255 - WheelPos;
  if(WheelPos < 85) {
   return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  } else if(WheelPos < 170) {
    WheelPos -= 85;
   return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  } else {
   WheelPos -= 170;
   return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);

This guide was first published on Jan 13, 2015. It was last updated on Jan 13, 2015.