Advanced Graphics (Compositions)

Advanced Graphics, internally called ImageComposition, is a powerful system for creating custom display graphics on panel screens. While simple icon or widget feedback covers most use cases, compositions allow you to build complex, layered graphics with dynamic text, conditional visibility, and precise positioning.

When to Use Compositions

Use the Composition data source when you need:

  • Multiple elements on a single display (text + icons + shapes)
  • Dynamic text with IO references showing real-time values
  • Conditional rendering where elements appear/hide based on system state
  • Custom layouts with precise positioning and alignment
  • Status dashboards combining multiple data sources

For simple cases, stick with the standard Icon, Widget, or IOref data sources.

Enabling Composition Mode

To use compositions, set the Graphic Source field to Composition in the Display Graphics feedback handler. This reveals the Composition configuration section.

Screenshot showing the Graphic Source dropdown set to Composition in the Display Graphics feedback configuration
Select "Composition" as the Graphic Source to enable advanced graphics

Composition Types

Each composition has a Type that determines what it renders. The most common is Layers for complex graphics, but you can also use simpler types directly.

Layers

The container type for building complex graphics. A Layers composition holds an array of child compositions that are rendered in order (first in array = bottom layer, last = top).

{
  "Type": "Layers",
  "Layers": [
    { /* bottom layer */ },
    { /* middle layer */ },
    { /* top layer */ }
  ]
}

Graphics

Draw vector shapes and TrueType text. Supports rectangles, ellipses, lines, pixels, and text with advanced styling.

{
  "Type": "Graphics",
  "Graphics": [
    {
      "Type": "Rectangle",
      "ColorCode": "#336699",
      "RoundedCorner": 3
    },
    {
      "Type": "Text",
      "Text": "Camera 1",
      "TextFont": "Small",
      "ColorCode": "WHITE"
    }
  ]
}

Image

Display icons, QR codes, or images from IO references.

MonoText

Pixel-style text using classic SKAARHOJ OLED fonts. Best for simple labels on monochrome or small displays.

MonoRect

Simple filled or outlined rectangles. Useful for title bars or frames.

Widget

Embed VU meters or strength indicators. See Display Widgets for details.


The Box Model (Positioning)

Every composition has a Box that defines its canvas size and position within the parent. Understanding the box model is essential for creating well-positioned graphics.

Diagram showing the Box model with width, height, alignment, and offset properties visualized on a canvas
The Box model controls size, alignment, and offset

Size (Width / Height)

ValueBehavior
0 (default)Use full parent dimension
Positive (e.g., 50)Exact size in pixels
Negative (e.g., -10)Parent size minus this value (creates margins)

Example: Width: -10 on a 128px parent = 118px canvas with 5px margin on each side.

Alignment

Vertical Align: Top, Center (default), Bottom

Horizontal Align: Left, Center (default), Right

Offset

OffsetX and OffsetY add pixel adjustments after alignment. Use for fine-tuning position.

Canvas Rotation

Rotate the entire canvas before rendering:

  • Empty = no rotation
  • CW = 90 degrees clockwise
  • CCW = 90 degrees counter-clockwise
  • 180 = upside down

Fitting (Scaling)

How the composition scales to fit its destination:

  • 1:1 = no scaling (default)
  • Fit = scale to fit inside, preserve aspect ratio
  • Fill = scale to fill, preserve aspect ratio (may crop)
  • Stretch = scale to fill, ignore aspect ratio

Graphics Elements

When using Type: "Graphics", you define an array of graphic elements. Each element has its own type and styling options.

Element Types

TypeDescription
RectangleFilled or outlined box with optional rounded corners
EllipseFilled or outlined circle or oval
LineStraight line between two points
PixelSingle colored pixel
TextTrueType font text with advanced alignment

Colors

Colors can be specified as:

  • Reactor color names: RED, GREEN, BLUE, WHITE, BLACK, AMBER, CYAN, DARKGRAY, etc.
  • HTML hex codes: #336699 or #369
  • IO references: {Device.TallyColor} for dynamic colors

Two color properties are available:

  • ColorCode - Fill color for shapes, text color for text
  • StrokeColorCode - Outline/border color (shapes only)

Available Fonts

Pixel Fonts (crisp at default sizes):

  • Small - 8pt, compact
  • PixelArial, PixelArial-Bold - 8pt
  • PixelType - 16pt, monospace-style
  • m5x7, m3x6 - Retro pixel fonts
  • DogicaPixel, DogicaPixel-Bold - 8pt stylized
  • Unifont - 16pt, excellent Unicode support

TrueType Fonts (smooth, scalable):

  • NotoSans-Regular, NotoSans-Bold, NotoSans-Italic, NotoSans-BoldItalic

Text Alignment

TextHorizontalAlign: Left, Center (default), Right, CenterLeft

CenterLeft centers text if it fits, otherwise left-aligns to prevent cutoff.

TextVerticalAlign: Top, Center (default), Bottom


Dynamic Content

IO References in Text

Embed dynamic values using curly brace syntax:

{
  "Type": "Text",
  "Text": "Source: {Device.Input.Name}"
}

