You are viewing an old version of this page. View the current version.

Compare with Current View Page History

Version 1 Next »

Purpose

Canvas displays are the paradigm for pixel art that happens to show live data. Process diagrams, P&IDs, equipment layouts, architectural overviews. Every element has an explicit Left / Top / Width / Height and you compose by placement, layering, and grouping.

Use Canvas when:

  • The display shows equipment in a spatial layout (pipe A connects to pump B connects to tank C)
  • The visual language is P&ID / process flow (operators scan it as a schematic)
  • Custom shapes and line work matter
  • You need the full set of dynamics (RotateDynamic, ScaleDynamic, MoveDragDynamic, SkewDynamic, BargraphDynamic are Canvas-only)

Use Dashboard (load Skill Display Construction — Dashboard instead) when the display is primarily data monitoring, grid-based cards, or there's no spatial relationship to preserve.

Prerequisite: load Skill Display Construction — Basics first. It covers theme-first thinking, write mechanics, the build loop, binding gotchas, and spacing/typography tokens.

Section 1 — Canvas mental model

Think in zones, not elements

The worst Canvas displays are built element-first — you place a Rectangle, then another, then wonder why nothing aligns. The good ones are built zone-first.

  1. Divide the canvas into zones. Rectangular regions for each process section (Intake, Treatment, Distribution) or each info panel (Equipment Detail, Live Metrics, Ontology Identity).
  2. Lay zone background Rectangles first. These are the visual scaffolding — operators read the display by scanning zones, not individual shapes.
  3. Place elements WITHIN zone coordinates. Everything in a zone has its Left/Top relative to the zone's origin.
  4. Connect zones with flow indicators. Arrows, pipe lines, direction markers.

Canvas sizes

Canvas

Width × Height

When

Standard HD

1366 × 728

Default, works everywhere

Wide

1600 × 900

Modern control-room monitors

Full HD

1920 × 1080

Dedicated operator displays

4K scaled

3840 × 2160

Rare — prefer 1920×1080 with StretchFill

Zone math (any canvas size, N zones)

margin   = 20
gap      = 15
titleBar = 60          // top strip for display title + status
bottomPanel = 140      // for trend/alarm/summary
zoneHeight = Height - titleBar - bottomPanel - margin
zoneWidth  = (Width - 2*margin - (N-1)*gap) / N
zone[i].Left  = margin + i * (zoneWidth + gap)
zone[i].Top   = titleBar
zone[i].Width = zoneWidth
zone[i].Height = zoneHeight

For a 1600×900 canvas with 3 zones: each zone is ~515 wide × 640 tall. For 4 zones: ~381 wide. For 2 zones: ~780 wide.

Z-order by Elements array order

Canvas has no z-index property. The order of the Elements array IS the z-order — earlier elements render behind, later elements in front. Always place:

  1. Full-canvas background Rectangle first (if overriding root Background)
  2. Zone background Rectangles next
  3. Zone-internal shapes and symbols
  4. Labels and text (on top of their containing zones)
  5. Interactive overlays (click-zones, hover highlights) last

Section 2 — Shapes (the 7 primitives)

All Canvas-only. All theme-aware (Fill/FillTheme, Stroke/StrokeTheme, StrokeThickness).

Shape

Required

Use when

Rectangle

Panels, status bars, tank bodies, bars, backgrounds. Has RadiusX/RadiusY for rounded corners.

Ellipse

Tank caps (top/bottom), status LEDs, sight glasses, pump bodies. Circle when Width=Height.

Polygon

Points ≥3

Arrows, funnels, hoppers, diamonds. Auto-closes. Set Stretch: "None" to preserve exact point coords.

Polyline

Points ≥2

Open curved lines. Doesn't close. Prefer Gridline for pipes.

Path

Data

Any curve, arc, complex shape. SVG mini-language (M L H V C Q A Z).

Gridline

Points ≥2

Use for pipes and orthogonal connections. Constrained to horizontal/vertical segments. The P&ID convention.

