‘Holographic’ Display for Miniature Projects!
I’ve been playing around with adding holographic displays into my builds and this uses the classic Pepper’s Ghost illusion, which looks seriously cool in person! It’s super simple and can even be done with any screen or phone if you don’t want to jump straight into electronics or coding.
Here’s a quick breakdown of how I did it. Feel free to ask questions or check the links for more details!
What I Used to create the effect:
– ST7735 1.8″ TFT Display Module
– ESP32 Development Board
– Dupont Jumper Wires
– 5V USB Power Pack
– 3D Printed Enclosure (STL files coming soon)
– Transparent acetate sheet or plastic film
The Process:
Step 1:
Followed this awesome tutorial → https://www.youtube.com/watch?v=GrNIfwUNaaw
Modified code from → bitbank2/AnimatedGIF GitHub
Step 2:
Wired the display to the ESP32 using this pinout (no soldering needed): VCC → 3v3, GND → GND, CS → 5, RESET → 4, AO → 2, SOA → 23, SCK → 18, LED → 3v3
Step 3:
Created an animated GIF (128x160px for my screen) and converted it using the tool suggested in tutorial.
Step 4:
Uploaded the modified code to the ESP32 using Arduino IDE. Note: You may need to tweak the User_Setup.h file based on your board.
Below is the main code I used
//TUTORIAL FROM https://www.youtube.com/watch?v=GrNIfwUNaaw
//CONVERT NEW GIF TO C (.h) WITH https://github.com/bitbank2/image_to_c
//Edit User_Setup.h for screen specific adjustments
// Edited by Saucermen Studios
//#define USE_DMA // ESP32 ~1.25x single frame rendering performance boost for badgers.h
// Note: Do not use SPI DMA if reading GIF images from SPI SD card on same bus as TFT
#define NORMAL_SPEED // Comment out for rame rate for render speed test
// Load GIF library
#include <AnimatedGIF.h>
AnimatedGIF gif;
// Example AnimatedGIF library images
// #include "anim2.h"
#include "anim3.h"
// #include "../test_images/badger.h"
// #include "vending1.h"
// #include "../test_images/homer_tiny.h"
// #include "../test_images/pattern.h"
// ESP32 40MHz SPI single frame rendering performance
// Note: no DMA performance gain on smaller images or transparent pixel GIFs
#define GIF_IMAGE anim3 // No DMA 63 fps, DMA: 71fps
//#define GIF_IMAGE ucHomer // No DMA 162 fps, DMA: 141 fps
//#define GIF_IMAGE homer_tiny // No DMA 564 fps, DMA: 481 fps
//#define GIF_IMAGE ucPattern // No DMA 90 fps, DMA: 78 fps
#include <SPI.h>
#include <TFT_eSPI.h>
// Color definitions
// #define BLACK 0x0000
// #define BLUE 0x001F
// #define RED 0xF800
// #define GREEN 0x07E0
// #define CYAN 0x07FF
// #define MAGENTA 0xF81F
// #define YELLOW 0xFFE0
// #define WHITE 0xFFFF
TFT_eSPI tft = TFT_eSPI();
#define imageWidth 128
#define imageHeight 160
void setup() {
Serial.begin(115200);
tft.begin();
#ifdef USE_DMA
tft.initDMA();
#endif
tft.setRotation(-1);
tft.fillScreen(TFT_BLACK);
// tft.invertDisplay(1);
gif.begin(BIG_ENDIAN_PIXELS); // COOKED mode
}
// Pin definitions
#define CS_PIN 5 // Chip select control pin
#define RST_PIN 4 // Reset pin (could connect to RST pin on board)
#define DC_PIN 2 // Data/Command control pin
#define SCLK_PIN 18 // Serial clock
#define MOSI__PIN 23 // Master Out Slave In (SPI data)
#define LED_PIN -1 // Use -1 if backlight is always on or connected to 3.3v
#ifdef NORMAL_SPEED // Render at rate that is GIF controlled
void loop()
{
// Put your main code here, to run repeatedly:
if (gif.open((uint8_t *)GIF_IMAGE, sizeof(GIF_IMAGE), GIFDraw))
{
Serial.printf("Successfully opened GIF; Canvas size = %d x %d\n", gif.getCanvasWidth(), gif.getCanvasHeight());
tft.startWrite(); // The TFT chip select is locked low
while (gif.playFrame(true, NULL))
{
yield();
}
gif.close();
tft.endWrite(); // Release TFT chip select for other SPI devices
}
}
#else // Test maximum rendering speed
void loop()
{
long lTime = micros();
int iFrames = 0;
if (gif.open((uint8_t *)GIF_IMAGE, sizeof(GIF_IMAGE), GIFDraw))
{
tft.startWrite(); // For DMA the TFT chip select is locked low
while (gif.playFrame(false, NULL))
{
// Each loop renders one frame
iFrames++;
yield();
}
gif.close();
tft.endWrite(); // Release TFT chip select for other SPI devices
lTime = micros() - lTime;
Serial.print(iFrames / (lTime / 1000000.0));
Serial.println(" fps");
}
}
#endif
Step 5:
3D printed the enclosure and slotted the screen in place.
Step 6:
Cut a piece of transparent film and mounted it at a 45° angle in front of the screen to get that floating hologram effect.


