CatoScript Docs
Contents
Basics
- Line-based — one statement per line, no semicolons required
- Comments start with
# - Blocks use
> {to open and}to close - File extension:
.cato - Entry point:
main.cato(auto-executed on the view page)
# This is a comment
console.out("Hello, Cato")
Variables
Declared with var.type name = value. Types are descriptive labels — they don't enforce runtime type checks.
var.text greeting = "Hello"
var.number count = 42
var.boolean active = true
var.element btn = element.getById('abc123')
Reassignment:
greeting = "Goodbye" count = count + 1
Types
| Type | Description |
|---|---|
text | String value |
number | Numeric value (integer or float) |
boolean | true or false |
element | Reference to a canvas element |
Operators
Comparison
| Operator | Description |
|---|---|
== | Equal |
!= | Not equal |
> | Greater than |
< | Less than |
>= | Greater or equal |
<= | Less or equal |
Math
| Operator | Description |
|---|---|
+ | Add (numbers) or concatenate (strings) |
- | Subtract |
* | Multiply |
/ | Divide |
var.number result = 10 + 5 * 2 var.text msg = "Hello " + "World"
Control Flow
If / Else
if (count > 10) > { console.out("big number") } else > { console.out("small number") }
While
Loops have a 10,000 iteration safety limit to prevent infinite loops.
var.number i = 0
while (i < 5) > {
console.out(i)
i = i + 1
}
Functions
Define reusable functions with func. Parameters are local to the function. Functions can return values with return.
func greet(name) > { console.out("Hello " + name) } func add(a, b) > { return a + b } # Call them greet("Cato") var.number sum = add(10, 20) console.out(sum)
Functions can call other functions:
func double(n) > { return n * 2 } func quadruple(n) > { return double(double(n)) } console.out(quadruple(5))
Scope
- Function parameters are local — they don't overwrite variables with the same name in the outer scope
- Functions can read and modify global variables
- Functions defined in imported files are available after the
usestatement
Imports
Use use to load functions from other .cato files in the same script repo. Imported functions are namespaced under the alias you provide.
use "helpers.cato" as helpers use "ui.cato" as ui # Call functions via their namespace helpers.greet("Cato") ui.setupUI() var.number val = helpers.add(10, 20)
How It Works
use "filename.cato" as aliasfetches and parses the file from the script repo- All
funcdefinitions in the imported file are registered underalias.funcName - Each file is only loaded once (no circular import issues)
- Import order matters —
usestatements should come before code that depends on them
Multi-File Example
helpers.cato:
func clamp(val, min, max) > { if (val < min) > { return min } if (val > max) > { return max } return val }
main.cato:
use "helpers.cato" as helpers var.element box = element.getById('mybox') var.number x = helpers.clamp(500, 0, 400) box.x = x console.out("Clamped x to: " + x)
Element References
Elements are the custom components placed on the canvas (text boxes, images, buttons, shapes). Reference them by their element ID.
var.element btn = element.getById('abc123')
The element ID is shown in the designer panel and stored in the database.
Common Properties (All Elements)
| Property | Read | Write | Description |
|---|---|---|---|
id | yes | no | Element ID (read-only) |
type | yes | no | Element type: "text", "image", "button", "shape" |
x | yes | yes | X position in pixels |
y | yes | yes | Y position in pixels |
width | yes | yes | Width in pixels |
height | yes | yes | Height in pixels |
zIndex | yes | yes | Stack order (higher = on top) |
visible | no | yes | Show/hide (true/false) |
var.element el = element.getById('myel')
el.x = 100
el.y = 200
el.width = 300
el.height = 150
el.zIndex = 10
el.visible = false
Common Methods (All Elements)
| Method | Description |
|---|---|
el.hide() | Hide the element (display: none) |
el.show() | Show the element |
el.moveTo(x, y) | Move to position in pixels |
el.resize(w, h) | Resize element in pixels |
el.hide() el.show() el.moveTo(200, 300) el.resize(150, 50)
Common Events (All Elements)
| Event | Trigger |
|---|---|
el.onClick | Element is clicked |
el.onDblClick | Element is double-clicked |
el.onHover | Mouse enters the element |
el.onLeave | Mouse leaves the element |
el.onClick > {
console.out("clicked!")
}
Text Element
Text content displayed on the canvas. Supports Mewize formatting (@mentions, links, emotes) when processed via the designer.
| Property | Read | Write | Description |
|---|---|---|---|
text | yes | yes | The text content string |
color | yes | yes | Text color (CSS color, e.g. "#ffffff") |
fontSize | no | yes | Font size in pixels |
Designer-only: fontFamily (Nunito, Jockey One, monospace, serif) • textAlign (left, center, right)
var.element label = element.getById('mylabel')
label.text = "Hello World"
label.color = "#ff5500"
label.fontSize = 24
Image Element
Displays an image on the canvas.
| Property | Read | Write | Description |
|---|---|---|---|
src | yes | yes | Image source URL (use media.getUrl() for uploaded files) |
Designer-only: alt (accessibility text) • objectFit (contain, cover, fill)
var.element pic = element.getById('mypic')
pic.src = media.getUrl('photo.png')
pic.src = "https://example.com/image.jpg"
Button Element
A clickable button with a label. Most commonly used with onClick events.
| Property | Read | Write | Description |
|---|---|---|---|
text | yes | yes | The button label text |
color | yes | yes | Text/border color (CSS color) |
bgColor | no | yes | Background color (CSS color) |
var.element btn = element.getById('mybtn')
btn.text = "Click Me"
btn.color = "#19f5aa"
btn.bgColor = "#47508b"
btn.onClick > {
btn.text = "Clicked!"
btn.bgColor = "#5a6aae"
}
btn.onHover > {
btn.bgColor = "#5a6aae"
}
btn.onLeave > {
btn.bgColor = "#47508b"
}
Shape Element
A rectangle or circle shape. Useful as backgrounds, dividers, containers, or visual decorations. Can also be a target for media.playVideo().
| Property | Read | Write | Description |
|---|---|---|---|
bgColor | yes | yes | Fill color (CSS color) |
Designer-only: shape (rectangle/circle) • borderColor • borderWidth • borderRadius
var.element box = element.getById('mybox')
box.bgColor = "#ff0000"
# Use a shape as a video container
media.playVideo('clip.mp4', 'mybox')
console
Output text to the script output panel on the view page.
| Function | Description |
|---|---|
console.out(value) | Print to script output |
console.clear() | Clear script output |
console.out("Hello, Cato")
console.out("Count: " + count)
console.clear()
math
| Function | Description |
|---|---|
math.random(min, max) | Random integer between min and max |
math.round(value) | Round to nearest integer |
element
| Function | Description |
|---|---|
element.getById('id') | Get element reference by ID |
element.getAll() | Get array of all elements |
media
Media files (sound, image, video) are uploaded via the designer's Media panel. Reference them by filename in CatoScript.
Sound
| Function | Description |
|---|---|
media.playSound('file.mp3') | Play a sound file |
media.pauseSound('file.mp3') | Pause playback |
media.stopSound('file.mp3') | Stop and reset to beginning |
media.setSoundVolume('file.mp3', 0.5) | Set volume (0.0 to 1.0) |
media.setSoundLoop('file.mp3', true) | Enable/disable looping |
Video
| Function | Description |
|---|---|
media.playVideo('file.mp4', 'elementId') | Play video inside an element |
media.pauseVideo('file.mp4') | Pause video |
media.stopVideo('file.mp4') | Stop and reset video |
media.setVideoVolume('file.mp4', 0.5) | Set video volume (0.0 to 1.0) |
media.setVideoLoop('file.mp4', true) | Enable/disable video looping |
URL
| Function | Description |
|---|---|
media.getUrl('file.png') | Get the URL of a media file (use with image src) |
# Background music with sound effects
var.element btn = element.getById('mybutton')
var.element pic = element.getById('mypic')
pic.src = media.getUrl('background.png')
media.setSoundVolume('bgm.mp3', 0.3)
media.setSoundLoop('bgm.mp3', true)
media.playSound('bgm.mp3')
btn.onClick > {
media.playSound('click.wav')
}
timer
Delayed and repeating execution. Uses the event handler block syntax with a seconds argument.
| Function | Description |
|---|---|
timer.wait(seconds) > { } | Execute the block once after a delay |
timer.interval(seconds) > { } | Execute the block repeatedly at an interval |
var.element label = element.getById('mylabel')
var.number count = 0
# Show message after 3 seconds
timer.wait(3) > {
label.text = "Hello!"
}
# Update a counter every second
timer.interval(1) > {
count = count + 1
label.text = "Count: " + count
}
video (Content Video)
Controls the main content video on video-type creations. The view page uses a custom video player with full script integration.
Playback Control
| Function | Description |
|---|---|
video.play() | Play the video |
video.pause() | Pause the video |
video.stop() | Stop and reset to beginning |
video.mute() | Mute the video |
video.unmute() | Unmute the video |
video.skipTo(seconds) | Jump to a specific time |
video.skipForward(seconds) | Skip forward (default 5s) |
video.skipBackward(seconds) | Skip backward (default 5s) |
video.setVolume(0.5) | Set volume (0.0 to 1.0) |
video.setLoop(true) | Enable/disable looping |
video.setSpeed(1.5) | Set playback speed (0.25 to 4.0) |
State Getters
| Function | Description |
|---|---|
video.getTime() | Current playback time in seconds |
video.getDuration() | Total duration in seconds |
video.isPaused() | true if paused |
video.isMuted() | true if muted |
video.getVolume() | Current volume (0.0 to 1.0) |
video.getSpeed() | Current playback rate |
Video Events
| Event | Trigger |
|---|---|
video.onPlay | Video starts playing |
video.onPause | Video is paused |
video.onEnd | Video finishes |
video.onSeek | User seeks to new position |
video.onVolumeChange | Volume or mute state changes |
video.onTimeUpdate | Fires continuously during playback (~4x/sec) |
video.onTimestamp(seconds) | Fires once when playback reaches the given second |
# Show/hide elements based on video playback
var.element subtitle = element.getById('sub1')
subtitle.visible = false
video.onTimestamp(5) > {
subtitle.text = "Welcome to MewGem"
subtitle.visible = true
}
video.onTimestamp(10) > {
subtitle.text = "Let's get started"
}
video.onTimestamp(15) > {
subtitle.visible = false
}
video.onPause > {
console.out("Video paused at " + video.getTime())
}
video.onEnd > {
console.out("Video finished!")
subtitle.text = "Thanks for watching"
subtitle.visible = true
}
content (Base Content)
Controls the main base content on image-type and text-type creations. This is the primary media set when the creation was created — not an element added in the designer.
For video and audio creations, use video.* and the audio player instead.
Image Content Properties
| Property | Read | Write | Description |
|---|---|---|---|
content.src | yes | yes | Image source URL |
content.visible | yes | yes | Show/hide the image |
content.width | yes | no | Natural image width in pixels |
content.height | yes | no | Natural image height in pixels |
content.type | yes | no | Returns "image" |
Text Content Properties
| Property | Read | Write | Description |
|---|---|---|---|
content.text | yes | yes | The text content string |
content.visible | yes | yes | Show/hide the text |
content.color | no | yes | Text color (CSS color) |
content.type | yes | no | Returns "text" |
Content Events
Works on both image and text base content.
| Event | Trigger |
|---|---|
content.onClick | Base content is clicked |
content.onDblClick | Base content is double-clicked |
content.onHover | Mouse enters the base content |
content.onLeave | Mouse leaves the base content |
# Play a sound when the base image is clicked content.onClick > { media.playSound('meow.mp3') } # Change text content color on hover content.onHover > { content.color = "#19f5aa" } content.onLeave > { content.color = "#ffffff" }
# Swap the base image on click
content.onClick > {
content.src = media.getUrl('alternate.png')
}
profile (Profile Page)
Controls the profile page elements when CES is used on a user profile. Available only on profile-type creations.
Read-Only Properties
| Property | Description |
|---|---|
profile.username | Profile owner's username |
profile.status | Profile status text |
profile.bio | Profile bio text |
profile.picture | Profile picture URL |
profile.banner | Banner image URL |
profile.friendCount | Number of friends |
profile.presence | Online status: "online", "offline", etc. |
profile.membershipTier | Membership tier ID (e.g. "free", "plus", "pro") |
profile.isVisitorLoggedIn | true if the person viewing is logged in |
profile.visitorName | Username of the person viewing (empty if not logged in) |
profile.savedBoxColor | Saved card background color from settings |
profile.savedTextColor | Saved text color from settings |
profile.ringColor | Saved ring color from settings |
Live Properties (read current state)
| Property | Description |
|---|---|
profile.boxColor | Current card background color |
profile.textColor | Current text color |
profile.usernameColor | Current username color |
Writable Properties (assignment syntax)
| Property | Membership | Description |
|---|---|---|
profile.boxColor | required | Set card background color |
profile.textColor | required | Set text color |
profile.usernameColor | required | Set username text color |
profile.pfpBorder | required | Set profile picture border color |
profile.statusText | free | Override displayed status text |
profile.bioText | free | Override displayed bio text |
profile.bannerSrc | free | Change banner image URL |
profile.extraHeight | free | Set extra canvas space height (px) |
Methods
| Method | Membership | Description |
|---|---|---|
profile.setBoxColor(color) | required | Set card background to a solid color |
profile.setBoxGradient(c1, c2, angle) | required | Set card background to a gradient |
profile.setBoxImage(url) | required | Set card background to an image |
profile.setTextColor(color) | required | Set card text color |
profile.setUsernameColor(color) | required | Set username text color |
profile.setPfpBorder(color) | required | Set profile picture border color |
profile.setStatusText(text) | free | Override displayed status text |
profile.setBioText(text) | free | Override displayed bio text |
profile.setBanner(url) | free | Change banner image |
profile.setBannerVisible(bool) | free | Show/hide banner |
profile.setPfpVisible(bool) | free | Show/hide profile picture |
profile.setFlairVisible(bool) | free | Show/hide membership flair icon |
profile.setBadgesVisible(bool) | free | Show/hide badge showcase |
profile.setExtraHeight(px) | free | Resize extra canvas space |
State Persistence
| Method | Description |
|---|---|
profile.getState(key) | Read a persistent value by key |
profile.setState(key, value) | Save a persistent value by key |
Events
| Event | Trigger |
|---|---|
profile.onVisit > { } | Fires immediately when someone visits the profile |
# Greet visitors (free) profile.onVisit > { if (profile.isVisitorLoggedIn == true) > { profile.statusText = "Welcome, " + profile.visitorName + "!" } else > { profile.statusText = "Welcome to my profile!" } } # Dynamic theming (requires membership) profile.setBoxGradient("#1a1a2e", "#2d2d5e", 135) profile.setTextColor("#e0e0ff") profile.setUsernameColor("#19f5aa") # Persistent visit counter var.number visits = profile.getState("visitCount") visits = visits + 1 profile.setState("visitCount", visits) profile.bioText = "Profile views: " + visits
visitor (Profile Messages)
Visitor messaging system for profile pages. Allows logged-in visitors to leave messages on a profile (like a guestbook).
| Method | Description |
|---|---|
visitor.getMessages(limit) | Get recent messages (default 20) |
visitor.postMessage(text) | Post a message as the current visitor (must be logged in) |
# Simple guestbook
var.element msgLabel = element.getById('messages')
var.element postBtn = element.getById('postbtn')
var.element input = element.getById('msginput')
postBtn.onClick > {
visitor.postMessage(input.text)
input.text = ""
}
Full Examples
Interactive Button Demo
# Interactive button demo var.element btn = element.getById('mybutton') var.element label = element.getById('mylabel') var.number clicks = 0 console.out("Script loaded!") btn.text = "Click me" label.text = "Clicks: 0" btn.onClick > { clicks = clicks + 1 label.text = "Clicks: " + clicks console.out("Click #" + clicks) if (clicks == 10) > { btn.text = "Done!" btn.color = "#ff0000" } } btn.onHover > { btn.bgColor = "#5a6aae" } btn.onLeave > { btn.bgColor = "#47508b" }
Interactive Video with Controls
# Interactive video with button triggers
var.element skipBtn = element.getById('skipbtn')
var.element label = element.getById('timelabel')
skipBtn.onClick > {
video.skipForward(10)
}
video.onTimeUpdate > {
var.number t = video.getTime()
label.text = "Time: " + t
}
Video with Shape Container
# Play video inside a shape element
var.element frame = element.getById('videoframe')
frame.onClick > {
media.playVideo('intro.mp4', 'videoframe')
media.setVideoLoop('intro.mp4', true)
}
Execution Model
- Content is viewed at
/view/{name} - Engine loads the content, elements, and script repo
main.catosource is sent to the processor for parsing- Parser returns an AST (abstract syntax tree)
- Client-side runtime executes the AST against the DOM elements on the canvas
- Event handlers are registered and fire on user interaction