Spline

Points ≥2

Smooth curves through control points (Catmull-Rom). Rare — Path covers most cases.

Pipe segment pattern

Error rendering macro 'code': Invalid value specified for parameter 'com.atlassian.confluence.ext.code.render.InvalidValueException'
{
  "Type": "Gridline",
  "Left": 300, "Top": 200,
  "Points": "0,0 100,0 100,60 200,60",
  "StrokeTheme": "Water",
  "StrokeThickness": 6,
  "StrokeLineJoin": "Round",
  "StrokeLineCap": "Round"
}

Then a direction arrow (Polygon, no stretch):

Error rendering macro 'code': Invalid value specified for parameter 'com.atlassian.confluence.ext.code.render.InvalidValueException'
{
  "Type": "Polygon",
  "Left": 490, "Top": 253,
  "Width": 20, "Height": 14,
  "Points": "0,0 20,7 0,14",
  "Stretch": "None",
  "FillTheme": "Water"
}

Reactor coil overlay (Path)

Zigzag heat-exchange coils over a reactor body:

Error rendering macro 'code': Invalid value specified for parameter 'com.atlassian.confluence.ext.code.render.InvalidValueException'
{
  "Type": "Path",
  "Left": 305, "Top": 220,
  "Width": 130, "Height": 240,
  "Data": "M0,0 Q65,20 130,0 M0,40 Q65,60 130,40 M0,80 Q65,100 130,80",
  "StrokeTheme": "StateRed",
  "StrokeThickness": 2,
  "Fill": "#00000000",
  "FillTheme": ""
}

Note the stroked-but-unfilled pattern: Fill: "#00000000" + FillTheme: "" gives a transparent fill so the stroke shows without a filled shape underneath.

Section 3 — First-class auto-shapes

These are first-class shape primitives that write with just Type + geometry + colors. The platform auto-injects the underlying Path/Polygon geometry on save. Massive productivity win over composing from primitives.

Type

Default geometry

Use for

Cylinder

Vertical cylinder with elliptical caps

Tanks, vessels, drums, silos

Gear

8-tooth gear

Machinery icons, manual/auto toggles

Arrow

Right-pointing arrow

Flow direction, callouts (rotate via RotateDynamic for other directions)

Cloud

Puffy cloud outline

MQTT broker, cloud service, weather

Star

5-pointed star

Favorites, highlights, quality marker

Hexagon

Regular hexagon

Node diagrams, honeycomb layouts

Pentagon

Regular pentagon

Rare — use for ANSI warning signs

Trapezoid

Isosceles trapezoid

Hoppers, funnels, cone-bottom tank sections

Error rendering macro 'code': Invalid value specified for parameter 'com.atlassian.confluence.ext.code.render.InvalidValueException'
{ "Type": "Cylinder", "Left": 300, "Top": 200, "Width": 80, "Height": 180, "FillTheme": "ElementBlue" }

That's an entire vessel. No Points, no Data, no compositing.

Writer normalization — read-back shows expanded form

When you read a display back after writing a Cylinder, you'll see a Path with auto-generated Data. This is expected — the shortcut is a write-time macro. For edits, either add new Cylinders (which normalize the same way) or edit the Path directly.

Known issue — phantom entries (TDEV-1274)

list_elements() also reports Triangle, Octagon, Parallelogram, Hill, Curve, Senoid, Wave, T-Junction under the Control category. Do NOT use these. They're schema phantoms — neither Type: "X" alone nor Type: "X" + SymbolName: "Wizard/X" works. For a triangle, use Polygon with three Points. For a "T-junction" on a pipe, use two Gridlines.

Section 4 — Containers (ShapeGroup, SvgGroup, Group)

Container

Children

Dynamics apply to

Use for

ShapeGroup

Shapes only

ALL children uniformly

"The whole vessel turns alarm red when Running=0"

SvgGroup

Auto-parsed from inline SVG string

