1"use strict";(self.webpackChunkcompanion_website=self.webpackChunkcompanion_website||[]).push([["2715"],{63820(e,s,n){n.r(s),n.d(s,{metadata:()=>r,default:()=>a,frontMatter:()=>l,contentTitle:()=>t,toc:()=>o,assets:()=>c});var r=JSON.parse('{"id":"module-development/connection-basics/graphics-elements","title":"Button Graphics Elements","description":"Reference for the drawing elements used by layered presets and composite elements.","source":"@site/for-developers/module-development/connection-basics/graphics-elements.md","sourceDirName":"module-development/connection-basics","slug":"/module-development/connection-basics/graphics-elements","permalink":"/for-developers/module-development/connection-basics/graphics-elements","draft":false,"unlisted":false,"editUrl":"https://github.com/bitfocus/website/tree/main/for-developers/module-development/connection-basics/graphics-elements.md","tags":[],"version":"current","sidebarPosition":22,"frontMatter":{"title":"Button Graphics Elements","sidebar_label":"Graphics Elements","sidebar_position":22,"description":"Reference for the drawing elements used by layered presets and composite elements."},"sidebar":"developersSidebar","previous":{"title":"Presets (API 2.x)","permalink":"/for-developers/module-development/connection-basics/presets"},"next":{"title":"Composite Elements","permalink":"/for-developers/module-development/connection-basics/composite-elements"}}'),d=n(74848),i=n(28453);let l={title:"Button Graphics Elements",sidebar_label:"Graphics Elements",sidebar_position:22,description:"Reference for the drawing elements used by layered presets and composite elements."},t,c={},o=[{value:"The coordinate model",id:"the-coordinate-model",level:2},{value:"Values and expressions",id:"values-and-expressions",level:2},{value:"Properties common to all elements",id:"properties-common-to-all-elements",level:2},{value:"Element types",id:"element-types",level:2},{value:"Text",id:"text",level:3},{value:"Image",id:"image",level:3},{value:"Driving an image from a variable",id:"driving-an-image-from-a-variable",level:4},{value:"Box",id:"box",level:3},{value:"Line",id:"line",level:3},{value:"Circle",id:"circle",level:3},{value:"Gauge",id:"gauge",level:3},{value:"Group",id:"group",level:3},{value:"Composite",id:"composite",level:3},{value:"Border properties",id:"border-properties",level:2},{value:"The canvas",id:"the-canvas",level:2},{value:"Further Reading",id:"further-reading",level:2}];function h(e){let s={a:"a",admonition:"admonition",code:"code",em:"em",h2:"h2",h3:"h3",h4:"h4",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,i.R)(),...e.components};return(0,d.jsxs)(d.Fragment,{children:[(0,d.jsx)(s.admonition,{type:"info",children:(0,d.jsxs)(s.p,{children:["This is a new feature in ",(0,d.jsx)(s.a,{href:"/for-developers/module-development/api-changes/v2.1",children:"API 2.1"})," (Companion 5.0+), part of the graphics overhaul."]})}),"\n",(0,d.jsxs)(s.p,{children:["Companion 5.0 introduces an element-based drawing system for buttons. Instead of describing a button with a single flat style, you can build it up from a stack of ",(0,d.jsx)(s.strong,{children:"graphics elements"})," \u2014 text, images, boxes, lines, circles, gauges, and groups \u2014 each positioned and styled independently."]}),"\n",(0,d.jsx)(s.p,{children:"These elements are the building blocks for two things:"}),"\n",(0,d.jsxs)(s.ul,{children:["\n",(0,d.jsxs)(s.li,{children:[(0,d.jsx)(s.a,{href:"/for-developers/module-development/connection-basics/presets#layered-button-presets",children:(0,d.jsx)(s.strong,{children:"Layered presets"})})," \u2014 a new preset type that draws its button from a list of elements."]}),"\n",(0,d.jsxs)(s.li,{children:[(0,d.jsx)(s.a,{href:"/for-developers/module-development/connection-basics/composite-elements",children:(0,d.jsx)(s.strong,{children:"Composite elements"})})," \u2014 reusable drawing components your module defines, which can be used in layered presets and added by users to their own buttons."]}),"\n"]}),"\n",(0,d.jsx)(s.p,{children:"This page is the reference for the element types themselves. The two pages above describe how to use them in context."}),"\n",(0,d.jsx)(s.admonition,{type:"tip",children:(0,d.jsxs)(s.p,{children:["You don't have to use any of this. The ",(0,d.jsx)(s.a,{href:"/for-developers/module-development/connection-basics/presets#simple-button-preset-definitions",children:"simple preset"})," style is still fully supported and is the right choice whenever you don't need detailed custom drawing \u2014 it is simpler to write and is required for compatibility with Bitfocus Buttons. Reach for graphics elements only when a button genuinely needs richer graphics than a single style can express."]})}),"\n",(0,d.jsx)(s.h2,{id:"the-coordinate-model",children:"The coordinate model"}),"\n",(0,d.jsx)(s.p,{children:"A few conventions apply across all elements:"}),"\n",(0,d.jsxs)(s.ul,{children:["\n",(0,d.jsxs)(s.li,{children:[(0,d.jsx)(s.strong,{children:"Positions and sizes"})," (",(0,d.jsx)(s.code,{children:"x"}),", ",(0,d.jsx)(s.code,{children:"y"}),", ",(0,d.jsx)(s.code,{children:"width"}),", ",(0,d.jsx)(s.code,{children:"height"}),", and the line endpoints) are expressed as ",(0,d.jsx)(s.strong,{children:"percentages from 0 to 100"})," of the button, not pixels. This keeps your graphics resolution-independent, so they look right regardless of the button's pixel size."]}),"\n",(0,d.jsxs)(s.li,{children:[(0,d.jsx)(s.strong,{children:"Colors"})," are packed RGB numbers, exactly as elsewhere in Companion \u2014 use ",(0,d.jsx)(s.code,{children:"combineRgb(255, 255, 255)"})," or a hex literal like ",(0,d.jsx)(s.code,{children:"0xffffff"}),". Since ",(0,d.jsx)(s.a,{href:"/for-developers/module-development/api-changes/v2.2",children:"API 2.2"}),", a CSS colour string such as ",(0,d.jsx)(s.code,{children:"'#ffffff'"})," or ",(0,d.jsx)(s.code,{children:"'rgb(255, 255, 255)'"})," can be used instead."]}),"\n",(0,d.jsxs)(s.li,{children:[(0,d.jsx)(s.strong,{children:"Rotation"})," and angles are in ",(0,d.jsx)(s.strong,{children:"degrees"})," (0\u2013359)."]}),"\n",(0,d.jsxs)(s.li,{children:[(0,d.jsx)(s.strong,{children:"Opacity"})," is a percentage from 0 to 100."]}),"\n"]}),"\n",(0,d.jsx)(s.h2,{id:"values-and-expressions",children:"Values and expressions"}),"\n",(0,d.jsxs)(s.p,{children:["Almost every property on an element is an ",(0,d.jsx)(s.em,{children:"expression-or-value"}),". There are three ways to write one:"]}),"\n",(0,d.jsx)(s.pre,{children:(0,d.jsx)(s.code,{className:"language-ts",children:"// A bare value \u2014 shorthand for a fixed value\
1n50\n\n// A fixed value (the explicit, wrapped form)\n{ isExpression: false, value: 50 }\n\n// An expression, evaluated live on the button\n{ isExpression: true, value: '$(my-module:level) * 2' }\n"})}),"\n",(0,d.jsxs)(s.p,{children:["A bare value is accepted as a shortcut for ",(0,d.jsx)(s.code,{children:"{ isExpression: false, value: ... }"}),", exactly as with the options on actions and feedbacks. Reach for the wrapped form only when you need an expression, or when you want to be explicit."]}),"\n",(0,d.jsx)(s.p,{children:"This is what lets a layered button react to module variables and local variables \u2014 any property can be driven by an expression, not just the text."}),"\n",(0,d.jsx)(s.pre,{children:(0,d.jsx)(s.code,{className:"language-ts",children:"{\n type: 'text',\n text: { isExpression: true, value: `$(my-module:channel_1_name)` },\n color: { isExpression: false, value: 0xffffff },\n}\n"})}),"\n",(0,d.jsx)(s.h2,{id:"properties-common-to-all-elements",children:"Properties common to all elements"}),"\n",(0,d.jsx)(s.p,{children:"Every element shares this set of optional base properties:"}),"\n",(0,d.jsxs)(s.table,{children:[(0,d.jsx)(s.thead,{children:(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.th,{children:"Property"}),(0,d.jsx)(s.th,{children:"Type"}),(0,d.jsx)(s.th,{children:"Notes"})]})}),(0,d.jsxs)(s.tbody,{children:[(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"id"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"string"})}),(0,d.jsxs)(s.td,{children:["A stable id for the element. Required if a feedback needs to target it for a ",(0,d.jsx)(s.a,{href:"/for-developers/module-development/connection-basics/presets#feedback-style-overrides",children:"style override"}),"."]})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"name"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"string"})}),(0,d.jsx)(s.td,{children:"A friendly name shown in the Companion UI element list."})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"enabled"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"boolean"})}),(0,d.jsxs)(s.td,{children:["When ",(0,d.jsx)(s.code,{children:"false"}),", the element is not drawn. Useful when driven by an expression."]})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"opacity"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"number"})}),(0,d.jsx)(s.td,{children:"0\u2013100. Defaults to fully opaque."})]})]})]}),"\n",(0,d.jsxs)(s.p,{children:["Most elements (everything except ",(0,d.jsx)(s.code,{children:"line"}),") also share a set of ",(0,d.jsx)(s.strong,{children:"bounds"}),", defining where the element is drawn:"]}),"\n",(0,d.jsxs)(s.table,{children:[(0,d.jsx)(s.thead,{children:(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.th,{children:"Property"}),(0,d.jsx)(s.th,{children:"Type"}),(0,d.jsx)(s.th,{children:"Notes"})]})}),(0,d.jsxs)(s.tbody,{children:[(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"x"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"number"})}),(0,d.jsx)(s.td,{children:"0\u2013100, left edge"})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"y"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"number"})}),(0,d.jsx)(s.td,{children:"0\u2013100, top edge"})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"width"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"number"})}),(0,d.jsx)(s.td,{children:"0\u2013100"})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"height"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"number"})}),(0,d.jsx)(s.td,{children:"0\u2013100"})]})]})]}),"\n",(0,d.jsxs)(s.p,{children:["Each of these values is an ",(0,d.jsx)(s.a,{href:"#values-and-expressions",children:"expression-or-value"}),": pass a bare value for a fixed setting, or the wrapped form to drive it from an expression."]}),"\n",(0,d.jsx)(s.h2,{id:"element-types",children:"Element types"}),"\n",(0,d.jsxs)(s.p,{children:["Each element is distinguished by its ",(0,d.jsx)(s.code,{children:"type"})," field."]}),"\n",(0,d.jsx)(s.h3,{id:"text",children:"Text"}),"\n",(0,d.jsx)(s.pre,{children:(0,d.jsx)(s.code,{className:"language-ts",children:"{\n type: 'text',\n id: 'label',\n x: { isExpression: false, value: 0 },\n y: { isExpression: false, value: 0 },\n width: { isExpression: false, value: 100 },\n height: { isExpression: false, value: 100 },\n text: { isExpression: true, value: `$(my-module:channel_name)` },\n fontsize: { isExpression: false, value: 20 }, // 3-200, percentage of element height\n fontsizeAllowShrink: { isExpression: false, value: true },\n font: { isExpression: false, value: 'companion-sans' }, // 'companion-sans' | 'companion-mono'\n weight: { isExpression: false, value: 'bold' }, // 'normal' | 'bold'\n styles: { isExpression: false, value: ['italic'] }, // any of 'italic' | 'underline' | 'strikethrough'\n color: { isExpression: false, value: 0xffffff },\n halign: { isExpression: false, value: 'center' }, // 'left' | 'center' | 'right'\n valign: { isExpression: false, value: 'center' }, // 'top' | 'center' | 'bottom'\n outlineColor: { isExpression: false, value: 0x000000 },\n}\n"})}),"\n",(0,d.jsxs)(s.table,{children:[(0,d.jsx)(s.thead,{children:(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.th,{children:"Property"}),(0,d.jsx)(s.th,{children:"Type"}),(0,d.jsx)(s.th,{children:"Notes"})]})}),(0,d.jsxs)(s.tbody,{children:[(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"text"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"string"})}),(0,d.jsx)(s.td,{children:"The text to draw (required)."})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"fontsize"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"number"})}),(0,d.jsx)(s.td,{children:"3\u2013200, as a percentage of the element height."})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"fontsizeAllowShrink"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"boolean"})}),(0,d.jsxs)(s.td,{children:["Let the text shrink below ",(0,d.jsx)(s.code,{children:"fontsize"})," when too long to fit."]})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"font"})}),(0,d.jsx)(s.td,{children:"font family"}),(0,d.jsxs)(s.td,{children:[(0,d.jsx)(s.code,{children:"'companion-sans'"})," | ",(0,d.jsx)(s.code,{children:"'companion-mono'"})]})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"weight"})}),(0,d.jsx)(s.td,{children:"font weight"}),(0,d.jsxs)(s.td,{children:[(0,d.jsx)(s.code,{children:"'normal'"})," | ",(0,d.jsx)(s.code,{children:"'bold'"})]})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"styles"})}),(0,d.jsx)(s.td,{children:"style[]"}),(0,d.jsxs)(s.td,{children:["Any of ",(0,d.jsx)(s.code,{children:"'italic'"}),", ",(0,d.jsx)(s.code,{children:"'underline'"}),", ",(0,d.jsx)(s.code,{children:"'strikethrough'"}),"."]})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"color"})}),(0,d.jsx)(s.td,{children:"color"}),(0,d.jsx)(s.td,{children:"Text color."})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"halign"})}),(0,d.jsx)(s.td,{children:"alignment"}),(0,d.jsxs)(s.td,{children:[(0,d.jsx)(s.code,{children:"'left'"})," | ",(0,d.jsx)(s.code,{children:"'center'"})," | ",(0,d.jsx)(s.code,{children:"'right'"})]})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"val
1ign"})}),(0,d.jsx)(s.td,{children:"alignment"}),(0,d.jsxs)(s.td,{children:[(0,d.jsx)(s.code,{children:"'top'"})," | ",(0,d.jsx)(s.code,{children:"'center'"})," | ",(0,d.jsx)(s.code,{children:"'bottom'"})]})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"outlineColor"})}),(0,d.jsx)(s.td,{children:"color"}),(0,d.jsx)(s.td,{children:"Optional outline color."})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"rotation"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"number"})}),(0,d.jsx)(s.td,{children:"Degrees 0\u2013359."})]})]})]}),"\n",(0,d.jsx)(s.h3,{id:"image",children:"Image"}),"\n",(0,d.jsx)(s.pre,{children:(0,d.jsx)(s.code,{className:"language-ts",children:"{\n type: 'image',\n base64Image: { isExpression: true, value: `$(my-module:thumbnail_base64)` },\n fillMode: { isExpression: false, value: 'fit' }, // 'crop' | 'fill' | 'fit'\n halign: { isExpression: false, value: 'center' },\n valign: { isExpression: false, value: 'center' },\n}\n"})}),"\n",(0,d.jsxs)(s.table,{children:[(0,d.jsx)(s.thead,{children:(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.th,{children:"Property"}),(0,d.jsx)(s.th,{children:"Type"}),(0,d.jsx)(s.th,{children:"Notes"})]})}),(0,d.jsxs)(s.tbody,{children:[(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"base64Image"})}),(0,d.jsxs)(s.td,{children:[(0,d.jsx)(s.code,{children:"string"})," | ",(0,d.jsx)(s.code,{children:"null"})]}),(0,d.jsxs)(s.td,{children:["A data URI containing a base64-encoded PNG/JPG, e.g. ",(0,d.jsx)(s.code,{children:"data:image/png;base64,\u2026"})," (required)."]})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"fillMode"})}),(0,d.jsx)(s.td,{children:"fill mode"}),(0,d.jsxs)(s.td,{children:[(0,d.jsx)(s.code,{children:"'crop'"})," | ",(0,d.jsx)(s.code,{children:"'fill'"})," | ",(0,d.jsx)(s.code,{children:"'fit'"})]})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"halign"})}),(0,d.jsx)(s.td,{children:"alignment"}),(0,d.jsxs)(s.td,{children:[(0,d.jsx)(s.code,{children:"'left'"})," | ",(0,d.jsx)(s.code,{children:"'center'"})," | ",(0,d.jsx)(s.code,{children:"'right'"})]})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"valign"})}),(0,d.jsx)(s.td,{children:"alignment"}),(0,d.jsxs)(s.td,{children:[(0,d.jsx)(s.code,{children:"'top'"})," | ",(0,d.jsx)(s.code,{children:"'center'"})," | ",(0,d.jsx)(s.code,{children:"'bottom'"})]})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"rotation"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"number"})}),(0,d.jsx)(s.td,{children:"Degrees 0\u2013359."})]})]})]}),"\n",(0,d.jsx)(s.h4,{id:"driving-an-image-from-a-variable",children:"Driving an image from a variable"}),"\n",(0,d.jsxs)(s.p,{children:["The ",(0,d.jsx)(s.code,{children:"base64Image"})," property can be useful as an expression that resolves to an image your module produces at runtime. The pattern has three parts:"]}),"\n",(0,d.jsxs)(s.ol,{children:["\n",(0,d.jsxs)(s.li,{children:[(0,d.jsx)(s.strong,{children:"Encode the image as a data URI."})," Take your PNG/JPG bytes, base64-encode them, and prefix the result so the value is a full data URI like ",(0,d.jsx)(s.code,{children:"data:image/png;base64,iVBORw0KGgo\u2026"}),". A bare base64 string is ",(0,d.jsx)(s.em,{children:"not"})," accepted \u2014 the ",(0,d.jsx)(s.code,{children:"data:"})," prefix is required."]}),"\n",(0,d.jsxs)(s.li,{children:[(0,d.jsx)(s.strong,{children:"Store the string somewhere the user can reference."})," Put it in a ",(0,d.jsx)(s.a,{href:"/for-developers/module-development/connection-basics/variables",children:"variable"})," with ",(0,d.jsx)(s.code,{children:"setVariableValues()"}),", or return it as the result of a ",(0,d.jsx)(s.a,{href:"/for-developers/module-development/connection-basics/feedbacks#value-feedbacks",children:"value feedback"})," (which the user binds to a local variable)."]}),"\n",(0,d.jsxs)(s.li,{children:[(0,d.jsx)(s.strong,{children:"Reference it from the Image element"})," through the ",(0,d.jsx)(s.code,{children:"base64Image"})," expression."]}),"\n"]}),"\n",(0,d.jsx)(s.pre,{children:(0,d.jsx)(s.code,{className:"language-ts",children:"// 1 + 2: the module pushes a data URI into a variable\nconst dataUri = `data:image/png;base64,${pngBuffer.toString('base64')}`\nthis.setVariableValues({ thumbnail_base64: dataUri })\n"})}),"\n",(0,d.jsx)(s.pre,{children:(0,d.jsx)(s.code,{className:"language-ts",children:"// 3: the Image element renders whatever that variable currently holds\n{\n type: 'image',\n base64Image: { isExpression: true, value: `$(my-module:thumbnail_base64)` },\n fillMode: { isExpression: false, value: 'fit' },\n}\n"})}),"\n",(0,d.jsxs)(s.p,{children:["This works with ",(0,d.jsx)(s.strong,{children:"any"})," variable \u2014 a plain module variable, a custom variable, or a local variable populated by a value feedback. There is nothing image-specific about the variable itself; it is just a string that happens to be a data URI. If the variable is empty, ",(0,d.jsx)(s.code,{children:"null"}),", or does not contain a valid image, the element simply draws nothing."]}),"\n",(0,d.jsx)(s.h3,{id:"box",children:"Box"}
1),"\n",(0,d.jsx)(s.p,{children:"A filled and/or stroked rectangle."}),"\n",(0,d.jsx)(s.pre,{children:(0,d.jsx)(s.code,{className:"language-ts",children:"{\n type: 'box',\n x: { isExpression: false, value: 10 },\n y: { isExpression: false, value: 10 },\n width: { isExpression: false, value: 80 },\n height: { isExpression: false, value: 80 },\n color: { isExpression: false, value: 0x222222 }, // fill color\n cornerRadius: { isExpression: false, value: 10 },\n borderWidth: { isExpression: false, value: 2 },\n borderColor: { isExpression: false, value: 0xff0000 },\n}\n"})}),"\n",(0,d.jsxs)(s.table,{children:[(0,d.jsx)(s.thead,{children:(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.th,{children:"Property"}),(0,d.jsx)(s.th,{children:"Type"}),(0,d.jsx)(s.th,{children:"Notes"})]})}),(0,d.jsxs)(s.tbody,{children:[(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"color"})}),(0,d.jsx)(s.td,{children:"color"}),(0,d.jsx)(s.td,{children:"Fill color."})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"rotation"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"number"})}),(0,d.jsx)(s.td,{children:"Degrees 0\u2013359."})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"cornerRadius"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"number"})}),(0,d.jsx)(s.td,{children:"Corner radius as a percentage of the shorter side, 0\u201350. 0 = square."})]})]})]}),"\n",(0,d.jsxs)(s.p,{children:["Plus the shared ",(0,d.jsx)(s.a,{href:"#border-properties",children:"border properties"}),"."]}),"\n",(0,d.jsx)(s.h3,{id:"line",children:"Line"}),"\n",(0,d.jsxs)(s.p,{children:["A line segment between two points. The line is drawn using the ",(0,d.jsx)(s.a,{href:"#border-properties",children:"border properties"})," \u2014 ",(0,d.jsx)(s.code,{children:"borderWidth"})," is its thickness and ",(0,d.jsx)(s.code,{children:"borderColor"})," its color."]}),"\n",(0,d.jsx)(s.pre,{children:(0,d.jsx)(s.code,{className:"language-ts",children:"{\n type: 'line',\n fromX: { isExpression: false, value: 0 },\n fromY: { isExpression: false, value: 0 },\n toX: { isExpression: false, value: 100 },\n toY: { isExpression: false, value: 100 },\n borderWidth: { isExpression: false, value: 3 },\n borderColor: { isExpression: false, value: 0xffffff },\n}\n"})}),"\n",(0,d.jsxs)(s.table,{children:[(0,d.jsx)(s.thead,{children:(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.th,{children:"Property"}),(0,d.jsx)(s.th,{children:"Type"}),(0,d.jsx)(s.th,{children:"Notes"})]})}),(0,d.jsxs)(s.tbody,{children:[(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"fromX"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"number"})}),(0,d.jsx)(s.td,{children:"0\u2013100, start point"})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"fromY"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"number"})}),(0,d.jsx)(s.td,{children:"0\u2013100, start point"})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"toX"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"number"})}),(0,d.jsx)(s.td,{children:"0\u2013100, end point"})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"toY"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"number"})}),(0,d.jsx)(s.td,{children:"0\u2013100, end point"})]})]})]}),"\n",(0,d.jsxs)(s.p,{children:["Note that a line uses its own endpoints rather than the shared ",(0,d.jsx)(s.code,{children:"x"}),"/",(0,d.jsx)(s.code,{children:"y"}),"/",(0,d.jsx)(s.code,{children:"width"}),"/",(0,d.jsx)(s.code,{children:"height"})," bounds."]}),"\n",(0,d.jsx)(s.h3,{id:"circle",children:"Circle"}),"\n",(0,d.jsx)(s.p,{children:"A filled circle, or an arc/pie slice."}),"\n",(0,d.jsx)(s.pre,{children:(0,d.jsx)(s.code,{className:"language-ts",children:"{\n type: 'circle',\n x: { isExpression: false, value: 25 },\n y: { isExpression: false, value: 25 },\n width: { isExpression: false, value: 50 },\n height: { isExpression: false, value: 50 },\n color: { isExpression: false, value: 0x00cc00 },\n startAngle: { isExpression: false, value: 0 },\n endAngle: { isExpression: false, value: 270 },\n drawSlice: { isExpression: false, value: true },\n}\n"})}),"\n",(0,d.jsxs)(s.table,{children:[(0,d.jsx)(s.thead,{children:(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.th,{children:"Property"}),(0,d.jsx)(s.th,{children:"Type"}),(0,d.jsx)(s.th,{children:"Notes"})]})}),(0,d.jsxs)(s.tbody,{children:[(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"color"})}),(0,d.jsx)(s.td,{children:"color"}),(0,d.jsx)(s.td,{children:"Fill color."})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"startAngle"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"number"})}),(0,d.jsx)(s.td,{children:"Degrees 0\u2013359, for drawing an arc."})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"endAngle"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"number"})}),(0,d.jsx)(s.td,{children:"Degrees 0\u2013359, for drawing an arc."})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"drawSlice"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"boolean"})}),(0,d.jsx)(s.td,{children:"When drawing an arc, close it as a pie slice."})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"borderOnlyArc"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"boolean"})}),(0,d.jsx)(s.td,{children:"Only stroke the arc portion of the border."})]})]})]}),"\n",(0,d.jsxs)(s.p,{children:["Plus the shared ",(0,d.jsx)(s.a,{href:"#border-properties",children:"border properties"}),"."]}),"\n",(0,d.jsx)(s.h3,{id:"gauge",children:"Gauge"}),"\n",(0,d.jsx)(s.p,{children:"A value-driven meter \u2014 a horizontal or vertical bar, or a circular ring \u2014 for showing a numeric value (a level, volume, percentage, temperature, and so on) directly on a button, without producing a custom image."}),"\n",(0,d.jsx)(s.pre,{children:(0,d.jsx)(s.code,{className:"language-ts",children:"{\n type: 'gauge',\n x: 10,\n y: 10,\n width: 80,\n height: 80,\n orientation: 'ring', // 'horizontal' | 'vertical' | 'ring'\n min: 0,\n max: 100,\n value: { isExpression: true, value: `$(my-module:level)` },\n ringWidth: 20,\n roundedEnds: true,\n fillEnabled: true,\n multiColour: true,\n stops: [\n { value: 0, color: 0x00ff00, gradient: true },\n { value: 80, color: 0xffff00, gradient: true },\n { value: 95, color: 0xff0000, gradient: false },\n ],\n trackStyle: 'dimmed',\n trackAmount: 20,\n}\n"})}),"\n",(0,d.jsxs)(s.p,{children:["Like every other element, each property below is an ",(0,d.jsx)(s.a,{href:"#values-and-expressions",children:"expression-or-value"})," \u2014 pass a bare value, or the wrapped form to drive it from an expression. (The one exception is ",(0,d.jsx)(s.code,{children:"stops"}),", which is a plain array; the fields ",(0,d.jsx)(s.em,{children:"inside"})," each stop are expression-or-values.) Colors follow the same rules as ",(0,d.jsx)(s.a,{href:"#the-coordinate-model",children:"everywhere else"}),"."]}),"\n",(0,d.jsx)(s.p,{children:(0,d.jsx)(s.strong,{children:"Value:"})}),"\n",(0,d.jsxs)(s.table,{children:[(0,d.jsx)(s.thead,{children:(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.th,{children:"Property"}),(0,d.jsx)(s.th,{children:"Type"}),(0,d.jsx)(s.th,{children:"Notes"})]})}),(0,d.jsxs)(s.tbody,{children:[(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"value"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"number"})}),(0,d.jsxs)(s.td,{children:["The current value, within the ",(0,d.jsx)(s.code,{children:"min"}),"\u2013",(0,d.jsx)(s.code,{children:"max"})," range."]})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"min"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"number"})}),(0,d.jsx)(s.td,{children:"The value mapped to the start of the gauge."})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"max"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"number"})}),(0,d.jsx)(s.td,{children:"The value mapped to the end of the gauge."})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"origin"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"number"})}),(0,d.jsx)(s.td,{children:"The value the fill grows from (defaults to the start)."})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"symmetric"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"boolean"})}),(0,d.jsxs)(s.td,{children:["Grow the fill in both directions from ",(0,d.jsx)(s.code,{children:"origin"}),"."]})]})]})]}),"\n",(0,d.jsx)(s.p,{children:(0,d.jsx)(s.strong,{children:"Appearance:"})}),"\n",(0,d.jsxs)(s.table,{children:[(0,d.jsx)(s.thead,{children:(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.th,{children:"Property"}),(0,d.jsx)(s.th,{children:"Type"}),(0,d.jsx)(s.th,{children:"Notes"})]})}),(0,d.jsxs)(s.tbody,{children:[(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"orientation"})}),(0,d.jsx)(s.td,{children:"orientation"}),(0,d.jsxs)(s.td,{children:[(0,d.jsx)(s.code,{children:"'horizontal'"})," | ",(0,d.jsx)(s.code,{children:"'vertical'"})," | ",(0,d.jsx)(s.code,{children:"'ring'"})]})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"reverse"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"boolean"})}),(0,d.jsx)(s.td,{children:"Fill from the opposite end."})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"rotation"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"number"})}),(0,d.jsx)(s.td,{children:"Degrees 0\u2013359."})]})]})]}),"\n",(0,d.jsx)(s.p,{children:(0,d.jsxs)(s.strong,{children:["Circular (when ",(0,d.jsx)(s.code,{children:"orientation"})," is ",(0,d.jsx)(s.code,{children:"'ring'"}),"):"]})}),"\n",(0,d.jsxs)(s.table,{children:[(0,d.jsx)(s.thead,{children:(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.th,{children:"Property"}),(0,d.jsx)(s.th,{children:"Type"}),(0,d.jsx)(s.th,{children:"Notes"})]})}),(0,d.jsxs)(s.tbody,{children:[(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"startAngle"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"number"})}),(0,d.jsx)(s.td,{children:"0\u2013360."})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"endAngle"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"number"})}),(0,d.jsx)(s.td,{children:"0\u2013360."})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"ringWidth"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"number"})}),(0,d.jsx)(s.td,{children:"Ring thickness as a percentage, 1\u201350."})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"roundedEnds"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"boolean"})}),(0,d.jsx)(s.td,{children:"Round the ends of the ring."})]})]})]}),"\n",(0,d.jsx)(s.p,{children:(0,d.jsx)(s.strong,{children:"Fill:"})}),"\n",(0,d.jsxs)(s.table,{children:[(0,d.jsx)(s.thead,{children:(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.th,{children:"Property"}),(0,d.jsx)(s.th,{children:"Type"}),(0,d.jsx)(s.th,{children:"Notes"})]})}),(0,d.jsxs)(s.tbody,{children:[(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"fillEnabled"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"boolean"})}),(0,d.jsx)(s.td,{children:"Whether the fill is drawn."})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"multiColour"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"boolean"})}),(0,d.jsx)(s.td,{children:"Show every stop as a gradient, rather than the single colour of the active stop."})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"fillWidth"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"number"})}),(0,d.jsx)(s.td,{children:"Width of the fill relative to the available space, 0\u2013100, centred."})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"stops"})}),(0,d.jsx)(s.td,{children:"stop[]"}),(0,d.jsx)(s.td,{children:"Colour stops \u2014 see below."})]})]})]}),"\n",(0,d.jsxs)(s.p,{children:["Each entry in ",(0,d.jsx)(s.code,{children:"stops"})," is ",(0,d.jsx)(s.code,{children:"{ value, color, gradient }"}),":"]}),"\n",(0,d.jsxs)(s.table,{children:[(0,d.jsx)(s.thead,{children:(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.th,{children:"Property"}),(0,d.jsx)(s.th,{children:"Type"}),(0,d.jsx)(s.th,{children:"Notes"})]})}),(0,d.jsxs)(s.tbody,{children:[(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"value"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"number"})}
1),(0,d.jsxs)(s.td,{children:["The value at which this stop applies, in ",(0,d.jsx)(s.code,{children:"min"}),"\u2013",(0,d.jsx)(s.code,{children:"max"}),"."]})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"color"})}),(0,d.jsx)(s.td,{children:"color"}),(0,d.jsx)(s.td,{children:"The colour at this stop."})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"gradient"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"boolean"})}),(0,d.jsx)(s.td,{children:"Blend towards the next stop rather than stepping."})]})]})]}),"\n",(0,d.jsx)(s.p,{children:(0,d.jsx)(s.strong,{children:"Marker:"})}),"\n",(0,d.jsxs)(s.table,{children:[(0,d.jsx)(s.thead,{children:(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.th,{children:"Property"}),(0,d.jsx)(s.th,{children:"Type"}),(0,d.jsx)(s.th,{children:"Notes"})]})}),(0,d.jsxs)(s.tbody,{children:[(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"markerEnabled"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"boolean"})}),(0,d.jsx)(s.td,{children:"Draw a marker at the current value."})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"markerColor"})}),(0,d.jsx)(s.td,{children:"color"}),(0,d.jsx)(s.td,{children:"Marker colour."})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"markerWidth"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"number"})}),(0,d.jsx)(s.td,{children:"Marker width as a percentage of the fill width, 1\u2013100."})]})]})]}),"\n",(0,d.jsxs)(s.p,{children:[(0,d.jsx)(s.strong,{children:"Track"})," (the unfilled portion):"]}),"\n",(0,d.jsxs)(s.table,{children:[(0,d.jsx)(s.thead,{children:(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.th,{children:"Property"}),(0,d.jsx)(s.th,{children:"Type"}),(0,d.jsx)(s.th,{children:"Notes"})]})}),(0,d.jsxs)(s.tbody,{children:[(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"trackStyle"})}),(0,d.jsx)(s.td,{children:"track style"}),(0,d.jsxs)(s.td,{children:[(0,d.jsx)(s.code,{children:"'transparent'"})," | ",(0,d.jsx)(s.code,{children:"'dimmed'"})]})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"trackAmount"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"number"})}),(0,d.jsx)(s.td,{children:"0\u2013100. 0 is black, 100 matches the active colour."})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"trackWidth"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"number"})}),(0,d.jsx)(s.td,{children:"0\u2013100, centred."})]})]})]}),"\n",(0,d.jsx)(s.admonition,{type:"tip",children:(0,d.jsxs)(s.p,{children:["A gauge is the recommended way to show a value as a bar or ring. Prefer it over producing a bitmap in an ",(0,d.jsx)(s.a,{href:"/for-developers/module-development/connection-basics/feedbacks",children:"advanced feedback"}),", which is harder to write and to maintain."]})}),"\n",(0,d.jsx)(s.h3,{id:"group",children:"Group"}),"\n",(0,d.jsx)(s.p,{children:"A group nests other elements together so you can position, rotate, enable/disable, or fade them as one unit. Groups can be nested inside groups."}),"\n",(0,d.jsx)(s.pre,{children:(0,d.jsx)(s.code,{className:"language-ts",children:"{\n type: 'group',\n x: { isExpression: false, value: 0 },\n y: { isExpression: false, value: 50 },\n width: { isExpression: false, value: 100 },\n height: { isExpression: false, value: 50 },\n rotation: { isExpression: false, value: 0 },\n squareCoords: { isExpression: false, value: false },\n children: [\n { type: 'box', /* ... */ },\n { type: 'text', /* ... */ },\n ],\n}\n"})}),"\n",(0,d.jsxs)(s.table,{children:[(0,d.jsx)(s.thead,{children:(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.th,{children:"Property"}),(0,d.jsx)(s.th,{children:"Type"}),(0,d.jsx)(s.th,{children:"Notes"})]})}),(0,d.jsxs)(s.tbody,{children:[(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"children"})}),(0,d.jsx)(s.td,{children:"element[]"}),(0,d.jsx)(s.td,{children:"The elements inside the group."})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"rotation"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"number"})}),(0,d.jsx)(s.td,{children:"Degrees 0\u2013359."})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"squareCoords"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"boolean"})}),(0,d.jsx)(s.td,{children:"Constrain children to a centred square (the shorter side) coordinate space."})]})]})]}),"\n",(0,d.jsx)(s.h3,{id:"composite",children:"Composite"}),"\n",(0,d.jsxs)(s.p,{children:["References one of the reusable ",(0,d.jsx)(s.a,{href:"/for-developers/module-development/connection-basics/composite-elements",children:"composite elements"})," your module defines. The ",(0,d.jsx)(s.code,{children:"elementId"})," selects the definition, and ",(0,d.jsx)(s.code,{children:"options"})," provides its input values."]}),"\n",(0,d.jsx)(s.pre,{children:(0,d.jsx)(s.code,{className:"language-ts",children:"{\n type: 'composite',\n elementId: 'signal-indicator',\n options: {\n level: { isExpression: true, value: `$(my-module:level)` },\n },\n}\n"})}),"\n",(0,d.jsxs)(s.p,{children:["See ",(0,d.jsx)(s.a,{href:"/for-developers/module-development/connection-basics/composite-elements",children:"Composite Elements"})," for how to define these."]}),"\n",(0,d.jsx)(s.h2,{id:"border-properties",children:"Border properties"}),"\n",(0,d.jsxs)(s.p,{children:["The ",(0,d.jsx)(s.code,{children:"box"}),", ",(0,d.jsx)(s.code,{children:"line"}),", and ",(0,d.jsx)(s.code,{children:"circle"})," elements share a common set of border properties:"]}),"\n",(0,d.jsxs)(s.table,{children:[(0,d.jsx)(s.thead,{children:(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.th,{children:"Property"}),(0,d.jsx)(s.th,{children:"Type"}),(0,d.jsx)(s.th,{children:"Notes"})]})}),(0,d.jsxs)(s.tbody,{children:[(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"borderWidth"})}),(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"number"})}),(0,d.jsxs)(s.td,{children:["Border thickness. Set to ",(0,d.jsx)(s.code,{children:"0"})," to disable."]})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"borderColor"})}),(0,d.jsx)(s.td,{children:"color"}),(0,d.jsx)(s.td,{children:"Border color."})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"borderPosition"})}),(0,d.jsx)(s.td,{children:"position"}),(0,d.jsxs)(s.td,{children:[(0,d.jsx)(s.code,{children:"'inside'"})," | ",(0,d.jsx)(s.code,{children:"'center'"})," | ",(0,d.jsx)(s.code,{children:"'outside'"})]})]})]})]}),"\n",(0,d.jsx)(s.h2,{id:"the-canvas",children:"The canvas"}),"\n",(0,d.jsxs)(s.p,{children:["A layered preset can optionally describe the base ",(0,d.jsx)(s.strong,{children:"canvas"})," the elements are drawn onto, via the ",(0,d.jsx)(s.code,{children:"canvas"})," property. It controls the button's decoration (which replaces the old ",(0,d.jsx)(s.code,{children:"show_topbar"})," toggle) and whether status icons are shown:"]}),"\n",(0,d.jsx)(s.pre,{children:(0,d.jsx)(s.code,{className:"language-ts",children:"canvas: {\n decoration: { isExpression: false, value: 'topbar' },\n showStatusIcons: { isExpression: false, value: 'default' },\n}\n"})}),"\n",(0,d.jsxs)(s.p,{children:[(0,d.jsx)(s.code,{children:"decoration"})," is a ",(0,d.jsx)(s.a,{href:"https://bitfocus.github.io/companion-module-base/enums/ButtonGraphicsDecorationType.html",children:(0,d.jsx)(s.code,{children:"ButtonGraphicsDecorationType"})})," and can be one of:"]}),"\n",(0,d.jsxs)(s.table,{children:[(0,d.jsx)(s.thead,{children:(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.th,{children:"Value"}),(0,d.jsx)(s.th,{children:"Meaning"})]})}),(0,d.jsxs)(s.tbody,{children:[(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"'default'"})}),(0,d.jsx)(s.td,{children:"Follow the user's global default."})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"'topbar'"})}),(0,d.jsx)(s.td,{children:"Show the top bar."})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"'border'"})}),(0,d.jsx)(s.td,{children:"Show a border."})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"'none'"})}),(0,d.jsx)(s.td,{children:"No decoration."})]})]})]}),"\n",(0,d.jsxs)(s.p,{children:[(0,d.jsx)(s.code,{children:"showStatusIcons"})," is a ",(0,d.jsx)(s.a,{href:"https://bitfocus.github.io/companion-module-base/enums/ButtonGraphicsShowStatusIcons.html",children:(0,d.jsx)(s.code,{children:"ButtonGraphicsShowStatusIcons"})})," controlling the status icons drawn in the top-right corner of the button:"]}),"\n",(0,d.jsxs)(s.table,{children:[(0,d.jsx)(s.thead,{children:(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.th,{children:"Value"}),(0,d.jsx)(s.th,{children:"Meaning"})]})}),(0,d.jsxs)(s.tbody,{children:[(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"'default'"})}),(0,d.jsx)(s.td,{children:"Follow the user's global default."})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"'all'"})}),(0,d.jsx)(s.td,{children:"Show all status icons."})]}),(0,d.jsxs)(s.tr,{children:[(0,d.jsx)(s.td,{children:(0,d.jsx)(s.code,{children:"'none'"})}),(0,d.jsx)(s.td,{children:"Hide status icons."})]})]})]}),"\n",(0,d.jsx)(s.h2,{id:"further-reading",children:"Further Reading"}),"\n",(0,d.jsxs)(s.ul,{children:["\n",(0,d.jsx)(s.li,{children:(0,d.jsx)(s.a,{href:"/for-developers/module-development/connection-basics/presets#layered-button-presets",children:"Layered presets"})}),"\n",(0,d.jsx)(s.li,{children:(0,d.jsx)(s.a,{href:"/for-developers/module-development/connection-basics/composite-elements",children:"Composite Elements"})}),"\n",(0,d.jsx)(s.li,{children:(0,d.jsx)(s.a,{href:"/for-developers/module-development/connection-basics/presets",children:"Presets (API 2.x)"})}),"\n",(0,d.jsx)(s.li,{children:(0,d.jsxs)(s.a,{href:"https://bitfocus.github.io/companion-module-base/types/SomeButtonGraphicsElement.html",children:["Autogenerated docs for ",(0,d.jsx)(s.code,{children:"SomeButtonGraphicsElement"})]})}),"\n",(0,d.jsx)(s.li,{children:(0,d.jsxs)(s.a,{href:"https://bitfocus.github.io/companion-module-base/interfaces/ButtonGraphicsGaugeElement.html",children:["Autogenerated docs for ",(0,d.jsx)(s.code,{children:"ButtonGraphicsGaugeElement"})]})}),"\n",(0,d.jsx)(s.li,{children:(0,d.jsx)(s.a,{href:"/for-developers/module-development/api-changes/v2.1",children:"API 2.1 changes"})}),"\n",(0,d.jsx)(s.li,{children:(0,d.jsx)(s.a,{href:"/for-developers/module-development/api-changes/v2.2",children:"API 2.2 changes"})}),"\n"]})]})}function a(e={}){let{wrapper:s}={...(0,i.R)(),...e.components};return s?(0,d.jsx)(s,{...e,children:(0,d.jsx)(h,{...e})}):h(e)}},28453(e,s,n){n.d(s,{R:()=>l,x:()=>t});var r=n(96540);let d={},i=r.createContext(d);function l(e){let s=r.useContext(i);return r.useMemo(function(){return"function"==typeof e?e(s):{...s,...e}},[s,e])}function t(e){let s;return s=e.disableParentContext?"function"==typeof e.components?e.components(d):e.components||d:l(e.components),r.createElement(i.Provider,{value:s},e.children)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.