Domain · Specifications

Uzume Domain — Technical Specifications

All 22 packages exist under libs/uzume/.

15sections37 minread

On this page

Named after Ame-no-Uzume-no-Mikoto — the Shinto goddess who performed the first show in recorded mythology — Uzume is the Oshun platform for everything that happens between "the doors open" and "the last cable is struck."

This document specifies the implemented Uzume domain as it exists in libs/uzume/. Uzume is a library-only domain: there are no apps/uzume/ or services/uzume/ directories. It consists of 21 TypeScript libraries plus one Rust/WASM workspace (uzume-protocol-engines).

This is the authoritative low-level reference for engineers working on Uzume. For a conceptual introduction to what each subsystem does and why it exists, see features.md. For the layered architecture and design patterns, see architecture.md. Every type, enum, schema, table, event, constant, and protocol described below is traceable to source files under libs/uzume/.


1. Library Inventory#

All 22 packages exist under libs/uzume/. The table below is the definitive package manifest — use it to find the path and npm name for any library. Note that @uzume/protocol-engines is the npm wrapper for the Rust workspace; the native module published separately as @uzume/protocol-native.

Package Path Type package.json description
@uzume/core libs/uzume/core TypeScript Core domain primitives, configuration contracts, and shared utilities
@uzume/nexus libs/uzume/nexus TypeScript Show control protocol bridging and subsystem integration
@uzume/protocol-engines libs/uzume/protocol-engines Rust/WASM Rust protocol engine workspace with WASM control-surface targets
@uzume/lumina libs/uzume/lumina TypeScript Lighting design and show control orchestration
@uzume/sonos libs/uzume/sonos TypeScript Audio engineering
@uzume/prism libs/uzume/prism TypeScript Video, projection, and LED content systems
@uzume/kinesis libs/uzume/kinesis TypeScript Rigging, flying, automation, robotics, motion control
@uzume/pyra libs/uzume/pyra TypeScript Special effects and atmospherics
@uzume/scena libs/uzume/scena TypeScript Scenic design, set construction, props
@uzume/koru libs/uzume/koru TypeScript Stage management and show calling
@uzume/atlas libs/uzume/atlas TypeScript Production and tour management
@uzume/aegis libs/uzume/aegis TypeScript Safety and compliance
@uzume/aurora libs/uzume/aurora TypeScript Extended reality and virtual production
@uzume/echo libs/uzume/echo TypeScript Audience engagement and accessibility
@uzume/vestis libs/uzume/vestis TypeScript Costume and wardrobe management
@uzume/previz libs/uzume/previz TypeScript Pre-visualization
@uzume/chronos libs/uzume/chronos TypeScript Scheduling
@uzume/tesla libs/uzume/tesla TypeScript Power distribution and electrical management
@uzume/hermes libs/uzume/hermes TypeScript Crew communication
@uzume/forge libs/uzume/forge TypeScript Network infrastructure
@uzume/muse libs/uzume/muse TypeScript AI assistance
@uzume/broadcast libs/uzume/broadcast TypeScript Broadcast switching, streaming, replay, and simulcast control

The Rust workspace npm wrapper is published as @uzume/protocol-engines; its native module crate (uzume-node-bridge) builds the npm package @uzume/protocol-native.

Each subsystem library exposes a UzumeLibraryMetadata constant (e.g. UZUME_CORE_METADATA, UZUME_LUMINA_METADATA, UZUME_BROADCAST_METADATA) and a corresponding getUzume<Subsystem>Metadata() accessor returning { id, subsystem, description }.

1.1 Subsystem Engine Counts#

Each subsystem library is a flat collection of independent *-engine.ts modules re-exported from src/index.ts. Each engine is a self-contained domain-specific implementation — not a generic service. The counts below are source modules, excluding index.ts and test files. They provide a useful signal for code review: a library where the count does not match likely has an engine missing from src/index.ts.

Library Engine modules
@uzume/broadcast 10
@uzume/prism 15
@uzume/aurora 25
@uzume/previz 15
@uzume/sonos 25
@uzume/echo 20
@uzume/koru 15
@uzume/scena 10
@uzume/vestis 10
@uzume/lumina 20
@uzume/kinesis 30
@uzume/pyra 18
@uzume/tesla 10
@uzume/forge 10
@uzume/hermes 10
@uzume/atlas 24
@uzume/chronos 10
@uzume/aegis 30
@uzume/muse 15

@uzume/core and @uzume/nexus follow a different shape (core: typed modules; nexus: a metadata-only package — see §11).


2. Technology Stack#

The table below records every technology choice that affects how the domain is built, tested, and deployed. The key design decision is the TypeScript/Rust split: TypeScript for domain logic and coordination, Rust for anything that requires deterministic timing or high-throughput packet processing. The Rust workspace release profile (lto = true, codegen-units = 1, opt-level = "s") is tuned for binary size and performance on embedded and server targets, not compilation speed.

Layer Technology
Primary language TypeScript (ESM, "type": "module")
Protocol language Rust (edition 2021, workspace version 0.1.0)
TypeScript build tsx / TypeScript compiler (no Nx executor pinned)
Rust build Cargo workspace; wasm-pack for the WASM crate
Database PostgreSQL via Drizzle ORM (drizzle-orm catalog)
Event bus NATS (nats npm package)
Validation Zod
Testing (TypeScript) Vitest
Testing (Rust) cargo test
Node.js native bridge napi-rs (napi 2.16, napi8 feature)
Browser bridge wasm-bindgen 0.2 + serde-wasm-bindgen

@uzume/core depends on the shared packages @oshun/database, @oshun/errors, @oshun/logging, plus nats, drizzle-orm, and zod. Subsystem libraries declare @uzume/core as a peerDependency (workspace:*).

The Rust workspace release profile uses lto = true, codegen-units = 1, opt-level = "s". Shared crate dependencies: serde, serde_json, thiserror, wasm-bindgen, js-sys, serde-wasm-bindgen, tokio (full features), bytes, napi/napi-derive/napi-build, midir.


3. Core Domain Types (@uzume/core/types)#

The core domain types define the shared vocabulary for the entire Uzume surface: what a show is, what a cue is, what a venue is, and how production departments are represented. These types are the contracts that subsystem libraries build on top of, and that consuming applications receive back.

Domain types are exported through the @uzume/core/types subpath (src/types/index.ts). They are not part of the package root export — the root src/index.ts exports config, database, errors, event-bus, logging, and utils only. This separation means a subsystem that only needs types does not pull in the NATS client and database ORM.

src/types/index.ts re-exports: department, cue, protocol-audio, protocol-automation-safety, protocol-control, protocol-dmx, protocol-equipment, protocol-gdtf, protocol-maintenance, protocol-mvr, protocol-patched-fixture, show, timeline, venue.

Every interface below has a matching Zod schema and a parse* helper. The parse* helpers throw with a descriptive message if validation fails — they are the recommended entry points for untrusted external data.

3.1 Department (department.ts)#

The Department enum is the organizational backbone of Uzume: it classifies who owns a given cue, resource, budget line, or alert. Every cue list belongs to a department, every budget allocation belongs to a department, and the event bus routes alerts to department dashboards. The DepartmentReadinessState enum tracks the real-time operational state of a department during a show — used by the stage manager's cue display to show which departments are ready to receive a "Go."

Department enum — 18 values:

lighting, audio, video, automation, effects, scenic, stage_management, production, safety, xr, audience, wardrobe, previz, scheduling, electrical, communication, network, ai.

DepartmentReadinessState enum — 7 values: not_ready, prepping, standby, ready, active, blocked, offline.

DepartmentAlertSeverity union: info | warning | critical | safety-critical.

Interface Fields
DepartmentContact fullName, email?, phone?
DepartmentBudgetAllocation currency (3-char), allocatedAmount, committedAmount, actualAmount, contingencyPercent? (0–100)
DepartmentEquipmentAllocation equipmentCategory, allocatedCount, reservedCount?, notes?
DepartmentConfig department, headOfDepartment, crewCount, budgetAllocation, equipmentAllocation[]
DepartmentCueReference cueId, cueNumber, cueLabel?
DepartmentAlert id, message, severity, createdAt (ISO datetime)
DepartmentStatus department, currentCue?, nextCue?, readinessState, activeAlerts[], updatedAt

Validation: DepartmentConfigSchema rejects committedAmount > allocatedAmount. Helpers: parseDepartmentConfig, parseDepartmentStatus, isDepartment, isDepartmentReady, hasBlockingDepartmentAlerts.