ALL children (normalized to ShapeGroup on write)

"I have an SVG, I want dynamics per element"

Group

Any element type

Each child has independent dynamics

"Interactive panel with chart+buttons that moves as a unit"

ShapeGroup — compose equipment with unified state

The killer feature: a FillColorDynamic on the ShapeGroup changes the fill of ALL children at once. Build a vessel from primitives, and the entire vessel can turn red on alarm:

Error rendering macro 'code': Invalid value specified for parameter 'com.atlassian.confluence.ext.code.render.InvalidValueException'
{
  "Type": "ShapeGroup",
  "Left": 300, "Top": 200,
  "Width": 180, "Height": 220,
  "Stretch": "None",
  "Children": [
    { "Type": "Ellipse",   "Left": 40, "Top": 0,   "Width": 100, "Height": 20 },
    { "Type": "Rectangle", "Left": 40, "Top": 10,  "Width": 100, "Height": 180 },
    { "Type": "Ellipse",   "Left": 40, "Top": 180, "Width": 100, "Height": 20 }
  ],
  "FillTheme": "ElementBlue",
  "Dynamics": [
    {
      "Type": "FillColorDynamic",
      "LinkedValue": "@Tag.Reactor/Alarm",
      "ChangeColorItems": [
        { "Type": "ChangeColorItem", "ChangeLimit": 0, "LimitColor": "#FF1E3A8A" },
        { "Type": "ChangeColorItem", "ChangeLimit": 1, "LimitColor": "#FFEF4444" }
      ]
    }
  ]
}

SvgGroup — when you'd rather author in SVG

Any inline SVG string becomes a ShapeGroup with native WPF shapes:

Error rendering macro 'code': Invalid value specified for parameter 'com.atlassian.confluence.ext.code.render.InvalidValueException'
{
  "Type": "SvgGroup",
  "Left": 224, "Top": 240,
  "Width": 180, "Height": 220,
  "SvgContent": "<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 180 220'><ellipse cx='90' cy='14' rx='60' ry='10' fill='#95a5a6'/><rect x='30' y='14' width='120' height='180' fill='#3498db'/><ellipse cx='90' cy='194' rx='60' ry='10' fill='#95a5a6'/></svg>",
  "Name": "ReactorVessel"
}

Supported SVG elements: rect, circle, ellipse, line, path, polyline, polygon, g.
Supported attributes: fill, stroke, stroke-width, transform, style, class, opacity, rx, ry.
Supported transforms: translate(), scale(), rotate(), matrix().
Avoid: gradients, filters, clip-paths, text, embedded images.

Trade-off: SvgContent hex colors are opaque to the theme system. Fine for process-meaning colors (heat red, water blue), wrong for UI chrome. If you need theme-reactive composed equipment, use ShapeGroup directly.

Group — for interactive panels

Use Group when children need INDEPENDENT dynamics:

Error rendering macro 'code': Invalid value specified for parameter 'com.atlassian.confluence.ext.code.render.InvalidValueException'
{
  "Type": "Group",
  "Left": 100, "Top": 100,
  "Width": 400, "Height": 280,
  "Children": [
    { "Type": "Rectangle", "Left": 0, "Top": 0, "Width": 400, "Height": 280, "FillTheme": "PanelBackground" },
    { "Type": "TextBlock", "Left": 16, "Top": 16, "Width": 360, "Height": 24, "LinkedValue": "Reactor Control" },
    { "Type": "Button",    "Left": 16, "Top": 220, "Width": 120, "Height": 40, "LabelLink": "Start",
      "Dynamics": [{ "Type": "ActionDynamic", "MouseLeftButtonDown": { "Type": "DynamicActionInfo", "ActionType": "SetValue", "ObjectLink": "@Tag.Reactor/Running", "ObjectValueLink": 1 }}] }
  ]
}

Section 5 — The equipment cookbook

Recipe 1 — Vessel with jacket

The archetype: a cylindrical vessel with a heating jacket that changes color when the heater is running.

