Skip to content

Latest commit

 

History

History
383 lines (283 loc) · 20.4 KB

fixture-format.md

File metadata and controls

383 lines (283 loc) · 20.4 KB

JSON Fixture Format

This document gives a high-level overview of the concepts used in the JSON format of the fixture definitions collected in the Open Fixture Library. Those fixture definitions (also called personalities or profiles) specify information about a fixture's DMX controlment and general attributes.

Note: The fixture format is not intended to be used directly by other software, as it may introduce breaking, not-backwards-compatible changes at any time. Instead, write a plugin to transform the data into a more stable format for your application. Internally in OFL, working with the fixture model is preferred, as it eases access to the fixture data.

Table of contents

Schema

The JSON Schema files can be found in the schemas/ directory. JSON Schema is a declarative way to describe allowed JSON properties and values. The fixtures-valid.js test automatically checks the fixtures against these schemas and additionally tests things like the correct use of channel keys etc. programmatically.

The schema files have a version property. Every time the schema is updated, this version needs to be incremented in all schema files using semantic versioning.

Given a version number MAJOR.MINOR.PATCH, increment the:

  1. MAJOR version when you make incompatible schema changes.
    i.e. old fixtures are not valid with the new schema anymore.
  2. MINOR version when you add functionality in a backwards-compatible manner.
    i.e. old fixtures are still valid with the new schema, new fixtures aren't valid with the old schema.
  3. PATCH version when you make backwards-compatible bug fixes.
    e.g. an upper bound to an integer value is added, which was likely done right in the past anyway.

Goals

The JSON fixture format is intended to be

  • readable by both humans and machines
  • easily extendable
  • as general as possible to include information for many fixture formats
  • abstract where possible, specific where needed

Directory structure

The manufacturer of a fixture is determined by its toplevel directory (relative to the fixtures directory), the fixture key is the filename without extension. Manufacturer data is stored in fixtures/manufacturers.json.

fixtures/register.json (which is generated by cli/build-register.js) is just an index to make searching specific attributes possible without having to read the whole directory structure, which makes it faster. This file is gitignored.

Fixture

A fixture's shortName must be unique amongst all fixtures.

The physical section describes properties not directly used in the DMX protocol, but often in lighting control software to display a preview of the fixtures in action.

The lastModifyDate should NOT be updated when updating fixture data that is not related to the fixtures capabilities or attributes. This includes things such as changing an author's names, updating links, or updating the order of channel modes.

Modes

A fixture can have multiple modes (also sometimes called personalities) like "Basic 3-channel mode" or "Extended 5-channel mode". Our modes are not allowed to have the word "mode" in them, as it is automatically appended at the end.

A mode can contain the physical property to override specific physical data of the fixture. E.g. one mode could set the power value different than the fixture default.

A mode's shortName must be unique amongst all modes of the respective fixture. The shortname should be similar to what is displayed on the device's LCD/LED displays if that information is known (e.g. from the manual). If not known, the standard 1ch format should be followed.

Channels

All channels that are used in one or more modes are listed in availableChannels. The modes then only contain a list of the channel keys.

A channel's defaultValue is the DMX value that this channel is set to without the user interacting (most often, this will be 0, but e.g. for Pan and Tilt channels, other values make more sense). Likewise, highlightValue specifies the DMX value if a user highlights this channel (defaults to the maximum DMX value). This is not available in every software.

If constant is true, the channel should be set to a static value in the operating lighting program. precedence specifies to which value the channel should be set if there are two conflicting active cues containing this channel: HTP (Highest takes precedence) or LTP (Latest (change) takes precedence).

Capabilities

A channel can do different things depending on which range its DMX value currently is in. Those ranges that can be triggered manually in many programs are called capabilities. Choose a type to declare which property of the fixture is changed by this capability, e.g. ShutterOpen, Intensity or Pan. Depending on the type, there exist more properties that further describe the capability, like the pan angle, the strobe rate or the wheel slot number. Most of these are physical entities that require to be entered using specific units (like "10.5Hz" or "100%"). Some entities offer keywords to replace specific percentage values, e.g. Distance: "near" = "1%", "far" = "100%". See the full list of units, entities and capability types with their properties. Example:

"availableChannels": {
  "Shutter": {
    "capabilities": [
      {
        "dmxRange": [0, 20],
        "type": "ShutterStrobe",
        "shutterEffect": "Closed",
        "comment": "Blackout"
      },
      {
        "dmxRange": [21, 255],
        "type": "ShutterStrobe",
        "shutterEffect": "Open"
      }
    ]
  }
}

If a channel consists of a single 0-255 capability, one should use the capability property (instead of capabilities), which only needs a single object instead of an array of objects. The dmxRange is implicit in this object (see example below).

Capabilities may be steps, which means that the whole DMX range has the same effect (e.g. "Gobo 1"), or proportional, which means that the effect is increasing / decreasing from the start to the end of the DMX range (e.g. "Intensity 0-100%"). A proportional capability can define a start and an end value of its type-specific properties. Example:

"availableChannels": {
  "Pan": {
    "capability": {
      "type": "Pan",
      "angleStart": "0deg",
      "angleEnd": "530deg"

      // DMX value 0 -> 0°
      // DMX value 127 -> 264°
      // DMX value 255 -> 530°
    }
  }
}

Please note that some properties don't allow start/end values, for example hold.

The menuClick property defines which DMX value to use if the whole capability is selected: start / center / end sets the channel's DMX value to the start / center / end of the range, respectively. hidden hides this capability from the trigger menu. This is one of those special features that are supported only by some lighting programs.

Fine channels

A channel can list fineChannelAliases to specify which channel keys are used to describe its finer variants. This results in two or more (8 bit) channels being combined into one 16 bit (or 24 bit, ...) channel to increase the resolution of the controlled functionality.

Example: Channel Dimmer contains fineChannelAliases: ["Dimmer 16-bit", "Dimmer 24-bit"]. Mode "Normal" uses only Dimmer in its channel list, mode "Fine" uses Dimmer and Dimmer 16-bit, mode "Super fine" uses all three.

See the Generic Desk Channel fixture for a simple application example.

DMX values (e.g. default / highlight value, capability ranges) have to be entered in the maximum resolution: If one fine channel is defined, DMX values from 0 to 65535 are possible. If a lower resolution is sufficient for entering DMX values, the channel's dmxValueResolution property can be set to the desired resolution (8bit for 0…255, 16bit for 0…65535, etc.). That means that both of the following examples are equivalent:

"Iris": {
  "fineChannelAliases": ["Iris fine"],
  "defaultValue": 33792,
  "capabilities": [
    {
      "dmxRange": [0, 33791],
      "type": "Iris",
      "openPercentStart": "100%",
      "openPercentEnd": "4%"
    },
    {
      "dmxRange": [33792, 65535],
      "type": "Iris",
      "openPercent": "4%"
    }
  ]
}
"Iris": {
  "fineChannelAliases": ["Iris fine"],
  "dmxValueResolution": "8bit",
  "defaultValue": 132,
  "capabilities": [
    {
      "dmxRange": [0, 131],
      "type": "Iris",
      "openPercentStart": "100%",
      "openPercentEnd": "4%"
    },
    {
      "dmxRange": [132, 255],
      "type": "Iris",
      "openPercent": "4%"
    }
  ]
}

Switching channels

A switching channel is a channel whose functionality depends on the value of another channel in the same mode.

E.g. in a given mode, the first channel could be used to select auto-programs and channel 2 could be either "Microphone Sensitivity" (if channel 1 is set to Sound control) or "Program Speed" (if channel 1 is set to anything else).

To define switching channels, add a switchChannels object to all capabilities of the dependency channel (the "Auto-Programs" channel in the example above). This object defines which switching channel alias is set to which available channel key if this capability is active. The switching channel alias is then used in the mode just like a regular channel. Note that a channel which defines switching channels needs an explicit defaultValue to make sure that the switching channel default is also well-defined.

See the Futurelight PRO Slim PAR-7 HCL fixture for a simple application example.

Matrices

Some fixtures have multiple light beams: A horizontal bar of LEDs, a pixel head with a grid of lamps, a fixture consisting of inner and outer rings of LEDs that can be controlled separately, etc. See the Eurolite LED KLS 801 and the Pixel Bar and Matrix categories for example fixtures.

Matrix structure

The information how these pixels are arranged is stored in the fixture's matrix object: Either by using the x × y × z syntax from pixelCount (e.g. [5, 5, 1] for a 5×5 matrix) or by naming each individual pixel in pixelKeys, e.g.:

"matrix": {
  "pixelKeys": [
    [
      [ null,  "Top",     null  ],
      ["Left", "Center", "Right"],
      [ null,  "Bottom",  null  ]
    ]
  ]
}

null refers to a "hole", i.e. there's no light beam, which allows for non-cubic frames. The above example represents 5 heads arranged like a "+".

Pixels can also be grouped if a fixture allows control in different fine grades, like fourths or halves of a light bar. There are three ways to define a pixel group:

  • The keyword all indicates that all pixel keys should belong to this group. This can be useful for channels like "Red Master".
  • An array of pixel keys exactly describes which pixels belong to this group.
  • An object with x, y, z or name constraints. All pixels that fulfill all constraints belong to this group. XYZ constraints are <=5, =5, >=5, 3n (divisible by 3), 3n+1 (divisible by 3 with remainder 1), even (≙ 2n) and odd (≙ 2n+1). Name constraints are regular expressions.
"matrix": {
  "pixelCount": [12, 1, 1],
  "pixelGroups": {
    "Master": "all",
    "1/3": { "x": ["<=4"] },
    "2/3": { "x": [">=5", "<=8"] },
    "3/3": { "x": [">=9"] },
    "Outer Thirds": ["1", "2", "3", "4", "9", "10", "11", "12"]
  }
}

See the TMB Solaris Flare for a rather complex example of pixel group constraints.

Pixel groups can also be used to better describe the pixel structure, for example to define circular rings consisting of virtual pixels, even if these pixels don't physically exist and only the whole rings can be controlled.

"matrix": {
  "pixelKeys": [
    [
      [null,  null,  "O1",  "O2",  null,  null],
      [null,  "O3",  "M1",  "M2",  "O4",  null],
      ["O5",  "M3",  "I1",  "I2",  "M4",  "O6"],
      ["O7",  "M5",  "I3",  "I4",  "M6",  "O8"],
      [null,  "O9",  "M7",  "M8",  "O10", null],
      [null,  null,  "O11", "O12", null,  null]
    ]
  ],
  "pixelGroups": {
    "Inner ring": { "name": ["^I[1-4]$"] },
    "Middle ring": { "name": ["^M[1-8]$"] },
    "Outer ring":  { "name": ["^O\\d+$"] }
  }
}

Template channels

