Skip to main content

Declaring the Surface Layout

Each device you open declares a layout (the surfaceLayout field of registerProps). The layout tells Companion two things: the controls the device has and where they sit on a grid, and the style each control needs drawn — a bitmap of a given size, a background colour, and/or text.

A layout has two parts: a set of named style presets (one called default is required), and a map of controls:

const myLayout = {
stylePresets: {
// Required. Used for any control that doesn't name its own preset.
default: {
bitmap: { w: 72, h: 72, format: 'rgb' },
},
// Optional extra presets, referenced by name from a control below.
encoder: {
text: true,
colors: 'hex',
},
},
controls: {
// Ids are typically "row/column". Companion maps these onto its button grid.
'0/0': { row: 0, column: 0 },
'0/1': { row: 0, column: 1 },
'0/2': { row: 0, column: 2, stylePreset: 'encoder' },
},
}

Style presets

A preset describes what Companion should produce for a control:

  • bitmap: { w, h, format } — request a rendered image of this pixel size. format is one of rgb, rgba, bgr, bgra (default rgb). This is what most button surfaces use.

  • colors: 'hex' | 'rgb' — request a background colour instead of (or alongside) a bitmap, for buttons with a plain RGB backlight.

  • leds: { segments, mode } — request colours for an addressable strip or ring of LEDs attached to the control, such as the ring around a Stream Deck Studio encoder. A gauge on the button drives these. segments is how many individually addressable LEDs there are, and mode is how Companion maps the gauge onto them:

    • 'full-ring' — the LEDs form a complete circle, so the gauge is rendered faithfully (its angles, deadzone and colours are respected 1:1). Segment 0 is at 6 o'clock and indices increase clockwise.
    • 'simple' — any other shape, such as a straight strip. The value is swept across all the segments, with segment 0 as the 0% end.

    Both describe a logical ordering; if your hardware is wired differently, re-map the segments locally. Check supportsLeds on the host capabilities first — when the host doesn't support LEDs, omit leds from your presets and fall back to whatever you'd otherwise draw (e.g. a plain backlight colour).

  • text / textStyle — request button text (and text styling) for text-only displays.

Whatever you request here is what arrives in draw() — see Rendering. Get the bitmap dimensions right: the resolution you declare is the resolution of the images you'll be given.

Controls

Each control has a row and column (zero-based) and an optional stylePreset naming one of your presets. The control id (the map key) should be unique and is typically row/column; it is the controlId you'll see in draw and input calls.

The full schema (including pixel formats and style options) is in the generated reference. For a device that describes several different models, see the Elgato Stream Deck module.