Error rendering macro 'code': Invalid value specified for parameter 'com.atlassian.confluence.ext.code.render.InvalidValueException'
{ "Type": "Ellipse",   "Left": 300, "Top": 180, "Width": 96, "Height": 24, "FillTheme": "ElementGray" },
{ "Type": "Rectangle", "Left": 328, "Top": 150, "Width": 40, "Height": 36, "FillTheme": "ElementGray" },
{ "Type": "Cylinder",  "Left": 276, "Top": 200, "Width": 144, "Height": 300, "FillTheme": "ElementBlue" },
{ "Type": "Rectangle", "Left": 256, "Top": 280, "Width": 22, "Height": 180, "FillTheme": "OffFill",
  "Dynamics": [
    { "Type": "FillColorDynamic", "LinkedValue": "@Tag.Reactor/Heater/Running",
      "ChangeColorItems": [
        { "Type": "ChangeColorItem", "ChangeLimit": 0, "LimitColor": "#FF7F1D1D" },
        { "Type": "ChangeColorItem", "ChangeLimit": 1, "LimitColor": "#FFEF4444" }
      ] }
  ] },
{ "Type": "Rectangle", "Left": 418, "Top": 280, "Width": 22, "Height": 180, "FillTheme": "OffFill",
  "Dynamics": [ /* same FillColorDynamic */ ] }

Elements top to bottom: drive cap (Ellipse), motor housing (Rectangle), vessel body (Cylinder with ElementBlue), left jacket rail (Rectangle with heater-gated FillColorDynamic), right jacket rail (same).

For an impeller shaft: add a thin vertical Rectangle, apply RotateDynamic gated by Running:

Error rendering macro 'code': Invalid value specified for parameter 'com.atlassian.confluence.ext.code.render.InvalidValueException'
{ "Type": "Rectangle", "Left": 344, "Top": 230, "Width": 8, "Height": 240, "FillTheme": "DefaultStroke",
  "Dynamics": [
    { "Type": "RotateDynamic", "LinkedValue": "30", "IsRpm": true, "OnOffLink": "@Tag.Reactor/Agitator/Running" }
  ] }

LinkedValue: "30" and IsRpm: true means "rotate at 30 rpm." OnOffLink gates the rotation — the shaft only spins when Running=1.

Recipe 2 — Centrifugal pump (Wizard symbol with live dynamics)

Error rendering macro 'code': Invalid value specified for parameter 'com.atlassian.confluence.ext.code.render.InvalidValueException'
{
  "Type": "Symbol",
  "SymbolName": "Wizard/PUMP",
  "Left": 500, "Top": 300,
  "Width": 80, "Height": 80,
  "SymbolLabels": [
    { "Type": "SymbolLabel", "Key": "State", "LabelName": "State", "LabelValue": "@Tag.Pump1/Running",  "FieldType": "Expression" },
    { "Type": "SymbolLabel", "Key": "RPM",   "LabelName": "RPM",   "LabelValue": "@Tag.Pump1/Speed",    "FieldType": "Expression" }
  ]
}

The symbol itself knows how to change its fill based on State — no extra dynamics needed.

To add a click-to-open-detail action, add the dynamic directly on the Symbol:

Error rendering macro 'code': Invalid value specified for parameter 'com.atlassian.confluence.ext.code.render.InvalidValueException'
"Dynamics": [
  { "Type": "ActionDynamic",
    "MouseLeftButtonDown": { "Type": "DynamicActionInfo", "ActionType": "OpenDisplay", "ObjectLink": "PumpDetail" } }
]

Recipe 3 — Pipe segment with flow direction

Error rendering macro 'code': Invalid value specified for parameter 'com.atlassian.confluence.ext.code.render.InvalidValueException'
{ "Type": "Gridline", "Left": 200, "Top": 400, "Width": 300, "Height": 60,
  "Points": "0,30 100,30 100,0 200,0 200,60 300,60",
  "StrokeTheme": "Water", "StrokeThickness": 6,
  "StrokeLineJoin": "Round", "StrokeLineCap": "Round" },

