Status: Canonical reference (2026-07) | Binary: bin/casparcg highascg-build-v1, deployed 2026-07-15 — see CASPARCG_BUILD_PROVENANCE.md
Walkthroughs: WALKTHROUGH_PIXELMAP_DESTINATION_TEST.md (Pixel Map destination: real-world hookup + hardware-free testing, WO-438) · WALKTHROUGH_ARTNET_LED_WALL.md (native engines, primary flow) · WALKTHROUGH_PIXELMAP_FIXTURES.md (live JS pipeline, [DEPRECATED — legacyJsPixelmap flag])
This rig has three independent engines that turn live video into DMX-over-network (Art-Net / sACN). They coexist; pick per production. Everything below is read from the code actually deployed — source cites are file:line into the built Caspar tree (/home/casparcg/caspar-build/src-tree/) and this repo.
Recommended default as of WO-242. Device View can now create a dedicated pixelmap screen
destination end-to-end: a Caspar channel (custom raster-exact video-mode) plus a generated native
<artnet> consumer, wired up automatically — no hand-editing config/casparcg.config and no risk of
the block being wiped by the next regen (that gap, flagged in WO-241 below, is closed).
client/components/device-view-destinations-inspector-form.js).<artnet> consumer block automatically on every regen —
see WALKTHROUGH_ARTNET_LED_WALL.md for the exact schema and a
worked 8×4-wall example, and src/config/config-generator-consumer-attach.js (buildPixelmapChannel)
for the implementation.settings.ui.legacyJsPixelmap instead.WO-242: this engine’s fixture inspector (in the “Pixel Map” tab) is now hidden by default — the code is untouched and still fully functional, but new fixtures can’t be created from the UI unless settings.ui.legacyJsPixelmap is set to true (default false/absent).
(Note: mapping nodes — the “+ Add mapping node” button in Device View — are NOT part of this pipeline; they are the canvas-splitting output feature and remain fully active.)
Prefer the native “Pixel-map screen” flow above unless you specifically need sACN output or
restart-free live remapping (see the walkthrough for the honest trade-off).
The WO-179 pipeline inside the Node server. Caspar streams a downscaled copy of a program channel back to Node (ADD <ch> STREAM MPEG-TS + local ffmpeg, or a FILE consumer on dedicated slot 97 — src/sampling/dmx-sampling-ingress.js:17), a worker thread samples per-fixture regions, and src/sampling/dmx-output.js transmits Art-Net (npm dmxnet) or sACN (npm sacn) per fixture. Fixtures are edited in the UI and applied without touching Caspar’s config or restarting anything (index.js:316 re-runs SamplingManager.updateConfig() on every settings save).
client/lib/dmx-state.js:69-99).src/sampling/fixture-transform.js:50-55).src/sampling/dmx-sampling.js:29,145); ingress downscale 10–50 % of PGM (dmx-sampling.js:79-82).src/artnet/artnet-slot-config.js:10-16) and an sACN input receiver (src/artnet/sacn-receiver.js).<artnet> consumer (improved-artnet, PR #1752) — [CONFIG+CASPAR-RESTART]Compiled into the deployed binary (provenance row 1). A real Caspar frame_consumer attached to a channel in casparcg.config; registered preconfigured-only (modules/artnet/artnet.cpp:36) — there is no AMCP ADD ... ARTNET, so every fixture change means config edit + Caspar restart.
artnet_consumer.cpp:63,371-410), mirror-x/y, per-fixture host/port/universe.SWS_AREA, artnet_consumer.cpp:512-525): each fixture group is downscaled to exactly cols×rows pixels — every source pixel contributes, no stride caps. This is the best-quality averaging on the rig.artnet_consumer.cpp:318-333).refresh-rate Hz (default 10, artnet_consumer.cpp:67,140-218) — DMX rate is decoupled from video rate.artnet_consumer.cpp:745-746).<pixel> consumer (PR #1751) — [CONFIG+CASPAR-RESTART]Also compiled in (provenance row 9). The opposite philosophy: no regions, no averaging — the whole channel raster is the pixel map. Every frame, every pixel of the video mode is converted (luma / rgb / rgbw / rgbx) and packed sequentially into consecutive Art-Net universes (modules/pixel/consumer/pixel_consumer.cpp:83-116, artdmx_sink.h:76-109). Grid resolution = channel video-mode resolution, so it is used with a small custom video mode matching the LED grid (e.g. 96×54). Per-channel color coefficients + gamma (pixel_consumer.cpp:176-187). Registered preconfigured-only as pixel (modules/pixel/pixel.cpp:29-31); Art-Net is the only protocol it accepts today (pixel_consumer.cpp:148-150).
| JS pipeline (WO-179) | Native <artnet> (improved-artnet) |
Native <pixel> (#1751) |
|
|---|---|---|---|
| Badge | [LIVE-EDITABLE] | [CONFIG+CASPAR-RESTART] | [CONFIG+CASPAR-RESTART] |
| Latency path | Caspar encode → UDP → ffmpeg decode → JS worker → dmxnet/sacn (extra encode/decode hop; runs at its own fps, default 25) | In-process: consumer holds the last frame, sends on its own thread at refresh-rate Hz (default 10, raise in config) |
In-process, sends every frame at channel rate (50 fps on this rig) |
| Live editability | Full — fixtures, regions, rates re-apply on settings save, no Caspar restart | None — config regen/edit + Caspar restart per change | None — same, plus video-mode changes for grid changes |
| Averaging quality | Box average capped ~64 samples/cell (stride skips pixels on big regions), or single center pixel (fixture-transform.js:50-55) |
Best: libswscale SWS_AREA full box filter, every pixel weighted (artnet_consumer.cpp:518); rotation via 4× supersampled bilinear |
None needed — 1 source pixel = 1 LED (compose/scale content on the channel instead) |
| Protocols out | Art-Net and sACN, per fixture | Art-Net only | Art-Net only |
| Universe range | Art-Net clamped to universes 0–15 by dmxnet (dmx-output.js:30); sACN unrestricted |
0–32767, auto-spill across universes | 0–32767, sequential spill |
| Fixture types | Any colorOrder string incl. amber (rgbwa) | DIMMER / RGB / RGBW (+fixture-channels padding) |
luma / rgb / rgbw / rgbx |
| Config surface | UI (Pixel Map tab + Inspector), persisted in settings.dmx |
<artnet> block in a channel’s <consumers> — full schema in the LED-wall walkthrough |
<pixel> block + custom video mode |
| Restart coupling | None | Caspar restart (Device View → Apply Caspar config) | Caspar restart |
| CPU cost | Highest (ffmpeg decode + JS loops per frame) | Low (SIMD libswscale, one small scale per fixture group) | Lowest per pixel, but sends W×H×bytes channels per frame — keep the grid small |
| Monitoring | [DMX] lines in app log, live color preview over WS (dmx-sampling.js:363-369) |
OSC/monitor state artnet/… + log warnings (artnet_consumer.cpp:242-254,453-505) |
Log errors on send failure only (pixel_consumer.cpp:104-112) |
Rule of thumb: mapping edited during the show → JS pipeline. Fixed rig, best color fidelity / lowest CPU → native <artnet>. Raw LED processor or wall that wants a full raster → native <pixel>.
Concrete production ideas, each pointing at the right engine.
<artnet> consumer with one fixture-count="WxH" group per panel section. Area-averaged, restart-once, then rock solid all show. → WALKTHROUGH_ARTNET_LED_WALL.md.sampleMode: 'average'. → WALKTHROUGH_PIXELMAP_FIXTURES.md.<artnet> consumer’s DIMMER type drive blinder cells (luma-weighted 0.279/0.547/0.106, artnet_consumer.cpp:429); RGBW matrix cells get proper white extraction (min(r,g,b), artnet_consumer.cpp:436-443).sacn, pointed at the house console’s input universes. Only the JS pipeline speaks sACN, and it multicasts natively (dmx-output.js:72-91).<artnet> when the floor is rigged once per venue; choose JS when the floor mapping is re-blocked between acts.<pixel> consumer on a tiny custom video mode (the raster IS the seat map), content authored as ordinary Caspar media on that channel. Sequential universe packing does the addressing for you.<pixel> consumer, type rgb, one universe boundary every 170 pixels; the processor re-maps downstream.scale=cols:rows:flags=area consumer feeding the existing live-editable output path (drafted in work/work-orders/225_WO_ARTNET_INVESTIGATION.md). Not implemented; today the UDP ingress already downscales with flags=area (dmx-sampling-ingress.js:152) but the per-cell average is still JS-side..gdtf) into/out of the pixel-map fixture model. Research-stage only (work/work-orders/180_WO_GDTF_FIXTURE_IMPORT_EXPORT.md).<artnet> consumer blocks automatically for
pixelmap screen destinations (src/config/config-generator-consumer-attach.js
buildPixelmapChannel) — those survive every regen. This does not cover the manual
single-fixture <artnet> edit from the LED-wall walkthrough’s step 4, nor the <pixel> consumer:
both are still hand-edited config and are lost on the next Device View regen — re-add after
every “Apply Caspar config” if you use either outside a pixelmap destination. Generator support
for <pixel> remains undrafted follow-up work.dmx-output.js:30); use sACN or the native consumers above that.artnet_consumer.cpp:745, pixel_consumer.cpp:140).