Build a Canvas

Create an interactive state machine with poses, transitions, and conditions. A canvas defines how your mascot behaves and reacts to user interactions in real time.

What is a Canvas?

A canvas is a state machine where each state is a mascot pose (an image or animation) and transitions are animated videos that play when moving between states. You define conditions and inputs that trigger transitions - like hover, click, or custom events from your app. The Masko embed player reads the canvas configuration and handles all the playback logic.

Nodes & Edges

Nodes represent poses or states. Each node references an image asset ID and has a position on the canvas editor grid. The itemName is the human-readable label.

Edges are transitions between nodes. Each edge connects a source node to a target node and can have:

  • conditions - Rules that must be met to trigger the transition (see below).
  • priority - When multiple edges can fire, the highest priority wins. Higher number = higher priority.
  • speed - Playback speed multiplier (e.g. 1.5 for faster, 0.5 for slower). Default is 1.
  • duration - Video duration in seconds. Used for generation.
  • description - Animation prompt used when generating the transition video.
  • reverse - If true, this edge plays the reverse of another edge's video instead of generating a new one.

Use source: "*" (any state) for edges that can fire from any node - useful for global triggers like an error state or reset.

Conditions & Inputs

Each edge can have an array of conditions. A condition has three fields:

  • input - The name of the input to check (e.g. "isHovered", "clickCount").
  • op - The comparison operator: "eq", "neq", "gt", "lt", "gte", "lte".
  • value - The value to compare against.

The canvas supports these input types:

  • boolean - True/false values. Example: isHovered, isActive.
  • number - Numeric values. Example: clickCount, scrollPosition.
  • trigger - Fire-once events. The value resets after the transition fires. Example: onClick.
  • string - Text values. Example: currentPage, userRole.

Create a Canvas

Create a canvas with an inline graph definition. The graph contains nodes, edges, viewport settings, and input declarations.

POST/v1/collections/:id/canvases
curl -X POST https://api.masko.ai/v1/collections/COLLECTION_ID/canvases \
  -H "Authorization: Bearer masko_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Main Canvas",
    "graph": {
      "nodes": [
        { "id": "ast_img_idle", "x": 0, "y": 0, "itemName": "Idle" },
        { "id": "ast_img_wave", "x": 300, "y": 0, "itemName": "Waving" }
      ],
      "edges": [
        {
          "id": "edge_001",
          "source": "ast_img_idle",
          "target": "ast_img_wave",
          "duration": 4,
          "description": "transitioning from idle to waving",
          "conditions": [
            { "input": "isHovered", "op": "eq", "value": true }
          ]
        },
        {
          "id": "edge_002",
          "source": "ast_img_wave",
          "target": "ast_img_idle",
          "duration": 4,
          "description": "returning from wave to idle",
          "conditions": [
            { "input": "isHovered", "op": "eq", "value": false }
          ],
          "reverse": true,
          "reverseOfEdgeId": "edge_001"
        }
      ],
      "viewport": { "x": 0, "y": 0, "zoom": 0.8 },
      "inputs": [
        { "name": "isHovered", "type": "boolean", "defaultValue": false }
      ]
    }
  }'

Update the Graph

Update a canvas by sending a full replacement graph via PUT. The entire graph (nodes, edges, inputs) is replaced - there is no partial update.

PUT/v1/collections/:id/canvases/:canvasId

Example: Sleep/Wake Canvas

A complete two-state canvas where the mascot sleeps by default and wakes up when clicked. Uses a trigger input that fires once per click.

curl -X POST https://api.masko.ai/v1/collections/COLLECTION_ID/canvases \
  -H "Authorization: Bearer masko_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Sleep Wake",
    "graph": {
      "nodes": [
        { "id": "ast_sleeping", "x": 0, "y": 0, "itemName": "Sleeping" },
        { "id": "ast_awake", "x": 400, "y": 0, "itemName": "Awake" }
      ],
      "edges": [
        {
          "id": "edge_wake",
          "source": "ast_sleeping",
          "target": "ast_awake",
          "duration": 3,
          "description": "waking up with a stretch and yawn",
          "conditions": [
            { "input": "onClick", "op": "eq", "value": true }
          ],
          "priority": 10
        },
        {
          "id": "edge_sleep",
          "source": "ast_awake",
          "target": "ast_sleeping",
          "duration": 4,
          "description": "slowly falling asleep, eyes drooping",
          "conditions": [
            { "input": "onClick", "op": "eq", "value": true }
          ],
          "priority": 10
        }
      ],
      "viewport": { "x": 0, "y": 0, "zoom": 0.8 },
      "inputs": [
        { "name": "onClick", "type": "trigger", "defaultValue": false }
      ]
    }
  }'
Tip

After creating a canvas with a graph, use the generate-all endpoint to generate all transition animations at once. Reverse transitions are created for free with auto_reverse.