draft: false
Name: LIGHTPEN
short-description: An RGB light-sensor wand as a fourteen-mode controller, sound source and effects box
Language: C++ (Pico SDK + ComputerCard)
Creator: Andy Jenkinson (uglifruit)
Version: "1.3.0"
Status: Released
License: CC-BY-4.0
repository: https://github.com/uglifruit/WorkshopLightPen
Editor: none
date-created: 2026-09-16
date-updated: 2026-09-26
contact:
social:
github: https://github.com/uglifruit
uf2:
- path: UF2/lightpen.uf2
name: LIGHTPEN 1.3.0
tags:
- controller
- sensor
- synthesis
- percussion
- looper
- quantiser
- filter
- delay
- reverb
- effect
summary: |
LIGHTPEN drives an RGB sensor wand: three light-dependent resistors under
red, green and blue gels in a marker-pen body, powered from CV Out 1 and
read on CV In 1, CV In 2 and Audio In 2. Point it at the room or scan
printed colour, and the colour becomes CV, gates and audio.
The wand is four wires and nothing else. Each LDR goes straight from the
CV Out 1 plug to one input plug: the Computer's inputs are each 120k to
ground internally, which forms the other half of the divider, and its
outputs already carry a 1k series resistor, so no components and no ground
wire are needed. Each channel draws about 50uA.
X sets sensitivity and Y smoothing in every mode. Switch Up steps through
fourteen modes; Down is each mode's action — and in the three modes that
record, a quick tap of Down cycles the sound or behaviour while a longer
press still records.
The LEDs are two columns of three: the left (0, 2, 4) counts the mode as a
three-bit number starting at one, with Modes 8 to 14 counting again at half
brightness, and the right is a live meter of red (LED 1), green (3)
and blue (5). The meter shows the reading the modes act on — after
calibration, sensitivity and smoothing — so it is also how you set the card
up: a colour pinned at full brightness or staying dark as the wand moves
means the modes see that too.
1 RGB CV Mirror: colour as three CVs, plus threshold gates.
2 Triad Drone: red, green and blue set the levels of a chord's three notes.
3 Barcode Reader: swipe across a black-and-white code while holding Down,
and its bars loop as triggers — every element on one pulse out, the wide
ones on the other, with the black/white gate as CV. It also plays drums: a
bar going dark hits a kick and coming back to light hits a snare, or
clicks, crackle or shaped noise, tapped through with the switch.
4 Tape Scrubber: hold Down to record Audio In 1 for as long as you hold it,
up to six seconds, then scrub through the take by moving the wand across a
colour map, with a colour-controlled filter. Tap Down to switch between
scrubbing, repeating one of sixteen slices, and sweeping the loop length down
to a buzz. The take is stored lo-fi on purpose — 24kHz in eight companded
bits — which is four times the length in the same memory, and sounds like
cassette.
5 Synesthesia Voice: a 1V/oct voice whose filter, wavefolder and decay
follow the colour.
6 Colour Organ: hue picks a note in a scale, as calibrated pitch CV,
triggers and an organ tone.
7 Jog Wheel: the same take runs as a loop and the wand sets its speed,
from a nudge to a full shuttle into reverse, against a flywheel whose
weight the colour controls. Tap Down for a motorless platter your hand
drives entirely, or a brake that stops when you cover the sensor.
8 Prism Voice: a sustaining voice with FM, sample-rate crush and filter
on the three colours.
Modes 9 to 14 are EFFECTS. They all take audio on Audio In 1 and return it
on both audio outs, the three colours are the three controls, plus Main knob.
Tap of Down rotates which colour does what.
9 Colour Filter: patch audio into Audio In 1 and the wand holds all three
filter controls at once — cutoff, resonance and a continuous low-pass to
band-pass to high-pass walk — with drive on the Main knob and an envelope
follower on the spare jacks.
10 Delay: red is time, 10ms to 416ms, green feedback, blue mix. The time is
smoothed and interpolated, so sweeping it bends the pitch of what is already
in the line the way a tape delay does. Main is the tone of the feedback path;
Pulse Out 1 clocks once per delay period.
11 Reverb: eight damped combs into four allpass diffusers, retuned to 48kHz.
Red is size, up to a 2.4s hall, green the brightness of the tail, blue mix.
Main is pre-delay.
12 Freeze: the last 426ms is always in the buffer. Hold Down and it stops
writing, and three granular voices make a pad out of the moment that has just
gone — red grain size, green pitch, blue density, and Main scatters the grains
from an orderly stretch to a cloud. The hold LATCHES, so the wand hand is
free, and the voices alternate between the two audio outs for width.
13 Modulation: one LFO, with Main walking a six-stage phaser into a flanger
into a chorus by crossfade rather than by switch. Red rate, green depth, blue
feedback, and CV Out 2 carries the LFO.
14 Mangle: no buffer at all. Red crushes bit depth and sample rate together,
green folds, blue ring-modulates, and Main is the carrier pitch.
Hold Down at power-on to calibrate: five captures, one per tap. Show it
red, green, blue, white and black and it measures how much each gel leaks
the other colours and un-mixes them, so blue reads as blue rather than as a
grey lift on all three, then reports how well the gels separate, one LED to
five. Show it white for the first four taps instead and it calibrates level
alone — setting each channel's range and straightening its response, an LDR
being a power-law device whose raw reading bunches up at the bright end.
There is no mode to pick: white is the sum of the primaries, so the
captures themselves say which calibration was meant. It is saved to flash
and survives power-off.
Two pages to open full-screen on whatever screen you are scanning, both in
tools/ and both on the web — the calibration targets
(https://uglifruit.github.io/WorkshopLightPen/tools/calibration-target.html)
and nine colour maps
(https://uglifruit.github.io/WorkshopLightPen/tools/colour-maps.html): the
red/green field the tape scrubber was designed around, a hue sweep that
plays as a rising scale, barcodes for the barcode reader, and saturated
fields for the drone.
panel:
inputs:
- id: CVIn1
name: Red
description: Red LDR return. Wand channel, not a patch point in normal use
- id: CVIn2
name: Green
description: Green LDR return. Wand channel, not a patch point in normal use
- id: AudioIn2
name: Blue
description: Blue LDR return, read as a steady voltage. Wand channel, not a patch point in normal use
- id: AudioIn1
name: Audio in / pitch
description: The audio in for every effect mode, 9 to 14; record source in Modes 4 and 7; 1V/oct pitch in Modes 2, 5 and 8. Unused in Modes 1, 3 and 6
- id: PulseIn1
name: Gate
description: Note gate for the two synth voices, Modes 5 and 8. Unused elsewhere
- id: PulseIn2
name: (unused)
description: Not read by any mode
outputs:
- id: CVOut1
name: Wand supply
description: Held at full scale as the excitation supply for all three LDRs. Not a signal output — no mode writes to it
- id: CVOut2
name: Mode CV
description: Red in Mode 1, element width or brightness in Mode 3, envelope in Modes 5 and 8, calibrated 1V/oct note in Mode 6, play position in Mode 7, an envelope follower in Modes 9 to 12 and 14, and the LFO in Mode 13
- id: AudioOut1
name: Audio / green
description: Green as CV in Mode 1, the drum voice or element width in Mode 3, the processed input in Modes 9 to 14, audio in every other mode
- id: AudioOut2
name: Audio / blue
description: Blue as CV in Mode 1, the black/white gate in Mode 3, the processed input in Modes 9 to 14 (the right-leaning half of the grain cloud in Mode 12), audio in every other mode
- id: PulseOut1
name: Trigger
description: Red over threshold (1), every barcode element (3), a new note (6), the loop start (7), signal present (9), the delay's own clock (10), each grain (12), the LFO's rising half (13)
- id: PulseOut2
name: Trigger 2
description: Blue over threshold (1), wide barcode elements only (3), colour detected (6), high while playing backwards (7)
controls:
knobs:
- main:
name: Mode parameter
description: Gate threshold (1), waveshape (2, 5, 8), playback speed (3), filter type (4), scale (6), jog depth (7), filter drive (9), feedback tone (10), pre-delay (11), grain scatter (12), phaser to flanger to chorus (13), ring carrier pitch (14)
x:
name: Sensitivity
description: Global, every mode. 0.25x to 4x of the calibrated black-to-white range, unity at noon
y:
name: Smoothing
description: Global, every mode. Slew on all three colour channels, from light to about a third of a second. Keep it low when scanning barcodes
switch:
up:
name: Next mode
description: Momentary up steps to the next of the fourteen modes, exactly one per click. The left LED column shows which
down:
name: Mode action
description: Freeze (1), chord type (2), record (3, 4, 7), latching freeze (12), colour rotation (5, 8, 9, 10, 11, 13, 14), transpose (6). Held at power-on it starts calibration instead
tap:
name: Option
description: In Modes 3, 4, 7 and 12 a quick tap cycles the drum kit, the scrub behaviour or the colour roles, while a longer press records, or toggles the freeze on and off
leds:
- display: list
items:
- id: LED0
name: Mode number, bit 0 (left column; half brightness past Mode 7)
- id: LED1
name: Red, live level (right column)
- id: LED2
name: Mode number, bit 1
- id: LED3
name: Green, live level
- id: LED4
name: Mode number, bit 2
- id: LED5
name: Blue, live level