Learn Creative Coding (#114) - Designing Interactive Installations

At the end of last episode I left you with a wee cliffhanger: the bracelet on your wrist reacts only to you, the one person wearing it. But what if the artwork had to watch a whole room? What if it had to notice everybody who walks in, respond to all of them at once, and keep doing it for three weeks straight while you're at home asleep? That's a completely different kind of making, and it's the one I want to talk about today. We're stepping off the body and into the room. We're designing an interactive installation.
Now, here's the honest bit up front. This episode has less brand-new code than usual and a lot more brand-new thinking. An installation is where all the toys from this whole chapter - the LEDs from episode 109, the projection from 110 and 111, the sensors from the wearables - get bolted together into one thing that lives in a space and survives contact with real, unpredictable humans. The craft stops being "what pretty pattern can I draw" and becomes "how do I build something that senses a room, responds beautifully, and never, ever crashes in front of an audience". Allez, let's design a machine that lives in a gallery :-).
What actually IS an interactive installation?
Let me pin the idea down, because it's slippery. An installation is art that occupies and transforms a space - not a picture on a wall you glance at, but a room, a corner, a whole environment you step into. Make it interactive and you add one magic ingredient: a feedback loop. The viewer's presence, their movement, their voice - it changes the artwork, and the changed artwork changes how they behave, and round it goes.
So an installation has three parts, and they're all equal. The space (where it lives), the technology (what senses and responds), and the audience (who completes it). Miss any one and it falls flat. This is the mental model I keep taped to my brain the whole time I'm building.
// the three-part soul of every interactive installation.
//
// SPACE the room, the light, where people stand & look
// \
// TECH -> sensors read the audience -> code -> output (light/sound/image)
// / ^ |
// AUDIENCE <---------------+--------------------------+
// they see the response, they react, the loop turns
//
// remove the audience and it's just a screensaver in a big room.
See the loop? That arrow from output back to audience is the entire point. A wall that just cycles colours on a timer is decoration. The moment the wall notices you and answers, it becomes an installation. Everything below is in service of making that loop feel alive and keeping it running.
Sensing the room: your choice of eyes and ears
The first design decision is always the same question: what do I need to detect? Your whole piece hangs off this, so you pick the sensor before you write a line of code. Here's the menu I reach for, with the tradeoffs, because every sensor lies to you in its own special way.
// femdev's sensor menu (notes-as-code, not a program :-)
const sensors = {
presence: "PIR or ultrasonic - cheap, binary-ish 'is someone there?'. reliable.",
distance: "lidar / ultrasonic / depth camera - HOW FAR is the person. great dial.",
touch: "capacitive pads or pressure mats - direct contact. very unambiguous.",
sound: "microphone - loudness or FFT (episode 19). fun, but rooms are noisy.",
vision: "camera + pose/hand tracking (episodes 93, 94) - richest, also fussiest.",
};
// rule of thumb: the RICHER the data, the MORE it breaks. start simple.
That last comment is hard-won. A depth camera doing full skeleton tracking is gorgeous and gives you a person's every joint - but it's also the thing that flakes out when the gallery lights change at noon. A humble PIR sensor that just says "yep, human present" is boring by comparison and it will run for a decade without a hiccup. My advice for your first installation: pick the simplest sensor that supports your idea. You can always get fancier once the basics are bulletproof.
Here's the shape of reading a distance sensor and normalising it, so the rest of your code deals in a clean 0-to-1 number instead of raw sensor units. We did this exact trick with the accelerometer last episode - normalise early, and your art logic never has to know what hardware is underneath.
// read an ultrasonic distance sensor, hand back a clean 0..1 "closeness".
// 0 = far away / nobody. 1 = right up against the piece.
function readCloseness(rawCm, nearCm = 30, farCm = 300) {
// clamp into the range we care about, then flip so CLOSER = BIGGER
const clamped = Math.min(Math.max(rawCm, nearCm), farCm);
const t = (clamped - nearCm) / (farCm - nearCm); // 0 near .. 1 far
return 1 - t; // flip: 1 near .. 0 far
}
The interaction model: how input becomes response
Right, you can sense the room. Now the real artistic choice: how does the viewer's input map to what the artwork does? This is the interaction model, and it's where two installations using identical hardware become totally different experiences.
There are two big axes I think along. The first is direct versus indirect. Direct means "move your hand, the particles follow your hand" - an obvious, immediate cause and effect the viewer figures out in two seconds. Indirect means "your presence slowly warms the mood of the whole room over a minute" - subtle, atmospheric, something they might only half-notice. The second axis is immediate versus accumulated: does the piece respond to what's happening right now, or does it build up a memory of everyone who's passed through?
// the same closeness input, three completely different feelings.
function directResponse(closeness) {
// immediate + direct: particles spawn RIGHT where the person is. obvious.
return { spawnRate: closeness * 50, hue: 200 - closeness * 200 };
}
let mood = 0; // <- persists between frames = the piece has a MEMORY
function accumulatedResponse(closeness) {
// indirect + accumulated: presence slowly charges a 'mood' that lingers.
mood += (closeness - 0.05) * 0.01; // creeps up with people near,
mood = Math.min(Math.max(mood, 0), 1); // gently sinks when the room's empty
return { warmth: mood, brightness: 0.3 + mood * 0.7 };
}
Feel the difference? The direct version is a toy you play with. The accumulated version is a space that remembers you were there, that's busier in the evening rush and calm at dawn, that tells a slow story over a whole day. Neither is better - but you have to choose, on purpose, because the model IS the experience. When I'm stuck, I ask myself: do I want people to play, or do I want them to feel watched-over? That usually decides it.
Designing for zero people, one person, and a crowd
Here's a trap screens never set for you. On your laptop there's always exactly one user: you. A public installation has to handle zero to many viewers, all at once, and be meaningful at every count. Empty room, solo explorer, and a rowdy crowd of fifteen - the piece has to work for all three.
The empty state matters more than beginners think. What does your installation do when nobody's there? It can't just go black and dead, or people walk straight past it. It needs an attract mode - a gentle, self-running ambient state that says "I'm alive, come closer" and lures the first person in.
// pick behaviour by how many people the room sees. all three must be lovely.
function chooseState(peopleCount) {
if (peopleCount === 0) return 'attract'; // ambient bait: alive but calm
if (peopleCount === 1) return 'intimate'; // full, focused, personal response
return 'crowd'; // shared - blend everyone's input
}
// in crowd mode, don't fight over one 'the user'. blend them all.
function crowdResponse(people) {
// average position pulls the art toward where the group clusters,
// total energy makes it wilder the more bodies are moving. one shared piece.
const avgX = people.reduce((s, p) => s + p.x, 0) / people.length;
const energy = people.reduce((s, p) => s + p.movement, 0);
return { focusX: avgX, intensity: Math.min(energy, 1) };
}
The design goal I chase is that a solo viewer feels like the piece is theirs, and a crowd feels like they're all playing one shared instrument together. Those are different joys and a good installation delivers both without you flipping a switch. Makes sense, right? The room decides, not you.
Reliability: it has to run when you're not there
Okay. Serious face, and this is the big one, the thing that separates a demo from an installation. Your piece will run for hours, days, sometimes weeks, unattended, in a gallery where the only technical staff is a lovely person on a stool who knows how to unlock the door. It cannot need you. Every single component has to be reliable, because you will not be standing there to restart it.
A few iron rules I've paid for in stress. Prefer wired connections over wireless every time - WiFi drops, Bluetooth pairs with someone's headphones, a USB cable just works. Assume every part will fail at some point and design so the piece recovers by itself. And never trust your program to simply keep running - wrap it in something that restarts it the instant it dies.
# don't hope your program stays up - GUARANTEE it restarts if it crashes.
# a process manager relaunches it automatically, even after a full reboot.
pm2 start installation.js --name gallery-piece
pm2 startup # make it survive a power cut - auto-launch when the box boots
pm2 save # remember what should be running
# the whole philosophy: assume it WILL crash. make crashing a non-event.
That "make crashing a non-event" idea is everything. On your laptop a crash is annoying; in a gallery it's a black screen for a day until someone emails you. So you plan for the crash before it happens. A process manager (this is the same PM2 idea a lot of always-on software leans on) relaunches your piece in a second or two, and configured right it even comes back on its own after the building's power blips overnight. The piece heals itself while you sleep.
And add a watchdog - a little timer that checks the piece is actually doing its job, not just technically "running". A program can be alive but frozen, sensor stuck, output stalled. The watchdog notices the heartbeat stopped and kicks it.
// a watchdog: if the main loop hasn't 'checked in' recently, something froze.
// force a clean restart rather than sit there dead-but-running.
let lastHeartbeat = Date.now();
function heartbeat() { lastHeartbeat = Date.now(); } // call this every frame
setInterval(() => {
const silence = Date.now() - lastHeartbeat;
if (silence > 5000) { // 5s with no frame = it's wedged
console.error('watchdog: main loop stalled, restarting');
process.exit(1); // let PM2 catch it and relaunch clean
}
}, 1000);
Graceful failure: the viewer must NEVER see the seams
Connected to reliability but its own art: when something does go wrong - and it will - the viewer should never know. No error dialog. No terminal full of red text. No Windows update popup mid-artwork (yes, I've seen it happen at a real show, and everyone in the room saw it too, and I wanted to sink into the floor). When a sensor dies, the piece should quietly fall back to a beautiful ambient mode, not crash and not scream.
// if the sensor stops answering, DON'T crash - drift into ambient mode.
// the audience sees a calm generative piece, not a dead installation.
function getInput() {
try {
const value = readSensor(); // might throw / might hang
if (value === null || Number.isNaN(value)) throw new Error('bad reading');
lastGoodInput = value;
sensorHealthy = true;
return value;
} catch (e) {
sensorHealthy = false;
return null; // caller falls back to ambient
}
}
function frame() {
const input = getInput();
if (input === null) {
renderAmbient(); // gorgeous self-running fallback. looks intentional.
} else {
renderInteractive(input);
}
}
The trick that makes this feel professional: your ambient fallback shouldn't look like a failure. It should look like a deliberate resting state of the artwork. A viewer walking up to a "broken" piece that's actually just gently breathing colours has no idea anything's wrong - they think that's the piece. Degrade gracefully, and a hardware failure becomes an invisible non-event instead of an embarrassing dead screen. That's the whole game.
Calibration: the room fights you every single day
Something nobody warns you about: the physical world drifts. Sensors read a little differently as they warm up. The gallery's daylight changes what a camera sees from morning to dusk. Someone nudges a projector while dusting. An installation that was perfect on install day is subtly wrong by the weekend if you can't re-tune it.
So you build calibration into the software from the start - a quick mode the gallery staff can trigger to re-teach the piece its space, without touching a single line of code. This is genuinly one of the most-skipped, most-important parts of a robust installation.
// a calibration mode: learn the room's 'empty' baseline, then sense RELATIVE
// to it. this survives drift because it re-learns instead of hard-coding.
let baseline = 0;
function calibrate(samples = 100) {
let sum = 0;
for (let i = 0; i < samples; i++) sum += readSensorRaw(); // empty room!
baseline = sum / samples; // this is what 'nobody here' looks like NOW
saveToDisk({ baseline }); // remember it across restarts
}
// then all real readings are measured against today's baseline, not a guess
function calibratedReading() {
return readSensorRaw() - baseline; // drift in the baseline cancels out
}
Give the staff a dead-simple way to run that - a physical button, a hidden key combo, whatever - and write the procedure on a laminated card taped inside the equipment box. Future-you, getting a calm text instead of a panicked call, will be so grateful. Document the calibration values too, so if a whole sensor needs swapping you know the numbers to aim for.
Spatial design: guiding people without a single sign
Here's a subtle one that's pure art, not engineering. Where does the viewer stand? Where do they look? How do they even discover that the piece responds to them? The dream is that people work it out on their own, with no instruction sign - because the moment you tape up a laminated "WAVE YOUR HAND HERE" sheet, the magic dies a little.
You guide behaviour with the space itself. A pool of light on the floor is an invisible "stand here". A sound that gets richer as you approach pulls people in without a word. A single clear moment of response - you step in and something obviously changes - teaches the whole interaction in one beat.
// design the DISCOVERY moment: the first response must be instant + obvious,
// so a newcomer instantly 'gets it' with zero instructions.
function onFirstDetection() {
// big, unmistakable, delightful. this one beat teaches the whole piece.
burstOfLight(); // "oh! it noticed me!"
playWelcomeTone(); // a reward for stepping in
// subtlety comes AFTER they understand they matter. teach first, nuance later.
}
If you find yourself wanting to add an instruction sign, take it as a smell that the interaction isn't discoverable enough yet, and fix the piece, not the signage. The best installations teach you how to use them in the first two seconds, wordlessly. That's a design skill worth chasing hard.
The unglamorous infrastructure that holds it all up
Behind every magical installation is a boring box of practicalities, and skimping here is what turns a beautiful idea into a support nightmare. Let me lay out the checklist I run before any piece goes into a space.
// femdev's installation infrastructure checklist (notes-as-code :-)
const infra = {
power: "clean, reliable, ideally on a UPS so a brief cut doesn't kill it.",
computer: "hidden, VENTILATED (they run hot for weeks), set to auto-start on boot.",
network: "prefer OFFLINE-capable. no wifi = one less thing to drop at 3am.",
display: "projector/screen mounted solid, but REACHABLE for maintenance.",
cables: "strain-relieved, taped down, hidden. a tripped cable ends the show.",
access: "you (or staff) can reach the reset button without a ladder + a prayer.",
};
Two of these deserve a moment. First, that computer running the whole thing wants to be small, silent, hidden and self-starting - you tuck it in a box behind the piece, set it to boot straight into your program when power returns, and forget it's there. There's a whole family of tiny cheap boards built for exactly this always-on, tucked-in-a-corner job, and picking the right little brain for an installation is a proper topic all of its own - one we'll dig into very soon. Second, offline-capable is a gift to your future self. If the piece needs no internet, that's an entire category of 3am failures that simply cannot happen.
Documentation, the technical rider, and the boring money bit
Two last habbits that mark the difference between a hobbyist and someone who gets invited back. Document everything while you build - photograph the wiring, video the piece running well, write down every cable route and calibration number. When the same installation gets shown in a different gallery in a year, that documentation becomes a technical rider: the recipe another person can follow to set your piece up without you flying out.
// a technical rider is your install instructions, frozen so ANYONE can follow.
const rider = {
space: "min 4x4m dark-ish room, one wall for projection, power within 5m.",
hardware: "1x mini computer, 1x projector (>=2500 lumens), 1x depth sensor.",
setup: "mount sensor at 2.2m facing floor, run calibrate(), aim projector.",
calibration: "empty-room baseline ~180-220. re-run if response feels off.",
failureMode: "if sensor dies it drifts to ambient - safe to leave, text me.",
contact: "reachable for remote help; most issues = re-run calibration.",
};
And the bit artists love to ignore: budget. An installation costs more than the art - hardware, materials, transport, the days of your life spent installing, spare parts for when something fails mid-show. Plan it early. Grants, residency stipends and commission fees exist precisely to cover this, so factor in a replacement sensor and a spare cable before you need them at 8pm on opening night. Boring? Totally. But a piece that dies because you didn't budget for a spare part is a sad piece.
Your exercise: design a complete installation on paper
No coding this time - and I mean that on purpose. Your exercise is to design, fully, on paper, an interactive installation you could hand to a fabrication team tomorrow. This is the single most valuable skill in this whole chapter, and it costs nothing but thinking. Fill in every one of these:
// THE DESIGN DOCUMENT: answer all six. no gaps allowed - gaps become 3am calls.
const myInstallation = {
concept: "?", // what EXPERIENCE? what should a stranger feel walking in?
space: "?", // what room / venue? how big, how dark, where do they enter?
technology: "?", // which sensor (keep it simple!), what output, what computer?
interaction: "?", // direct or indirect? immediate or accumulated? (pick, on purpose)
states: "?", // what happens at 0 people, 1 person, a crowd? attract mode?
failure: "?", // sensor dies -> ? power blips -> ? staff sees a freeze -> ?
};
Write it out properly, in real sentences, like you're briefing someone who's never met you. Force yourself to answer the failure line especially - "what if X breaks" is the question that turns a daydream into a buildable, survivable piece. A thorough design document is worth ten enthusiastic hours of coding the wrong thing.
If you want a concrete brief to design against, try this one: a dark corridor where a soft river of light flows along the floor beside you as you walk, brightening and quickening with your pace, and slowly returning to a still, dim glow after you've passed. Now answer all six boxes for that. Which sensor? What's the attract mode when the corridor's empty? What does it do with a whole tour group at once? What happens when the sensor freezes? Design it fully - that's the exercise, and honestly it's harder and more useful than any code I could give you.
't Komt erop neer...
- An interactive installation is art that occupies and transforms a space, with a feedback loop: the viewer's presence changes the artwork, which changes how they behave. Space + technology + audience are all equal parts, and remove the audience and it's just a screensaver in a big room
- You pick your sensor first, because everything hangs off it: presence (PIR), distance (ultrasonic/lidar/depth), touch (capacitive/pressure), sound (mic + episode 19's FFT), or full vision (camera + pose tracking, episodes 93/94). Richer data = more things that break, so start with the simplest sensor your idea allows
- Normalise sensor input to a clean 0..1 number early, exactly like the accelerometer last episode, so your art logic never has to know what hardware is underneath
- The interaction model IS the experience: direct ("move your hand, particles follow") versus indirect ("your presence slowly warms the room"), and immediate versus accumulated (does the piece have a memory of everyone who passed through?). Choose on purpose
- Design for 0, 1, and many viewers. An empty room needs an ATTRACT mode that says "I'm alive, come closer". A solo viewer should feel the piece is theirs; a crowd should feel like one shared instrument
- Reliability is the thing that separates a demo from an installation. It runs unattended for weeks, so: prefer wired over wireless, assume every part will fail, wrap the program in a process manager (PM2) that auto-restarts on crash AND after a power cut, and add a watchdog that kicks it if the loop freezes
- Graceful failure means the viewer NEVER sees the seams. A dead sensor should drift into a beautiful ambient fallback that looks intentional, never an error dialog or a black screen
- Build CALIBRATION into the software: sensors drift and light changes, so a quick staff-triggered mode re-learns the empty-room baseline without touching code. Measure relative to today's baseline, not a hard-coded guess
- Spatial design guides people without signs: a pool of light says "stand here", a sound that swells pulls them in, and one instant obvious response teaches the whole interaction in two seconds. Wanting an instruction sign is a smell that the piece isn't discoverable enough yet
- The boring infrastructure holds it all up: clean power (ideally a UPS), a hidden ventilated auto-starting computer, offline-capable networking, reachable cables and reset. Plus documentation, a technical rider so anyone can reinstall it, and an honest budget with spare parts
So that's the mindset shift of this episode: your art stops being something you babysit and becomes something that lives on its own, out in a room full of strangers, sensing and responding and healing itself while you're nowhere near. That's a genuinely different discipline - half artist, half engineer - and it's the one that gets you invited to actual shows.
Did you notice how little new code there was, though? The FFT, the easing, the pose tracking, the noise fields - the sensing and the visuals were all tools we already owned from earlier episodes. What was new was the engineering around them: reliability, failure, calibration, the room. And there's one piece of that engineering I kept gesturing at and never quite named - that small, silent, hidden little computer that has to run the whole thing for weeks without complaint. Which board? How do you set it up to just work? That's exactly where we're headed next. Start looking at the tiny computers people leave running in corners, and think about which one could be the brain of your piece :-).
Sallukes! Thanks for reading.
X