3.2 Cue (cue.ts)#

The Cue is the fundamental unit of show execution — an instruction to a department to change something at a specific time or trigger. Cues have a trigger mechanism (CueTriggerType), a lifecycle state (CueState), and a map of parameter changes to apply to target devices. The CueList groups cues into a sequence, tracks which cue is active, and enforces consistency between cueCount and the actual list length.

CueTriggerType enum — 6 values: manual, follow, auto_follow, timecode, midi, osc.

CueState enum — 6 values: standby, go, running, complete, skipped, disabled.

CueParameterValue is a recursive union: string | number | boolean | null | CueParameterMap | CueParameterValue[]; CueParameterMap is Record<string, CueParameterValue>.

Cue field Type Notes
id string (UUID)
number string regex ^([A-Za-z]{1,6}\s+)?\d+(\.\d+)?$ — e.g. Q 5, Q 5.5
label string non-empty
department Department
triggerType CueTriggerType
waitTimeMs number non-negative integer
durationMs number? non-negative integer
fadeTimeMs number? non-negative integer
targetDeviceIds readonly string[] min length 1
parameterChanges CueParameterMap
state CueState
isEnabled boolean

CueList fields: id (UUID), department, sequenceNumber, label, cueCount, activeCueIndex (≥ −1), cues[].

Validation rules:

  • Cue: isEnabled must be false when state === disabled.
  • CueList: cueCount must equal cues.length; activeCueIndex must be -1 for an empty list and otherwise point to an existing cue.

Helpers: parseCue, parseCueList, cueNumberToSortableValue, sortCuesByNumber, isCueReadyToExecute, getNextCue.

3.3 Show (show.ts)#

The Show type is the root aggregate for a production in Uzume: it carries the show's identity, creative team, production dates, venue assignments, and configuration (which subsystems are enabled, how cues are numbered, what timecode format is used). The ShowStatus lifecycle mirrors the real phases of a production from planning through archiving.

ShowType enum — 8 values: theatre, concert, festival, corporate, ceremony, broadcast, immersive, touring.

ShowStatus enum — 8 values: planning, pre-production, tech, dress, preview, running, closed, archived.

CueNumberingMode enum — 4 values: numeric, decimal, departmental, custom.

SmpteFrameRate (show.ts): literal union 24 | 25 | 29.97 | 30.

Interface Key fields
ShowPersonContact fullName, email?, phone?, organization?
ShowDesignerAssignment person, assistantDesigners?, notes?
ShowProductionDates preProductionStart (required); techStart?, dressStart?, previewStart?, openingNight?, runningStart?, closingNight?, loadInStart?, loadOutEnd?
ShowVenueAssignment venueId, venueName, assignmentRole (primary | rehearsal | tour-stop | backup), startDate, endDate?
ShowMetadata title, producer, director, designers (map by department), dates, venueAssignments[] (min 1)
CueNumberingScheme mode, prefix?, separator ('' | ' ' | '-' | '.'), startAt, increment (>0), decimalPlaces (0–3), departmentPrefixes?, customPattern?
ShowTimecodeFormat frameRate (24/25/29.97/30), dropFrame, displayFormat (hh:mm:ss:ff | hh:mm:ss;ff), startTimecode
ShowConfiguration enabledSubsystems[], departmentList[], cueNumberingScheme, timecodeFormat
Show id (UUID), code, type, status, metadata, configuration, createdAt, updatedAt

Validation: every departmentList entry must appear in enabledSubsystems; dropFrame is valid only with frameRate 29.97 or 30.

Helpers: parseShow, isShowType, normalizeShowConfiguration (de-dupes department lists), isShowActive (true for tech/dress/preview/running).

3.4 Timeline (timeline.ts)#

The Timeline type maps show events to SMPTE timecode frame positions. This is what allows lighting cues, video triggers, and automation moves to be locked to an audio or video timecode source — everything that happens at a given timecode position is grouped into a TimelineEvent. Markers and regions provide editorial annotations that do not trigger execution. The timecode arithmetic helpers implement the SMPTE drop-frame correction that affects 29.97 fps timecode, which is the standard for NTSC broadcast.

TimelineFrameRate: 24 | 25 | 29.97 | 30.

TimelineEventType union: cue_trigger | cue_complete | manual_note | automation_checkpoint | safety_checkpoint.

