lib-maestro-dmx 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +729 -0
  3. package/dist/control/osc-control.d.ts +156 -0
  4. package/dist/control/osc-control.js +312 -0
  5. package/dist/control.d.ts +96 -0
  6. package/dist/control.js +259 -0
  7. package/dist/http.d.ts +10 -0
  8. package/dist/http.js +46 -0
  9. package/dist/index.d.ts +98 -0
  10. package/dist/index.js +90 -0
  11. package/dist/internal/normalize.d.ts +10 -0
  12. package/dist/internal/normalize.js +25 -0
  13. package/dist/live.d.ts +42 -0
  14. package/dist/live.js +44 -0
  15. package/dist/normalize.d.ts +5 -0
  16. package/dist/normalize.js +20 -0
  17. package/dist/osc.d.ts +45 -0
  18. package/dist/osc.js +279 -0
  19. package/dist/patterns.d.ts +35 -0
  20. package/dist/patterns.js +69 -0
  21. package/dist/read/brightness.d.ts +17 -0
  22. package/dist/read/brightness.js +18 -0
  23. package/dist/read/color-palettes.d.ts +46 -0
  24. package/dist/read/color-palettes.js +86 -0
  25. package/dist/read/fixture-groups.d.ts +31 -0
  26. package/dist/read/fixture-groups.js +56 -0
  27. package/dist/read/fx-palettes.d.ts +28 -0
  28. package/dist/read/fx-palettes.js +38 -0
  29. package/dist/read/live.d.ts +37 -0
  30. package/dist/read/live.js +40 -0
  31. package/dist/read/lookup.d.ts +71 -0
  32. package/dist/read/lookup.js +91 -0
  33. package/dist/read/palette-assignments.d.ts +31 -0
  34. package/dist/read/palette-assignments.js +47 -0
  35. package/dist/read/patterns-available.d.ts +19 -0
  36. package/dist/read/patterns-available.js +21 -0
  37. package/dist/read/patterns.d.ts +48 -0
  38. package/dist/read/patterns.js +95 -0
  39. package/dist/read/read-api.d.ts +20 -0
  40. package/dist/read/read-api.js +30 -0
  41. package/dist/read/shared.d.ts +45 -0
  42. package/dist/read/shared.js +65 -0
  43. package/dist/read/show-state.d.ts +35 -0
  44. package/dist/read/show-state.js +38 -0
  45. package/dist/read/show.d.ts +51 -0
  46. package/dist/read/show.js +62 -0
  47. package/dist/read/system-info.d.ts +39 -0
  48. package/dist/read/system-info.js +29 -0
  49. package/dist/read-api.d.ts +10 -0
  50. package/dist/read-api.js +18 -0
  51. package/dist/transport/http.d.ts +19 -0
  52. package/dist/transport/http.js +86 -0
  53. package/dist/transport/osc.d.ts +73 -0
  54. package/dist/transport/osc.js +301 -0
  55. package/package.json +58 -0
