Skip to content

Release 9 — DMX & Professional Lighting

Theme: Releases 3–8 covered addressable LEDs end-to-end. Release 9 brings projectMM into stage-lighting territory: DMX512 input and output over RS-485, moving-head fixtures with pan/tilt/gobo/zoom channels, and a Channels UI for debugging unknown fixtures. By the end, a projectMM device can control a DMX moving head and render scrolling text or WLED-ported effects across any layout.


Release Overview

Gap Addressed by
No RS-485 driver; DMX hardware can't be driven at all Sprint 1
No DMX Out — projectMM can only drive pixels, not fixtures Sprint 2
No DMX In — can't receive from a DMX console Sprints 3–4
No per-channel visibility for debugging DMX fixtures Sprint 5
No notion of "control channel" (last-wins for pan/tilt/gobo/etc.) Sprint 6
No moving-head effects Sprints 7–8
No text rendering — can't show IP / clock / status on matrix Sprint 9
Several MoonLight-worthy effects still missing Sprint 10

Sprint 1 — RS-485 Driver (MAX485 Half-Duplex)

Scope

Goal: a reusable RS-485 UART wrapper; both DMX and future Modbus/etc. will build on it.

Part A — Rs485Module. IoModule pin types: rs485_tx, rs485_rx, rs485_de (direction-enable). Initializes UART with MAX485 half-duplex flow control. Configurable baud (DMX uses 250 kbaud).

Part B — Raw write + read API. Other modules (DMX Out/In in Sprints 2–4) acquire the bus, write a frame, release. DE pin auto-toggled around writes.

Part C — Bus arbitration. Only one owner at a time; DMX Out and DMX In on the same bus would need separate UARTs (documented).

Definition of Done:

  • Loopback test: tx='A'; delay; rx reads 'A' back on a bench-wired MAX485
  • 250 kbaud sustained with no byte drop over 60 s
  • Two-bus test: two RS-485 modules on separate UARTs coexist

Result

To be completed after implementation.

Retrospective

To be completed after implementation.


Sprint 2 — DMX Out (Channels 1–512)

Scope

Goal: send one DMX universe (512 channels) at the standard 44 Hz.

Part A — DmxOutputModule. Children of VirtualLayer OR direct channel writers. Controls: start_channel, channel_count, refresh_hz (cap 44).

Part B — Light-preset mapping. Same light-presets as R6 S10 (IRGB, CW/WW, CCT) now applicable to DMX fixtures — an IRGB fixture occupies 4 consecutive channels.

Part C — Universe guard. UI warns if two DmxOutputModules target the same start channel range.

Definition of Done:

  • A DMX-controllable RGB fixture driven visually correct
  • 512 channels written at 44 Hz, no timing violations per DMX spec
  • Light-preset round-trip: SolidEffect(red) on IRGB DMX fixture → intensity 255 + R=255 + G=0 + B=0

Result

To be completed after implementation.

Retrospective

To be completed after implementation.


Sprint 3 — DMX In: Direct Channel Buffer Mode

Scope

Goal: receive a DMX universe; expose the full 512-channel buffer to the runtime for arbitrary use.

Part A — DmxInputModule. Listens on its configured RS-485 bus; maintains uint8_t channels[512]. Exposes getChannel(ch).

Part B — Frame-rate counter. Display control showing incoming frame rate; warns if below 20 Hz.

Definition of Done:

  • DMX console sending known test patterns updates channels[]
  • Frame-rate counter reads ≈ 44 Hz with a standard console
  • Break + MAB timing correct per DMX512 spec (measured with logic analyzer)

Result

To be completed after implementation.

Retrospective

To be completed after implementation.


Sprint 4 — DMX In: Lights-Control Mapping Mode

Scope

Goal: incoming DMX channels bind directly to control keys — a physical DMX console driving brightness, palette, speed without scripts.

Part A — Channel mapping table. Pairs (dmx_channel, module_id, control_key); UI for editing. Incoming value (0–255) writes to the control.

Part B — Range re-scaling. Map a DMX channel's 0–255 into the control's actual range — e.g. brightness (0–255) is identity, but a palette index (0–7) needs val / 32.

Part C — Mode switch. DmxInputModule has a mode control: buffer (Sprint 3 behavior) or controls (this sprint). Can be both simultaneously if two modules are configured on same bus.

Definition of Done:

  • Assigning "channel 10 → LightsControl.brightness" propagates console slider to actual brightness
  • 4 mapped channels verified with a real console
  • Mode switch demoed: same DMX In can feed buffer for effects AND controls for config

Result

To be completed after implementation.

Retrospective

To be completed after implementation.


Sprint 5 — Channels Module UI

Scope

Goal: the per-channel diagnostic view MoonLight's Channels module provides.

Part A — ChannelsModule (read-only diagnostic). Displays 512 channels in a grid; hover shows the current 0–255 value. View selector: physical (what the driver is about to output), virtual (what a selected VirtualLayer has composed).

Part B — Universe selector. Multi-universe drivers (DDP, Art-Net with > 1 universe) can page per universe.

Part C — Group-to-max toggle. When debugging an unknown DMX fixture, a "set all channels of this light to 255" button helps reverse-engineer which channels do what.

Definition of Done:

  • Channel grid shows live values; hover matches what the driver writes
  • Universe switch correct for an Art-Net configuration with 3 universes
  • Group-to-max toggles a fixture's channels to 255 for 5 seconds then restores

