The open toolkit for modern lighting control.
@helioslx/core is a TypeScript toolkit for sending and observing sACN (E1.31)
from Node.js. Validated 512-slot DMX frames, sparse channel writes, fades,
optional persistence, and packet viewing — without fixture, personality, scene,
or show concepts.
Live-lighting warning: Test with disconnected fixtures or a closed test network first. Incorrect values, universes, priorities, or interface selection can move equipment, trigger strobes, or black out a venue. See live-lighting safety before connecting to a live rig.
- Node.js 22 or newer for the supported UDP runtime
- An IPv4 interface that can reach the sACN network
- TypeScript/ESM recommended
- Bun is compatibility-tested, but Node.js is the supported production network runtime
The root module is runtime-neutral. UDP, Redis, and HTTP support are isolated in optional subpaths, so install only the peers you use.
npm install @helioslx/core sacnimport { createSacnSource } from "@helioslx/core/node";
const universe = createSacnSource().universe(1);
await universe.setChannels({ 1: 255, 2: 128 });Public channels are one-based (1..512); values are integers from 0..255.
Universes are 1..63999, priorities are 0..200, and priority defaults to
100. A full frame must contain exactly 512 values.
Mutations auto-start the scheduler. Reads (get, listUniverses) do not.
Awaiting a mutation means the write is scheduled and persisted, not that a fade
has finished.
See the complete quick-start example.
Snap channels immediately:
await universe.setChannels({ 1: 255, 2: 128 });Fade several channels with one shared duration:
await universe.fadeChannels({ 1: 0, 2: 0 }, { durationMs: 1_000 });Per-channel durations:
await universe.transition([
{ channel: 1, value: 0, durationMs: 500 },
{ channel: 10, value: 255, durationMs: 2_000 },
]);Write a complete frame:
const frame = new Uint8Array(512);
frame[0] = 255;
frame[1] = 128;
await universe.write(frame, { durationMs: 2_000 });Later writes win for channels already fading. Unmentioned channels retain their current transitions and targets.
Inspect and clear output:
const output = await universe.get();
const outputs = await source.listUniverses();
const removed = await universe.clear();| Import | Peer dependency | Purpose |
|---|---|---|
@helioslx/core/node |
sacn |
Node UDP sender, receiver, process handlers, and runtime telemetry |
@helioslx/core/redis |
redis |
Versioned output and viewer persistence |
@helioslx/core/http |
elysia, @elysiajs/node, @elysiajs/openapi |
Unbound REST, OpenAPI, and viewer WebSocket routes |
@helioslx/core/testing |
none | Fake clock/receiver and recording transport |
The HTTP adapter does not bind a port, configure CORS, rate limit requests, or choose an authentication policy. The host application owns those decisions.
- Construct a source (and optional universe handles).
- Mutate output — the first output-demanding op restores state and starts
scheduling — or call
start()explicitly. - Await mutations; they are ordered with persistence.
- Call
stop()to pause the scheduler while keeping state, orclose()for final teardown. Repeatedclose()calls are safe.
Root sources and viewers do not close injected transports, receivers, or stores
by default. Set the corresponding ownership option when transferring ownership.
createSacnSource from @helioslx/core/node creates and owns its transport and
registers for process-signal teardown (opt out with
installProcessHandlers: false). Default memory stores and internally-created
Redis clients are also owned.
Universe mutators accept signal. A timed-out send remains serialized until
the underlying transport promise settles, preventing overlapping sends even
when a transport ignores cancellation. Source transport shutdown is bounded by
shutdownTimeoutMs (2 seconds by default).
Guides, API reference, examples, and community policies: docs.helioslx.com.
Runnable samples also live in examples/.
Apache-2.0. See LICENSE.