Common system references:

  • {System:ProjectTitle} - Current project name
  • {System:ConfigTitle} - Current configuration name
  • {System:UptimeFormatted} - System uptime
  • {System:IPAddress} - System IP address
  • {System:Layers} - Number of active layers
  • {System:HWCs} - Number of hardware components
  • {System:Devices/1:Name} - Name of device at index 1
  • {Panels:Panel/1/Name} - Name of panel at index 1

Conditional Visibility (ActiveIf)

Show or hide entire layers based on conditions:

{
  "ActiveIf": "System:Devices:Unconnected == 0",
  "Type": "Graphics",
  "Graphics": [
    {
      "Type": "Rectangle",
      "ColorCode": "GREEN"
    },
    {
      "Type": "Text",
      "Text": "All OK",
      "ColorCode": "BLACK"
    }
  ]
}

This layer only renders when all devices are connected. Use standard condition syntax with ==, >, <, &&, || operators.


Case Study: Reactor Activity Configuration

The Blue Pill - Reactor Activity configuration demonstrates advanced composition techniques. It displays a real-time system status dashboard on the Blue Pill's OLED display.

Photo of a Blue Pill device showing the Reactor Activity display with project info, panels status, devices status, and IP address
The Reactor Activity configuration running on a Blue Pill

Display Structure

The configuration divides the display into 5 regions:

RegionContent
TopQuarterReactor logo icon
SecondQuarterProject name, uptime, layer/HWC counts, config title
ThirdQuarterPanel names and connection status
BottomQuarterDevice names and connection status
BottomStripIP address

Key Technique: Layered Status Section

The device status section demonstrates combining multiple layers with conditional visibility:

{
  "Type": "Layers",
  "Layers": [
    {
      "Box": { "Width": 40, "Height": 8, "VerticalAlign": "Top", "HorizontalAlign": "Left" },
      "Type": "Graphics",
      "Graphics": [
        { "Type": "Rectangle", "ColorCode": "#cce3f0", "RoundedCorner": 2 },
        { "Type": "Text", "Text": "Devices", "ColorCode": "BLACK", "TextFont": "Small", "OffsetX": 2 }
      ]
    },
    {
      "Box": { "Width": -45, "HorizontalAlign": "Right" },
      "Type": "Graphics",
      "Graphics": [
        { "Type": "Text", "Text": "{System:Devices/1:Name}", "ColorCode": "WHITE", "TextFont": "Small", "OffsetY": 1 },
        { "Type": "Text", "Text": "{System:Devices/2:Name}", "ColorCode": "WHITE", "TextFont": "Small", "OffsetY": 9 }
      ]
    },
    {
      "ActiveIf": "System:Devices:Warnings == 0 && System:Devices:Unconnected == 0",
      "Box": { "Width": 40, "Height": 9, "VerticalAlign": "Top", "HorizontalAlign": "Left", "OffsetY": 10 },
      "Type": "Graphics",
      "Graphics": [
        { "Type": "Rectangle", "ColorCode": "GREEN", "RoundedCorner": 2 },
        { "Type": "Text", "Text": "{System:Devices:Connected} OK", "ColorCode": "BLACK", "TextFont": "Small" }
      ]
    },
    {
      "ActiveIf": "System:Devices:Unconnected > 0",
      "Box": { "Width": 19, "Height": 9, "VerticalAlign": "Top", "HorizontalAlign": "Left", "OffsetX": 21, "OffsetY": 10 },
      "Type": "Graphics",
      "Graphics": [
        { "Type": "Rectangle", "ColorCode": "RED", "RoundedCorner": 2 },
        { "Type": "Text", "Text": "{System:Devices:Unconnected} !!", "ColorCode": "BLACK", "TextFont": "Small" }
      ]
    }
  ]
}

What this does:

  1. Header layer - Light blue rounded rectangle with "Devices" label (always visible)
  2. Device list layer - Shows device names on the right side
  3. Green OK indicator - Only shows when all devices are healthy
  4. Red error indicator - Only shows when devices are disconnected

The ActiveIf conditions create a dynamic status display that automatically updates based on device health.

Annotated diagram showing the layered structure of the Reactor Activity device status section with labels for header, device list, and conditional status indicators
Layer structure of the device status section

Tips and Best Practices

Layer Ordering

Layers render from first to last in the array, meaning the first layer is at the bottom. Place background elements first, foreground elements last.

Using Negative Dimensions

Negative width/height values create automatic margins:

  • Width: -10 = 5px margin on left and right
  • Height: -4 = 2px margin on top and bottom

This is more maintainable than calculating exact sizes.

Debugging Layouts

Enable ShowBox to draw a red border around any composition layer. This helps visualize boundaries during development:

{
  "ShowBox": true,
  "Type": "Graphics",
  "Graphics": [ ... ]
}

Font Selection

  • Use pixel fonts (Small, PixelArial) for small displays or when crisp rendering is important
  • Use NotoSans fonts when you need scalable, smooth text
  • Unifont is best for international characters

Performance

Compositions are cached and render at a maximum of 25 frames per second. For rapidly changing data, this is usually sufficient. Avoid extremely complex nested structures if you notice performance issues.