package/README.md ADDED
@@ -0,0 +1,729 @@
1
+ # lib-maestro-dmx
2
+
3
+ Node.js library for accessing MaestroDMX via OSC and show-relevant HTTP reads.
4
+
5
+ ## Runtime
6
+
7
+ This library targets Node.js 24 LTS.
8
+ It is published as a pure ESM package.
9
+
10
+ ## API
11
+
12
+ The library uses one shared host for both protocols:
13
+
14
+ - OSC writes are sent to port `7672`
15
+ - HTTP reads are loaded from the Maestro Web API under `/api/v1/...`
16
+
17
+ ```ts
18
+ import { createClient } from "lib-maestro-dmx";
19
+
20
+ const client = createClient({
21
+ host: "maestro.local"
22
+ });
23
+
24
+ const liveState = await client.live.read();
25
+ const showState = await client.showState.read();
26
+ const colorPalettes = await client.colorPalettes.read();
27
+
28
+ console.log(liveState.primary.patternId);
29
+ console.log(showState.type);
30
+ console.log(colorPalettes.palettes[0]?.name);
31
+
32
+ await client.control.group(1).setPattern("Solid Color");
33
+ await client.control.group(1).setBrightness(0.75);
34
+ await client.control.global.setBrightness(0.9);
35
+ await client.control.show.play();
36
+ ```
37
+
38
+ `client.live.read()` performs one explicit HTTP request and returns the full live snapshot.
39
+ `client.live.getLastRead()` returns the most recently fetched snapshot without making a new request.
40
+ The same `read()` / `getLastRead()` pattern is available for the other HTTP reader APIs.
41
+ `client.control` provides typed OSC helpers for the full parameter list published in the MaestroDMX OSC specification.
42
+ Continuous group and global value setters are throttled per OSC address with a leading-and-trailing window.
43
+ Brightness uses 500 ms. The other throttled continuous value setters use 250 ms.
44
+ Trigger commands and trigger parameter setters are sent immediately without throttling.
45
+
46
+ ## HTTP Read API
47
+
48
+ The library intentionally focuses on read access that is useful during show automation and cue orchestration.
49
+ It includes typed readers for:
50
+
51
+ - `/api/v1/live` via `client.live`
52
+ - `/api/v1/patterns` via `client.patterns`
53
+ - `/api/v1/patterns/available` via `client.patternsAvailable`
54
+ - `/api/v1/palettes` via `client.paletteAssignments`
55
+ - `/api/v1/palettes/color` via `client.colorPalettes`
56
+ - `/api/v1/palettes/fx` via `client.fxPalettes`
57
+ - `/api/v1/brightness` via `client.brightness`
58
+ - `/api/v1/show` via `client.show`
59
+ - `/api/v1/show/state` via `client.showState`
60
+ - `/api/v1/fixture_groups` via `client.fixtureGroups`
61
+ - `/api/v1/system_info` via `client.systemInfo`
62
+
63
+ These readers are aimed at runtime metadata, palette and pattern catalogs, active palette assignment, cue inspection, and current playback state.
64
+ Configuration-heavy endpoints such as stages, fixtures, active stage details, and frame driver setup are intentionally not wrapped by this library at the moment.
65
+
66
+ ### Reader Semantics
67
+
68
+ `client.systemInfo`
69
+
70
+ - Reads software and device metadata such as product name, software version, UI version, API version, release type, and build information.
71
+ - Useful for diagnostics, compatibility checks, and logging which MaestroDMX unit or software generation your automation is currently talking to.
72
+
73
+ `client.brightness`
74
+
75
+ - Reads the global brightness master for the whole stage.
76
+ - In MaestroDMX terms this is the top-level brightness control of the Show page, applied on top of fixture-group brightness and cue/live settings.
77
+
78
+ `client.live`
79
+
80
+ - Reads the current Live Control state for the four fixture groups: `PRIMARY`, `SECONDARY`, `TERTIARY`, and `QUATERNARY`.
81
+ - This corresponds to the real-time control area of the Show page where each fixture group has its own pattern, color palette, FX palette, parameters, and trigger-toggle permissions.
82
+ - Use it when you need to know what is currently active on stage right now, regardless of whether that state originated from manual live control, OSC, or a running cue.
83
+
84
+ `client.patterns`
85
+
86
+ - Reads the full pattern catalog, including manifests, pattern ids, display names, descriptions, regular parameters, and advanced parameters.
87
+ - MaestroDMX distinguishes between `Maestro Patterns` and `Core Patterns`.
88
+ - Maestro patterns are autonomous, music-driven “vibes” such as `Still`, `Ambient`, `Dance`, or `Party`.
89
+ - Core patterns are more explicit looks such as `Solid Color`, `Wash`, `Spectrum`, `Chase`, or `All Black`, and can often be used with or without audio input.
90
+
91
+ `client.patternsAvailable`
92
+
93
+ - Reads the flattened list of currently available pattern ids.
94
+ - This is useful as a quick existence check before trying to select or validate a pattern id from external automation.
95
+
96
+ `client.paletteAssignments`
97
+
98
+ - Reads the currently active color palette id and FX snapshot id per fixture group.
99
+ - This is helpful because Live Control exposes both the currently selected palette and the current active palette state for a group.
100
+ - In practice this gives you the palette selection that MaestroDMX is actively using for each param group at the moment.
101
+
102
+ `client.colorPalettes`
103
+
104
+ - Reads the color palette catalog from MaestroDMX.
105
+ - MaestroDMX distinguishes between `Grouped Palettes` and `Individual/Extended Palettes`.
106
+ - Grouped palettes contain multiple individual palettes and are especially important for Maestro patterns, because Maestro patterns intelligently move through the palettes in a group based on the music.
107
+ - Individual/Extended palettes represent either a single color or a gradient; extended palettes may also include Amber, White, and UV channel values.
108
+
109
+ `client.fxPalettes`
110
+
111
+ - Reads the available FX palette / snapshot definitions exposed by the Web API.
112
+ - In MaestroDMX terminology, snapshots are saved fixture configurations that can later be recalled through FX palettes.
113
+ - This is primarily useful when cues or live groups refer to FX palette selections that you want to resolve into a friendlier name or id.
114
+
115
+ `client.show`
116
+
117
+ - Reads the currently selected show and all of its cues.
118
+ - A show in MaestroDMX behaves like a playlist of cues; each cue contains fixture-group pattern, palette, FX palette, parameter, transition, and timing information.
119
+ - Use this to inspect the authored show structure, cue order, durations, and the pattern/palette content embedded in each cue.
120
+
121
+ `client.showState`
122
+
123
+ - Reads the runtime playback state of the active show.
124
+ - This includes whether MaestroDMX currently reports `Stopped`, `Playing`, or another state, which cue index is active, and the elapsed play time.
125
+ - Use it when you need transport-state awareness for automation, monitoring, or UI overlays.
126
+
127
+ `client.fixtureGroups`
128
+
129
+ - Reads the logical fixture groups on the stage and the fixtures assigned to them.
130
+ - MaestroDMX fixture groups are the central runtime grouping concept for patterns, palettes, brightness, pixel mapping, and trigger participation.
131
+ - This reader is intentionally limited to group-level runtime topology and does not expose full stage-editing or fixture-patching workflows.
132
+
133
+ ```ts
134
+ const patterns = await client.patterns.read();
135
+ const availablePatterns = await client.patternsAvailable.read();
136
+ const paletteAssignments = await client.paletteAssignments.read();
137
+ const colorPalettes = await client.colorPalettes.read();
138
+ const fxPalettes = await client.fxPalettes.read();
139
+ const brightness = await client.brightness.read();
140
+ const show = await client.show.read();
141
+ const showState = await client.showState.read();
142
+ const fixtureGroups = await client.fixtureGroups.read();
143
+ const systemInfo = await client.systemInfo.read();
144
+
145
+ console.log(patterns.manifests[0]?.patterns[0]?.name);
146
+ console.log(availablePatterns.ids);
147
+ console.log(paletteAssignments.states[0]?.activeColorPaletteId);
148
+ console.log(colorPalettes.palettes[0]?.children);
149
+ console.log(fxPalettes.palettes);
150
+ console.log(brightness.value);
151
+ console.log(show.cues[0]?.primary.patternId);
152
+ console.log(showState.currentCue);
153
+ console.log(fixtureGroups.groups[0]?.fixtureIds);
154
+ console.log(systemInfo.version);
155
+ ```
156
+
157
+ Common convenience lookups:
158
+
159
+ ```ts
160
+ await client.live.read();
161
+ await client.patterns.read();
162
+ await client.patternsAvailable.read();
163
+ await client.paletteAssignments.read();
164
+ await client.colorPalettes.read();
165
+ await client.show.read();
166
+ await client.showState.read();
167
+ await client.fixtureGroups.read();
168
+
169
+ console.log(client.live.getGroup(1)?.patternId);
170
+ console.log(client.live.getPaletteId("SECONDARY"));
171
+
172
+ console.log(client.patterns.findPatternById("Wash")?.name);
173
+ console.log(client.patterns.findParameter("Wash", "brightness")?.name);
174
+ console.log(client.patternsAvailable.has("Wash"));
175
+
176
+ console.log(client.paletteAssignments.getActiveColorPaletteId("PRIMARY"));
177
+ console.log(client.colorPalettes.findById("110")?.name);
178
+ console.log(client.colorPalettes.resolveChildren("701").map((palette) => palette.name));
179
+
180
+ console.log(client.show.getCueByIndex(0)?.name);
181
+ console.log(client.show.getCueSlot(0, "PRIMARY")?.patternId);
182
+ console.log(client.showState.isPlaying());
183
+ console.log(client.showState.getCurrentCueName());
184
+
185
+ console.log(client.fixtureGroups.getGroupByParamGroup("PRIMARY")?.fixtureIds);
186
+ ```
187
+
188
+ ### Convenience Method Reference
189
+
190
+ `client.live.getGroup(paramGroup)`
191
+
192
+ - Returns the current live slot for a fixture group using either `1..4` or `PRIMARY..QUATERNARY`.
193
+ - Useful when external code thinks in group names instead of the raw `primary` / `secondary` object keys.
194
+
195
+ `client.live.getPatternId(paramGroup)`
196
+
197
+ - Returns only the active pattern id of the selected live group.
198
+ - Useful for quick comparisons or logging.
199
+
200
+ `client.live.getPaletteId(paramGroup)`
201
+
202
+ - Returns only the active palette id of the selected live group.
203
+
204
+ `client.patterns.listPatterns()`
205
+
206
+ - Flattens all manifests into one list of pattern definitions.
207
+ - Useful when you do not care which manifest a pattern came from.
208
+
209
+ `client.patterns.findManifestById(id)`
210
+
211
+ - Finds a pattern manifest by id.
212
+ - Useful if you want to keep the distinction between manifests such as Maestro and Core pattern collections.
213
+
214
+ `client.patterns.findPatternById(id)`
215
+
216
+ - Finds one pattern definition by pattern id.
217
+ - This is usually the most useful pattern lookup when resolving live state or cue content to human-readable metadata.
218
+
219
+ `client.patterns.findParameter(patternId, param)`
220
+
221
+ - Resolves a regular or advanced parameter definition for a given pattern.
222
+ - Useful when building dynamic controls or showing labels and descriptions for pattern parameters.
223
+
224
+ `client.patternsAvailable.has(id)`
225
+
226
+ - Returns whether a pattern id is currently listed as available by MaestroDMX.
227
+
228
+ `client.paletteAssignments.getAssignment(paramGroup)`
229
+
230
+ - Returns the full active palette assignment object for a fixture group.
231
+
232
+ `client.paletteAssignments.getActiveColorPaletteId(paramGroup)`
233
+
234
+ - Returns only the currently active color palette id for a fixture group.
235
+
236
+ `client.paletteAssignments.getActiveFxSnapshotId(paramGroup)`
237
+
238
+ - Returns only the currently active FX snapshot id for a fixture group.
239
+
240
+ `client.colorPalettes.findById(paletteId)`
241
+
242
+ - Finds one color palette by id.
243
+
244
+ `client.colorPalettes.findByName(name)`
245
+
246
+ - Finds one color palette by its display name.
247
+
248
+ `client.colorPalettes.listGroups()`
249
+
250
+ - Returns only grouped palettes.
251
+ - Useful for UIs or automation flows that should only offer palette groups to Maestro patterns.
252
+
253
+ `client.colorPalettes.listLeafPalettes()`
254
+
255
+ - Returns only non-group palettes.
256
+ - Useful for cases where you want a concrete single palette or gradient instead of a palette collection.
257
+
258
+ `client.colorPalettes.resolveChildren(paletteId)`
259
+
260
+ - Resolves a grouped palette into its child palettes.
261
+ - Useful because Maestro patterns work particularly well with grouped palettes, while external tools often need to inspect the actual individual palettes contained inside.
262
+
263
+ `client.fxPalettes.findById(id)`
264
+
265
+ - Resolves an FX palette / snapshot id to its stored metadata.
266
+
267
+ `client.show.getCueByIndex(index)`
268
+
269
+ - Returns a cue from the selected show by zero-based array index.
270
+ - This is library indexing, not the OSC cue transport index.
271
+
272
+ `client.show.findCueByName(name)`
273
+
274
+ - Finds a cue by its cue name.
275
+
276
+ `client.show.getCueSlot(index, paramGroup)`
277
+
278
+ - Returns the slot state of one cue for one fixture group.
279
+ - Useful for questions like “what pattern does cue 7 use on SECONDARY?” without manually branching over `primary`, `secondary`, and so on.
280
+
281
+ `client.showState.isPlaying()`
282
+
283
+ - Returns `true` if the current show-state string ends in `_PLAYING`.
284
+
285
+ `client.showState.isStopped()`
286
+
287
+ - Returns `true` if the current show-state string ends in `_STOPPED`.
288
+
289
+ `client.showState.getCurrentCueName()`
290
+
291
+ - Extracts the current cue name from the runtime show-state payload when available.
292
+
293
+ `client.fixtureGroups.getGroupById(id)`
294
+
295
+ - Finds a fixture group by the internal group id.
296
+
297
+ `client.fixtureGroups.getGroupByParamGroup(paramGroup)`
298
+
299
+ - Resolves the stage fixture group that belongs to `PRIMARY`, `SECONDARY`, `TERTIARY`, or `QUATERNARY`.
300
+
301
+ `client.fixtureGroups.listFixtureIds(group)`
302
+
303
+ - Returns the fixture ids of a group, either by param-group name/index or by group id.
304
+
305
+ There is also a high-level lookup facade that combines already loaded snapshots:
306
+
307
+ ```ts
308
+ await client.live.read();
309
+ await client.patterns.read();
310
+ await client.patternsAvailable.read();
311
+ await client.paletteAssignments.read();
312
+ await client.colorPalettes.read();
313
+ await client.fxPalettes.read();
314
+ await client.show.read();
315
+ await client.showState.read();
316
+ await client.fixtureGroups.read();
317
+
318
+ const livePrimary = client.lookup.resolveLiveGroupContext("PRIMARY");
319
+ const currentCuePrimary = client.lookup.resolveCurrentCueGroupContext("PRIMARY");
320
+
321
+ console.log(livePrimary?.pattern?.name);
322
+ console.log(livePrimary?.activeColorPalette?.name);
323
+ console.log(currentCuePrimary?.cue?.name);
324
+ console.log(currentCuePrimary?.slot?.paletteId);
325
+ ```
326
+
327
+ ### High-Level Lookup API
328
+
329
+ `client.lookup.resolveLiveGroupContext(paramGroup)`
330
+
331
+ - Combines the last loaded snapshots of `live`, `patterns`, `patternsAvailable`, `paletteAssignments`, `colorPalettes`, `fxPalettes`, and `fixtureGroups`.
332
+ - Returns one merged object for a fixture group with:
333
+ - current live slot
334
+ - resolved pattern definition
335
+ - resolved active color palette
336
+ - resolved active FX palette
337
+ - fixture-group metadata
338
+ - `patternAvailable` boolean
339
+ - Use this when you want to inspect “what is PRIMARY doing right now?” in one call.
340
+
341
+ `client.lookup.resolveCueGroupContext(cueIndex, paramGroup)`
342
+
343
+ - Combines `show`, `patterns`, `patternsAvailable`, `colorPalettes`, and `fixtureGroups` for one cue slot.
344
+ - Use this when you want a structured view of one cue group, for example to render show-overview tooling or validate cue content.
345
+
346
+ `client.lookup.resolveCurrentCueGroupContext(paramGroup)`
347
+
348
+ - Uses the loaded `showState` to find the active cue index and then resolves the cue/group context for that runtime position.
349
+ - Useful for dashboards, stream overlays, or controller feedback that needs to know what the currently playing cue is doing on a specific fixture group.
350
+
351
+ ## OSC Control API
352
+
353
+ The low-level OSC transport remains available via `client.osc.send(...)`.
354
+ For MaestroDMX-specific commands, prefer `client.control`.
355
+
356
+ ```ts
357
+ await client.control.audio.setInput("USB Audio");
358
+ await client.control.audio.nextInput();
359
+
360
+ await client.control.live.pause();
361
+ await client.control.live.resume();
362
+ await client.control.live.stop();
363
+
364
+ await client.control.group(1).setPattern("Solid Color");
365
+ await client.control.group(1).setPatternIndex(3);
366
+ await client.control.group(1).setPalette(12);
367
+ await client.control.group(1).setPaletteIndex(2);
368
+ await client.control.group(1).setFxPaletteIndex(1);
369
+ await client.control.group(1).setBrightness(0.8);
370
+ await client.control.group(1).setExcitement(0.5);
371
+ await client.control.group(1).setBackground(0.2);
372
+ await client.control.group(1).setMotionRange(0.6);
373
+ await client.control.group(1).setMotionSpeed(0.7);
374
+ await client.control.group(1).setSpeed(0.4);
375
+ await client.control.group(1).setEnergy(0.9);
376
+ await client.control.group(1).setVariance(0.3);
377
+ await client.control.group(1).setDecay(0.1);
378
+ await client.control.group(1).setAttack(0.8);
379
+ await client.control.group(1).setShape(4);
380
+
381
+ await client.control.show.loadByName("Main Show");
382
+ await client.control.show.loadByIndex(0);
383
+ await client.control.show.loadCueByIndex(1);
384
+ await client.control.show.nextCue();
385
+ await client.control.show.previousCue();
386
+ await client.control.show.next();
387
+ await client.control.show.previous();
388
+ await client.control.show.playPause();
389
+ await client.control.show.play();
390
+ await client.control.show.stop();
391
+
392
+ await client.control.triggers.setStrobe(true);
393
+ await client.control.triggers.toggleStrobe();
394
+ await client.control.triggers.setStrobeBrightness(1);
395
+ await client.control.triggers.setStrobeRate(0.7);
396
+ await client.control.triggers.setBlinder(true);
397
+ await client.control.triggers.toggleBlinder();
398
+ await client.control.triggers.setBlinderBrightness(0.9);
399
+ await client.control.triggers.setBlackout(true);
400
+ await client.control.triggers.toggleBlackout();
401
+ await client.control.triggers.setFog(true);
402
+ await client.control.triggers.toggleFog();
403
+ await client.control.triggers.setFogInterval(0.5);
404
+ await client.control.triggers.setFogDuration(0.2);
405
+ await client.control.triggers.setFogVolume(0.8);
406
+ await client.control.triggers.setFogSpeed(0.4);
407
+ await client.control.triggers.setEffect(true);
408
+ await client.control.triggers.toggleEffect();
409
+ ```
410
+
411
+ ### OSC Method Reference
412
+
413
+ `client.control.global.setBrightness(value)`
414
+
415
+ - Sets the global stage brightness.
416
+ - MaestroDMX describes this as the global brightness of the lights on the Show page.
417
+ - This value multiplies with fixture-group brightness inside live state or cues, so it behaves like a stage-wide master dimmer rather than replacing per-group brightness.
418
+
419
+ `client.control.audio.setInput(name)`
420
+
421
+ - Selects the audio input by its configured input name.
422
+ - Useful when your automation needs to switch between built-in and USB audio devices by name.
423
+
424
+ `client.control.audio.nextInput()`
425
+
426
+ - Advances to the next configured audio input.
427
+ - Best suited for hardware-button or simple controller workflows where cycling inputs is easier than sending a named target.
428
+
429
+ `client.control.live.pause()`
430
+
431
+ - Pauses the current live show state.
432
+ - Use this when running in live mode and you want the current generated state to stop advancing temporarily.
433
+
434
+ `client.control.live.resume()`
435
+
436
+ - Resumes a previously paused live state.
437
+
438
+ `client.control.live.stop()`
439
+
440
+ - Stops the current live show.
441
+ - This is a live-mode transport action, not a show-playlist stop.
442
+
443
+ `client.control.group(group).setPattern(name)`
444
+
445
+ - Selects a pattern for a fixture group by pattern name.
446
+ - In MaestroDMX, patterns are the core lighting behaviors. Maestro patterns act like autonomous music-driven vibes, while Core patterns are more explicit looks.
447
+
448
+ `client.control.group(group).setPatternIndex(index)`
449
+
450
+ - Selects a pattern by its order in the current MaestroDMX list.
451
+ - Useful for controller surfaces with encoders, faders, or indexed selection rather than text labels.
452
+
453
+ `client.control.group(group).setPalette(id)`
454
+
455
+ - Selects a color palette by palette id.
456
+ - This is usually the better choice when your automation already works with palette ids returned by `client.colorPalettes`.
457
+
458
+ `client.control.group(group).setPaletteIndex(index)`
459
+
460
+ - Selects a palette by its order in the palette list.
461
+ - Mainly useful for generic controller UIs where you do not want to hard-code palette ids.
462
+
463
+ `client.control.group(group).setFxPaletteIndex(index)`
464
+
465
+ - Selects an FX palette by its order in the FX palette list.
466
+ - In MaestroDMX, FX palettes are used to recall saved snapshots and effect-related stage states.
467
+
468
+ `client.control.group(group).setBrightness(value)`
469
+
470
+ - Sets fixture-group brightness for the currently active live pattern.
471
+ - This is the per-group brightness described in Maestro pattern parameters and combines with global brightness.
472
+
473
+ `client.control.group(group).setExcitement(value)`
474
+
475
+ - Sets the Maestro pattern excitement parameter.
476
+ - MaestroDMX describes Excitement as controlling how fast, flashy, and sudden the autonomous effect feels; lower values are smoother and calmer.
477
+
478
+ `client.control.group(group).setBackground(value)`
479
+
480
+ - Sets the Maestro pattern background parameter.
481
+ - Higher background values keep more light present between accents; lower values increase contrast and make flashes feel more dramatic.
482
+
483
+ `client.control.group(group).setMotionRange(value)`
484
+
485
+ - Sets moving-head motion range for the group.
486
+ - MaestroDMX describes this as the amount of PAN/TILT movement, where `0` keeps movers near their configured offset position and higher values use more of the configured width.
487
+
488
+ `client.control.group(group).setMotionSpeed(value)`
489
+
490
+ - Sets moving-head motion speed for the group.
491
+ - This specifically affects PAN/TILT-style motion on fixtures with mover attributes.
492
+
493
+ `client.control.group(group).setSpeed(value)`
494
+
495
+ - Sets the pattern speed parameter.
496
+ - For many core patterns this directly controls how fast the effect evolves; on Maestro patterns it acts more like an advanced fine-tuning control.
497
+
498
+ `client.control.group(group).setEnergy(value)`
499
+
500
+ - Sets the pattern energy parameter.
501
+ - In MaestroDMX documentation this often influences how much of a palette is used and, depending on the pattern, overall brightness and color intensity.
502
+
503
+ `client.control.group(group).setVariance(value)`
504
+
505
+ - Sets the pattern variance parameter.
506
+ - MaestroDMX describes Variance as conceptually similar to an inverse background control for core patterns.
507
+
508
+ `client.control.group(group).setDecay(value)`
509
+
510
+ - Sets the pattern decay parameter.
511
+ - This usually controls how long pulses or effects fade out, or how wide/smeared an effect feels, depending on the pattern.
512
+
513
+ `client.control.group(group).setAttack(value)`
514
+
515
+ - Sets the pattern attack parameter.
516
+ - This usually controls how quickly an effect ramps in or how sharply pulses begin.
517
+
518
+ `client.control.group(group).setShape(value)`
519
+
520
+ - Sets the shape index used by supported patterns.
521
+ - According to the OSC spec this is especially relevant for core patterns and works best in 2D mappings.
522
+
523
+ `client.control.show.loadByName(name)`
524
+
525
+ - Loads a show by its stored name.
526
+ - In MaestroDMX a show is a playlist of cues including pattern, palette, FX palette, timing, and transition data.
527
+
528
+ `client.control.show.loadByIndex(index)`
529
+
530
+ - Loads a show by its order in the show list.
531
+
532
+ `client.control.show.next()`
533
+
534
+ - Advances to the next show in the show list.
535
+
536
+ `client.control.show.previous()`
537
+
538
+ - Goes to the previous show in the show list.
539
+
540
+ `client.control.show.loadCueByIndex(index)`
541
+
542
+ - Jumps to a specific cue number in the loaded show.
543
+ - This uses the OSC cue numbering expected by MaestroDMX, which starts at `1`.
544
+
545
+ `client.control.show.nextCue()`
546
+
547
+ - Advances to the next cue in the currently loaded show.
548
+
549
+ `client.control.show.previousCue()`
550
+
551
+ - Goes back to the previous cue in the currently loaded show.
552
+
553
+ `client.control.show.playPause()`
554
+
555
+ - Toggles between playing and paused show playback.
556
+
557
+ `client.control.show.play()`
558
+
559
+ - Starts show playback from the loaded/current cue context.
560
+
561
+ `client.control.show.stop()`
562
+
563
+ - Stops show playback.
564
+
565
+ `client.control.triggers.setStrobe(enabled)`
566
+
567
+ - Engages or disengages the strobe trigger.
568
+ - Trigger buttons only work while MaestroDMX is actually playing, either in Live mode or from show cues.
569
+
570
+ `client.control.triggers.toggleStrobe()`
571
+
572
+ - Toggles the strobe trigger state.
573
+
574
+ `client.control.triggers.setStrobeBrightness(value)`
575
+
576
+ - Sets strobe brightness.
577
+
578
+ `client.control.triggers.setStrobeRate(value)`
579
+
580
+ - Sets strobe flash rate.
581
+
582
+ `client.control.triggers.setBlinder(enabled)`
583
+
584
+ - Engages or disengages the blinder trigger.
585
+ - MaestroDMX describes this as driving LED fixtures to full white or the configured white/blinder behavior of supported fixtures.
586
+
587
+ `client.control.triggers.toggleBlinder()`
588
+
589
+ - Toggles the blinder trigger state.
590
+
591
+ `client.control.triggers.setBlinderBrightness(value)`
592
+
593
+ - Sets blinder brightness.
594
+
595
+ `client.control.triggers.setBlackout(enabled)`
596
+
597
+ - Engages or disengages the blackout trigger so lights go dark.
598
+
599
+ `client.control.triggers.toggleBlackout()`
600
+
601
+ - Toggles the blackout trigger state.
602
+
603
+ `client.control.triggers.setFog(enabled)`
604
+
605
+ - Engages or disengages the fog trigger.
606
+ - The exact fixture reaction depends on whether stage fixtures expose FOG ON/OFF and related fog attributes.
607
+
608
+ `client.control.triggers.toggleFog()`
609
+
610
+ - Toggles the fog trigger state.
611
+
612
+ `client.control.triggers.setFogInterval(value)`
613
+
614
+ - Sets the fog interval parameter used for timer-style fog bursts.
615
+
616
+ `client.control.triggers.setFogDuration(value)`
617
+
618
+ - Sets the fog burst duration used for timer-style fog bursts.
619
+
620
+ `client.control.triggers.setFogVolume(value)`
621
+
622
+ - Sets fog volume for fixtures or machines that expose a Fog Volume attribute.
623
+
624
+ `client.control.triggers.setFogSpeed(value)`
625
+
626
+ - Sets fog speed for fixtures or machines that expose a Fog Speed attribute.
627
+
628
+ `client.control.triggers.setEffect(enabled)`
629
+
630
+ - Engages or disengages the generic EFFECT trigger.
631
+ - MaestroDMX positions this as a catch-all trigger for effect channels such as flame or custom effect hardware.
632
+
633
+ `client.control.triggers.toggleEffect()`
634
+
635
+ - Toggles the EFFECT trigger state.
636
+
637
+ ## Method Notes
638
+
639
+ - All continuous float setters in the control API use the normalized MaestroDMX OSC range `0.0 .. 1.0`.
640
+ - `client.control.group(group)` accepts only fixture groups `1..4`.
641
+ - `client.control.show.loadCueByIndex(index)` requires `index >= 1` because MaestroDMX cue transport numbering is one-based.
642
+ - Brightness setters are throttled more conservatively than other continuous parameters to reduce chatter while still tracking manual slider movement well.
643
+
644
+ ## MaestroDMX Background
645
+
646
+ The descriptions above are aligned with the MaestroDMX knowledge base:
647
+
648
+ - MaestroDMX uses `Fixture Groups` as the runtime grouping for patterns, palettes, parameters, mapping, and trigger participation.
649
+ - `Live Control` is the real-time editing surface where each fixture group can have its own pattern, palettes, parameters, and trigger toggles.
650
+ - `Show Control` is a playlist-like sequence of cues with names, durations, transitions, and per-group content.
651
+ - `Color Palettes` are either grouped palettes or individual/extended palettes, and Maestro patterns are designed to move intelligently through grouped palettes based on the music.
652
+ - `Trigger Buttons` cover BLACKOUT, BLINDER, STROBE, FOG, and EFFECT and only work while MaestroDMX is actively playing.
653
+
654
+ ## Entwicklung
655
+
656
+ ```bash
657
+ npm install
658
+ npm test
659
+ ```
660
+
661
+ ## Live Test
662
+
663
+ The normal `npm test` run stays local and does not require a MaestroDMX device.
664
+
665
+ Run the opt-in live integration test explicitly:
666
+
667
+ ```bash
668
+ npm run live-test
669
+ ```
670
+
671
+ It talks to `maestro.local` and runs a fixed verification sequence on group `1`:
672
+
673
+ - set brightness to `0.37`
674
+ - set excitement to `0.63`
675
+ - set pattern to `Solid Color`
676
+ - set pattern to `Ambient`
677
+ - set palette id to `223`
678
+ - set palette index to `1` and verify that the reported `paletteId` is still `223`
679
+
680
+ The script polls `/api/v1/live` until each change is visible again. It is intentionally opt-in because it mutates real MaestroDMX state.
681
+
682
+ There is also an opt-in latency experiment for brightness ramps:
683
+
684
+ ```bash
685
+ npm run live-test:brightness-latency
686
+ ```
687
+
688
+ The script sends a 1 second brightness ramp from `0.0` to `1.0` twice:
689
+
690
+ - once as raw OSC `/live/1/brightness` messages without library throttling
691
+ - once as HTTP `PUT /api/v1/live` updates with a full `params` object
692
+
693
+ Both runs poll `/api/v1/live` and report when each target brightness becomes visible again. This is meant for comparing transport behavior on a real MaestroDMX device.
694
+
695
+ ## Sandbox CLI
696
+
697
+ For ad hoc experiments there is also a small sandbox CLI:
698
+
699
+ ```bash
700
+ npm run sandbox -- help
701
+ ```
702
+
703
+ Examples:
704
+
705
+ ```bash
706
+ npm run sandbox -- live:get
707
+ npm run sandbox -- live:watch 100
708
+ npm run sandbox -- osc:send /live/1/brightness f:0.5
709
+ npm run sandbox -- osc:brightness 1 0.5
710
+ npm run sandbox -- http:put-live '{"params":{"brightness":0.5}}'
711
+ npm run sandbox -- http:set-brightness 0.5
712
+ ```
713
+
714
+ ## Notification WebSocket Test
715
+
716
+ For the WebSocket notification stream, there is a separate opt-in console test:
717
+
718
+ ```bash
719
+ npm run live-test:notifications
720
+ ```
721
+
722
+ It connects to `ws://maestro.local/notifications`, expects each frame to contain Base64-encoded GZIP data, decompresses it, and prints the decoded payload to the console.
723
+ It connects to `ws://maestro.local/notifications`, decodes the Base64 payload, and prints the detected Protobuf structure to the console. The example payloads currently look like Protobuf envelopes with a `type.googleapis.com/...` type URL and a nested binary payload.
724
+
725
+ You can also pass a custom URL directly:
726
+
727
+ ```bash
728
+ tsx test/notifications-live-test.ts ws://maestro.local/notifications
729
+ ```