{ "Type": "Polygon", "Left": 490, "Top": 53, "Width": 20, "Height": 14,
  "Points": "0,0 20,7 0,14", "Stretch": "None",
  "FillTheme": "Water",
  "Dynamics": [
    { "Type": "VisibilityDynamic", "LinkedValue": "@Tag.Pipe1/FlowRate" }
  ] }

The arrow only appears when FlowRate is non-zero — a simple, strong visual cue.

For multi-colored pipe based on flow threshold:

Error rendering macro 'code': Invalid value specified for parameter 'com.atlassian.confluence.ext.code.render.InvalidValueException'
"Dynamics": [
  { "Type": "LineColorDynamic", "LinkedValue": "@Tag.Pipe1/FlowRate",
    "ChangeColorItems": [
      { "Type": "ChangeColorItem", "ChangeLimit": 0,   "LimitColor": "#FF64748B" },
      { "Type": "ChangeColorItem", "ChangeLimit": 10,  "LimitColor": "#FF38BDF8" },
      { "Type": "ChangeColorItem", "ChangeLimit": 50,  "LimitColor": "#FF0369A1" }
    ] }
]

Recipe 4 — Reactor with heating coils

Uses Recipe 1 (vessel) + Path overlay for coils:

Error rendering macro 'code': Invalid value specified for parameter 'com.atlassian.confluence.ext.code.render.InvalidValueException'
{ /* Recipe 1 elements for vessel body with jacket */ },

{ "Type": "Path", "Left": 305, "Top": 220, "Width": 130, "Height": 240,
  "Data": "M0,0 Q65,20 130,0 M0,40 Q65,60 130,40 M0,80 Q65,100 130,80 M0,120 Q65,140 130,120 M0,160 Q65,180 130,160 M0,200 Q65,220 130,200",
  "StrokeTheme": "StateRed",
  "StrokeThickness": 2,
  "Fill": "#00000000", "FillTheme": "",
  "Dynamics": [
    { "Type": "VisibilityDynamic", "LinkedValue": "@Tag.Reactor/Heater/Running" }
  ] }

The coils are only visible when the heater is active — a subtle but unmistakable visual cue for operators.

Section 6 — Dynamics reference

Call list_dynamics() for the full list. Here are the 14 types grouped by what they do:

Action category

Dynamic

What it does

Use for

ActionDynamic

Run an action on mouse event

Navigation, tag writes, scripts, toggles

CodeBehindDynamic

Run code on display lifecycle events

Init, cleanup, periodic updates

HyperlinkDynamic

Open external URL on click

Documentation links, external dashboards

Color category

Dynamic

What it does

Use for

FillColorDynamic

Change element Fill based on thresholds

Status indicators, process meaning

LineColorDynamic

Change element Stroke based on thresholds

Pipe color-by-flow, boundary-alarm borders

TextColorDynamic

Change text Foreground based on thresholds

Alert text, highlighted values

Animation category (Canvas-only)

Dynamic

What it does

Use for

RotateDynamic

Rotate element by angle or rpm

Pointers, impeller shafts, motors, compass needles

ScaleDynamic

Scale element by tag value

Growth/shrink animations, level indicators

MoveDragDynamic

Move element by tag value OR let user drag

Sliding valves, operator drag-to-set

SkewDynamic

Skew element

Perspective effects, rare

Data category (Canvas-only)

Dynamic

What it does

Use for

BargraphDynamic

Fill a Rectangle proportionally based on value

Tank level fill, progress fills, power meter strips

Visibility, Security, Feedback

Dynamic

What it does

Use for

VisibilityDynamic

Show/hide based on expression

Conditional panels, state-dependent overlays, coils-only-when-heating

SecurityDynamic

Hide/disable based on user permission

Admin-only controls, role-based HMI

ShineDynamic