Interface Fields
SmpteTimecode hours, minutes (0–59), seconds (0–59), frames, frameRate, dropFrame
TimelineCueReference cueListId, cueId, cueNumber, cueLabel?
TimelineEvent id, timestampFrames, department, cueReference, eventType, note?
TimelineMarker id, timestampFrames, label, color (hex #RRGGBB)
TimelineRegion id, startFrame, endFrame, label, department?, description?
Timeline id, showId, label, frameRate, dropFrame, events[], markers[], regions[]

Validation: frames must be ≤ round(frameRate) − 1; dropFrame valid only for 29.97/30; TimelineRegion.endFrame ≥ startFrame.

Timecode arithmetic helpers (all SMPTE-aware, drop-frame-correct for 30 fps): parseSmpteTimecode, formatSmpteTimecode, timecodeToFrames, framesToTimecode, convertFramesBetweenRates, convertTimecodeRate, addTimecodes, subtractTimecodes, parseTimeline, normalizeTimeline.

3.5 Venue (venue.ts)#

The Venue type stores the physical and technical specification of a performance space. The technical sub-types (HouseLightingSystem, HouseAudioSystem, VenueNetworkInfrastructure) record what is permanently installed at the venue so that a touring production knows what it needs to bring versus what it can use in-house. The access sub-types (DockAccessHours, ElevatorCapacity, HallwayDimensions) capture the physical logistics of getting equipment in and out.

VenueType enum — 8 values: proscenium, thrust, arena, traverse, black_box, outdoor, stadium, custom.

Interface Fields
VenueDimensions widthMeters, depthMeters, heightMeters, stageWidthMeters?, stageDepthMeters?, stageHeightMeters?
VenueRiggingPoint id, label, xMeters, yMeters, zMeters, safeWorkingLoadKg
VenuePowerCapacity location, phases (1 | 3), voltage, amperage, availableKw
LoadingDockDimensions bayCount, dockHeightMeters, widthMeters, depthMeters, rollUpDoorWidthMeters, rollUpDoorHeightMeters
FlyTowerSpecs heightMeters, lineSetCount, counterweightSystem
VenueSpecs dimensions, seatingCapacity, riggingGridHeightMeters, riggingPoints[], powerCapacityByLocation[], loadingDockDimensions, flyTower
HouseLightingSystem consoleModel, dmxUniverses, dimmerCount, protocolSupport[]
HouseAudioSystem consoleModel, inputChannelCount, outputZoneCount, paSystemModel, networkProtocols[]
InstalledVideoSystem switcherModel, projectionSurfaceCount, ledProcessorModel?, ledResolution?, ndiEnabled
PatchPanelLocation id, name, locationDescription, availableProtocols[]
VenueNetworkInfrastructure coreSwitchModel, vlanCapable, ptpGrandmasterAvailable, fiberBackbone, wirelessCoverage (none|partial|full), managedSubnets[] (CIDR)
VenueTechnical houseLightingSystem, houseAudioSystem, installedVideo, patchPanelLocations[], networkInfrastructure
DockAccessHours days[] (weekday names), opensAt/closesAt (HH:MM 24-hour)
ElevatorCapacity available, maxWeightKg, cabWidthMeters, cabDepthMeters, cabHeightMeters
HallwayDimensions name, widthMeters, heightMeters, turnRadiusMeters
FloorLoadLimit areaName, maxLoadKgPerSquareMeter, notes?
VenueAccess dockAccessHours, elevatorCapacity, scenicMovementHallwayDimensions[], floorLoadLimitsByArea[]
Venue id (UUID), code, name, type, specs, technical, access, timezone, createdAt, updatedAt

Helpers: parseVenue, isVenueType, supportsHeavyRigging (default min SWL 1000 kg), getMaxFloorLoadKgPerSquareMeter, hasProtocolAtPatchPanel.


4. Protocol Type Specifications (@uzume/core/types)#

The protocol types define the low-level wire format structures that Uzume uses to communicate with physical hardware. These are distinct from the domain types in §3 — they represent the byte-level concepts (universes, channels, packets, device UIDs) rather than the production-management concepts (shows, cues, venues). Each protocol module defines constants, interfaces, validation rules, and helpers for one or two related protocols.

4.1 DMX512 (protocol-dmx.ts)#

DMX512 is the ANSI E1.11 standard for lighting control: a serial protocol that delivers 512 channel values (each 0–255) per universe at up to 44 Hz. Art-Net and sACN are IP transports for DMX universes — they carry the same 512-channel payload over UDP, enabling much larger channel counts and network distances than physical DMX cabling. RDM (Remote Device Management, ANSI E1.20) is a bidirectional extension of DMX that allows console-to-fixture parameter queries and commands.

Constants: DMX_CHANNEL_COUNT = 512, SACN_UNIVERSE_MIN = 1, SACN_UNIVERSE_MAX = 63999.

Interface Fields
DMXUniverse universe, sourcePriority (0–200), channels (Uint8Array, exactly 512), updatedAt
DMXAddress universe (0–63999), channel (1–512)
DMXPatch fixtureId, startAddress, footprintSize (1–512), label?
ArtNetConfig ipAddress (IPv4), subnet (0–15), universe, mode (broadcast | unicast), targetIpAddress?
SACNConfig universe (1–63999), multicastGroup (IPv4), priority (0–200), cid (UUID)
RdmSensorData sensorId, label, value, unit, state (normal | warning | alarm)
RDMDevice uid (12-char hex), manufacturer, model, dmxAddress, sensorData[], statusMessages[]

Validation: DMXPatch rejects footprints overrunning channel 512; ArtNetConfig requires targetIpAddress when mode === unicast; SACNConfig requires multicastGroup to equal the computed group for its universe.

Helpers: createDMXUniverse, setDmxChannel (value 0–255), getDmxChannel, computeSacnMulticastGroup (239.255.<hi>.<lo>), parseDMXPatch, parseArtNetConfig, parseSACNConfig, parseRDMDevice.

4.2 Control Protocols (protocol-control.ts)#

OSC (Open Sound Control), MIDI, and SMPTE timecode are the three most common show control protocols beyond DMX. OSC is an address-pattern-based message protocol (similar to HTTP URLs) used widely by audio consoles, video servers, and custom control systems. MIDI Show Control (MSC) is a MIDI extension specifically designed for theatrical cue triggering. Timecode (LTC and MTC) carries the master clock signal that all timecode-locked cues chase.

OSCArgument discriminated union — 8 variants: int32, float32, string, blob (Uint8Array), true, false, nil, timetag.

MIDIMessageType union — 6 values: note_on, note_off, cc, program_change, sysex, msc.

MSCCommandFormat union — 8 values: lighting, sound, machinery, video, projection, process_control, pyro, all.

MSCCommandType union — 7 values: go, stop, resume, timed_go, set, fire, all_off.

TimecodeFrameRate union — 5 values: 24, 25, 29.97df, 29.97ndf, 30 (string literals). TimecodeType union: ltc | mtc.

Interface Fields
OSCMessage addressPattern (must start with /), arguments[]
MSCCommand commandFormat, commandType, cueNumber?, cueList?, cuePath?
MIDIMessage type, channel (1–16), dataBytes[], mscCommand?
Timecode hours, minutes (0–59), seconds (0–59), frames, frameRate, type

Validation: MSC non-all_off commands require cueNumber; note_on/note_off/ cc require exactly 2 data bytes; program_change exactly 1; sysex must be 0xF0 … 0xF7; msc type requires an mscCommand. Timecode frames capped per frame rate (23/24/29/29/29).

Helpers: parseOSCMessage, parseMIDIMessage, parseMSCCommand, parseTimecode, parseTimecodeString, formatTimecode, midiStatusByte.

4.3 Network Audio (protocol-audio.ts)#

Dante is Audinate's proprietary network audio protocol — the most widely deployed standard in professional live sound — while AES67 is the interoperability layer that allows Dante devices to talk to competing systems (Q-SYS, RAVENNA, Livewire). Both route audio over standard Ethernet but require PTP (Precision Time Protocol) synchronization to within a few microseconds to avoid audible glitches. WirelessMicrophone represents the RF and battery telemetry that wireless systems report back to the mixing position.

Constants: DANTE_MAX_CHANNELS = 1024, AES67_PTP_DOMAIN_MIN = 0, AES67_PTP_DOMAIN_MAX = 127.

AudioSampleRate: 44100 | 48000 | 88200 | 96000 | 176400 | 192000. AudioBitDepth: 16 | 24 | 32. DanteLatencySettingMs: 0.25 | 0.5 | 1 | 2 | 5 | 10.

Interface Fields
DanteRoute sourceDevice, sourceChannel, destinationDevice, destinationChannel, isMulticast
DanteDevice name, rxChannelCount, txChannelCount, sampleRate, latencySettingMs, subscriptions[]
AES67Stream multicastAddress, sampleRate, bitDepth, channelCount (1–128), ptpDomain (0–127)
WirelessMicrophone frequencyMHz (30–3000), powerDbm, batteryPercentage, rfSignalStrength, audioLevel, deviceModel, transmitterId
SpeakerPosition coordinates, orientation (yaw/pitch/roll degrees), model, arrayMembership

Validation: a Dante route cannot loop a channel to itself; subscription destinationDevice must match the owning DanteDevice.name; AES67Stream multicastAddress must be in 224.0.0.0/4.

Helpers: parseDanteRoute, parseDanteDevice, parseAES67Stream, parseWirelessMicrophone, parseSpeakerPosition, validateDanteRouteForDevices, computeWirelessMicBatteryClass (critical <15%, low <35%, else ok).

4.4 Video (protocol-video.ts)#

The video protocol types cover both the signal format layer (SDI frame rates and formats, NDI streams) and the application layer (LED panel mapping, projection surface geometry, media asset metadata). SDI is the traditional uncompressed digital video standard for broadcast; NDI is NewTek's IP-based alternative that routes video over standard Ethernet. LEDProcessor represents the Brompton, Megapixel, or other LED management hardware that sits between the media server and the LED panels.

VideoFrameRate: 23.976 | 24 | 25 | 29.97 | 30 | 50 | 59.94 | 60 | 120. VideoColorSpace: bt709 | bt2020 | srgb | dci-p3 | display-p3 | acescg. SDIFormat: HD | 3G | 6G | 12G. MediaCodec: prores | dnxhr | h264 | h265 | av1 | vp9 | jpeg2000 | notchlc | hap.

Interface Fields
VideoResolution width, height (positive integers)
NDISource name, ipAddress, resolution, frameRate, colorSpace, bandwidthMbps
SDISignal format, resolution, frameRate, embeddedAudioChannels (0–64)
LEDPanelMapping panelId, outputPort, x, y, width, height
LEDProcessor model, inputCount, outputCount, panelMapping[], brightness (0–100), colorTemperature (1000–20000 K)
ProjectionSurface meshVertices[] (≥3), uvMapping[] (≥3), resolution, blendingZones[]
BlendingZone edge (left|right|top|bottom), start, end, feather (all 0–1)
MediaAsset filePath, codec, resolution, durationSeconds, frameRate, colorSpace, thumbnail

Validation: SDI embedded-audio channel limit per format (HD/3G 16, 6G 32, 12G 64); LEDProcessor panel ports must be ≤ outputCount and panelId unique; ProjectionSurface uvMapping length must equal meshVertices length.

Helpers: parseNDISource, parseSDISignal, parseLEDProcessor, parseProjectionSurface, parseMediaAsset, estimateVideoBandwidthMbps, mediaAssetFrameCount, mediaAssetAspectRatio.

4.5 Automation and Safety (protocol-automation-safety.ts)#

Automation safety types represent the physical safety infrastructure that governs moving equipment. A MotionAxis is an individual motorized axis (one chain hoist, one flying rail, one turntable) with position and velocity ranges enforced by the control system. A LoadCell is a weighing transducer attached to a rigging point that reports the actual load in real time — critical for detecting overloads before a structural failure. The SafetyPLC (Programmable Logic Controller) is the hardware safety layer that enforces emergency stop logic independently of the show control software.

MotionAxisType: hoist | fly | turntable | lift | track | custom. MotionAxisStatus: idle | moving | fault | e_stopped. LoadCellStatus: normal | warning | alarm | fault. SafetyPlcState: run | stopped | fault. GPIODirection: input | output.

Interface Fields
MotionAxis axisId, type, positionRange, velocityRange, accelerationRange, currentPosition, currentVelocity, status, customTypeLabel?
LoadCell id, location, currentLoadKg, ratedCapacityKg, alarmThresholdKg, status
SafetyPLC manufacturer, model, ipAddress, safetyState, inputStates, outputStates, emergencyStopActive
GPIOPin pinNumber, direction, state, debounceMs (0–10000)

Validation: axis currentPosition within positionRange; idle/e_stopped axes must have near-zero velocity; custom type requires customTypeLabel; LoadCell.alarmThresholdKg ≤ ratedCapacityKg with status/load coherence checks; SafetyPLC cannot be run while emergencyStopActive.

Helpers: parseMotionAxis, parseLoadCell, parseSafetyPLC, parseGPIOPin, motionAxisTravelPercent, loadCellUtilizationPercent, evaluateLoadCellStatus, canEnableSafetyOutputs.

4.6 Equipment (protocol-equipment.ts)#

The equipment types form the inventory backbone of the domain. The Equipment type is a discriminated union keyed on EquipmentCategory — each category selects a distinct specification interface with category-appropriate fields (e.g. LightingFixtureSpec has DMX footprint and fixture type; RiggingHoistSpec has rated capacity and chain speed). The isSafetyCriticalEquipment helper identifies equipment that requires additional inspection rigor.

EquipmentCategory enum — 24 values: lighting_fixture, lighting_accessory, audio_speaker, audio_console, audio_microphone, audio_wireless, audio_processing, video_display, video_projector, video_processor, video_camera, rigging_hoist, rigging_truss, rigging_hardware, effects_pyro, effects_atmospheric, effects_laser, scenic_element, electrical_distro, electrical_cable, communication_intercom, communication_radio, network_switch, network_cable.

Equipment<C> extends EquipmentBase (id, name, manufacturer, model, serialNumber, statusavailable|in_use|maintenance|retired, location?, tags[]) and adds category plus a specification whose shape is selected by category via EquipmentSpecificationByCategory. Each of the 24 categories has a distinct typed specification (e.g. LightingFixtureSpec, RiggingHoistSpec, EffectsLaserSpec, NetworkSwitchSpec).

EquipmentRecord is the discriminated union over all 24 typed equipment shapes.

Helpers: parseEquipment, parseEquipmentList, isEquipmentCategory, estimateEquipmentPowerDrawWatts, isSafetyCriticalEquipment (true for rigging hoists/hardware, pyro, electrical distro).

4.7 Maintenance (protocol-maintenance.ts)#

Maintenance records in live entertainment are not optional paperwork — they are the legal basis for operating equipment above audiences. A chain hoist that has not had a load test in the past year may not be legally rigged in many jurisdictions. The MaintenanceComplianceSummary aggregate is what a production manager or insurance auditor reviews to confirm a production's equipment is in compliance.

MaintenanceInspectionType: visual | functional | load_test | electrical_test | calibration.

MaintenanceResult discriminated union: { pass } | { conditional_pass, notes } | { fail, notes? }.

Interface Fields
CorrectiveAction id, description, status (open|in_progress|resolved|waived), assigneeId?, dueAt?, resolvedAt?
MaintenanceRecord id, equipmentId, inspectionType, result, inspectorId, inspectorCertification, inspectedAt, nextDueAt?, photos[], correctiveActions[]
MaintenanceComplianceSummary aggregate counts: compliant/non-compliant/overdue/dueSoon records, complianceRate, openCorrectiveActions, failedRecordCount, conditionalPassRecordCount, byInspectionType breakdown

Helpers: parseMaintenanceRecord, parseMaintenanceRecordList, isMaintenanceRecordOverdue, isMaintenanceRecordDueSoon, listOverdueMaintenanceRecords, generateMaintenanceComplianceSummary (deduplicates to the latest record per equipment/inspection-type pair).

4.8 GDTF (protocol-gdtf.ts)#

GDTF (General Device Type Format) is the open standard — developed jointly by MA Lighting, Robe, and the GDTF group — for describing the complete capabilities of a lighting fixture in a machine-readable file. A GDTF file (.gdtf, a ZIP archive) contains the fixture's DMX modes, physical dimensions, wheel contents, and geometry hierarchy. The parseGDTFFixtureArchive function reads these archives directly, which is what enables Lumina to ingest any manufacturer's GDTF file without custom code.

GDTF (General Device Type Format) fixture profiles. GDTFWheelType: color | gobo. GDTFGeometryType: base | yoke | head | beam | pixel_group | other.

Interface Fields
GDTFChannelFunction name, attribute, dmxFrom/dmxTo (0–255), physicalFrom?, physicalTo?, description?
GDTFDMXChannel name, offset (1–2048), defaultValue, highlightValue?, physicalDescription?, functions[]
GDTFDMXMode name, channelCount, channelLayout[]
GDTFPhysicalProperties weightKg, dimensions, powerDrawWatts, beamAngleRangeDegrees, colorTemperatureRangeKelvin, cri (0–100), lumenOutput
GDTFWheel name, type, slots[]
GDTFGeometryNode name, type, children[] (recursive)
GDTFFixture manufacturer, model, dmxModes[], physical, wheels[], geometryHierarchy[], sourceArchive?

Parsers (real implementations, not stubs): parseGDTFFixtureXml parses GDTF description.xml via an in-module XML tree parser; parseGDTFFixtureArchive extracts a .gdtf ZIP archive (handles stored and DEFLATE-compressed entries via node:zlib); parseGDTFFixtureFile reads from disk.

4.9 MVR (protocol-mvr.ts)#

MVR (My Virtual Rig) is the show-file exchange format that GDTF-based software uses to transfer a complete lighting design between tools — from the CAD design application (Vectorworks Spotlight) to the lighting console (grandMA3) to Uzume. An MVR file is a ZIP archive containing a GDTF file per fixture and a scene XML. Uzume implements full bidirectional MVR exchange: it can both import designs from other tools and export its own for use in external software.

MVR (My Virtual Rig) scene exchange. MVRLayerType: fixtures | trusses | scenic | focus_points. MVRSourceApplication: vectorworks_spotlight | grandma3 | capture | uzume | other.

Interface Fields
MVRVector3 x, y, z
MVRTransform position, rotation, scale
MVRLayer id, name, type, visible, locked, order
MVRFixturePlacement id, fixtureId, fixtureType, layerId, transform, focusPointId?, groupIds[]
MVRTrussDefinition id, name, layerId, trussType, lengthMeters, transform, attachments[]
MVRScenicElement id, name, layerId, category, transform
MVRFocusPoint id, name, layerId, position
MVRGroupDefinition id, name, memberIds[]
MVRSceneMetadata title, author?, createdAt, updatedAt, sourceApplication, units (m|ft), notes?
MVRScene metadata, layers[], fixturePlacements[], trusses[], scenic[], focusPoints[], groups[], sourceArchive?

Validation: every entity's layerId must reference a layer of the matching type; focusPointId references must exist; group memberIds must reference existing scene entities.

MVR exchange (full bidirectional implementation): parseMVRSceneXml, parseMVRSceneArchive, parseMVRSceneFile, serializeMVRSceneXml, serializeMVRSceneArchive (writes a stored-mode ZIP), writeMVRSceneFile, parseMVRScene.

4.10 Patched Fixture (protocol-patched-fixture.ts)#

The patched fixture is the runtime representation of a real lighting fixture that has been assigned a physical DMX address in the patch. It bridges the static GDTF fixture profile (what the fixture is capable of) with the live production context (where it is, which DMX address it uses, what its current parameters are). The revision counter on PatchedFixture enables optimistic concurrency: two operators cannot silently overwrite each other's parameter changes.

Bridges GDTF profiles into a placed, patched, live fixture.

Interface Fields
FixtureColorParameters red/green/blue (0–255), white?, amber?, uv?
FixturePositionParameters panDegrees, tiltDegrees
FixtureBeamParameters zoomDegrees, focusPercent (0–100), irisPercent?, frostPercent?
PatchedFixtureCurrentParameters intensityPercent (0–100), color, position, beam
PatchedFixture fixtureId, label, gdtfFixture, modeName, universe (0–63999), dmxAddress (1–512), placement, focusTarget?, colorGel?, groupMemberships[], currentParameters, updatedAt, revision
PatchedFixtureRealtimeUpdate partial intensityPercent/color/position/beam patch

Validation: modeName must exist in gdtfFixture.dmxModes; the patched mode must not overrun channel 512.

Helpers: parsePatchedFixture, createPatchedFixture (de-dupes groups, sets revision 0), applyPatchedFixtureRealtimeUpdate (merges and increments revision), patchedFixtureChannelFootprint, patchedFixturePatchEndAddress.


5. Event Bus (@uzume/core/event-bus)#

The event bus is the coordination mechanism that allows subsystem libraries to react to each other's state changes without importing one another. When the stage manager calls a cue in @uzume/koru, it publishes a cue.trigger event; @uzume/lumina, @uzume/sonos, and any other subscribed subsystem each receive that event and take action independently. This is what makes subsystem isolation possible at the architecture level.

The event bus is a NATS-backed publish/subscribe layer. Exported from src/event-bus/index.ts: types, transport, in-memory-transport, uzume-nats-event-bus.

5.1 Event Types and Subjects#

There are 6 event types. Each type has a constant name, a string type value embedded in the envelope, and a NATS subject used for routing. The table below maps all three for easy lookup when writing publishers or subscribers.

Event type constant type value NATS subject
CUE_TRIGGER cue.trigger uzume.cue.trigger
DEVICE_STATUS_CHANGED device.status.changed uzume.device.status
SAFETY_ALERT safety.alert uzume.safety.alert
SCHEDULE_UPDATED schedule.updated uzume.schedule.update
EQUIPMENT_STATUS_CHANGED equipment.status.changed uzume.equipment.status
CREW_NOTIFICATION crew.notification uzume.crew.notification

5.2 Event Payload Schemas#

Each event type has a Zod schema in UZUME_EVENT_PAYLOAD_SCHEMAS that validates the payload at publish and subscribe boundaries. The schemas are the contract between publishers and subscribers — if a field is missing or of the wrong type, NATS delivery still succeeds but Zod validation will throw before the subscriber processes the event. The table below lists each schema and its key payload fields.

Schema Payload fields
UzumeCueTriggerPayloadSchema showId, cueListId, cueId, triggerSource (manual|timeline|timecode|api), plannedTimeMs, actualTimeMs, driftMs
UzumeDeviceStatusPayloadSchema deviceId, subsystem, status (online|degraded|offline|maintenance), changedAt, details?
UzumeSafetyAlertPayloadSchema alertId, zone, severity (warning|critical|safety-critical), message, requiresEvacuation, acknowledgedBy?
UzumeScheduleUpdatedPayloadSchema scheduleId, showId, updateType (call_time|rehearsal|load_in|load_out|milestone), effectiveAt, impactedDepartments[], summary
UzumeEquipmentStatusPayloadSchema equipmentId, category, status (available|allocated|maintenance|failed), location, assignedShowId?
UzumeCrewNotificationPayloadSchema notificationId, crewId, department, priority (info|warning|urgent), channel (app|sms|radio|email), message, requiresAcknowledgement

5.3 Envelope, Priority, Delivery#

The delivery guarantee is selected automatically from the event priority: a safety-critical event uses guaranteed delivery (request/ack with retry) while informational events use best-effort. This means safety alerts cannot be silently dropped by a NATS connection issue without triggering retries, while routine status updates do not add ack latency.

UZUME_EVENT_PRIORITIES: informational | operational | safety-critical. UZUME_DELIVERY_GUARANTEES: best-effort | guaranteed.

UzumeEventEnvelope<T> fields: eventId, type, subject, occurredAt, correlationId?, sourceSubsystem?, priority, deliveryGuarantee, payload.

UzumePublishOptions: correlationId?, sourceSubsystem?, priority?, guaranteedRetryLimit?, retryDelayMs?, ackTimeoutMs?. UzumeSubscriptionOptions: queueGroup?.

5.4 Transports and Bus#

Two transport implementations share the same UzumeNatsTransport interface: the production transport wraps a real NATS connection, while the in-memory transport runs entirely in-process for unit tests and embedded scenarios. Switching between them requires only changing the transport constructor call — the bus and all subscriber code remain identical.

  • UzumeNatsTransport interface — publish, request, subscribe, close.
  • NatsJsUzumeTransport — production transport wrapping a real nats connection; createNatsJsUzumeTransport(config) connects with UzumeNatsConnectionConfig (servers, name?, token?, user?, password?, timeoutMs?, default timeout 5000 ms).
  • InMemoryUzumeNatsTransport — in-process transport implementing the same interface for tests and embedded use.
  • UzumeNatsEventBus — typed bus over a transport. publish selects best-effort vs guaranteed delivery from event priority; guaranteed events use request/ack with retry (default guaranteedRetryLimit 3, guaranteedRetryDelayMs 100, guaranteedAckTimeoutMs 1000). Public methods: publish, subscribe, close.

6. Persistence — Drizzle ORM Schema (@uzume/core/database)#

All persistence for the Uzume domain lives in @uzume/core. Concentrating the database schema in one library avoids fragmentation across 22 separate schemas and prevents subsystem libraries from creating implicit cross-schema dependencies. Subsystem libraries are stateless computation libraries; they return values to the consuming application, which decides what to persist.

The PostgreSQL schema namespace is uzume (pgSchema('uzume')). Exported from src/database/index.ts: schema, migration definitions/index/service, and seeds.

6.1 PostgreSQL Enums (19)#

The following 19 enums are created in the uzume schema. They are listed here with their value count so that a schema diff can confirm completeness.

show_status (8), department_type (7: lighting, audio, video, automation, effects, scenic, stage_management), cue_target_type (6), cue_trigger_type (manual, timecode, follow, auto), equipment_condition (5), ownership_status (4), maintenance_result (pass, fail, needs_attention), assignment_type (show, truck, warehouse), certification_status (4), purchase_order_status (6), contract_status (5), settlement_status (4), inspection_result (3), incident_severity (4), incident_status (4), certification_log_status (4), safety_document_approval_status (4), safety_audit_event_type (insert, update, delete, state_change).

6.2 Tables (24)#

UZUME_CORE_TABLES enumerates all 24 tables. Every table carries a UUID primary key (defaultRandom()), JSONB metadata where applicable, and timestamp columns. Drizzle relations() are defined for every table, and InferSelectModel/InferInsertModel types are exported per table (e.g. Venue/NewVenue, Show/NewShow, Cue/NewCue).

Table Purpose
venues Venue records: dimensions, rigging points, power capacity (JSONB), capacity
shows Show records: code, title, venue FK, status, dates, planned/actual budget
departments Per-show departments (unique per show + department_type)
equipment_categories Hierarchical equipment categories (self-referencing parent_category_id)
equipment_items Equipment inventory: serial, manufacturer, model, condition, ownership, RFID, barcode
maintenance_logs Equipment maintenance/inspection logs with next_due_at
equipment_assignments Equipment-to-show/truck/warehouse assignments
crew Crew roster: name, contact, skills, union affiliation, day rate, availability
certifications Crew certifications with issuer, jurisdiction, expiry, status
labor_rules Union labor rules: overtime threshold, meal penalty, turnaround, rest break
crew_assignments Crew-to-show assignments with department, labor rule, call/wrap times
vendors Vendor directory with pricing terms, lead time, rating
budgets Per-show/department budget lines: allocated/actual/variance, currency, FX rate
purchase_orders Purchase orders: line items, approval chain, totals, status
contracts Contracts: parties, terms, milestones, payment schedule, value
settlements Financial settlements: gross/expense/net amounts, reconciliation status
risk_assessments Risk assessments: likelihood, severity, mitigations, residual risk
inspections Safety inspections: checklist type, result, photos, next_due_at
incidents Incidents: type, severity, status, root cause, corrective actions
certifications_log Certification status-change log
safety_documents Safety document versions with approval status and file URI
safety_audit_log Append-only safety audit trail (table/record/event-type/actor)
cue_lists Cue lists per show + department, with cue prefix and numbering start
cues Cues: number, label, trigger type/time, pre/post wait, duration, target, parameters

6.3 Migrations#

There is a single bootstrap migration that creates the entire schema from scratch. This design means the schema has one authoritative starting state — incremental migrations are added only when the schema evolves after initial deployment. The migration tracking table and advisory lock ensure that concurrent application startup does not run the migration twice.

definitions.ts defines the single bootstrap migration 20260210120000_uzume_core_schema ("uzume core schema bootstrap"), with full CREATE/DROP SQL for the schema, the 19 enums, all 24 tables, and indexes. UZUME_CORE_MIGRATIONS lists it; getUzumeCoreMigrations, registerUzumeCoreMigrations integrate with the @oshun/database MigrationRunner.

service.ts provides UzumeCoreMigrationService and createUzumeCoreMigrationService, migrateUzumeCoreUp, migrateUzumeCoreDown, resolveUzumePostgresConfigFromEnv. The migration tracking table is public.uzume_schema_migrations; the advisory lock id is 620001.

6.4 Seeds#

seeds/generator.ts exports generateUzumeSeedDataset with UzumeSeedGeneratorOptions, UzumeSeedSummary, and UzumeSeedDataset, producing reference data for the schema.


7. Errors (@uzume/core/errors)#

The error system serves two purposes that go beyond a simple exception hierarchy. First, it routes errors to the correct department dashboard so that a lighting error surfaces to the lighting operator's display, not the sound board. Second, it escalates safety-critical errors through dedicated channels (audible and visual alerts) to ensure they are not silently swallowed. These requirements are why the error system is more complex than a simple throw new Error().

Exported from src/errors/index.ts: error-codes, error-framework, error-routing, safety-escalation, uzume-error.

7.1 Error Codes#

UZUME_ERROR_SUBSYSTEMS — 19 subsystems: LUMINA, SONOS, PRISM, KINESIS, PYRA, SCENA, KORU, NEXUS, ATLAS, AEGIS, AURORA, ECHO, VESTIS, PREVIZ, CHRONOS, TESLA, HERMES, FORGE, MUSE.

UzumeErrorCode is the template-literal type ${Subsystem}-${ThreeDigitCode} (e.g. LUMINA-042, sequence 001–999). Helpers: isUzumeErrorCode, createUzumeErrorCode, parseUzumeErrorCode.

7.2 UzumeError#

UZUME_ERROR_SEVERITIES: info | warning | critical | safety-critical.

UzumeError extends @oshun/errors' OshunError and adds subsystem, uzumeCode, severity, errorId (UUID), escalationRequired, plus isSafetyCritical(). UzumeOperationalContext carries showId?, venueId?, cueListId?, cueId?, deviceId?, operatorId?. Default code is <subsystem>-900; safety-critical severity defaults escalationRequired to true. Helpers: isUzumeError, toUzumeError.

7.3 Error Routing and Escalation#

error-routing.ts: UzumeErrorRouter routes errors to department dashboards. UzumeDepartmentDashboard has 17 values; SUBSYSTEM_DASHBOARD_MAP maps each of the 19 subsystems to a primary dashboard. buildUzumeDashboardRoutes adds a show_control route for critical errors and safety + stage_management routes for safety-critical errors. Topics follow uzume.dashboard.<dashboard>.errors.

safety-escalation.ts: UzumeSafetyEscalationService escalates safety-critical errors across UzumeSafetyEscalationChannels. UZUME_SAFETY_ALERT_MODES: audible | visual. The result reports delivered/failed channels and covered/missing alert modes.

error-framework.ts: UzumeErrorFramework (and createUzumeErrorFramework) ties routing, escalation, and logging together with UzumeErrorFrameworkConfig.


8. Configuration (@uzume/core/config)#

The configuration schema is designed for fail-fast startup: all required environment variables are validated and typed at boot time so that a missing UZUME_NATS_SERVERS is discovered before the first cue fires, not during the show. Feature flags allow a consuming application to enable only the subsystems it needs, which also drives which NATS subscriptions are established at startup.

config/env.ts defines UzumeConfigSchema (a Zod transform of an environment schema). Environment variables:

Variable Required Purpose
UZUME_DATABASE_URL yes Primary PostgreSQL URL
UZUME_TIMESCALE_URL no TimescaleDB URL (falls back to UZUME_DATABASE_URL)
UZUME_CLICKHOUSE_URL no ClickHouse URL
UZUME_REDIS_URL yes Redis URL
UZUME_NATS_SERVERS yes Comma-separated NATS server list
UZUME_NATS_STREAM_NAME no NATS stream name (default uzume.events)
UZUME_S3_ENDPOINT yes S3-compatible object storage endpoint
UZUME_S3_BUCKET yes Object storage bucket
UZUME_S3_REGION no Object storage region (default us-east-1)
UZUME_S3_ACCESS_KEY yes Object storage access key
UZUME_S3_SECRET_KEY yes Object storage secret key
UZUME_S3_FORCE_PATH_STYLE no Path-style addressing toggle (default true)
UZUME_FEATURE_LIGHTING no Feature flag (default true)
UZUME_FEATURE_AUDIO no Feature flag (default true)
UZUME_FEATURE_VIDEO no Feature flag (default true)
UZUME_FEATURE_AUTOMATION no Feature flag (default true)
UZUME_FEATURE_EFFECTS no Feature flag (default true)
UZUME_FEATURE_SCENIC no Feature flag (default true)
UZUME_FEATURE_STAGE_MANAGEMENT no Feature flag (default true)
UZUME_FEATURE_SHOW_CONTROL no Feature flag (default true)
UZUME_FEATURE_PRODUCTION_MANAGEMENT no Feature flag (default true)
UZUME_FEATURE_SAFETY no Feature flag (default true)
UZUME_FEATURE_AUDIENCE_EXPERIENCE no Feature flag (default true)
UZUME_FEATURE_PREVIZ no Feature flag (default true)
UZUME_FEATURE_AI no Feature flag (default true)

The transform shapes config into database, redis, nats, objectStorage, and features sections. loadUzumeConfig parses and caches; on failure it throws an aggregated message. Helpers: resetUzumeConfigCache, isUzumeFeatureEnabled, types UzumeConfig, UzumeFeatureKey.


9. Logging (@uzume/core/logging)#

Structured logging with subsystem context allows log aggregation systems to filter events by subsystem (LUMINA, AEGIS, etc.) and correlate related events across subsystems using the UzumeCorrelationContext. This is essential for diagnosing show-time incidents where events from multiple subsystems are interleaved in the log stream.

logging/uzume-logger.ts provides structured logging with subsystem context. UzumeSubsystem is a union of subsystem names; UzumeCorrelationContext and UzumeLogOutputTarget describe correlation propagation and output targets. UzumeSubsystemLogger is the per-subsystem logger; UzumeLoggingConfig and UzumeLoggingInfrastructure configure it; createUzumeLoggingInfrastructure builds the logging stack.


10. Utilities (@uzume/core/utils)#

The utilities module is a collection of pure computation functions that multiple subsystem libraries need. They are kept in @uzume/core rather than in the subsystem libraries to avoid duplication and to ensure that, for example, every subsystem's SMPTE timecode arithmetic uses the same drop-frame-correct implementation.

Exported from src/utils/index.ts: dmx, protocol-address, safety-calculations, smpte-timecode, unit-conversion.

10.1 smpte-timecode.ts#

SMPTE timecode arithmetic is subtle: 29.97 drop-frame timecode skips frame numbers 0 and 1 at the start of each minute (except every 10th minute) to compensate for the 0.1% difference between 30 and 29.97 fps. Getting this wrong causes timecode-locked cues to drift by 3.6 seconds per hour. The functions below handle drop-frame correction transparently.

SmpteFrameRate (24|25|29.97|30), TimecodeRoundingMode (round|floor|ceil|trunc), SmpteTimecode, TimecodeConversionOptions. Functions: parseSmpteTimecode, formatSmpteTimecode, timecodeToTotalFrames, totalFramesToTimecode, convertSmpteTimecodeFrameRate, addSmpteTimecodes, subtractSmpteTimecodes, multiplySmpteTimecode, compareSmpteTimecodes, createSmpteTimecodeRange.

10.2 dmx.ts#

DMX merge (HTP = highest-takes-priority, LTP = latest-takes-priority) is the mechanism for combining DMX output from multiple sources — the operator desk, a timecode playback system, and an effects engine may all be writing to the same universe simultaneously. mergeDmxUniverseSources produces the merged output; captureDmxSnapshot records the state for later comparison or restore.

Constants DMX_UNIVERSE_MIN = 1, DMX_UNIVERSE_MAX = 65535. DmxMergeMode (htp|ltp), DmxFadeCurve. Interfaces for patch entries, conflicts, source state, merged state, snapshots, and fades. Functions include detectDmxPatchConflicts, mergeDmxUniverseSources, captureDmxSnapshot, calculateDmxFade, calculateDmxUniverseFadeSnapshot, plus validators.

10.3 safety-calculations.ts#

These functions implement the structural and electrical load calculations that appear in rigging permit documentation and power distribution design. They are based on standard engineering formulas (ASCE 7 for wind load, standard bridle geometry for point loads) and return a SafetyStatus so callers can distinguish between confirmed safe, confirmed over-capacity, and capacity-unknown cases.

SafetyStatus (within_limit|over_capacity|capacity_not_provided). Structural, electrical, and environmental load math: calculatePointLoad, calculateDistributedLoad, calculateBridleLegTension, calculateSinglePhaseElectricalLoad, calculateThreePhaseElectricalLoad, calculateVerticalCableWeight, calculateWindLoadAsce7Simplified.

10.4 protocol-address.ts#

Protocol address strings follow different conventions in different tools and console displays (e.g., 1.001 vs 1/1 vs U1C1 for DMX universe 1 channel 1). These helpers parse human-readable address strings into typed structs and format typed structs back to canonical strings, insulating the rest of the codebase from the fragmentation.

DMX/Art-Net/sACN/Dante/NDI/IP-subnet/MIDI address parsing and formatting (e.g. parseDmxAddressString, artNetPortAddress, parseSacnUniverse, parseDanteChannelString, parseIpSubnet, midiNoteNumberToName, parseMidiCcString).

10.5 unit-conversion.ts#

Distance/weight/angle conversions, fractional-inch formatting, DMX↔degrees and DMX↔Kelvin conversions, single/three-phase power math (watts/VA/amps), and audio-level conversions (dBu/dBV/dBFS/dBSPL, Pa).


11. @uzume/nexus#

@uzume/nexus is the intended TypeScript entry point for the show control protocol bridge. The current TypeScript implementation is a metadata-only package: src/index.ts exports UZUME_NEXUS_METADATA and getUzumeNexusMetadata() and nothing else. The protocol-bridging behavior its description refers to is fully implemented in the Rust uzume-protocol-engines workspace and consumed by TypeScript applications via the napi-rs native module and the WASM control surface. The split exists because the protocol engines require sub-microsecond precision that Node.js cannot provide — moving them to Rust was a deliberate performance decision, not an implementation gap.


12. Rust Protocol Engines (@uzume/protocol-engines)#

The Rust workspace is the performance foundation of Uzume. It is a Cargo workspace at libs/uzume/protocol-engines/ (resolver = "2", edition 2021) with six crates organized into three layers: the shared type definitions (uzume-protocol-types), the timing and orchestration logic (uzume-timing-core), the network I/O engines (uzume-network-io), and two platform bridges that expose the workspace to TypeScript and browser environments. The integration test crate validates cross-crate behavior.

Crate Role
uzume-protocol-types Core protocol types: DMX, RDM, MIDI, OSC, SMPTE timecode
uzume-timing-core High-precision timing, timecode sync, master timeline, show state
uzume-network-io UDP/TCP I/O and Art-Net / sACN / OSC / MIDI / MSC engines
uzume-node-bridge napi-rs Node.js native module (@uzume/protocol-native)
uzume-control-surface-wasm wasm-bindgen browser control surface
uzume-integration-tests Cross-crate integration test suite

12.1 uzume-protocol-types#

This crate defines the shared types used across all other crates in the workspace. Keeping them in a separate crate avoids circular dependencies between uzume-timing-core and uzume-network-io, both of which need DMX, MIDI, OSC, and timecode types.

Constants: DMX_UNIVERSE_CHANNEL_COUNT = 512, DMX_MAX_UNIVERSES = 65535, DMX_MIN_REFRESH_HZ = 44.0, DMX_MAX_REFRESH_HZ = 100.0, RDM_MAX_UID = 0xFFFFFFFFFFFF, RDM_DEFAULT_REDISCOVERY_INTERVAL_MICROS = 30_000_000, RDM_MAX_LABEL_LENGTH = 32, DMX_RECORDING_MAGIC = b"UZDMXREC", DMX_RECORDING_FORMAT_VERSION = 1.

ProtocolTypeError enumerates the crate's error variants (invalid DMX length/channel/universe/refresh-rate/source-metadata, RDM UID/PID/parameter errors, recording I/O and data errors, MIDI channel, OSC address, timecode).

DMX: DMXUniverse (fixed 512-channel buffer); DmxMergeMode (Htp/Ltp/Priority); DmxUniverseManager merges per-channel writes from multiple tracked sources (DmxChannelSource, DmxChannelWrite) and exposes DmxUniverseSnapshots. DMX recording: DmxRecording, DmxRecordingSession, DmxPlaybackEngine with a binary on-disk format, delta frames, timecode-locked seek, and live-vs-recorded A/B comparison (DmxAbComparisonReport).

RDM: RdmCommandClass, RdmStandardPid (DISC_UNIQUE_BRANCH, DISC_MUTE, DEVICE_INFO, DMX_START_ADDRESS, IDENTIFY_DEVICE, DEVICE_LABEL, MANUFACTURER_LABEL, SOFTWARE_VERSION_LABEL, SENSOR_VALUE), RdmRequest/ RdmResponse, RdmDiscoveryRange (binary-search splitting), RdmDiscoveredDevice, and RdmEngine (discovery cycles, device tracking, re-discovery interval).

MIDI: MIDIMessage (status/data1/data2?/timestamp_micros) with note_on and control_change constructors (channel 1–16 validated).

OSC: OSCArgument (Int/Float/String/Bool/Blob), OSCMessage (address must start with /, optional timetag).

Timecode: TimecodeRate (Fps24/Fps25/Fps2997/Fps30) with nominal_fps(); TimecodeFrame with total_frames(), from_total_frames, add_frames, and frame-range validation.

12.2 uzume-timing-core#

This is the show's master clock and sequencer. HighPrecisionClock provides the time source; TimerWheel fires scheduled events at the right frame; SmpteTimecodeCounter tracks the running timecode from one of three sources (system clock, incoming LTC audio, incoming MTC MIDI); MasterTimelineEngine coordinates which cues fire at which timecode positions; and the CrossSubsystemCueSequencer fans out a single cue-go event to multiple subsystems simultaneously.

Constants include DMX_MIN_REFRESH_HZ, LTC_BITS_PER_FRAME = 80, MTC_QUARTER_FRAME_COUNT = 8, MIN/MAX_TIMELINE_PLAYBACK_SPEED (0.1–10.0), and discovery/health/failover defaults.

Major components: HighPrecisionClock/HighPrecisionTimestamp, TimerWheel (ScheduledEvent/ScheduledEventKind), SmpteTimecodeCounter and TimecodeSyncEngine (TimecodeSource ∈ system clock / external LTC / external MTC; MtcQuarterFrameDecoder; LTC config), the MasterTimelineEngine (TimelineRole, TimelineTransportState, TimelineSubsystem, loop regions, state recall, dispatch events), the CrossSubsystemCueSequencer (CueGoSource, cross-subsystem cue plans/dispatch), the ShowStateSnapshotEngine, the ProtocolTranslationEngine (rule-based protocol translation with visual mapping graphs and reverse mappings), and show-file commit/merge structures (ShowStateManifest, ShowFileCommit, MergeConflictStrategy, ShowMergeResult).

12.3 uzume-network-io#

This crate owns the UDP/TCP sockets and protocol packet parsers. Art-Net, sACN, and OSC all run over UDP; MIDI Show Control uses a TCP control channel. The output engines format outgoing packets and manage discovery handshakes (Art-Net's ArtPoll/ArtPollReply sequence, sACN's universe discovery mechanism). The MIDI engine integrates with the midir crate for actual MIDI port I/O.

Constants: ARTNET_PORT = 6454, ARTNET_PROTOCOL_VERSION = 14, Art-Net opcodes (ArtDmx 0x5000, ArtPoll 0x2000, ArtPollReply 0x2100, ArtSync 0x5200), ARTNET_MAX_DMX_PAYLOAD = 512, SACN_PORT = 5568, SACN_PRIORITY_MIN/MAX (0/200), SACN_MAX_DMX_PAYLOAD = 512, OSC_DEFAULT_PORT = 8000, MIDI_CLOCK_PPQ = 24.

Components: UdpEndpoint/UdpDatagram (NetworkIoConfig, NetworkIoError), TcpControlServer/TcpControlConnection, Art-Net/sACN/OSC packet parsers (ArtNetPacket, SacnPacket, OscPacket/OscMessagePacket/ OscBundlePacket), the ArtNetOutputEngine and SacnOutputEngine (with discovery: ArtNetDiscoveredDevice, SacnUniverseDiscovery), the OscEngine, the MidiEngine (MidiMessage, MidiClockState, MidiInboundEvent, MidiPortInfo), and the MidiShowControlEngine (MscPacket, MscCommandType, MscTarget, MscTimedGoTime).

12.4 uzume-control-surface-wasm#

This crate is the browser bridge. It exposes a small WASM API surface so that a browser-based control surface (a lighting console running in a tablet browser, for example) can construct and send protocol messages directly — without a server round-trip for each button press. The surface is intentionally minimal to keep the WASM binary small and load-time short.

A wasm-bindgen surface exposing WasmDMXUniverse (setChannel, getChannel, toUint8Array) and the free functions createMidiNoteOn, createOscMessage, and createTimecodeFrame. Built with wasm-pack build crates/uzume-control-surface-wasm --target web --release.

12.5 uzume-node-bridge#

This crate is the server-side Node.js bridge. It compiles to a native .node module via napi-rs and is published as @uzume/protocol-native. TypeScript server code can call UzumeProtocolBridge methods synchronously (they execute in the Node.js thread) for operations that need Rust performance without launching a subprocess. The message history limit (2048 entries) prevents unbounded memory growth in long-running show-control servers.

A napi-rs native module (@uzume/protocol-native). Exposes the UzumeProtocolBridge class with methods for DMX channel I/O (set_universe_channel, get_universe_channel, universe_output), device discovery (discover_devices), timecode sync (sync_timecode_to_system_clock, sync_timecode_external, set_timecode_chase_offset_frames, current_timecode), and OSC/MIDI message send/receive with bounded history (MESSAGE_HISTORY_LIMIT = 2048). napi object types: DiscoveredDevice, TimecodeFrameBinding, OscMessageBinding, MidiMessageBinding.

12.6 Build Commands#

Run these from libs/uzume/protocol-engines/ unless noted. The pnpm aliases (cargo:test, cargo:check, etc.) wrap these commands for use within the Nx monorepo build system.

bash
# All Rust tests
cargo test --workspace          # (npm: cargo:test)
# Integration tests
cargo test -p uzume-integration-tests -- --nocapture   # (npm: cargo:test:integration)
# Workspace check
cargo check --workspace         # (npm: cargo:check)
# WASM control surface
pnpm --filter @uzume/protocol-engines build:wasm
# Node native module
napi build --platform --dts index.d.ts     # (in uzume-node-bridge, npm: build)

13. Subsystem Library Surface#

Each of the 19 subsystem libraries (and @uzume/lumina, @uzume/broadcast, etc.) is a flat collection of independent *-engine.ts modules re-exported from src/index.ts alongside the library metadata constant. Subsystem libraries do not import from one another; cross-subsystem coordination flows through the @uzume/core event bus. This section documents two libraries in detail as canonical examples of the module-per-engine pattern. The remaining 17 follow the same structure; per-file inventories live alongside each library's src/index.ts.

The following engine module lists are verified against src/index.ts in each library:

  • @uzume/lumina (lighting): fixture-patch-engine, fixture-library-manager, gdtf-parser, mvr-exchange-engine, fixture-parameter-engine, color-engine, gel-library, color-picker-engine, color-consistency-engine, subtractive-mixing-engine, tracking-cue-stack-engine, fade-engine, cue-trigger-engine, multi-cue-list-playback-engine, cue-macro-engine, parametric-effects-engine, pixel-mapping-engine, generative-content-engine, console-integration-bridge, atmospheric-effects-engine.
  • @uzume/broadcast: broadcast-switcher-integration-engine, broadcast-multiviewer-management-engine, replay-system-integration-engine, broadcast-graphics-engine, broadcast-audio-split-management-engine, broadcast-multi-platform-streaming-engine, stream-health-monitoring-dashboard-engine, srt-contribution-feed-management-engine, multi-venue-simulcast-distribution-engine, iso-recording-management-engine.

Subsystem engines are domain-specific implementations, not generic CRUD. For example: @uzume/aegis's risk-assessment-engine.ts defines RiskLikelihoodScore/RiskSeverityScore 1–5 scales, RiskLevel, and a probability×severity scoring matrix; @uzume/lumina's fixture-patch-engine.ts consumes @uzume/core/types GDTF/MVR helpers and detects DMX channel patch overlaps.


14. V2 Esports Integration (consumer-side)#

This section documents the V2 esports tooling's consumption of Uzume libraries. It is included in the Uzume specifications because it is the primary external consumer of @uzume/broadcast, @uzume/lumina, and @uzume/prism, and because the integration policies (primary package selection, NDI delegation, rollback isolation) are set at the Uzume boundary.

The V2 esports tooling package @v2/esports-tools (apps/v2/esports-tools/) consumes Uzume libraries — Uzume itself does not depend on V2. Two named contracts live in that package.

V2 Esports Broadcast Pipeline#

esports-broadcast-pipeline.ts imports from @uzume/broadcast and binds it as V2's primary esports broadcast pipeline through buildV2EsportsBroadcastPipeline (binding id v2.esports.uzume-broadcast-pipeline, primary package @uzume/broadcast). The pipeline composes the real broadcast subsystem engines — BroadcastMultiPlatformStreamingEngine, BroadcastSwitcherIntegrationEngine, BroadcastGraphicsEngine, ReplaySystemIntegrationEngine, SrtContributionFeedManagementEngine, and StreamHealthMonitoringDashboardEngine.

The requested-primary type is '@uzume/broadcast' | 'obs' | 'ndi' | 'vmix', but the contract pins standaloneObsAsPrimary: false, standaloneNdiAsPrimary: false, and standaloneVmixAsPrimary: false@uzume/broadcast is always the program authority and NDI routing is delegated to @uzume/prism. The one piece of OBS that is retained (obsWebSocketRetained: true) is scoped purely to streamer-mode notification suppression: the OBS WebSocket exists only to mute desktop/overlay notifications for on-camera talent, never to drive the program feed. That purpose is fixed by V2_ESPORTS_BROADCAST_OBS_WEBSOCKET_PURPOSE (streamer-mode-notification-suppression-only) and emits the v2.streamer-mode.notifications.suppressed event. The rollback policy is off-rollback-broadcast-operations with mayInfluenceRollback: false.

V2 In-Arena LED + Projection Integration#

arena-led-projection-integration.ts composes @uzume/lumina and @uzume/prism through buildV2ArenaLedProjectionIntegration (binding id v2.esports.uzume-arena-led-projection) for live-tournament in-arena LED walls and projection mapping. Lighting and cue triggering come from @uzume/lumina (PixelMappingEngine, CueTriggerEngine); LED-wall layout, projection mapping, auto-alignment, and video routing come from @uzume/prism (LedWallLayoutDesignerEngine, ProjectionMappingEngine, ProjectionAutoAlignmentEngine, VideoRoutingMatrixEngine), with per-pixel correction generated by generatePerPixelCorrectionMap and aligned panels emitting v2.esports.arena.projection.aligned. Its rollback policy is off-rollback-arena-production-operations.

Both bridges expose mayInfluenceRollback: false — they are presentation/show-control state only and cannot affect deterministic match simulation.

This integration is documented under V2/docs/integration/ and is verified by V2/ue/Tools/check-v2-uzume-broadcast-pipeline.py and check-v2-uzume-arena-led-projection.py.


15. Acceptance Criteria#

These criteria define what "done" means for a change to the Uzume domain. They are ordered from most mechanical (type checking) to most structural (schema consistency). All criteria must pass before a change is merged, not just the ones affected by the specific change — the criteria are a holistic gate.

A change to the Uzume domain is acceptable when:

  1. npx tsc --noEmit passes for each modified TypeScript library.
  2. npx vitest run passes for each modified library's test files (*.spec.ts / *.test.ts).
  3. cargo test --workspace and cargo check --workspace pass for changes to uzume-protocol-engines.
  4. New domain objects, enums, or protocol types in @uzume/core/types ship with a matching Zod schema and parse* helper.
  5. New event types are registered in UZUME_EVENT_TYPES, UZUME_EVENT_SUBJECTS, UZUME_EVENT_PAYLOAD_SCHEMAS, and UzumeEventPayloadMap together.
  6. Database schema changes update schema.ts, the bootstrap migration SQL in definitions.ts, and UZUME_CORE_TABLES.
  7. Subsystem engine modules added to a library are re-exported from that library's src/index.ts.