146 Widgets

Sentrix Help Center

Everything you need to build powerful apps — widgets, scripting, data integration, and more. Fully searchable reference for all 146 widgets and the complete SMART Script language.

Widget Categories

Key Capabilities

🎨
Visual Builder
Drag widgets from the palette onto a multi-card canvas. Resize, position, and group them visually — no code required to build your layout.
📜
SMART Script
A plain-English scripting language for adding interactivity. Read and set widget properties, call APIs, navigate cards, loop over data, and more.
🔌
No-Code Data Layer
Connect REST APIs to widgets without writing a script. Define Data Sources, create Data Models with dot-notation field mapping, then bind fields to widget properties.
📱
Multi-Device Canvas
Design separate layouts for Desktop, Tablet, and Phone. Each device mode can have its own independent widget arrangement.
🚀
Export Anywhere
Export your app as a self-contained HTML file, a Tauri desktop app scaffold, or a Flutter Dart widget tree.
🐛
Visual Script Debugger
Set breakpoints (click gutter or F9), then Step Over (F10), Step Into (F11), or Step Out (⇧F11). Full call-stack display, watch expressions, and variable inspector in the dedicated Debugger tab.
Interactive State Overrides
Configure per-widget visual changes for hover, active/pressed, focus, and disabled states — no script required. Set up in the Properties panel's Interactive States section.
🤖
AI Assistant
Ask the built-in AI to write SMART Script or build canvas layouts. Supports Claude, Gemini, and local Ollama models.
🔁
Undo / Redo
Every canvas action pushes a snapshot to the undo stack. Name and restore snapshots for safe experimentation. Script editor has its own independent undo history.

Quick Links

📜
SMART Script Quick Reference
Variables, conditions, loops, HTTP requests, functions, timers, and more — all in one place.
⌨️
Keyboard Shortcuts
Canvas, copy/group/paste, zoom, script editor, and debugger shortcuts.
🔌
Data Layer Guide
Connect REST APIs to your widgets using the no-code data binding system.
🚀
Getting Started
Build your first app in minutes — canvas basics, your first script, preview and publish.

Getting Started

Build your first interactive app in a few minutes. No prior experience required.

The Builder Interface

📦
Left Panel
Tabbed panel with Widgets palette, Scripts list, Data Layer, Variables debugger, Help, and Export tools.
🖼️
Canvas
The main drag-and-drop area. Widgets are placed here. Use Card Tabs at the top to switch between pages.
⚙️
Properties Panel
Auto-generated editor for the selected widget's properties and event bindings. Toggle on/off from the top bar.

Your First App — Step by Step

1
Add a Widget

Open the Widgets tab in the left panel. Find a widget (e.g. Button) and drag it onto the canvas. It appears at your drop position.

2
Edit Properties

Click the widget to select it. The right Properties Panel shows all configurable properties — change the label text, colours, size, and font directly.

3
Add a Script

In Properties Panel, scroll to Events and click the script icon next to onClick. The Script Editor opens — write your first script:

show toast "Hello, World!"
4
Preview Your App

Click the ▶ Preview button in the top bar. Your app goes live in an interactive preview. Click your button to see the toast message appear.

5
Add More Cards

Click the + next to the Card Tabs at the top of the canvas to add new pages/screens. Use go to card CardName in scripts to navigate between them.

6
Publish

When ready, click Publish in the top bar. The app appears in the App Library for regular users to launch. Or use Export to download a standalone HTML file.

Essential Script Patterns

Show / Hide Widgets

show widget MyPanel
hide widget LoadingSpinner
show loading                   -- full-screen overlay
hide loading

Read and Set Widget Properties

-- Read the current value of a widget
set variable userName to the text of widget NameField

-- Set a widget property
set the text of widget StatusLabel to "Welcome, " + userName + "!"
set the bgColor of widget MyButton to "#10b981"
set the value of widget VolumeSlider to 75

Variables

set variable count to 0
set variable message to "Hello"
set variable total to variable price * variable quantity

-- Variables persist across card navigations automatically

Navigation

go to card Dashboard
go to card SettingsPage
go back

-- Show/hide a card tab dynamically (role-based navigation)
set card AdminPanel visibility to false
set card AdminPanel visibility to true

-- Open an external URL (same tab or new tab)
open url "https://example.com"
open url "https://docs.example.com" in new tab

-- Print / PDF (single card)
print card as pdf

-- Batch print (multi-record — one page per DB record)
start print batch
-- ... loop updating widgets ...
add current card to batch
-- ... end loop ...
print batch as pdf

Conditions

if the text of widget EmailField is empty then
  show toast "Please enter your email" with background color "#ef4444"
else if the text of widget EmailField contains "@" then
  show toast "Valid email!"
else
  show toast "Enter a real email address" with background color "#f59e0b"
end if

HTTP Requests

-- GET request
get url "https://api.example.com/products"
set variable products to result

