...
The choice isn't about aesthetics — it's about the question the operator is answering when they open the page.
| Operator question | Canvas | Dashboard |
|---|---|---|
| "Where in the plant is this happening?" |
| x | |
| "Is flow going through path A or path B?" |
| x | |
| "What's the state of equipment X right now?" |
| x (if on the flow) |
| x (if ungrouped KPI) | |
| "How is KPI X trending?" | x (possible) |
| x |
| "Which area has the most alarms?" |
| x (possible) | x |
| "Is the plant running within normal bounds today?" |
| x (possible) | x |
| "I need to click on a valve / pump / tank." |
| x (better here) | x (possible) |
| "I need a one-glance shift summary." |
| x | x |
Rule of thumb: if removing the equipment layout and putting the same data in a grid of tiles would lose meaning, it's a Canvas. If the layout is indifferent to plant geometry, it's a Dashboard. Most plants need both — a Canvas per process area, and a Dashboard for the plant as a whole.
...
| 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 |
...
Call list_elements('Shapes') for the authoritative shape catalog in the current release. Common 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. |
json { "Type": "Gridline", "Left": 300, "Top": 200, "Points": "0,0 100,0 100,60 200,60", "StrokeTheme": "Water", "StrokeThickness": 6, "StrokeLineJoin": "Round", "StrokeLineCap": "Round" }
...
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. Call list_elements('Shapes') for the authoritative list in the current release. Common auto-shapes:
| 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 |
<ac:structured-macro ac:name="code"> <ac:parameter ac:name="language">json</ac:parameter> ac:plain-text-body{ "Type": "Cylinder", "Left": 300, "Top": 200, "Width": 80, "Height": 180, "FillTheme": "ElementBlue" }</ac:plain-text-body> </ac:structured-macro>
...
| 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" |
...
Visual customization — orientation, style variant, pipe-connection direction, foot details — is handled by the user in Designer via the Wizard configuration button (double-click the symbol in the editor). Do not attempt to reproduce these variants via raw geometry or extra elements; the Wizard holds them.
Equipment vocabulary → which Wizard. Map the operator's words to the right SymbolName before reaching for a Library or composing from primitives. Wizard/BLOWER is for fans, blowers, and forced-draft units — anything that moves air. Wizard/MOTOR is for the rotating drive itself when it's the focal element, decoupled from a pump or fan. Wizard/PUMP covers any liquid mover (centrifugal, positive-displacement, dosing). Wizard/TANK is for vessels with level dynamics — storage tanks, drums, day tanks, surge vessels. Wizard/VALVE is the universal flow-control element — manual, motorized, on/off, modulating. When the equipment in the spec doesn't fall cleanly into one of these five categories, fall through to the §4.5 source order (Solution → Library/HPG → Library/HMI → primitives).
Rename and SymbolLabels. Wizards drop with a generic prefix (PUMP1, PUMP2, TANK1) — that's just the placed-instance name on the canvas, not the bound tag. The actual data wiring is in SymbolLabels: each label Key matches a slot the symbol declares internally (State, RPM, Level, Position), and LabelValue is the @Tag.<path> that drives it. The same Wizard/PUMP placed twice with different SymbolLabels payloads becomes two independently-bound pumps. Never bind via direct properties on the Symbol element itself — SymbolLabels is the only path data takes into a Wizard.
<ac:structured-macro ac:name="code"> <ac:parameter ac:name="language">json</ac:parameter> ac:plain-text-body{ "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" } ] }</ac:plain-text-body> </ac:structured-macro>
...
| 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.
...