Canvas2DMX is a Processing library for mapping pixels from your sketch directly to DMX fixtures.
It lets you define LED mappings (strips, grids, rings, corners), apply color correction, and send data to any DMX backend or bridge (ENTTEC, DMX4Artists, OLA/Art-Net, SP201E translators, or your own).
Github Pages link: Canvas2DMX.
Inspired by FadeCandy and Open Pixel Control (OPC) by Micah Elizabeth Scott.
- Real-time color sampling from Processing canvas
- Flexible LED mapping: strips, rings, grids, single points, square corners
- Custom DMX channel patterns (e.g.
"rgb","drgb","drgbsc") - Default channel values for dimmer, strobe, color wheel, etc.
- Gamma correction and color temperature adjustment
- Built-in visualization (color bars, LED markers)
- Agnostic DMX output: works with DMX4Artists, ENTTEC, SP201E, or any controller via a simple callback
- Off-screen buffer support via
setCanvasSize()for PGraphics workflows - Ships with eight examples from beginner sampling to hardware-specific backends
Click the thumbnail above to watch Canvas2DMX in action on YouTube.
-
Install the required Processing libraries via Sketch -> Import Library -> Add Library...:
dmxP512for ENTTEC USB Pro devicesDMX4Artistsfor FT232RL / Open DMX devices
-
Install Canvas2DMX into your Processing sketchbook libraries folder:
- release zip: unzip to
<Sketchbook>/libraries/canvas2dmx - from this repo: run
./gradlew deployToProcessingSketchbook - once accepted by Processing: install via the PDE Library Manager
- release zip: unzip to
-
Restart Processing. The library will appear under Sketch -> Import Library -> Canvas2DMX.
-
Explore the included examples via
File -> Examples -> Contributed Libraries -> Canvas2DMX.
Two families of USB DMX dongle exist and they need different libraries. Every example has a single flag to switch between them:
| Dongle | Library | USE_ENTTEC_PRO |
|---|---|---|
| ENTTEC USB Pro (or compatible pro-grade dongle) | dmxP512 | true |
| FT232RL "Open DMX" β cheap USB cable, Amazon "USB to DMX 512", FreeStyler dongle | DMX4Artists | false |
| Any dongle via OLA β Open Lighting Architecture as middleware | UDP/Art-Net | use HardwareOLA example |
Install both dmxP512 and DMX4Artists via
Sketch -> Import Library -> Add Libraryif you want to run the mixed-backend examples.HardwareOpenDMXandHardwareOLAare single-backend examples.
import com.studiojordanshaw.canvas2dmx.*;
Canvas2DMX c2d;
void setup() {
size(400, 200);
pixelDensity(1);
c2d = new Canvas2DMX(this);
c2d.mapLedStrip(0, 8, width/2f, height/2f, 40, 0, false);
c2d.setChannelPattern("grb");
c2d.setDefaultValue('d', 255);
c2d.setStartAt(1);
}
void draw() {
background(0);
ellipse(mouseX, mouseY, 100, 100);
int[] colors = c2d.getLedColors();
c2d.visualize(colors);
c2d.showLedLocations();
// Replace this callback with your backend:
// dmx.sendValue(ch, val), artnet.writeUniverse(...), etc.
c2d.sendToDmx((ch, val) -> println("ch " + ch + " = " + val));
}For hardware-specific setup, use the included examples:
Basics,StripMapping,OffscreenBuffer,PolygonMapping,InteractiveDemo,ColorBandTestfor switchable ENTTEC Pro / Open DMX sketchesHardwareOpenDMXfor DMX4Artists-only FT232RL outputHardwareOLAfor OLA / Art-Net output
When sampling from a PGraphics buffer instead of the main sketch canvas, use setCanvasSize() to tell Canvas2DMX the buffer dimensions. This is essential when your off-screen buffer has different dimensions than your sketch window.
PGraphics buffer;
Canvas2DMX c2d;
void setup() {
size(800, 600);
// Create an off-screen buffer with different dimensions
buffer = createGraphics(200, 200);
c2d = new Canvas2DMX(this);
// Tell Canvas2DMX the buffer dimensions (not the sketch window size)
c2d.setCanvasSize(200, 200);
// Map LEDs relative to the buffer size
c2d.mapLedStrip(0, 10, 100, 100, 80, 0, false);
}
void draw() {
// Draw to the off-screen buffer
buffer.beginDraw();
buffer.background(0);
buffer.fill(255, 0, 0);
buffer.ellipse(mouseX * 0.25, mouseY * 0.33, 50, 50);
buffer.endDraw();
// Display the buffer on screen (scaled up)
image(buffer, 0, 0, width, height);
// Sample LED colors from the buffer's pixels
buffer.loadPixels();
int[] colors = c2d.getLedColors(buffer.pixels);
c2d.visualize(colors);
}The library ships with examples, found in the Processing IDE under File β Examples β Contributed Libraries β Canvas2DMX.
- Basics β the smallest possible sketch: one LED, one sampled color, live DMX output
- StripMapping β linear strip with reversible wiring and scrolling rainbow background
- OffscreenBuffer β sample from a
PGraphicsbuffer withsetCanvasSize() - PolygonMapping β fill arbitrary shapes; interactive wiring direction and spacing controls
- InteractiveDemo β drag a color orb around a ring; press 1/2/3 to switch channel patterns
- ColorBandTest β diagnostic sketch: 4 solid color bands to verify channel mapping and gamma
- HardwareOpenDMX β FT232RL dongle only, using DMX4Artists directly
- HardwareOLA β any dongle via OLA middleware; sends Art-Net UDP to localhost
The general-purpose examples use the USE_ENTTEC_PRO flag β set it to true for ENTTEC Pro or false for FT232RL dongles. HardwareOpenDMX and HardwareOLA use dedicated backends instead.
- Performance: Sample from a smaller buffer while displaying at full resolution
- Flexibility: Keep LED mapping resolution independent from display resolution
- Effects: Apply different processing to the DMX output vs. the display
c2d.setLed(0, x, y);c2d.mapLedStrip(0, 10, 200, 200, 20, radians(45), false);c2d.mapLedRing(0, 12, 200, 200, 50, 0);c2d.mapLedGrid(0, 8, 4, 200, 200, 20, 25, 0, true, false);c2d.mapSquareCorners(0, 200, 200, 100, 45);Canvas2DMX.PolygonFillConfig cfg = new Canvas2DMX.PolygonFillConfig(20, 24)
.startAt(0) // 0=TL, 1=TR, 2=BR, 3=BL
.serpentine(true) // zigzag
.horizontal(true) // rows (false = columns)
.margin(5);
c2d.mapLedPolygon(0, shapeVerts, cfg);Use this when each physical LED string has a fixed count per row (tapered gables, triangles, etc.).
int[] rows = { 20, 18, 16, 14, 12, 10 };
Canvas2DMX.RowLayoutConfig rowCfg = new Canvas2DMX.RowLayoutConfig(rows)
.startAt(0) // 0=TL, 1=TR, 2=BR, 3=BL
.serpentine(true) // zigzag
.horizontal(true) // rows (false = columns)
.angleDeg(0) // row direction angle in degrees
.rowSpacing(0) // 0 = evenly distributed across height
.margin(5);
c2d.setRowLayout(0, shapeVerts, rowCfg);Configure fixtures with channel layouts:
c2d.setChannelPattern("rgb"); // RGB only
c2d.setChannelPattern("rgbw"); // RGB + White
c2d.setChannelPattern("drgb"); // Dimmer + RGB
c2d.setChannelPattern("drgbsc"); // Dimmer + RGB + Strobe + Color wheel
c2d.setDefaultValue('d', 255); // Default dimmer value
c2d.setDefaultValue('s', 0); // Strobe offsetChannelPattern(String pattern)β define fixture layoutsetStartAt(int startAt)β starting DMX channel (1-based)setDefaultValue(char channel, int value)β default values for non-RGB channelsgetLedColors()β sample pixels and apply correctionssendToDmx(DmxSender)β send DMX via any backendbuildDmxFrame(int universeSize)β generate full DMX frame arraysetCanvasSize(int width, int height)β set custom canvas dimensions for LED mapping (for off-screen buffers)mapLedPolygon(int start, float[][] verts, PolygonFillConfig cfg)β fill any polygon with auto spacingmapLedRowLayout(int start, float[][] verts, RowLayoutConfig cfg)β fixed LEDs per rowsetRowLayout(int start, float[][] verts, RowLayoutConfig cfg)β alias of mapLedRowLayout
setResponse(float gamma)β gamma correction (1.0 = linear, 2.2 typical)setTemperature(float t)β adjust color temperature (-1 = warm, 1 = cool)setCustomCurve(float[] curve)β custom correction curve
showLedLocations()β draw LED markers on canvasvisualize(int[] colors)β draw sampled LED colorssetShowLocations(boolean enabled)β toggle marker drawing
You can save the current response/temperature/curve settings to a file and reload them later.
This is useful for keeping fixture profiles consistent across sketches.
// Save current settings to a file
c2d.saveSettings("mySettings.txt");
// Later, reload them
c2d.loadSettings("mySettings.txt");Instead of a simple gamma correction, you can define your own brightness curve.
The curve is an array of values between 0.0 and 1.0 that remap input brightness β output brightness.
This lets you calibrate your LEDs more precisely than with setResponse().
// Example: nonlinear custom brightness curve
float[] customCurve = {
0.0, // off
0.05, // very dim
0.2,
0.5,
0.8,
1.0 // full brightness
};
c2d.setCustomCurve(customCurve);Colors look washed out / pastel on LED strips
- WS2812/WS2815 LEDs have linear output but human vision is perceptual β add gamma correction:
c2d.setResponse(2.2); // or up to 2.6; start here for WS2815 via SP201E
- Use
ColorBandTestwithsetResponse(1.0)to verify raw channel mapping first, then dial in gamma.
Red and green are swapped on the fixture
- Your LED chip is GRB order β swap
rβgin the pattern:c2d.setChannelPattern("dgrb"); // was "drgb" c2d.setChannelPattern("dgrbsc"); // was "drgbsc"
DMX not connecting
- Make sure youβre using the right library for your dongle:
- ENTTEC USB Pro β dmxP512,
USE_ENTTEC_PRO = true - FT232RL cheap dongle β DMX4Artists,
USE_ENTTEC_PRO = false - These are not interchangeable β using the wrong one will silently do nothing
- ENTTEC USB Pro β dmxP512,
- On macOS, the port must use
cu.prefix:/dev/cu.usbserial-XXXXXXXX(nottty.) - To list all connected serial ports, add
println(Serial.list());tosetup()
LED strip updates roll/cascade down the strip
- dmxP512 sends DMX on a background timer thread. Use
buildDmxFrame()for atomic updates:int[] frame = c2d.buildDmxFrame(DMX_UNIVERSE); for (int i = 0; i < frame.length; i++) dmxPro.set(i + DMX_OFFSET, frame[i]);
- Also check your DMXβSPI translator for a "buffered" vs "streaming" mode setting.
Colors wrong or always white
- Ensure
pixelDensity(1)insetup() - Check LED positions with
c2d.showLedLocations() - Sample after drawing β
getLedColors()reads the current frame
Performance / slow updates
- Pre-build background images in
setup()instead of redrawing per-pixel indraw() - Reduce LED count
- Use
frameRate(30)if 60fps isnβt needed
See troubleshooting.md for the full guide.
Real-world installations by Studio Jordan Shaw built using this library:
![]() |
Constellation Range β Six illuminated faceted peaks glowing with aurora-like gradients, responding to nearby Bluetooth signals. OCAD U Gala, 2026. |
![]() |
Same Material / Different Time β Anamorphic LED installation transforming a tree into a sail through addressable strip lighting. Millennium Square. |
![]() |
Crosshatch β Kinetic interactive light installation where handles alter lighting, shadows, and projected patterns in real time. |
![]() |
Signal β Interactive light sculpture driven by open weather data and visitor interaction, exploring data transportation through the electromagnetic spectrum. |
![]() |
Rays β Infrared-interactive public light sculpture celebrating post-pandemic community reconnection. Hamilton. |
- Built-in Art-Net / sACN adapters so users do not need to write their own sender bridge
- Multi-universe output helpers when a mapped layout exceeds 512 DMX channels
- Fixture presets for common channel patterns instead of requiring manual pattern strings
- Alternate sampling modes such as averaged regions instead of single-pixel taps
- A calibration workflow for per-fixture white balance and brightness matching
- FadeCandy by Micah Elizabeth Scott
- Open Pixel Control
Original OPC Credit: Micah Elizabeth Scott, 2013. Released into the public domain.
MIT License Β© 2025 Studio Jordan Shaw