-- POST request
set variable payload to "{\"name\":\"" + the text of widget NameField + "\"}"
post payload to url "https://api.example.com/users" as json

-- After any HTTP call, these variables are set:
-- result      → response body
-- httpStatus  → "200", "404", etc.
-- httpError   → error message or "" on success

Tip: Watch variables update in real-time during preview. Switch to the Variables tab in the left panel while preview is running — every variable shows its live value.

Show Toast Notifications

show toast "Saved!"
show toast "Error saving" with background color "#ef4444"
show toast "Info message" with duration 5000 with position "top-right"

Loop Over Data

for each item in myList
  print item
end for

repeat 3 times
  set variable count to count + 1
end repeat

Undo / Redo & Snapshots

Use Ctrl+Z / Ctrl+Shift+Z to undo and redo canvas changes. Click the 📸 button in the top bar to save a named snapshot — restore it any time to jump back to that exact state.

SMART Script Reference

A plain-English scripting language. Attach scripts to widget events, card loads, or run them from other scripts.

Scripts are case-insensitive for keywords. Widget names are case-sensitive. Lines starting with -- are comments.

Variables

set variable myVar to "Hello World"
set variable count to 42
set variable price to 9.99
set variable isActive to true
set variable items to ["apple", "banana", "cherry"]

-- Math
set variable total to variable price * variable quantity
set variable pct to variable correct / variable total * 100

-- String concatenation
set variable greeting to "Hello, " + variable userName + "!"

-- String interpolation (use curly braces)
set variable msg to "Order #{orderId} is ready!"

Reading Widget Properties

-- Text inputs
set variable name to the text of widget NameField

-- Other properties
set variable checked to the checked of widget AgreeBox
set variable rating to the value of widget StarRating1
set variable tags to the tags of widget TagInput1
set variable data to the data of widget MyTable

Setting Widget Properties

set the text of widget MyLabel to "Updated!"
set the bgColor of widget MyCard to "#3b82f6"
set the value of widget MySlider to 75
set the data of widget MyTable to variable rows
set the visible of widget MyPanel to "false"
show widget MyPanel        -- shorthand for visible = true
hide widget MyPanel        -- shorthand for visible = false

Conditions

if variable count is greater than 10 then
  show toast "Count exceeded!"
end if

if the text of widget Input is empty then
  show toast "Required"
else if the text of widget Input contains "@" then
  show toast "Looks like an email"
else
  show toast "Text entered"
end if

-- Boolean conditions
if variable isActive is "true" then ... end if
if variable status is not "error" then ... end if
if variable name contains "Smith" then ... end if
if variable list is not empty then ... end if

-- AND / OR
if variable age is greater than 18 and variable country is "UK" then ... end if
if variable type is "admin" or variable type is "superadmin" then ... end if

Loops

-- Count loop
repeat 5 times
  set variable total to total + 1
end repeat

-- For each loop
for each item in myList
  print item
end for

-- While loop
set variable attempts to 0
repeat while attempts is less than 3
  set variable attempts to attempts + 1
  call webhook "TryConnect"
  if webhookStatus is "200" then
    break
  end if
  wait 1 seconds
end repeat

-- Until loop (inverse of while)
repeat until variable done is "true"
  call webhook "PollStatus"
  set variable done to webhookResponse
  wait 2 seconds
end repeat

-- Loop control
break      -- exit loop immediately
continue   -- skip to next iteration

HTTP Requests

-- GET request
get url "https://api.example.com/data"
set variable data to result
set variable status to httpStatus

-- POST with JSON
set variable payload to "{\"name\":\"Alice\",\"age\":30}"
post payload to url "https://api.example.com/users" as json

-- POST with a variable as body
post variable formData to url "https://api.example.com/submit" as json

-- Custom headers
set header "Authorization" to "Bearer " + variable token
set header "X-Api-Key" to "my-key"
get url "https://api.example.com/protected"
clear headers

-- After any HTTP call:
-- result      → raw response body
-- httpStatus  → "200", "404", etc.
-- httpError   → "" on success, error message on failure

-- Error handling
try
  get url "https://api.example.com/data"
  set the data of widget Table1 to result
on error
  show toast "Failed: {httpError}" with background color "#ef4444"
end try

JSON Handling

-- Read a field from a JSON string
set variable name to json field "name" of result
set variable price to json field "data.product.price" of result
set variable first to json field "items[0].title" of result

-- Build JSON manually
set variable obj to "{\"key\":\"" + variable val + "\"}"

-- Parse JSON array
set variable list to result
for each row in list
  set variable id to json field "id" of row
  print id
end for

Math Functions

round(x) or round of X
Round to nearest integer
floor(x) or floor of X
Round down
ceiling(x) or ceiling of X
Round up
abs(x) or abs of X
Absolute value
min(x,y) or min of X and Y
Smaller of two values
max(x,y) or max of X and Y
Larger of two values
pow(x,n)
x to the power of n
sqrt(x)
Square root
random(min,max) or random between X and Y
Random number in range

String Functions