Mouse-over highlight / glow effect

Hover feedback on clickable shapes

Copy-paste patterns

status_indicator (shape that changes color on running/stopped):

Error rendering macro 'code': Invalid value specified for parameter 'com.atlassian.confluence.ext.code.render.InvalidValueException'
{
  "Type": "Ellipse",
  "Left": 100, "Top": 100, "Width": 24, "Height": 24,
  "Dynamics": [
    { "Type": "FillColorDynamic", "LinkedValue": "@Tag.Equipment/Running",
      "ChangeColorItems": [
        { "Type": "ChangeColorItem", "ChangeLimit": 0, "LimitColor": "#FF808080" },
        { "Type": "ChangeColorItem", "ChangeLimit": 1, "LimitColor": "#FF34D399" }
      ] }
  ]
}

toggle_button (click toggles a boolean, color reflects state):

Error rendering macro 'code': Invalid value specified for parameter 'com.atlassian.confluence.ext.code.render.InvalidValueException'
{
  "Type": "Rectangle",
  "Left": 100, "Top": 200, "Width": 120, "Height": 40,
  "Dynamics": [
    { "Type": "ActionDynamic",
      "MouseLeftButtonDown": { "Type": "DynamicActionInfo", "ActionType": "ToggleValue", "ObjectLink": "@Tag.Motor/Start" } },
    { "Type": "FillColorDynamic", "LinkedValue": "@Tag.Motor/Start",
      "ChangeColorItems": [
        { "Type": "ChangeColorItem", "ChangeLimit": 0, "LimitColor": "#FFEF4444" },
        { "Type": "ChangeColorItem", "ChangeLimit": 1, "LimitColor": "#FF34D399" }
      ] },
    { "Type": "ShineDynamic" }
  ]
}

animated_motor (continuous rotation gated by boolean):

Error rendering macro 'code': Invalid value specified for parameter 'com.atlassian.confluence.ext.code.render.InvalidValueException'
{
  "Type": "Symbol",
  "SymbolName": "Wizard/MOTOR",
  "Left": 400, "Top": 300, "Width": 80, "Height": 80,
  "Dynamics": [
    { "Type": "RotateDynamic", "LinkedValue": "30", "IsRpm": true, "OnOffLink": "@Tag.Motor/Running" }
  ]
}

level_bar (tank-fill effect):

Error rendering macro 'code': Invalid value specified for parameter 'com.atlassian.confluence.ext.code.render.InvalidValueException'
{
  "Type": "Rectangle",
  "Left": 200, "Top": 200, "Width": 120, "Height": 240,
  "Dynamics": [
    { "Type": "BargraphDynamic", "LinkedValue": "@Tag.Tank/Level",
      "MinValueLink": "0", "MaxValueLink": "100",
      "BarColor": "#FF38BDF8",
      "Orientation": "VerticalUp" }
  ]
}

ActionDynamic action types

ActionType

Extra fields

What it does

OpenDisplay

ObjectLink: "DisplayName"

Navigate to another display

ToggleValue

ObjectLink: "@Tag.X"

Flip a boolean tag

SetValue

ObjectLink: "@Tag.X", ObjectValueLink: value

Write a specific value

RunScript

ActionScript: "MethodName"

Run a CodeBehind method

Mouse events beyond MouseLeftButtonDown: MouseRightButtonDown, MouseDoubleClick, MouseEnter, MouseLeave. Each is a top-level key on the ActionDynamic.

Format rules

  • Dynamics go in the Dynamics array. Never as direct properties on the element.
  • ChangeColorItems is a flat array. Not {"Type": "ColorChangeList", "Children": [...]}.
  • An element can have MULTIPLE dynamics of different types in the same Dynamics array.

Page-to-page navigation belongs in the Header display, not on content pages. Content pages only get in-page actions (start/stop, open popup, acknowledge).