To reuse similar channels for each pixel or pixel group (like "Red 1", Red 2", ...), add template channels: They are specified very similar to normal available channels, except that each template channel key / alias / name must contain the $pixelKey variable:

"templateChannels": {
  "Red $pixelKey": {
    "fineChannelAliases": ["Red $pixelKey fine"],
    "capability": {
      "type": "ColorIntensity",
      "color": "Red"
    }
  }
}

Template channels can also introduce fine and switching channels. Specific resolved matrix channels can be overridden by available channels (e.g. if "Speed 1" has different capabilities than "Speed 2" until "Speed 25"). See the cameo Hydrabeam 300 RGBW that uses these features.

Then, either use the resolved channel keys directly in a mode's channel list, or use a matrix channel insert block that repeats a list of template channels for a list of pixels:

{
  "name": "14-channel",
  "shortName": "14ch",
  "channels": [
    "Master Dimmer",
    "Strobe",
    {
      "insert": "matrixChannels", // static value for matrix channels
      "repeatFor": "eachPixelXYZ", // see below
      "channelOrder": "perPixel", // or "perChannel"
      "templateChannels": [
        "Red $pixelKey",
        "Green $pixelKey",
        "Blue $pixelKey"
      ]
    }
  ]
}

repeatFor defines in which order and for which pixels / pixel groups the template channels shall be repeated. Possible values are:

  • An array of pixel (group) keys in the proper order
  • "eachPixelABC": Gets computed into an alphanumerically sorted list of all pixelKeys
  • "eachPixelXYZ" / "eachPixelZYX" / ...: Gets computed into a list of all pixelKeys, sorted by position, depending on the used X/Y/Z combination.
    • For example, XYZ orders the pixels like reading a book (latin script): First left-to-right (X, letter by letter), then top-to-bottom (Y, line by line), then front-to-back (Z, page by page). For a 3-dimensional 2×2×2 matrix, this results in ["(1, 1, 1)", "(2, 1, 1)", "(1, 2, 1)", "(2, 2, 1)", "(1, 1, 2)", "(2, 1, 2)", "(1, 2, 2)", "(2, 2, 2)]".
  • "eachPixelGroup": Gets computed into an array of all pixel group keys, ordered by appearance in the JSON file.
    • For the above matrix structure example, this results in ["Inner ring", "Middle ring", "Outer ring"].

Wheels

Fixtures (usually moving heads) can have internal wheels, where you can select the active slot via DMX. In our fixture format, wheels are defined in the fixture's wheels object, where the key defines the wheel's name.

The slots in a wheel have types, similar to capability types. Depending on the type, different properties can be set on the slot.

  • Open / Closed
  • Color
    • name (string)
    • colors (array of hex strings)
    • colorTemperature (Entity ColorTemperature)
  • Gobo
    • resource (resource reference string, see below)
    • name (string)
  • Prism
    • name (string)
    • facets (integer)
  • Iris
    • openPercent (Entity IrisPercent)
  • Frost
    • frostIntensity (Entity Percent)
  • AnimationGoboStart
    • name (string)
  • AnimationGoboEnd

Animation Gobo slots are wider than normal gobos (sometimes they fill the whole wheel); rotating the wheel over these slots creates an animation. To model the wider slots, an AnimationGoboEnd slot must be used directly after an AnimationGoboStart slot.

Gobo resources

Gobos are referenced with a resource reference in the form gobos/<gobo key>.

Gobo resources are stored in the resources/gobos/ directory. Each one consists of a JSON file (<gobo key>.json) describing the gobo (with name, keywords, and a source where the gobo image was extracted from) and the gobo image itself (<gobo key>.svg or <gobo key>.png).

In the resources/gobos/aliases/ directory, sets of aliases can be defined as separate JSON files in which aliases are mapped to gobo keys. This is useful for plugins (e.g. the QLC+ import plugin knows which OFL gobo key to use when QLC+ gobo Others/0001.svg is referenced in a fixture). It also enables referencing gobos in fixture files with an alias like gobos/aliases/<alias file>/<alias key> (e.g. a Robe fixture could reference gobos/aliases/robe/15020246-rafia) to make validating the gobo information easier with a manual where product numbers are specified.

Using wheels in capabilities

In wheel-related capabilities, the wheel property references the wheel by its name. If the wheel property is not set, the channel name is used as wheel name.

WheelSlot capabilities select a slot from the wheel. If the capability selects the place in between two slots, the slotNumber property can be set to a fractional value (or be proportional as slotNumberStart / slotNumberEnd). See also footnote slotNumber in the capability types documentation.

WheelShake capabilities set the shaking (i.e. continuously rotating back and forth) of the whole wheel around the currently selected slot. A slot can also be activated directly by setting the slotNumber property like in WheelSlot capabilities.
By setting the property isShaking to slot, one can specify that only the currently selected slot rotates back and forth around its center (sometimes called Gobo bounce effect) instead of the whole wheel.

WheelSlotRotation capabilities control the rotation of the currently selected slot (i.e. Gobo, Prism, etc.). A slot can also be activated directly by setting the slotNumber property like in WheelSlot capabilities.

WheelRotation capabilities rotate the whole wheel, i.e. over all slots.

RDM (Remote Device Management) data

We link to Open Lighting's RDM database if possible. Thus, we need to specify the RDM manufacturer ID per manufacturer and the RDM model ID per fixture. Additionally, each mode is mapped to the respective RDM personality via the rdmPersonalityIndex property. To ensure compatibility, we also track, for which RDM fixture software (firmware) version the mode indices are specified.

If RDM manufacturer and model ID are known, we open the respective fixture page when going to /rdm (handled in ui/pages/rdm.vue).

Fixture redirects

Fixtures may be renamed by their manufacturers. If we would just update the fixture definition, links to its old fixture page would now lead to a 404 Not found error. Instead, we add a fixture redirect JSON file (see its schema) with the old manufacturer / fixture key, pointing to the updated fixture definition. See Minuit Une M-Carré (and its fixture page on OFL) as an example.

Another use case for redirects are fixtures that are sold under different brands, but which are technically the same. We add them to the library only once and let redirects with other names point to it.