length(x) or length of X
Character count
uppercase(x) or uppercase of X
Convert to uppercase
lowercase(x) or lowercase of X
Convert to lowercase
trim(x) or trim of X
Remove leading/trailing spaces
replace(x,old,new)
Replace all occurrences of a substring. Supports escape sequences: \n (newline), \r\n (CRLF), \t (tab)
replacepattern(str,pattern,repl)
Regex find-and-replace (all matches, global). Pattern can be "/foo/gi" or plain text. Backreferences: $1, $2
matchpattern(str,pattern)
Returns the first regex match, or "" if none. Use in expressions: set variable d to matchpattern(text, "\d+")
matchall(str,pattern)
Returns a list of all non-overlapping regex matches. Use with for each.
replace pattern P in X with R [into V]
Statement form — replaces all regex matches and stores result in replaceResult (or VResult with optional into).
split(x,delim) or split X by Y
Split string into list
indexof(str,search)
Find position of substring (1-based)
substring(str,start,len)
Extract part of string (1-based)
number(x) / tonumber(x)
Convert to number
text(x) / totext(x)
Convert to string

String Escape Sequences

Use these inside any string literal (double-quoted value) in SMART Script:

\n
Newline — LF (ASCII 10)
\r
Carriage return — CR (ASCII 13)
\r\n
CRLF — Windows line endings and most database memo field output
\t
Tab — useful for parsing TSV data
\\
Literal backslash
\"
Literal double-quote inside a string
-- Strip CRLF line breaks from a database memo field before JSON parsing:
get url "https://yourserver/getClients.esp"
set variable myClients to replace(result, "\r\n", "")
set variable myClients to replace(myClients, "\n", "")
set the clients of widget RouteMap to myClients

-- Split tab-separated values:
set variable cols to split(rowData, "\t")

List / Array Operations

-- Create a list
set variable colors to ["red", "green", "blue"]

-- Add / remove items
add "yellow" to list colors
remove "red" from list colors

-- Read items
set variable first to item 1 of colors
set variable last to item last of colors
set variable count to count of colors

-- Sort and filter
set variable sorted to sort colors by "name" ascending
set variable active to filter myList where "status" equals "active"
set variable top5 to limit myList to 5

-- In-place mutations
sort list myList by "date"
reverse list myList
shuffle list myList

-- Aggregate
set variable total to sum of priceList
set variable avg to avg of scoreList
set variable unique to unique of tagList

-- Pluck and group
set variable names to pluck "name" from userList
set variable grouped to group userList by "department"

-- Multi-condition filter
set variable result to filter orders where "status" equals "open" and "amount" is greater than 100

Date & Time

set variable now to date now           -- current date/time as string
set variable today to date today       -- today's date (YYYY-MM-DD)
set variable ts to timestamp now       -- Unix timestamp in ms

Storage (Persistent Variables)

-- Save a variable to localStorage (persists after page refresh)
save variable myData to storage

-- Load it back
load variable myData from storage

-- Clear a specific key
clear storage myData

Navigation

go to card HomePage
go to card OrderSummary
go back

-- Show/hide a card tab dynamically (role-based navigation)
set card AdminPanel visibility to false
set card AdminPanel visibility to true

-- Open an external URL
open url "https://example.com"
open url "https://example.com" in new tab

Print / PDF

-- Print the current card (opens browser Save as PDF dialog)
print card as pdf

-- Conditional print
if patientName is not empty then
  print card as pdf
end if

Generate PDF (direct download, no dialog)

Use the PDF Generator widget or the generate pdf command to capture the current card as a PDF and download it immediately — no browser print dialog.

-- Download with default filename
generate pdf

-- Download with a custom filename
generate pdf "invoice-" & variable orderId & ".pdf"

-- Check result
if variable pdfStatus is "ok" then
  show toast "PDF saved!"
else
  show toast "Error: " & variable pdfError
end if

Batch Print (multi-record PDF)

Loop through database records and render each as a page in one PDF — for run sheets, meal cards, client summaries, etc.

-- 1. Reset the collector
start print batch

-- 2. Loop through records, updating widgets and snapshotting each
open table "Meals"
go to first record
set variable i to 1
repeat while i <= total
  set the mealName of widget MealTitle to db field "mealName"
  set the value of widget NutritionFacts to db field "nutritionJson"
  add current card to batch
  go to next record
  set variable i to i + 1
end repeat

-- 3. Open one print dialog with all collected pages
print batch as pdf

File Manager

Use the File Manager widget to browse, upload, download, and delete uploaded assets. The refresh files command reloads the file list programmatically.

-- Reload the file list after an external action
refresh files of widget DocLibrary

-- React to file selection (onFileSelect event)
on widget DocLibrary onFileSelect
  set the pdfUrl of widget DocViewer to selectedFileUrl
  set the text of widget FileLabel to selectedFilename
end on

-- React to upload (onFileUpload event)
on widget DocLibrary onFileUpload
  show toast "Uploaded: " & uploadedFilename
  refresh files of widget DocLibrary
