Skip to content
maskostudioDocs

All pages

  • Overview/docs/use-cases
  • Mobile app/docs/use-cases#mobile
  • Website/docs/use-cases#website
  • Desktop/docs/use-cases#desktop
  • AI agents/docs/use-cases#agents
  • Videos/docs/use-cases#videos
  • Brand/docs/use-cases#brand
  • Start building/docs/ai-agents
  • Set up once/docs/ai-agents#set-up-once
  • Ask in plain words/docs/ai-agents#ask-in-plain-words
  • What your agent does/docs/ai-agents#what-your-agent-does
  • MCP server/docs/mcp
  • Masko for Cursor/docs/ai-tools/cursor
  • Masko in ChatGPT/docs/ai-tools/chatgpt
  • Start here/docs/tutorials#start-here
  • All tutorials/docs/tutorials
  • Create your first mascot/docs/tutorials/first-mascot
  • Create an animated character/docs/tutorials/first-animation
  • Make a character talk/docs/tutorials/make-it-talk
  • Put your mascot on your website/docs/tutorials/mascot-on-your-website
  • Guide onboarding with a talking mascot/docs/tutorials/web-onboarding-mascot
  • Add a mascot that celebrates progress and welcomes users back/docs/tutorials/web-progress-companion
  • Add a talking support mascot in the bottom right/docs/tutorials/web-support-mascot
  • Show a mascot while your AI thinks/docs/tutorials/ai-loading-mascot
  • Give your AI agent a face/docs/tutorials/ai-agent-face
  • Animate the mascot you already have/docs/tutorials/animate-your-mascot
  • How to make Telegram stickers/docs/tutorials/telegram-stickers
  • How to make Discord stickers/docs/tutorials/discord-stickers
  • Quickstart: your first animation/docs/quickstart
  • Terminal quickstart/docs/terminal
  • API keys and workspaces/docs/authentication
  • CLI browser login/docs/authentication/cli
  • How mascots work/docs/how-mascots-work
  • Credits and costs/docs/credits
  • From text/docs/create/from-text
  • From an image/docs/create/from-image
  • From a website/docs/create/from-website
  • From a brand book/docs/create/from-brand-book
  • Reference images/docs/manage/references
  • What you can generate/docs/generation
  • Pose-to-animation walkthrough/docs/generate/workflow
  • Images and poses/docs/generate/images
  • Animations/docs/generate/animations
  • Talking animations/docs/generate/talking
  • Logos, backgrounds and stickers/docs/generate/design-assets
  • Cursor follower/docs/generate/cursor-follower
  • Batch generation/docs/generate/batch
  • Image and video exports/docs/manage/media-exports
  • Canvases and releases/docs/canvas
  • Build a canvas/docs/canvas/build
  • Canvas templates/docs/canvas/templates
  • Generate canvas assets/docs/canvas/generate-all
  • Export a canvas/docs/canvas/export
  • Overview and demo/docs/player
  • Play one animation/docs/player/one-animation
  • Play a canvas/docs/player/canvas
  • Hosting and file formats/docs/generate/cdn
  • File sizes/docs/generate/file-sizes
  • Float a mascot on your Mac/docs/integrations/desktop
  • Jobs and polling/docs/manage/jobs
  • Webhooks/docs/manage/webhooks
  • Manage mascots and assets/docs/manage/collections
  • All endpoints/docs/reference
  • Requests and responses/docs/reference/conventions
  • Errors and recovery/docs/reference/errors
  • Command line reference/docs/terminal/commands
  • TypeScript SDK/docs/sdk/typescript
  • Changelog/docs/reference/changelog
  • Migrate to mascots and canvases/docs/manage/studio-migration
Get an API key
Documentation

Give your AI agent a face

shop-app — claude
✻ Welcome to Claude Codecwd: ~/shop-app

    >

    Connected to Claude Code

    Waiting for Claude Code

    Your AI agent runs in the background. Your mascot shows what it is doing and tells you when it needs you. Each step of the agent sends an event, and each event moves the mascot to a new pose.

    20 min · 66 credits · Web, Mac, any agent

    1. Make the clips

    Start with one five-second loop per state: Idle, Thinking, Working, Needs approval, Done and Error. Send the six requests in one batch call, 11 credits each.

    {
      "requests": [
        {
          "type": "animation",
          "animation_model": "standard",
          "name": "Needs approval",
          "image_prompt": "waving one hand to get attention",
          "animation_prompt": "waves twice, then waits",
          "duration": 5,
          "loop": true
        }
      ]
    }

    Add the five other states to requests, then wait for the jobs and keep each clip's urls.webm and urls.hevc. Fun extras like Searching, Found it, Running tests and Deploying are one more request each.

    2. Get the events

    From Claude Code or Codex

    A hook is a command your agent runs at each event, with the event as JSON. Point every event at your app:

    {
      "hooks": {
        "UserPromptSubmit": [
          {
            "hooks": [
              {
                "type": "command",
                "command": "curl -s -m 1 -X POST localhost:4545/event --data-binary @- || true"
              }
            ]
          }
        ]
      }
    }

    Add the same entry for PreToolUse, PostToolUse, PermissionRequest, Notification, Stop, StopFailure and SessionEnd. Codex reads the same format from ~/.codex/hooks.json. Your app reads hook_event_name, and tool_name for tools, and picks the state:

    EventToolState
    UserPromptSubmitThinking
    PreToolUseGrep, Glob, ReadSearching
    PreToolUseEdit, WriteWorking
    PreToolUseBash running testsRunning tests
    PreToolUseBash running a deployDeploying
    PermissionRequest, NotificationNeeds approval
    StopDone
    StopFailureError
    SessionEndIdle

    Let a small model catch the moments

    The hook says which tool runs, not what the agent found. For moments like "found the bug" or "the build failed", send the agent's last words to a small OpenAI model and let it pick. Claude Code puts them in tool_response and last_assistant_message. With no hooks at all, like a chatbot or your own agent loop, the same call drives every state.

    const decision = await openai.decisions.create({
      model: 'gpt-6-luna',
      input: lastMessages,
      questions: [
        {
          type: 'choice',
          name: 'state',
          instructions: 'What is the AI agent doing now?',
          choices: [
            { value: 'thinking', description: 'Reads, plans or writes.' },
            { value: 'found_it', description: 'Just found the cause of a bug.' },
            { value: 'needs_approval', description: 'Asks the user for a yes.' },
            { value: 'done', description: 'Finished and reports back.' },
            { value: 'error', description: 'Something failed.' }
          ]
        }
      ]
    });

    It answers in about a third of a second. If it is unsure or slow, keep the current state.

    3. Show the right clip

    Put the clips in a canvas, one pose per state with a move on each state's input, release it and play the release with the Masko player. It switches clips without a blink. Your app only names the state:

    // mascot is the Masko player playing your canvas release.
    const states = ['thinking', 'working', 'done'];
    
    function show(state) {
      for (const name of states) mascot.set(name, name === state);
    }

    Next