Skip to content

jshaw/Canvas2DMX

Repository files navigation

Canvas2DMX: Map Processing Canvases to DMX

Canvas2DMX demo image

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.


✨ Features

  • 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

πŸŽ₯ Demo Video

Watch the demo

Click the thumbnail above to watch Canvas2DMX in action on YouTube.


πŸ“¦ Installation

  1. Install the required Processing libraries via Sketch -> Import Library -> Add Library...:

    • dmxP512 for ENTTEC USB Pro devices
    • DMX4Artists for FT232RL / Open DMX devices
  2. 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
  3. Restart Processing. The library will appear under Sketch -> Import Library -> Canvas2DMX.

  4. Explore the included examples via
    File -> Examples -> Contributed Libraries -> Canvas2DMX.


πŸ”Œ Which dongle do I have?

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 Library if you want to run the mixed-backend examples. HardwareOpenDMX and HardwareOLA are single-backend examples.


πŸš€ Basic Usage

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, ColorBandTest for switchable ENTTEC Pro / Open DMX sketches
  • HardwareOpenDMX for DMX4Artists-only FT232RL output
  • HardwareOLA for OLA / Art-Net output

πŸ–ΌοΈ Off-Screen Buffer Support

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);
}

🧩 Examples

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 PGraphics buffer with setCanvasSize()
  • 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.


Why use off-screen buffers?

  • 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

πŸ”§ LED Mapping Methods

Single LED

c2d.setLed(0, x, y);

LED Strip

c2d.mapLedStrip(0, 10, 200, 200, 20, radians(45), false);

LED Ring

c2d.mapLedRing(0, 12, 200, 200, 50, 0);

LED Grid

c2d.mapLedGrid(0, 8, 4, 200, 200, 20, 25, 0, true, false);

Square Corners

c2d.mapSquareCorners(0, 200, 200, 100, 45);

Polygon Fill (Auto Spacing)

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);

Row Layout (Fixed LEDs per Row)

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);

🎚 DMX Channel Patterns

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 off

πŸ›  Key Methods

Core

  • setChannelPattern(String pattern) β€” define fixture layout
  • setStartAt(int startAt) β€” starting DMX channel (1-based)
  • setDefaultValue(char channel, int value) β€” default values for non-RGB channels
  • getLedColors() β€” sample pixels and apply corrections
  • sendToDmx(DmxSender) β€” send DMX via any backend
  • buildDmxFrame(int universeSize) β€” generate full DMX frame array
  • setCanvasSize(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 spacing
  • mapLedRowLayout(int start, float[][] verts, RowLayoutConfig cfg) β€” fixed LEDs per row
  • setRowLayout(int start, float[][] verts, RowLayoutConfig cfg) β€” alias of mapLedRowLayout

Color Correction

  • 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

Visualization & Debugging

  • showLedLocations() β€” draw LED markers on canvas
  • visualize(int[] colors) β€” draw sampled LED colors
  • setShowLocations(boolean enabled) β€” toggle marker drawing

πŸ”’ Advanced Features

Save & Load Settings

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");

Custom Response Curves

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);

⚠️ Troubleshooting

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 ColorBandTest with setResponse(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↔g in 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
  • On macOS, the port must use cu. prefix: /dev/cu.usbserial-XXXXXXXX (not tty.)
  • To list all connected serial ports, add println(Serial.list()); to setup()

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) in setup()
  • 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 in draw()
  • Reduce LED count
  • Use frameRate(30) if 60fps isn’t needed

See troubleshooting.md for the full guide.


🌟 Made with Canvas2DMX

Real-world installations by Studio Jordan Shaw built using this library:

Constellation Range Constellation Range β€” Six illuminated faceted peaks glowing with aurora-like gradients, responding to nearby Bluetooth signals. OCAD U Gala, 2026.
Same Material / Different Time Same Material / Different Time β€” Anamorphic LED installation transforming a tree into a sail through addressable strip lighting. Millennium Square.
Crosshatch Crosshatch β€” Kinetic interactive light installation where handles alter lighting, shadows, and projected patterns in real time.
Signal Signal β€” Interactive light sculpture driven by open weather data and visitor interaction, exploring data transportation through the electromagnetic spectrum.
Rays Rays β€” Infrared-interactive public light sculpture celebrating post-pandemic community reconnection. Hamilton.

πŸ—Ί Roadmap / Missing Features

  • 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

πŸ“š Inspirations

Original OPC Credit: Micah Elizabeth Scott, 2013. Released into the public domain.


πŸ“œ License

MIT License Β© 2025 Studio Jordan Shaw

About

Sample colors from your Processing canvas and send them to DMX fixtures in real-time

Resources

License

Stars

5 stars

Watchers

1 watching

Forks

Sponsor this project

  •  

Packages

 
 
 

Contributors

Languages