end on

Timers

-- Repeating timer
every 5 seconds run script UpdateFeed
every 1 seconds run script TickClock

-- One-shot delay
after 3 seconds run script ShowWelcome
after 0.5 seconds run script AnimateIn

-- Stop all timers
stop timer

Media & Animation

-- Video (Video widget)
play video MyPlayer
pause video MyPlayer

-- Sound (PlaySound widget / audio URL)
play sound "success"
stop sound "success"

-- Lottie Animation (LottieAnimation widget)
play animation widget MyAnim
pause animation widget MyAnim
stop animation widget MyAnim

-- Change animation properties at runtime
set the src of widget MyAnim to "https://assets.lottiefiles.com/lf20_xyz.json"
set the speed of widget MyAnim to 2
set the loop of widget MyAnim to false

-- Audio Player (AudioPlayer widget)
play audio widget MyAudio
pause audio widget MyAudio
stop audio widget MyAudio   -- pause + reset to beginning

-- Set source and volume at runtime
set the src of widget MyAudio to "https://example.com/track.mp3"
set the volume of widget MyAudio to 0.5

-- Read current playback position (seconds — updated during playback)
set variable elapsed to audioCurrentTime

Vibrate / Haptic Feedback

vibrate           -- 100 ms short tick (default)
vibrate 200       -- 200 ms
vibrate 500       -- 500 ms

-- Confirm a saved action
vibrate 150
show toast "Saved!"

-- Alert on error
vibrate 400
set the text of widget ErrorMsg to "Invalid input"

-- Double pulse (two short buzzes)
vibrate 80
wait 0.1 seconds
vibrate 80

Uses the browser Vibration API. Silently ignored on desktop and iOS Safari. Requires HTTPS or localhost.

Share (Web Share API)

-- Share a URL
share url "https://myapp.com"

-- Share URL with title and body text
share url "https://myapp.com/product/123" title "Check this out" text "Found something great!"

-- Share just text (no URL)
share text "I scored " & score & " points — can you beat me?"

-- Share using variables
share url pageUrl title pageTitle text pageDesc

Opens the device's native share sheet (Chrome Android, Safari iOS). All three parts — url, title, text — are optional but at least one should be provided. User dismissal is silently ignored. Requires HTTPS.

Text-to-Speech

-- Basic: speak any text or variable
speak text "Hello, welcome to the app!"
speak text myVariable

-- With optional voice parameters
speak text "Warning: step incomplete." with rate 0.9 with pitch 1.2 with volume 0.8

-- Stop any ongoing speech
stop speaking

-- Read a widget value aloud on button press
on button ReadOut pressed
  speak text the text of widget ResultLabel
end

-- Step instructions at reduced speed
speak text "Step one: connect the cable." with rate 0.8

Uses the browser Web Speech API (SpeechSynthesis). Each speak text cancels any active utterance first. with rate (0.1–10), with pitch (0–2), with volume (0–1) are all optional. Silently ignored if the browser does not support speech synthesis.

Clipboard

-- Copy any value to the clipboard
copy "https://app.example.com/share/4821" to clipboard
copy the text of widget InviteCode to clipboard
copy myVariable to clipboard

-- Paste clipboard text into a variable
set variable pastedText to paste from clipboard
set the text of widget SearchBox to pastedText

-- clipboardStatus is set automatically after every copy / paste
if clipboardStatus is "success" then
  show toast "Copied!" with duration 1500
else
  show toast "Clipboard unavailable" with background color "#ef4444"
end if

Uses the browser Clipboard API (navigator.clipboard). Requires HTTPS or localhost. clipboardStatus is automatically set to "success" or "error" after every copy or paste call.

Theme Switching

-- Switch to any preset theme at runtime
set theme to "Light"
set theme to "Dark Blue"
set theme to "Midnight"

-- Toggle dark / light from a button
if variable appTheme is "light" then
  set theme to "Dark Blue"
  set variable appTheme to "dark"
else
  set theme to "Light"
  set variable appTheme to "light"
end if

-- Drive from a Dropdown widget
set theme to the value of widget ThemePicker

Available theme names: Dark Blue · Dark Cyan · Midnight · Ocean · Forest · Sunset · Rose · Light. The change takes effect immediately. The project's saved theme (App Settings) is restored when preview restarts.

Webhooks

-- Call a named webhook (configured in App Settings → Webhooks)
call webhook "SubmitOrder"

-- Call with specific variables as payload
call webhook "SubmitOrder" with data "orderId,total,email"

-- After call:
-- webhookStatus   → HTTP status code
-- webhookResponse → raw response body

Send Email (Resend)

-- Configure API key in App Settings → Email first
send email to "user@example.com" subject "Welcome" body "Thanks for signing up!"
send email to recipient subject "Receipt #{orderId}" body "Total: £{total}" as html

-- After sending:
-- emailStatus  → "200" = sent, other = error
-- emailResult  → raw Resend API response