Workflow

  1. Build all your content pages first.
  2. Read the Startup layout: get_objects('DisplaysLayouts', names=['Startup'], detail='full').
  3. Read the Header display: get_objects('DisplaysList', names=['Header'], detail='full').
  4. Add navigation buttons right-aligned in the header (100–130 × 30–35, 10px gap).
  5. Write the modified Header display back.

Back-navigation on detail pages

Error rendering macro 'code': Invalid value specified for parameter 'com.atlassian.confluence.ext.code.render.InvalidValueException'
{
  "Type": "TextBlock",
  "Left": 48, "Top": 32, "Width": 400, "Height": 20,
  "LinkedValue": "? Granulation Cell A",
  "ForegroundTheme": "AccentBrush",
  "Dynamics": [
    { "Type": "ActionDynamic",
      "MouseLeftButtonDown": { "Type": "DynamicActionInfo", "ActionType": "OpenDisplay", "ObjectLink": "GranulationCellA" } }
  ]
}

Section 8 — Canvas quirks and write-time normalizations

  • Cylinder / Gear / Arrow / Cloud / Star / Hexagon / Pentagon / Trapezoid become Path or Polygon on disk. Auto-geometry expanded.
  • SvgGroup → ShapeGroup on save. SVG parsed into native WPF shapes.
  • Theme brushes stored with theme: prefix: {"FillTheme": "ElementBlue"}{"Fill": "theme:ElementBlue"}.
  • Stretch: "Fill" default silently dropped on Polygon/Polyline/Path/Spline. If you want Stretch: "None", it IS stored.
  • Background default #FFFAFAFA baked in. Explicitly set Background: "theme:PageBackground".
  • Polygon without Points silently skipped. Always include Points.

Section 9 — Canvas checklist

  • ? Background set explicitly (not #FFFAFAFA default)
  • ? Zones calculated to fill the full canvas width and height
  • ? Every zone has a background Rectangle with FillTheme: "PanelBackground" — FIRST in Elements
  • ? Symbols ≥ 60×60 (Wizard), ≥ 80×80 recommended on process overview displays
  • ? Library symbols scaled proportionally — maintain aspect ratio
  • ? No equipment symbols overlap unless intentionally layered
  • ? Zone titles FontSize ≥ 14, value text FontSize ≥ 12
  • ? Value and Unit in the SAME TextBlock with composite LinkedValue
  • ? No element extends beyond the display's Width/Height
  • ? Page navigation is in the Header, not on content pages
  • ? All dynamics inside Dynamics array (never as direct properties)
  • ? ChangeColorItems is a flat array (no ColorChangeList wrapper)
  • ? No use of @Label. in element bindings (only @Tag.)
  • ? No binding to UDT-inherited members (TDEV-1272 workaround: direct members only)
  • ? No binding to tag system columns like .SourceIri (TDEV-1273 workaround: literal text)
  • ? No use of phantom types: Triangle, Octagon, Parallelogram, Hill, Curve, Senoid, Wave, T-Junction (TDEV-1274)
  • ? get_state after write shows errorList empty

Section 10 — Quick reference

The 10 element types you'll actually use on most Canvas displays

Rectangle         - backgrounds, bars, pipes (when rectangular)
Ellipse           - caps, LEDs, pump bodies
Polygon           - arrows, funnels, custom closed shapes
Gridline          - pipes (always prefer over Polyline)
Path              - curves, coils, complex shapes
Cylinder          - vessels, tanks (first-class shortcut)
TextBlock         - all text (labels, values, composite)
Symbol            - Wizard/Library/Solution symbols
ShapeGroup        - composed equipment with unified dynamics
RadialGauge       - temperature, pressure, any circular gauge

Tool-call recipes

# Before first use of an element
list_elements('RadialGauge')

# Before first use of a dynamic
list_dynamics('FillColorDynamic')

# Pattern search in library
list_elements('Library/HMI/Pumps')

# Wizard catalog (always 5 symbols)
list_elements('Wizard')

# Theme brushes
list_elements('ThemeColors')
  • No labels