# Tippable Overlay Playground llms.txt This file is for external LLMs that generate or edit overlays for Tippable Overlay Playground. Use it as the authoritative JSON authoring guide for the builder page. Current overlay schema version: 3.0.0 Primary editor page: / Machine-readable import target: the editor accepts JSON through the Import button and through the Build using LLMs modal. Production handoff: download the Overlay File and import it into Tippable Dashboard. Do not generate OBS credentials or websocket tickets. ## How to respond to users When a user asks you to build or edit an overlay: 1. Return exactly one JSON object. Do not wrap it in markdown fences. 2. Prefer an Overlay File export envelope: { "version": "3.0.0", "project": { ... Project ... }, "exportedAt": "2026-05-24T00:00:00.000Z" } launchMetadata is optional on import; the editor recalculates launch metadata on export. 3. A raw Project object is also accepted. Use the envelope unless the user explicitly requests the raw project. 4. Preserve ids when editing an existing overlay. Create new unique string ids for new layers/components. UUID-shaped ids are best, but the schema only requires strings. 5. For every layer, set layer.componentId exactly equal to layer.component.id. 6. Do not include comments, trailing commas, NaN, Infinity, undefined, functions, credentials, tokens, websocket URLs, tickets, or private data. 7. If you are unsure about assets, use absolute HTTPS URLs or empty strings. Relative image and audio paths are not suitable for OBS. 8. Validate your own output against the field lists below before returning it. ## Top-level JSON shapes ### Export envelope Field | Type | Required | Used for --- | --- | --- | --- version | string | yes | Import version gate. Must be "3.0.0" for this editor build. project | Project | yes | The actual overlay document loaded into the builder and runtime. exportedAt | string | yes | ISO timestamp. Used for export metadata. launchMetadata | LaunchMetadata | optional on import | Dashboard handoff metadata. The editor can regenerate it. ### Project Field | Type | Required | Used for --- | --- | --- | --- name | string | yes | Display name and downloaded file name. createdAt | string | yes | ISO timestamp for document creation. modifiedAt | string | yes | ISO timestamp for last edit. schemaVersion | string | yes | Must be "3.0.0". scene | Scene | yes | Canvas and layer stack. Default new project: name "Untitled Overlay", schemaVersion "3.0.0", empty layers, transparent 1920x1080 canvas. ### Scene Field | Type | Required | Used for --- | --- | --- | --- canvas | Canvas | yes | Editor and runtime canvas dimensions/background. layers | Layer[] | yes | Top-to-bottom overlay layer stack. Later layers render above earlier layers. ### Canvas Field | Type | Required | Constraints | Used for --- | --- | --- | --- | --- width | number | yes | positive finite | OBS/source width and editor canvas. height | number | yes | positive finite | OBS/source height and editor canvas. background | string | yes | any CSS color string or "transparent" | Canvas backdrop. Use "transparent" for normal OBS overlays. ### Layer Field | Type | Required | Used for --- | --- | --- | --- id | string | yes | Stable layer id. name | string | yes | Layer list display name. componentId | string | yes | Must equal component.id. component | Component | yes | Root component rendered by the layer. ## Shared component shape Every component, including children inside containers, must include these fields. Field | Type | Required | Constraints/defaults | Used for --- | --- | --- | --- | --- id | string | yes | unique across all components | Selection, layers, automations, validation. type | ComponentType | yes | see component types | Discriminates the component schema. name | string | yes | default varies by type | Inspector and scene tree label. position | { x:number, y:number } | yes | finite numbers, default {100,100} | Absolute canvas position, or child position when parent layout is "none". size | { width:number, height:number } | yes | positive finite, default {200,60} | Rendered box size. rotation | number | yes | finite degrees, default 0 | CSS rotation. opacity | number | yes | 0..1, default 1 | CSS opacity. visible | boolean | yes | default true | Rendering and event-driven show/hide. locked | boolean | yes | default false | Editor interaction lock. styles | ComponentStyles | yes | see below | Shared wrapper style. animations | Animation[] | yes | [] allowed | CSS animations and optional sounds. automations | AutomationRule[] | yes | [] allowed | Event/state/variable-driven behavior. ### ComponentStyles Field | Type | Constraints/defaults | Used for --- | --- | --- | --- backgroundColor | string | default "transparent" | Wrapper background. Use CSS color values. borderRadius | number | nonnegative, default 0 | Wrapper border radius in px. borderWidth | number | nonnegative, default 0 | Wrapper border width in px. borderColor | string | default "transparent" | Wrapper border color. shadow | string | default "none" | CSS box-shadow. padding | number | nonnegative, default 0 | Wrapper padding in px. overflow | "visible" | "hidden" | "scroll" | "auto" | default "visible" | Wrapper overflow. ## Component types ComponentType values: text, image, alertContainer, goalBar, counter, timer, shape, container, recentEventList ### text Use for labels, dynamic tip messages, usernames, amounts, headings, and any textual overlay element. Additional fields: Field | Type | Default | Used for --- | --- | --- | --- content | string | "Hello World" | Text rendered when no automation overrides it. fontFamily | string | "Inter, sans-serif" | CSS font-family. fontSize | number | 24 | CSS font-size px. fontWeight | string | "400" | CSS font-weight. textAlign | "left" | "center" | "right" | "left" | Text alignment and flex justification. lineHeight | number | 1.4 | CSS line-height. textColor | string | "#ffffff" | Text color. textShadow | string | "none" | CSS text-shadow. Recommended automation target properties: content, textColor, fontSize, plus common properties. Editor text presets are suggestions, not schema limits: - fontFamily presets in the inspector: "Inter, sans-serif", "monospace", "Georgia, serif", "Arial, sans-serif". - fontWeight presets in the inspector: "300", "400", "600", "700", "900". - External LLMs may still emit other valid CSS font-family/font-weight strings when the user asks for a specific brand or style. ### image Use for logos, avatars, badges, sponsor images, and generated static art. Additional fields: Field | Type | Default | Used for --- | --- | --- | --- src | string | "" | Image URL or data URL. Empty shows an editor placeholder. objectFit | "cover" | "contain" | "fill" | "none" | "cover" | CSS object-fit. alt | string | "" | Image alt text. Recommended automation target properties: src, plus common properties. Use absolute HTTPS URLs for OBS compatibility. ### alertContainer Use for event-driven alerts that show on tip/follow/subscription/raid/custom events and then hide. Additional fields: Field | Type | Default | Used for --- | --- | --- | --- alertType | "tip" | "follow" | "subscription" | "raid" | "custom" | "tip" | Event that should show this alert. showDuration | number | 5000 | Visible time in ms after the alert fires. enterAnimation | AnimationType | "fadeIn" | Animation when the alert appears. enterAnimationDuration | number | 600 | Enter animation duration in ms. exitAnimation | AnimationType | "fadeOut" | Animation when the alert hides. exitAnimationDuration | number | 600 | Exit animation duration in ms. layout | "none" | "flex-row" | "flex-col" | "none" | Child layout mode. justifyContent | "flex-start" | "center" | "flex-end" | "space-between" | "flex-start" | Flex main-axis alignment. alignItems | "flex-start" | "center" | "flex-end" | "stretch" | "stretch" | Flex cross-axis alignment. gap | number | 0 | Flex gap in px. enterSoundUrl | string | "" | Sound URL/data URL when shown. enterSoundVolume | number | 1 | 0..1 volume. exitSoundUrl | string | "" | Sound URL/data URL when hidden. exitSoundVolume | number | 1 | 0..1 volume. children | Component[] | [] | Components rendered inside the alert. When layout is "none", child position/size are absolute inside the alert. When layout is "flex-row" or "flex-col", child position is ignored and size is used as each flex item box. Inspector-supported alert animation option lists: - enterAnimation: none, fadeIn, slideInLeft, slideInRight, slideInTop, slideInBottom, zoomIn, flipInX, flipInY, bounce, scale. - exitAnimation: none, fadeOut, slideOutLeft, slideOutRight, slideOutTop, slideOutBottom, zoomOut, flipOutX, flipOutY. - The import schema accepts the broader AnimationType enum for these fields, but values outside the inspector lists may not be easy for users to edit through the alert inspector. Prefer the inspector lists for alert enter/exit settings. ### goalBar Use for fundraising goals, progress bars, subscriber goals, or any current/target progress display. Additional fields: Field | Type | Default | Used for --- | --- | --- | --- currentValue | number | 0 | Progress numerator. targetValue | number | 100 | Progress denominator. Avoid 0. barColor | string | "#e94560" | Fill color. trackColor | string | "#333333" | Track color. label | string | "Goal Progress" | Center label text. Recommended automation target properties: currentValue, targetValue, label, barColor, plus common properties. ### counter Use for totals, counts, streaks, goals, or numeric state. Additional fields: Field | Type | Default | Used for --- | --- | --- | --- value | number | 0 | Number displayed. prefix | string | "" | Text before formatted value. suffix | string | "" | Text after formatted value. format | string | "#,##0" | Numeric display format. Recommended automation target properties: value, prefix, suffix, plus common properties. ### timer Use for countdowns or elapsed timers. Additional fields: Field | Type | Default | Used for --- | --- | --- | --- durationMs | number | 300000 | Timer duration in ms. Must be nonnegative. direction | "up" | "down" | "down" | Count direction. format | string | "mm:ss" | Timer display format. Recommended automation target properties: durationMs, format, plus common properties. ### shape Use for panels, cards, dividers, backgrounds, circles, and geometric decoration. Additional fields: Field | Type | Default | Used for --- | --- | --- | --- shapeType | "rect" | "circle" | "rounded-rect" | "rect" | Rendered geometry. fillColor | string | "#e94560" | Fill color. strokeColor | string | "transparent" | Stroke color. strokeWidth | number | 0 | Stroke width in px, nonnegative. Recommended automation target properties: fillColor, strokeColor, plus common properties. ### container Use for grouping components or flex layout that is always visible unless visible=false. Additional fields: Field | Type | Default | Used for --- | --- | --- | --- children | Component[] | [] | Components rendered inside the container. layout | "none" | "flex-row" | "flex-col" | "none" | Child layout mode. justifyContent | "flex-start" | "center" | "flex-end" | "space-between" | "flex-start" | Flex main-axis alignment. alignItems | "flex-start" | "center" | "flex-end" | "stretch" | "stretch" | Flex cross-axis alignment. gap | number | 0 | Flex gap in px. When layout is "none", child position/size are absolute inside the container. When layout is flex, child position is ignored. ### recentEventList Use for recent tips/follows/subscriptions/raids or custom event history. Additional fields: Field | Type | Default | Used for --- | --- | --- | --- maxItems | number | 5 | Integer >= 1. Number of events displayed. eventTypes | string[] | ["tip", "follow"] | Event type filter. Empty means all event types. itemTemplate | string | "{username} - {type}" | Template for each event row. Recommended automation target properties: itemTemplate, maxItems, plus common properties. ## Animation model Animation fields: Field | Type | Constraints/defaults | Used for --- | --- | --- | --- id | string | unique string | Editor and runtime identity. trigger | AnimationTrigger | required | When the animation should run. type | AnimationType | required | CSS animation preset. duration | number | nonnegative ms | CSS animation duration. delay | number | nonnegative ms | CSS animation delay. easing | string | CSS easing string | CSS animation timing function. soundUrl | string | "" for no sound | Optional sound on animation. soundVolume | number | 0..1 | Optional sound volume. loop | boolean | optional | Use true for ambient loops. AnimationTrigger values: onShow, onHide, onEvent, onStateChange Runtime note: validation warns that only onShow and onEvent are currently supported triggers. Prefer onShow for component/child entrance animation and onEvent for event-tied animation. AnimationType values: fadeIn, slideIn, slideInLeft, slideInRight, slideInTop, slideInBottom, zoomIn, flipInX, flipInY, fadeOut, slideOut, slideOutLeft, slideOutRight, slideOutTop, slideOutBottom, zoomOut, flipOutX, flipOutY, bounce, shake, pulse, heartbeat, tada, wobble, scale, spin, flash, borderChase, glowBreath, auroraSweep, rayRotate, popIn, none Legacy aliases: slideIn maps to slide-in-right behavior in older documents; slideOut maps to slide-out-left behavior in older documents. Prefer directional names for new JSON. Builder Add Animation default: { "id": "unique-animation-id", "trigger": "onShow", "type": "fadeIn", "duration": 500, "delay": 0, "easing": "ease", "soundUrl": "", "soundVolume": 1 } Use that default shape when the user asks for a normal builder-created animation and has not specified timing, easing, sound, or loop behavior. ## Automation model Automations let events, state, or variables update component properties. AutomationRule is a discriminated union on type. ### mapping rule Use mapping rules to copy a source value into a target property, optionally through a template. { "id": "rule-1", "type": "mapping", "name": "Tip message", "enabled": true, "source": { "kind": "event", "key": "tip", "field": "username", "valueType": "string" }, "target": { "componentId": "message-text", "property": "content" }, "template": { "mode": "template", "value": "{{username}} tipped {{amountFormatted}}!" } } Field | Type | Constraints | Used for --- | --- | --- | --- id | string | unique string | Rule identity. type | "mapping" | literal | Discriminator. name | string | nonempty | Inspector label and validation messages. enabled | boolean | required | Disabled rules are ignored by runtime and some validation. source | AutomationSourceRef | required | Event/state/variable source. target | AutomationTargetRef | required | Component/property to write. template | AutomationTemplate | required | Formatting mode. AutomationTemplate: - mode "none" requires value "" and writes the source field value directly. - mode "template" requires a nonempty value and can include placeholders such as {{value}}, {{username}}, {{amount}}, {{amountFormatted}}, {{message}}, {{supercharge}}. ### logic rule Use logic rules for conditional show/hide, property changes, sounds, and triggering animations. { "id": "rule-2", "type": "logic", "name": "Show large tip badge", "enabled": true, "predicate": { "source": { "kind": "event", "key": "tip", "field": "amount", "valueType": "number" }, "comparator": "gte", "compareValue": "50" }, "action": { "type": "showComponent", "target": { "componentId": "large-tip-badge", "property": "visible" }, "value": "true" } } Field | Type | Constraints | Used for --- | --- | --- | --- id | string | unique string | Rule identity. type | "logic" | literal | Discriminator. name | string | nonempty | Inspector label and validation messages. enabled | boolean | required | Disabled rules are ignored. predicate | { source, comparator, compareValue } | required | Condition. action | { type, target, value } | required | Effect when predicate matches. AutomationSourceRef fields: - kind: "event", "state", or "variable". - key: event type for event sources, state key for state sources, variable key for variable sources. - field: payload field for event sources. - valueType: "string", "number", or "boolean". State source key prefixes allowed by validation: "alert:", "timer:", "counter:". AutomationTargetRef fields: - componentId: id of the component being changed. - property: property path being changed. AutomationActionType values: showComponent, hideComponent, setProperty, addClass, playSound, triggerAnimation Comparator values by source valueType: - string: eq, neq, contains, startsWith, endsWith, empty, notEmpty - number: eq, neq, gt, lt, gte, lte - boolean: eq, neq Allowed target properties: - Common to all component types: visible, opacity, styles.backgroundColor, styles.borderColor, styles.shadow - text: content, textColor, fontSize - image: src - goalBar: currentValue, targetValue, label, barColor - counter: value, prefix, suffix - timer: durationMs, format - shape: fillColor, strokeColor - recentEventList: itemTemplate, maxItems - alertContainer: common properties only - container: common properties only Validation rejects missing source keys/fields, missing target component/property, invalid comparator for value type, invalid template mode/value pairs, invalid target properties, invalid state source prefixes, invalid show/hide action values, and invalid catalog event fields for non-custom event sources. ## Event catalog Event source keys and fields: ### tip Label: Tip Fields: - username: string, default "TestUser" - amount: number, default 5 - amountFormatted: string, default "$5.00" - message: string, default "Great stream!" - supercharge: boolean, default false Use supercharge to differentiate premium/supercharged tips. Good LLM-generated overlays should usually include at least one extra visual or sound effect that is only active when supercharge is true. ### follow Label: Follow Fields: - username: string, default "NewFollower" ### subscription Label: Subscription Fields: - username: string, default "SubUser" - tier: string, default "1" - months: number, default 1 ### raid Label: Raid Fields: - username: string, default "RaidLeader" - viewers: number, default 50 ### goalProgress Label: Goal Progress Fields: - currentValue: number, default 75 - targetValue: number, default 100 ### custom Label: Custom Fields: none predefined. Custom event automations may use custom fields supplied by the sender/simulator. Alert containers can use alertType tip, follow, subscription, raid, or custom. goalProgress exists as an event source for automations and recent event lists, but not as an alertType. ## LaunchMetadata LaunchMetadata is generated by the editor for Dashboard handoff. LLMs normally do not need to include it. If included, fields are: - intendedUse: literal "tippable-dashboard-import" - productionRuntimeOwner: literal "tippable-dashboard" - browserSourceOwner: literal "tippable-dashboard" - editorExportKind: literal "overlay-project" - setupInstructionsVersion: literal 1 - canvas: { width:number, height:number, background:string, transparent:boolean } - requiredEvents: string[] - assetSummary: { embeddedAssetCount:number, externalAssetCount:number, relativeOrUnsupportedAssetCount:number } - createdWithEditor: { name:"tippable-overlay-playground", schemaVersion:string, exportedAt:string } ## Validation and import constraints Hard import/schema constraints: - version and project.schemaVersion must match "3.0.0" when present. - JSON must be valid strict JSON. - All required fields listed above must be present. - Component schemas are discriminated by component.type. - Automation schemas are discriminated by automation.type. - width and height values must be positive finite numbers. - position, rotation, fontSize, lineHeight, currentValue, targetValue, value, durationMs, strokeWidth, showDuration, animation duration/delay, and gap must be finite numbers where applicable. - Nonnegative fields must not be negative: borderRadius, borderWidth, padding, animation duration, animation delay, showDuration, enter/exit animation durations, durationMs, strokeWidth, gap, sound volumes. - opacity and all soundVolume fields must be between 0 and 1. - recentEventList.maxItems must be an integer >= 1. - template.mode "none" requires template.value "". - template.mode "template" requires a nonempty template.value. Validation warnings and infos to avoid: - Empty scenes have an error: include at least one layer/component. - Duplicate component ids are errors. - layer.componentId must equal layer.component.id. - Circular nesting is invalid. - Empty text content warns unless automation will fill it. - Empty image src warns. - Goal bars with targetValue 0 warn. - Duplicate component names warn. - Alert containers with no children warn. - Images without alt text warn. - Unsupported animation triggers warn; prefer onShow/onEvent. - Components fully outside the canvas are informational. - Components with opacity 0 are informational. ## Non-importable editor and runtime state Do not serialize editor-only state into generated overlay JSON. The importable document is only the export envelope or raw Project shape above. Editor-only state includes: - current selection, primary selected component, multi-select state, marquee selection, drag/resize state, snap state, and group-edit focus. - canvas zoom, pan offset, fit-to-view requests, edit/preview mode, and preview viewport mode. - clipboard contents, undo/redo history, autosave status, before-unload state, drawer open state, and modal open state. - simulator selected event type, custom payload editor text, saved simulator templates, replay status, event timeline/log entries, selected log entry, fire-and-keep setting, and runtime debug panels. - validation results, validation badge counts, grouped findings, and selected validation finding. If a user asks for these settings, explain that they are builder UI/session state. Use them as editing instructions for the human, not fields in the JSON. ## Builder workflow functions These are UI functions available to people using the builder; they are not JSON properties: - New/Clear starts a fresh Project. - Import loads an Overlay File envelope or raw Project JSON and replaces the current builder state. - Download Overlay File exports the JSON document for Tippable Dashboard. - Download Static Preview HTML emits a static HTML snapshot for preview/share use only. - Use This Overlay validates and opens the Dashboard handoff flow. - Edit/Preview mode toggles between canvas editing and runtime preview. - Preview viewport mode can preview source/mobile/tablet-like sizes without changing scene.canvas unless the user edits canvas dimensions. - Pan/zoom/fit affect only the editor viewport. - Drag, resize, nudge, marquee select, duplicate, copy/paste, group, ungroup, and double-click group entry are editing operations that mutate component positions, sizes, layers, children, or ids through the Project shape. - Presets and Add Text are builder shortcuts that create normal Project/layer/component JSON. If a temporary tipping-only mode is active, the UI may show only a subset of presets/events even though this document describes the full importable schema. Keyboard shortcut reference for human instructions: - Ctrl/Cmd+C copies selected components. - Ctrl/Cmd+V pastes copied components. - Ctrl/Cmd+D duplicates the selected component. - Ctrl/Cmd+Z and Ctrl/Cmd+Shift+Z undo/redo. - Delete/Backspace deletes selected components. - Shift+click adds/removes from selection. - Drag on canvas marquee-selects. - Arrow keys nudge by 1px; Shift+Arrow nudges by 10px. - Escape deselects or exits group focus. - Ctrl/Cmd+G groups; Ctrl/Cmd+Shift+G ungroups. - Ctrl/Cmd+scroll zooms; middle-click drag or space+drag pans. - ? opens keyboard shortcuts. ## Simulator and runtime testing Simulator events have this runtime shape: { "type": "tip", "payload": { "username": "TestUser", "amount": 5, "amountFormatted": "$5.00", "message": "Great stream!", "supercharge": false }, "timestamp": "2026-05-24T00:00:00.000Z" } Simulator behavior: - Catalog event inputs are coerced by field type: string, number, or boolean. - Custom JSON payload mode must parse to an object, not an array or primitive. - Fire Event migrates the current project if needed, processes the event, and switches to preview mode. - Fire and Keep keeps the alert/runtime state visible for inspection. - Saved simulator templates, replay controls, duplicate-into-builder, clear timeline, and reset runtime state are builder/testing tools. They are not exported in Overlay File JSON. - Runtime state panels show resolved component values, condition results, animation state, timer value, active alert state, and event history for debugging. Do not include these panels or observations as Project fields. ## Validation panel behavior Validation runs automatically after project changes, reports errors/warnings/info, and shows counts in the top bar. Clicking a component-linked finding selects that component in the builder. Validation output is feedback only and must not be serialized into generated JSON. ## Static HTML export vs Overlay File The Overlay File JSON is the canonical Dashboard handoff. Prefer it for real overlays and for LLM-generated output. Static HTML export is a separate preview/share path: - It embeds escaped Overlay File JSON in a script tag and renders a static DOM snapshot. - It renders visible components and shared wrapper styles, including text, image, shape, goalBar, counter, timer, container, alertContainer children, and flex layout. - It does not provide live event transport, Dashboard import, runtime tickets, automations, alert timing, animation playback, sounds, recentEventList runtime rendering, or live timer countdown. - Static goalBar fill is clamped to 0..100%; targetValue 0 renders 0%. - Static timer output renders the timer format string; static counter output renders prefix + raw value + suffix. ## Authoring patterns ### Static text card Use a shape as background and a text component above it. Put the shape layer before the text layer. ### Tip alert Use one alertContainer with alertType "tip", visible false for exported templates, children for background/text/avatar, and mapping automations that write event fields into child text or image components. Common fields are username, amount, amountFormatted, message, and supercharge. Include a supercharge-only effect when possible: for example, a hidden "SUPERCHARGED" badge or glow shape with a logic automation whose predicate is event tip field supercharge eq true and whose action shows the badge or increases opacity. ### Recent tips list Use recentEventList with eventTypes ["tip"] and an itemTemplate such as "{username} tipped {amountFormatted}". ### Progress goal Use goalBar. Use automation mapping or logic to update currentValue and label from goalProgress or tip events. ### Flex layout inside a card Use container or alertContainer with layout "flex-row" or "flex-col". Child position is ignored in flex mode; set each child size and use justifyContent, alignItems, and gap. ## Minimal valid envelope example { "version": "3.0.0", "exportedAt": "2026-05-24T00:00:00.000Z", "project": { "name": "Simple Tip Banner", "createdAt": "2026-05-24T00:00:00.000Z", "modifiedAt": "2026-05-24T00:00:00.000Z", "schemaVersion": "3.0.0", "scene": { "canvas": { "width": 1920, "height": 1080, "background": "transparent" }, "layers": [ { "id": "layer-banner-bg", "name": "Banner Background", "componentId": "shape-banner-bg", "component": { "id": "shape-banner-bg", "type": "shape", "name": "Banner Background", "position": { "x": 660, "y": 860 }, "size": { "width": 600, "height": 96 }, "rotation": 0, "opacity": 0.92, "visible": true, "locked": false, "styles": { "backgroundColor": "transparent", "borderRadius": 0, "borderWidth": 0, "borderColor": "transparent", "shadow": "0 18px 48px rgba(0,0,0,0.35)", "padding": 0, "overflow": "visible" }, "animations": [], "automations": [], "shapeType": "rounded-rect", "fillColor": "#16161d", "strokeColor": "#ffffff", "strokeWidth": 2 } }, { "id": "layer-tip-text", "name": "Tip Message", "componentId": "text-tip-message", "component": { "id": "text-tip-message", "type": "text", "name": "Tip Message", "position": { "x": 700, "y": 884 }, "size": { "width": 520, "height": 48 }, "rotation": 0, "opacity": 1, "visible": true, "locked": false, "styles": { "backgroundColor": "transparent", "borderRadius": 0, "borderWidth": 0, "borderColor": "transparent", "shadow": "none", "padding": 0, "overflow": "visible" }, "animations": [ { "id": "anim-tip-pulse", "trigger": "onShow", "type": "pulse", "duration": 900, "delay": 0, "easing": "ease-out", "soundUrl": "", "soundVolume": 1 } ], "automations": [ { "id": "map-tip-message", "type": "mapping", "name": "Tip message", "enabled": true, "source": { "kind": "event", "key": "tip", "field": "username", "valueType": "string" }, "target": { "componentId": "text-tip-message", "property": "content" }, "template": { "mode": "template", "value": "{{username}} tipped {{amountFormatted}}! {{message}}" } } ], "content": "Waiting for tips...", "fontFamily": "Inter, sans-serif", "fontSize": 28, "fontWeight": "700", "textAlign": "center", "lineHeight": 1.2, "textColor": "#ffffff", "textShadow": "0 2px 12px rgba(0,0,0,0.5)" } } ] } } }