What if getting closer made things more messy? The Dirty Video Mirror is an interactive analog video installation that crossfades between two live camera feeds based on how close you are to the display. You are both the observer and the subject. The closer you get, the more your reflection distorts.


Let’s see how this was made!
How It Works
At the heart of the project is a digital potentiometer IC (such as the AD5256) wired as a video crossfader between two analog camera inputs. This is basically a 1k potentiometer controlled not by your hand but by a microcontroller. This approach draws directly from the popular Dirty Video Mixer project. The twist here is an ultrasonic distance sensor that continuously reads how far the subject is from the screen. An ESP32 microcontroller takes that distance reading and sweeps the pot’s wiper accordingly.
The result is a live analog glitch: as a person walks toward the screen, the output image gradually bleeds from one source to the other. As the cameras are placed on top of the screen, the installation invites the subject to explore which camera truly sees him and how to access the view from the other camera by getting closer.

Hardware
Here’s what’s needed:
- Any ESP32 dev board, I used the Dasduino CONNECTPLUS by Soldered, you can make this project with any basic Arduino-compatible board!
- 1k digital potentiometer e.g. AD5256 or equivalent
- Ultrasonic Distance Sensor by Soldered (or any preferred distance sensor, I’m using the Qwiic version for easy connecting)
- Two analog cameras, I used cheap FPV drone cameras from AliExpress
- Analog TV or composite monitor as the output display


Wiring It Up
The digital pot’s I2C pins connect to the ESP32’s SDA/SCL lines. The two camera outputs feed into the A and B terminals of the pot, and the wiper output goes to the monitor. All camera grounds need to be tied together.
The Code
The core logic is straightforward: read distance, map it to a wiper value from 0–127, and write that value to the digipot over I2C at roughly 4 Hz.
const uint8_t WIPER_MIN = 0; // Side A (0%)
const uint8_t WIPER_MAX = 127; // Side B (100%)
const float DIST_FAR = 500.0; // cm — start of crossfade range
const float DIST_NEAR = 30.0; // cm — full Side BThese four constants at the top of the sketch are all you need to fine tune everything. This is the main loop of the ESP32 and how it continuously reads from the proximity sensor, maps the value and then writes it to the digipot:
void loop()
{
hc.takeMeasure(); // Trigger an ultrasonic pulse
delay(50); // Wait for the echo (sensor needs up to 38 ms)
float dist = hc.getDistance(); // Distance in cm
uint8_t wiperValue;
if (dist > DIST_FAR) {
// Subject is out of range — hold at Side A
wiperValue = WIPER_MIN;
} else if (dist <= DIST_NEAR) {
// Subject is very close — hold at Side B
wiperValue = WIPER_MAX;
} else {
// Linearly interpolate: t goes from 0 (at 500 cm) to 1 (at 30 cm)
float t = (DIST_FAR - dist) / (DIST_FAR - DIST_NEAR);
wiperValue = (uint8_t)(t * WIPER_MAX + 0.5f);
}
writeWiper(wiperValue);
delay(200); // Update rate ~4 Hz (50 ms measure + 200 ms settle)
}What’s next?
I’ll probably add an optional audio input on this, making it reactive to bass in an audio signal! That or a better proximity sensor. Stay tuned for that!