User-Defined Commands

-- Define a reusable command (in any script)
command RefreshDashboard
  get url "https://api.example.com/stats"
  set the data of widget StatsTable to result
  set the value of widget RevGauge to json field "revenue" of result
end command

-- Call it anywhere
RefreshDashboard

Validation

validate widget EmailField as email
validate widget PhoneField as required
validate widget AgeField as min-value 18
validate widget DescriptionField as max-length 500

-- After validation:
-- validationPassed → "true" or "false"
-- validationError  → error message or ""

if validationPassed is "false" then
  show toast validationError with background color "#ef4444"
end if

clear validation widget EmailField

Form Groups

-- Collect all child inputs at once
submit form widget ContactForm      -- triggers onSubmit with formData variable
reset form widget ContactForm       -- clears all child inputs

Phone, Currency & Time Inputs

-- PhoneInput — read combined value (e.g. "+44 7700 900000")
set variable phone to phoneNumber          -- set via outputVariable property
set the value of widget PhoneField to "7700 900123"
set the countryCode of widget PhoneField to "+44"

-- CurrencyInput — value is always a number
set variable amount to currencyValue       -- set via outputVariable property
set the value of widget PriceBox to 99.99

-- TimePicker — value is always HH:MM (24-hour internally)
set variable t to the value of widget StartTime
set the value of widget StartTime to "09:00"
-- timeValue variable is also set automatically on every selection

-- Combine date + time for an appointment
set variable appointment to dateValue + " " + timeValue

File Download

-- Trigger a browser download from any variable — no server needed
save file "results.csv" with content csvData
save file "export.json" with content jsonString
save file "photo.png" with content croppedImageData   -- base64 data URLs auto-decoded

-- Dynamic filename
set variable today to "2025-06-20"
save file "report-" + today + ".csv" with content reportCsv

