CatoScript Docs

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

TypeDescription
textString value
numberNumeric value (integer or float)
booleantrue or false
elementReference to a canvas element

Operators

Comparison

OperatorDescription
==Equal
!=Not equal
>Greater than
<Less than
>=Greater or equal
<=Less or equal

Math

OperatorDescription
+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 use statement

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 alias fetches and parses the file from the script repo
  • All func definitions in the imported file are registered under alias.funcName
  • Each file is only loaded once (no circular import issues)
  • Import order matters — use statements 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)

PropertyReadWriteDescription
idyesnoElement ID (read-only)
typeyesnoElement type: "text", "image", "button", "shape"
xyesyesX position in pixels
yyesyesY position in pixels
widthyesyesWidth in pixels
heightyesyesHeight in pixels
zIndexyesyesStack order (higher = on top)
visiblenoyesShow/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)

MethodDescription
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)

EventTrigger
el.onClickElement is clicked
el.onDblClickElement is double-clicked
el.onHoverMouse enters the element
el.onLeaveMouse 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.

PropertyReadWriteDescription
textyesyesThe text content string
coloryesyesText color (CSS color, e.g. "#ffffff")
fontSizenoyesFont 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.

PropertyReadWriteDescription
srcyesyesImage 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.

PropertyReadWriteDescription
textyesyesThe button label text
coloryesyesText/border color (CSS color)
bgColornoyesBackground 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().

PropertyReadWriteDescription
bgColoryesyesFill 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.

FunctionDescription
console.out(value)Print to script output
console.clear()Clear script output
console.out("Hello, Cato")
console.out("Count: " + count)
console.clear()

math

FunctionDescription
math.random(min, max)Random integer between min and max
math.round(value)Round to nearest integer

element

FunctionDescription
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

FunctionDescription
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

FunctionDescription
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

FunctionDescription
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.

FunctionDescription
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

FunctionDescription
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

FunctionDescription
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

EventTrigger
video.onPlayVideo starts playing
video.onPauseVideo is paused
video.onEndVideo finishes
video.onSeekUser seeks to new position
video.onVolumeChangeVolume or mute state changes
video.onTimeUpdateFires 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

PropertyReadWriteDescription
content.srcyesyesImage source URL
content.visibleyesyesShow/hide the image
content.widthyesnoNatural image width in pixels
content.heightyesnoNatural image height in pixels
content.typeyesnoReturns "image"

Text Content Properties

PropertyReadWriteDescription
content.textyesyesThe text content string
content.visibleyesyesShow/hide the text
content.colornoyesText color (CSS color)
content.typeyesnoReturns "text"

Content Events

Works on both image and text base content.

EventTrigger
content.onClickBase content is clicked
content.onDblClickBase content is double-clicked
content.onHoverMouse enters the base content
content.onLeaveMouse 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

PropertyDescription
profile.usernameProfile owner's username
profile.statusProfile status text
profile.bioProfile bio text
profile.pictureProfile picture URL
profile.bannerBanner image URL
profile.friendCountNumber of friends
profile.presenceOnline status: "online", "offline", etc.
profile.membershipTierMembership tier ID (e.g. "free", "plus", "pro")
profile.isVisitorLoggedIntrue if the person viewing is logged in
profile.visitorNameUsername of the person viewing (empty if not logged in)
profile.savedBoxColorSaved card background color from settings
profile.savedTextColorSaved text color from settings
profile.ringColorSaved ring color from settings

Live Properties (read current state)

PropertyDescription
profile.boxColorCurrent card background color
profile.textColorCurrent text color
profile.usernameColorCurrent username color

Writable Properties (assignment syntax)

PropertyMembershipDescription
profile.boxColorrequiredSet card background color
profile.textColorrequiredSet text color
profile.usernameColorrequiredSet username text color
profile.pfpBorderrequiredSet profile picture border color
profile.statusTextfreeOverride displayed status text
profile.bioTextfreeOverride displayed bio text
profile.bannerSrcfreeChange banner image URL
profile.extraHeightfreeSet extra canvas space height (px)

Methods

MethodMembershipDescription
profile.setBoxColor(color)requiredSet card background to a solid color
profile.setBoxGradient(c1, c2, angle)requiredSet card background to a gradient
profile.setBoxImage(url)requiredSet card background to an image
profile.setTextColor(color)requiredSet card text color
profile.setUsernameColor(color)requiredSet username text color
profile.setPfpBorder(color)requiredSet profile picture border color
profile.setStatusText(text)freeOverride displayed status text
profile.setBioText(text)freeOverride displayed bio text
profile.setBanner(url)freeChange banner image
profile.setBannerVisible(bool)freeShow/hide banner
profile.setPfpVisible(bool)freeShow/hide profile picture
profile.setFlairVisible(bool)freeShow/hide membership flair icon
profile.setBadgesVisible(bool)freeShow/hide badge showcase
profile.setExtraHeight(px)freeResize extra canvas space

State Persistence

MethodDescription
profile.getState(key)Read a persistent value by key
profile.setState(key, value)Save a persistent value by key

Events

EventTrigger
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).

MethodDescription
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

  1. Content is viewed at /view/{name}
  2. Engine loads the content, elements, and script repo
  3. main.cato source is sent to the processor for parsing
  4. Parser returns an AST (abstract syntax tree)
  5. Client-side runtime executes the AST against the DOM elements on the canvas
  6. Event handlers are registered and fire on user interaction
Error