Result

To be completed after implementation.

Retrospective

To be completed after implementation.


Sprint 6 — Moving-Head Framework

Scope

Goal: fixtures that are not just color — they have pan, tilt, gobo, zoom. Control channels have last-wins semantics.

Part A — MovingHeadFixtureModule. Config: channel layout (pan_coarse, pan_fine, tilt_coarse, tilt_fine, gobo, zoom, strobe, dimmer, R, G, B, W). A fixture is a logical unit over N DMX channels.

Part B — Last-wins compositing. For control channels (pan/tilt/gobo/zoom/strobe/dimmer), the last layer to write wins — not additive. For color channels, additive still applies (matches MoonLight's decision).

Part C — Fixture presets. Preset JSON for common fixtures (generic 12-channel moving head + a couple of real-world fixtures — choose based on what we can test).

Definition of Done:

  • A bench moving head addressable via pan/tilt
  • Two layers targeting same fixture: layer 2 pan/tilt overrides layer 1 exactly
  • Layer 1 RGB + layer 2 RGB add normally

Result

To be completed after implementation.

Retrospective

To be completed after implementation.


Sprint 7 — Moving-Head Effects: Troy1 Color + Move

Scope

Goal: first two moving-head effects, ported from MoonLight.

Part A — Troy1ColorEffect. Color cycles across the fixtures' color channels; tempo can be global BPM or an effect-level slider.

Part B — Troy1MoveEffect. Pan/tilt pattern across N fixtures — Lissajous / circle / figure-eight options.

Part C — Test fixture layout. Preset for a 4-fixture bar (common stage setup); effects render meaningfully across it.

Definition of Done:

  • Troy1ColorEffect running on 4 RGB fixtures produces coordinated color cycling
  • Troy1MoveEffect runs pan/tilt pattern visibly across 4 pan/tilt fixtures
  • Combined: Troy1Color on one layer + Troy1Move on another layer both work (last-wins for movement, additive for color)

Result

To be completed after implementation.

Retrospective

To be completed after implementation.


Sprint 8 — Moving-Head Effects: Troy2, FreqColors, Wowi, Ambient

Scope

Goal: four more MoonLight moving-head effects — audio-reactive + ambient variants.

Part A — Troy2ColorEffect + Troy2MoveEffect. Richer Troy variants with more parameters.

Part B — FreqColorsEffect. Audio-reactive: fixture color follows dominant frequency band.

Part C — WowiMoveEffect. Sweeping choreographed motion — fixtures move in wave patterns triggered by audio magnitude.

Part D — AmbientMoveEffect. Slow, low-energy movement for background/atmosphere use.

Definition of Done:

  • All 5 effects registered, each produces its expected behavior on the bench rig
  • Audio-reactive variants respond to WLED-sync audio (doesn't need local mic on the fixture-driving device)
  • At least one "performance" test: combined effect stack + real DMX console running simultaneously — no frame drops

Result

To be completed after implementation.

Retrospective

To be completed after implementation.


Sprint 9 — Scrolling Text Effect + Font Rendering

Scope

Goal: display IP address / time / FPS / uptime / client count / arbitrary text on a 2D layout.

Part A — FontModule. 5×7 pixel font table (ASCII subset). Exposes drawChar(x, y, c, color) + measureText(s). One font initially; extensible.

Part B — ScrollingTextEffect. Controls: text (free text), preset (dropdown: custom, ip, fps, time, uptime, clients, status), speed, color, direction. Preset auto-populates text each frame from the corresponding system source.

Part C — Layout sizing. Text renders correctly on panels of any size; for narrow panels (< font height), auto-scales or shows a warning.

Definition of Done:

  • IP address scrolling across a 32×8 panel at a readable speed
  • preset=time updates every second; preset=fps updates live
  • Text renders correctly on 16-pixel-high panel and clearly on 8-pixel-high

Result

To be completed after implementation.

Retrospective

To be completed after implementation.


Sprint 10 — Additional WLED-Ported Effects

Scope

Goal: round out the effect library with the last set of high-value WLED ports.

Part A — PaintBrushEffect. 6D bass-driven paint-stroke effect from MoonModules.

Part B — BouncingBallsEffect. N balls bouncing within a 1D/2D volume; audio-reactive variant triggers new balls on beats.

Part C — FrequencySawsEffect. Audio-reactive saw-waves synced to bands.

Part D — RandomEffect + PraxisEffect. Two more MoonLight natives.

Part E — Effect gallery doc. Each effect with a one-sentence description + a GIF (or screenshot) on docs/modules/effects.md.

Definition of Done:

  • All 5 effects registered
  • Effect gallery page published
  • Combined footprint delta < 30 KB flash

Result

To be completed after implementation.

Retrospective

To be completed after implementation.


Release 9 Backlog

  • DMX merging (HTP/LTP strategies). HTP (highest-takes-precedence) and LTP (latest-takes-precedence) merge semantics. Pick up when two-console setups demand it.
  • RDM (Remote Device Management). DMX-over-DMX device discovery. Significant work; pick up when a real fixture benefits from it.
  • Full fixture library. Import OpenFixtureLibrary JSON. Pick up when fixture count on bench exceeds ~5.
  • Multi-font support. Bigger/smaller fonts, proportional fonts. Pick up when text effect demand grows.
  • Custom pixel-font editor. UI for drawing custom characters. Pick up when users request.