-- MIME type is inferred from the extension:
-- .csv → text/csv  .json → application/json  .txt / .md → text/plain
-- .html → text/html  .xml → application/xml
-- .png / .jpg / .gif / .svg → image/*  .pdf → application/pdf

Download File from URL

Fetch a file from any URL and trigger a browser download. Filename is inferred from the URL if not given.

download file from url "https://api.example.com/report.pdf"
download file from url invoiceUrl as "invoice-" & invoiceNumber & ".pdf"

-- Variable set:
-- downloadStatus → "ok" or error message

Push Notifications

-- OS-level browser notification (appears in system tray / notification centre)
send notification "Title"
send notification "Order ready" with message "Your order #4821 is ready to collect."
send notification "Alert" with message "Low stock warning" with icon "https://yourapp.com/icon.png"

-- notificationStatus is set automatically:
--   "sent"        → notification fired successfully
--   "denied"      → user blocked permission
--   "unsupported" → browser doesn't support Notification API

if notificationStatus is not "sent"
  show toast "Notifications blocked: " + notificationStatus
end if

Custom Analytics Events

-- Log a named event — appears in Analytics tab → Custom events
log event "ButtonClicked"

-- Log with an optional value for richer filtering
log event "ProductViewed" with value currentProduct
log event "FormSubmitted" with value "ContactForm"

-- Any expression works as the event name or value
log event "StepCompleted" with value stepNumber

Geolocation

-- Get device position (async — waits for browser permission + GPS fix)
get current location

-- Variables set automatically:
--   locationLat      e.g. "51.5074"
--   locationLng      e.g. "-0.1278"
--   locationAccuracy metres, e.g. "18"
--   locationStatus   "ok" or error message

if locationStatus is "ok"
  set the text of widget LatLabel to "Lat: " + locationLat
  set the text of widget LngLabel to "Lng: " + locationLng
else
  set the text of widget Status to "Error: " + locationStatus
end if

-- Build a map link
get current location
set variable mapUrl to "https://maps.google.com/?q=" + locationLat + "," + locationLng

Batch Geocoding (Geocode Widget)

The Geocode widget converts a JSON array of address strings into latitude/longitude coordinates. Set the addresses property, then click Geocode All in preview — or drive it from a script. Supports free Nominatim (OpenStreetMap, 1 req/sec) and Google Maps Geocoding API.

-- Load addresses from an API
on card LocationsPage load
  get url "/api/delivery-stops"
  set the addresses of widget Geocoder1 to json field "addresses" of response
end on

-- When batch completes — variables set automatically:
--   geocodeResults       JSON array of {address, lat, lng, formattedAddress}
--   geocodeFailed        JSON array of {address, error}
--   geocodeSuccessCount  number of successful geocodes
--   geocodeFailCount     number of failures
on widget Geocoder1 onGeocodeComplete
  set the markers of widget LiveMap1 to geocodeResults
  if geocodeFailCount > 0 then
    show toast geocodeFailCount & " address(es) could not be resolved"
  end if
end on

-- A single address failed — variables set:
--   geocodeAddress   the address string that failed
--   geocodeError     reason (e.g. "No results found")
on widget Geocoder1 onGeocodeError
  show toast "Could not geocode: " & geocodeAddress
end on

-- User clicks a geocoded row — variables set:
--   geocodeAddress           original address string
--   geocodeLat               latitude (number)
--   geocodeLng               longitude (number)
--   geocodeFormattedAddress  full formatted address from geocoder
--   geocodeRow               full JSON object {address, lat, lng, formattedAddress}
--   geocodeMarker            map-ready JSON {id, lat, lon, label, color} — note "lon" not "lng"
on widget Geocoder1 onRowClick
  set the markers of widget LiveMap1 to "[" & geocodeMarker & "]"
  set the text of widget LatLabel to geocodeLat
  set the text of widget LngLabel to geocodeLng
end on

Device Detection

Detect whether the app is running on a phone, tablet, or desktop. No permissions required — runs instantly.

get device type

-- Variable set:
-- deviceType → "phone" | "tablet" | "desktop"
-- Redirect to the right layout
get device type
if deviceType is "phone"
  go to card MobileHome
else if deviceType is "tablet"
  go to card TabletHome
else
  go to card DesktopHome
end if

Script Output (Print / Toast)

print "Debug message"              -- shows in Console (Variables panel)

Show Toast Notifications

Display a non-blocking popup message to the user. All options are optional and can be combined in any order.

Syntax

show toast "message"
show toast "message" with duration <milliseconds>
show toast "message" with position "<position>"
show toast "message" with background color "<hex>"
show toast "message" with text color "<hex>"

Duration

Duration is in milliseconds. Default is 3000 (3 seconds). Use 0 to keep it on screen until the next toast replaces it.

show toast "Saved!" with duration 2000
show toast "Processing…" with duration 8000
show toast "Done" with duration 1500

Position

Six positions are available:

show toast "Top left"     with position "top-left"
show toast "Top centre"   with position "top-center"
show toast "Top right"    with position "top-right"      -- default
show toast "Bottom left"  with position "bottom-left"
show toast "Bottom centre" with position "bottom-center"
show toast "Bottom right" with position "bottom-right"

Background & Text Colour

-- Success (green)
show toast "Record saved!" with background color "#16a34a"

-- Warning (amber)
show toast "Low stock warning" with background color "#d97706"

-- Error (red)
show toast "Save failed" with background color "#dc2626"

-- Info (blue)
show toast "Sync complete" with background color "#2563eb"

-- Custom text colour
show toast "Note" with background color "#1e293b" with text color "#94a3b8"

Combining Options

-- Full example: colour + duration + position
show toast "✓ Delivery confirmed" with background color "#16a34a" with duration 4000 with position "bottom-right"

-- Error at top with longer display
show toast "⚠ Connection lost — retrying" with background color "#dc2626" with text color "#fff" with duration 6000 with position "top-center"

-- Quick dismissal
show toast "Copied!" with duration 1200 with position "bottom-center"

Dynamic Messages

-- Use variables and concatenation in the message
set variable clientName to "Alice"
show toast "Welcome back, " & clientName & "!"

-- Show count in toast
show toast geocodeSuccessCount & " addresses geocoded"

-- Conditional colour based on result
if httpStatus is "200" then
  show toast "Saved!" with background color "#16a34a"
else
  show toast "Error: " & httpStatus with background color "#dc2626"
end if

After HTTP Requests

post url "/api/orders" with body orderData

if response is empty then
  show toast "No response from server" with background color "#dc2626"
else if httpStatus is "200" then
  show toast "Order placed!" with background color "#16a34a" with duration 3000
else
  show toast "Failed: " & httpStatus with background color "#f59e0b"
end if

Run Other Scripts

run script MyHelperScript
run script ValidateAndSubmit

Auth (Published Apps)

login user with variable credentials
logout user
restore session

-- After login:
-- sessionToken → JWT access token
-- userEmail    → logged-in email
-- userRole     → user's role

WebSockets & SSE

-- WebSocket
connect to websocket "wss://api.example.com/live"
-- Messages arrive as onMessage events (set on the script)
-- wsMessage contains the incoming text

-- Server-Sent Events
subscribe to sse "https://api.example.com/stream"
-- sseMessage contains the incoming data

Barcode Scanner

-- Open the scanner overlay and wait for a scan (camera / upload / manual)
scan barcode into parcelId

-- With a custom variable name
scan barcode into ticketCode

-- Handle cancel (resolves to empty string)
scan barcode into code
if code is "" then
  show toast "Scan cancelled"
else
  get url "https://api.example.com/items/" + code
end if

NFC

-- Read the next NFC tag and store its text (Chrome on Android, HTTPS only)
scan nfc tag into tagData

-- With a custom variable name
scan nfc tag into productId

-- Write plain text to a tag
write nfc tag with "Hello from Sentrix"

-- Write a JSON payload
write nfc tag with "{\"userId\":\"" + userId + "\"}"

-- Write using "with data" phrasing
write nfc tag with data accessCode

Signature Pad

-- Get the signature as a base64 PNG data URL
get signature of widget SigPad into mySig

-- Clear the canvas
clear signature of widget SigPad

-- Stamp HH:MM DD/MM/YYYY onto the signature
stamp widget SigPad with timestamp

Temperature Logging

-- Record a temperature reading (fires onLog / onFail)
log temperature 4.2 for widget TempLog
log temperature currentTemp for widget TempLog

-- Retrieve full log as JSON array string
get temperature log of widget TempLog into myLog

Row Status

-- Set the status of a row in any list widget
set row status of widget MyList row 2 to "complete"

-- Count all rows, or rows matching a status
get row count of widget MyList into total
get row count of widget MyList where status is "pending" into pendingCount

Row Colour Coding (DataTable)

Apply a background colour to individual rows in a DataTable. Row numbers are 1-based. Accepts any CSS colour string.

-- Colour a specific row
set row color of widget ClientTable row 1 to "#fee2e2"
set row color of widget ClientTable row 3 to "#dcfce7"

-- Clear one row's colour
set row color of widget ClientTable row 1 to ""

-- Clear all custom row colours
clear row colors of widget ClientTable

Background Push Notifications

True background push using the Web Push / VAPID protocol — notifications arrive even when the app tab is closed. Subscribe with your service worker, then send to your own devices or to a specific user in the same org.

-- Subscribe / unsubscribe (run after login)
subscribe to push notifications
unsubscribe from push notifications

-- Send to current user's own devices
send push notification "Title"
send push notification "Title" with body "Body text"
send push notification "Reminder" in 30 seconds
send push notification "Reminder" in 5 minutes

-- Send to a specific user by their user ID
send push notification to user assignedUserId "You have a new task"
send push notification to user assignedUserId "You have a new task" with body taskTitle

-- Variable set automatically:
-- pushStatus → "subscribed" | "unsubscribed" | "sent" | error message

Welfare Alerts — Push to Coordinators

Broadcasts a push notification to all coordinator-role devices in the organisation. Coordinator must call subscribe to push after login. Alert auto-includes driver name, wellness indicators, and GPS.

-- Coordinator setup (once, after login)
subscribe to push

-- Driver: escalate a welfare concern
send welfare alert for client "Mrs Johnson"
send welfare alert for client clientName with notes wellnessNotes

-- Variables set:
-- welfareAlertStatus     → "sent" | "error" | "unavailable"
-- welfareAlertRecipients → number of coordinator devices notified
-- WellnessCheckPanel onSubmit — send alert if concerns noted
on widget WellnessCheck onSubmit
  if concernsNoted is "yes"
    send welfare alert for client currentClientName with notes wellnessNotes
    show toast "⚠️ " & welfareAlertRecipients & " coordinator(s) notified"
  end if
end on

Calendar Event Commands

Add, remove, and read events on a Calendar widget at runtime. Events are stored as a JSON array on the widget's events property. Each event object must include at minimum an id, title, date, startTime, and endTime.

-- Add an event to a Calendar widget
add event to widget MyCalendar using "{""id"":""e1"",""title"":""Team Meeting"",""date"":""2025-06-12"",""startTime"":""09:00"",""endTime"":""10:00"",""color"":""#3b82f6""}"

-- Remove an event by its id
remove event from widget MyCalendar where id is "e1"

-- Read the date the user last clicked / navigated to
set variable chosen to the selected date of widget MyCalendar
show toast "Selected: " & chosen
-- Dynamic booking flow example
on widget BookBtn onClick
  set variable newEvent to "{""id"":""" & bookingId & """,""title"":""" & clientName & """,""date"":""" & bookingDate & """,""startTime"":""" & startTime & """,""endTime"":""" & endTime & """}"
  add event to widget AppointmentCalendar using newEvent
  show toast "Appointment added"
end on

-- Cancel a booking
on widget CancelBtn onClick
  remove event from widget AppointmentCalendar where id is selectedBookingId
  show toast "Booking removed"
end on

Time Slot Picker Commands

Control the available/booked/blocked state of individual time slots in a TimeSlotPicker widget. Slots are identified by their time string (e.g. "09:00"). Valid statuses are available, booked, and blocked.

-- Mark a slot as booked
mark slot "09:00" in widget MySlotPicker to "booked"

-- Mark a slot as blocked (unavailable for selection)
mark slot "14:30" in widget MySlotPicker to "blocked"

-- Restore a slot to available
mark slot "11:00" in widget MySlotPicker to "available"

-- Use a variable for the slot time
mark slot selectedTime in widget MySlotPicker to "booked"
-- Booking confirmation flow
on widget SlotPicker onSlotSelect
  -- slotTime and slotStatus are set automatically by onSlotSelect
  if slotStatus is "available"
    mark slot slotTime in widget SlotPicker to "booked"
    set the text of widget ConfirmLabel to "Booked: " & slotTime
  end if
end on

-- Admin: block lunch break
on widget BlockLunchBtn onClick
  mark slot "12:00" in widget SlotPicker to "blocked"
  mark slot "12:30" in widget SlotPicker to "blocked"
  show toast "Lunch break blocked"
end on

Interactive State Overrides

Configure visual changes that apply automatically when a widget enters hover, active, focus, or disabled state — no script required. Set up in the Properties panel → Interactive States section.

StateWhen active
hoverPointer enters the widget
activeMouse/touch held down (pressed)
focusWidget has keyboard focus
disabledWidget's disabled or readonly property is true

For each state you can override any visual property (bgColor, textColor, borderRadius, shadow, etc.). Overrides apply only in Preview; the canvas always shows design-time values.

-- No script needed — configure in Properties panel:
-- Button hover:    bgColor #2563eb  (darker blue on hover)
-- Button active:   bgColor #1d4ed8  (even darker when pressed)
-- TextField focus: borderColor #06b6d4  (cyan focus ring)
-- Card hover:      shadow true  (elevation effect)
-- Label disabled:  textColor #475569  (muted when readonly)

Visual Script Debugger

Step through scripts line-by-line with the built-in debugger. Enable it with the 🐛 Debug toggle, set breakpoints by clicking the editor gutter (or press F9 at cursor), then use the step controls.

KeyAction
F5Continue — run to next breakpoint
F10Step Over — skip nested run script calls
F11Step Into — descend into run script calls
⇧F11Step Out — return to the script caller
F9Toggle breakpoint at cursor line

The 🐛 Debugger tab in the Preview right panel shows: current pause location, full call stack with line numbers, watch expressions, and all runtime variables. Auto-activates when execution pauses.

Data Layer

Connect REST APIs to your widgets without writing a single script line. Define sources, model their fields, then bind those fields to widget properties.

How It Works

1
Add a Data Source

Open the 🔌 Data tab in the left panel. Click Add Data Source. Paste a URL, choose GET/POST method, add optional headers and body, and toggle Auto-fetch if you want it to run when the card loads.

2
Test the Source

Click Test to make the actual API call and see the raw JSON response inline. Verify the shape of the data before moving on.

3
Create a Data Model

Click Add Data Model. Pick the source, then add fields using dot-notation paths to extract values from the JSON:

title   →  data.product.title
price   →  data.product.price
stock   →  data.inventory[0].qty
4
Test the Model

Click Test Model — each field lights up green showing its resolved value, or red if the path is wrong.

5
Bind Fields to Widgets

Select a widget on the canvas. Scroll to Data Bindings in the Properties Panel. Click Bind next to any property and choose a model field.

6
Preview

Press Preview — bound widgets populate automatically. No scripts needed.

Using Data Sources in Scripts

-- Trigger a fetch manually in a script
fetch data from ProductsAPI

-- After fetch, model field values are available as variables:
-- ModelName_fieldKey
set the text of widget PriceLabel to variable ProductModel_price
set the text of widget TitleLabel to variable ProductModel_title

Tip: Use Auto-fetch on your data source for data you always want loaded when the card appears. Use the script command fetch data from SourceName for on-demand or triggered fetches.

Real-Time Data

WebSocket

-- Open a persistent WebSocket connection
connect to websocket "wss://api.example.com/live"

-- The script's onMessage event fires for each message
-- wsMessage variable contains the incoming text or JSON

Server-Sent Events (SSE)

-- Subscribe to an SSE stream
subscribe to sse "https://api.example.com/stream"

-- The script's onMessage event fires for each event
-- sseMessage variable contains the event data

Webhooks (Outbound)

Configure outbound webhooks in App Settings → Webhooks. Add a name and URL, then call from any script:

call webhook "SubmitOrder"
call webhook "NotifySlack" with data "orderId,customerName,total"

-- After call:
-- webhookStatus   → HTTP status code ("200" = success)
-- webhookResponse → raw response body

Email (Resend API)

Configure your Resend API key in App Settings → Email. Set the From Address and From Name.

send email to "customer@example.com" subject "Order Confirmed" body "Your order is on its way!"
send email to variable emailAddr subject "Invoice #{num}" body htmlContent as html

-- emailStatus  → "200" on success
-- emailResult  → raw API response

User Authentication (Published Apps)

-- Login
login user with variable credentials

-- Logout
logout user

-- Restore session on card load
restore session

-- After login:
-- sessionToken → JWT access token
-- userEmail    → logged-in user's email
-- userRole     → "admin" / "builder" / "viewer"

Authentication calls go directly from the browser to the backend. Ensure your backend is running and CORS is configured for the app's domain when using web exports.

Widget Reference

All 146 widgets available in Sentrix. Click any widget to see its full property reference and example scripts.

Keyboard Shortcuts

All shortcuts are active while the canvas has focus. They're automatically disabled when a text input or the script editor has focus.

Press ? at any time on the canvas to open the interactive shortcuts reference directly inside the app.