# Masko API docs matching "talking" Showing top 3 results --- ## Talking mascot animations with voice slug: generate/talking url: https://masko.ai/docs/generate/talking # Talking animations Make your mascot say a line in its own voice, moving as it talks. You get MP4 and transparent WebM and HEVC with sound, the voice as MP3 and a word-timed transcript. Ko welcoming a new user, from this line: ```text [waves hello, cheerful] Welcome in! [leans in, whispering] Psst... the big orange button does everything. [points down, proud] That one! ``` ## 1. Give the mascot a voice A mascot has one voice; a variant uses the Original's until it gets its own. Get ideas, hear three samples, keep one. Every account can add voices. GET /v1/mascots/:id/voice/suggestions Ideas come from the mascot's references and description; `refresh=true` gives new ones. ```bash curl https://api.masko.ai/v1/mascots/MASCOT_ID/voice/suggestions \ -H "Authorization: Bearer $MASKO_API_KEY" ``` ```json { "data": { "ideas": [ { "title": "Cozy and warm", "description": "A round, cozy pond creature with a big belly. Male voice, warm and round, medium-low, smiling while he talks, relaxed and kind, easy natural pace. American accent." }, { "title": "Excited little sidekick", "description": "An excited little cartoon sidekick. Young male voice, fast and bouncy, high energy, can barely contain his excitement, slightly breathless and giggly. American accent." } ] } } ``` POST /v1/mascots/:id/voice/adjust Send a description and a `direction` such as "Older" or "A little grumpy" to get the rewritten text, the changes and new directions. Without `direction`, only directions come back. ```json { "data": { "description": "A round, cozy pond creature with a big belly. Male voice, warm and round, medium-high, smiling while he talks, relaxed and kind, easy natural pace. American accent.", "changes": [{ "from": "medium-low", "to": "medium-high" }], "directions": ["Younger", "More excited", "Slower", "Drier", "Sleepier"] } } ``` POST /v1/mascots/:id/voice/samples Three voices from one description reading the same line, for 1 credit. `sample_line` is optional. ```bash curl -X POST https://api.masko.ai/v1/mascots/MASCOT_ID/voice/samples \ -H "Authorization: Bearer $MASKO_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "description": "An excited little cartoon sidekick. Young male voice, fast and bouncy, high energy, slightly breathless and giggly. American accent." }' ``` ```json { "data": { "samples": [ { "id": "5b1c2d8e-8a0f-4c55-9f7e-1d2a3b4c5d61", "url": "https://storage.googleapis.com/...", "duration": 9.6 }, { "id": "6c2d3e9f-9b10-4d66-a08f-2e3b4c5d6e72", "url": "https://storage.googleapis.com/...", "duration": 8.3 }, { "id": "7d3e4f0a-ac21-4e77-b190-3f4c5d6e7f83", "url": "https://storage.googleapis.com/...", "duration": 9.3 } ], "sample_line": "Hi! I'm Gubby. I live in your app, and I love showing people around.", "cost_credits": 1, "expires_at": "2026-09-30T09:12:00Z" } } ``` PUT /v1/mascots/:id/voice Keep a sample within 24 hours; it replaces the current voice. `name` is optional. ```bash curl -X PUT https://api.masko.ai/v1/mascots/MASCOT_ID/voice \ -H "Authorization: Bearer $MASKO_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "sample_id": "7d3e4f0a-ac21-4e77-b190-3f4c5d6e7f83" }' ``` ```json { "data": { "object": "voice", "name": "Gubby's voice", "description": "An excited little cartoon sidekick. Young male voice, fast and bouncy, high energy, slightly breathless and giggly. American accent.", "sample_url": "https://storage.googleapis.com/...", "source": "original", "created_at": "2026-09-29T09:14:00Z" } } ``` - `GET /v1/mascots/{id}/voice` returns the voice or `null`. `source` is `original`, `variant` or `creator` (a Marketplace mascot using its creator's voice). - A new Original voice also applies to every variant without its own. - Variants use the same calls under `/v1/mascots/{id}/variants/{variantId}/voice`; `DELETE` there restores the Original's voice. ## 2. Write the line Send `speech.script` with bracketed movements where each starts. Bracketed words are never spoken; a feeling after a comma steers the voice. ```text [waves hello, excited] Hi! I'm Gubby. [points to the right] The docs are right here! ``` - A movement starts on the words after it. With no words after it, it leads into the next one, or plays in the closing silence. - Movements happen in place, so leaning in never changes the framing. - The voice only says what is written. To hear a laugh, write it: `[throws its head back, laughing] Ha ha!`. - Or send `speech.text` with an optional `speech.direction`, such as "excited, points at the docs at the end". Masko writes the movements and returns the script. - `speech.language` takes an ISO 639-1 code such as `fr`; without it, the language is detected from the words. Length follows the speech, up to 5 minutes. Longer than 15 seconds, the voice is recorded once and cut at real pauses into 5 to 15 second takes; each starts and ends on the start image, so the mascot returns to that pose at cuts and pauses can grow slightly. ## 3. Estimate for free Add `dry_run: true` to get the script and estimate without charging or generating. ```bash curl -X POST https://api.masko.ai/v1/mascots/MASCOT_ID/generate \ -H "Authorization: Bearer $MASKO_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "type": "animation", "item_id": "ITEM_ID", "speech": { "text": "Hi! I'\''m Gubby. Here'\''s how the Masko API works.", "direction": "excited about what he does" }, "dry_run": true }' ``` ```json { "data": { "dry_run": true, "script": "[waves hello, excited] Hi! I'm Gubby. [opens an arm to the right] Here's how the Masko API works.", "estimate": { "speech_seconds": 4.3, "duration": 6, "max_duration": 6, "credits": 12, "too_long": false } } } ``` ## 4. Generate POST /v1/mascots/:id/generate Send an animation with `speech`. It starts from `item_id` or `source_image_asset_id` and ends on `end_image_asset_id`, or its start image; `variant_id` also picks that variant's voice. ```bash curl -X POST https://api.masko.ai/v1/mascots/MASCOT_ID/generate \ -H "Authorization: Bearer $MASKO_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "type": "animation", "item_id": "ITEM_ID", "end_image_asset_id": "END_IMAGE_ID", "speech": { "script": "[waves hello, excited] Hi! I'\''m Gubby. [opens an arm to the right] Here'\''s how the Masko API works." } }' ``` ```json { "data": { "job_id": "3c4d5e6f-7a8b-4c9d-8e0f-1a2b3c4d5e6f", "status": "pending", "type": "animation", "animation_model": "standard", "item_id": "4b5c6d7e-8f90-4a1b-9c2d-3e4f5a6b7c8d", "item_name": "Hi, I'm Gubby", "estimated_cost": 12, "estimate": { "speech_seconds": 4.3, "duration": 6, "max_duration": 6, "credits": 12, "too_long": false }, "script": "[waves hello, excited] Hi! I'm Gubby. [opens an arm to the right] Here's how the Masko API works.", "asset_ids": { "video": "5d6e7f80-91a2-4b3c-8d4e-5f6a7b8c9d0e", "webm": "6e7f8091-a2b3-4c4d-9e5f-6a7b8c9d0e1f", "hevc": "7f8091a2-b3c4-4d5e-8f6a-7b8c9d0e1f20", "audio": "8091a2b3-c4d5-4e6f-9a7b-8c9d0e1f2031", "transcript": "91a2b3c4-d5e6-4f7a-8b8c-9d0e1f203142" }, "poll_url": "/api/v1/jobs/3c4d5e6f-7a8b-4c9d-8e0f-1a2b3c4d5e6f?api_version=2026-09-26" } } ``` It costs **2 credits per second**. The request charges for `estimate.max_duration`, the longest the line could need, and refunds unused seconds once the voice is recorded; the job's `cost_credits` shows the final price. Poll `https://api.masko.ai/v1/jobs/JOB_ID?api_version=2026-09-26` ([jobs and polling](/docs/manage/jobs)) and retry safely with the same `Idempotency-Key`. ## The transcript Fetch the `transcript` JSON from the `file_url` of `GET /v1/assets/{id}`. Times are seconds from the first video frame, silence included, and `lines` end at `.`, `!` or `?` for captions. ```json { "text": "Hi! I'm Gubby. Here's how the Masko API works.", "language": "en", "duration": 6, "words": [ { "text": "Hi!", "start": 0.26, "end": 0.6 }, { "text": "I'm", "start": 0.92, "end": 1.04 }, { "text": "Gubby.", "start": 1.16, "end": 1.5 }, { "text": "Here's", "start": 2.04, "end": 2.24 }, { "text": "how", "start": 2.26, "end": 2.38 }, { "text": "the", "start": 2.42, "end": 2.5 }, { "text": "Masko", "start": 2.54, "end": 2.9 }, { "text": "API", "start": 3.0, "end": 3.46 }, { "text": "works.", "start": 3.56, "end": 3.9 } ], "lines": [ { "text": "Hi! I'm Gubby.", "start": 0.26, "end": 1.5 }, { "text": "Here's how the Masko API works.", "start": 2.04, "end": 3.9 } ], "movements": [ { "text": "waves hello, excited", "start": 0.26, "end": 2.04 }, { "text": "opens an arm to the right", "start": 2.04, "end": 3.9 } ] } ``` The `audio` asset is the voice alone as MP3; video assets report `has_audio: true` in their metadata. ## What a line can do Tubey, a robot whose screen is his face, shows one ability per clip (his real lines also asked for a pixel mouth). **Whisper, shout and laugh.** ```text [raises one hand beside his screen, whispering] I can whisper a little secret... [throws both fists up, excited] or shout the big news! [shakes with laughter, laughing] Ha ha! ``` **Several languages in one line.** ```text [waves, happy] I speak your language too. [waves with both hands, excited] Bonjour ! ¡Hola! Ciao! [puts a hand on his chest, proud] And my voice was made from my look. ``` **Act with the mascot's own features**, such as Tubey's screen. ```text [his screen shows a big pixel heart, happy] I love this feature. [his screen shows a question mark, curious] Any questions? [his screen shows two smiling eyes, calm] Just ask. ``` ## Limits - `speech` needs a start image: `item_id` or `source_image_asset_id`. - The line sets the length, so `speech` refuses `duration`, `loop`, `reverse`, `auto_reverse`, `sizes`, `animation_prompt`, `image_prompt` and the image crops. Talking uses Standard; `animation_model: "premium"` is refused. - A mascot without a voice returns `409` with `details.reason: "voice_required"`, before any charge. - A talk longer than 5 minutes returns `400`; split it into two animations. - A minute of talk is about 12 MB in WebM and 30 MB in HEVC at 720 px; see [file sizes](/docs/generate/file-sizes). - Talking animations cannot be reversed or edited, since the voice would not follow. For a new take, resend the script. - `generate-batch` does not accept `speech`; send each talking animation to `/generate`. --- ## Guide onboarding with a talking mascot | Masko tutorial slug: tutorials/web-onboarding-mascot url: https://masko.ai/docs/tutorials/web-onboarding-mascot # Guide onboarding with a talking mascot Build Fold’s three-step setup with Nori, a paper manta ray. The visitor names a workspace, creates a project, and sees the finished result. Nori speaks one short, captioned line at each stage. [Reference prompts and Masko v1 recipe](/docs/use-cases/web-onboarding) · [Download the full React examples](/examples/website-mascot-demos.zip) ## What you will build A responsive web interface with a new brand character, working interactions and transparent video playback. This tutorial uses **Fold**, a fictional product. The demo is free to try; generating your own assets spends your Masko credits. **What you need:** a React app, a Masko account, and a mascot’s published files or local downloads. Use Studio for generation, or keep a write API key on your server. Never ship the key in browser code. ## Create Nori for your brand ![Nori: approved character reference and animation recipe](/website-use-cases/nori-recipe.svg) Copy this reference prompt: ```text A friendly origami manta ray made of periwinkle and ivory folded paper, large dark eyes, a small apricot badge, soft tactile paper, calm smile, full character centered, no text or extra objects. ``` A little paper manta ray with a calm voice and an apricot badge. Nori makes a blank workspace feel less intimidating. Create the reference in [Studio](/mascots/new), or follow [Create a mascot from text](/docs/create/from-text). Keep the approved image as the mascot’s reference so future poses share its identity. The downloaded examples include the completed demonstration media; replace the files when you make your own character. ## Map the interaction states ![Nori: website states and clips](/website-use-cases/nori-flow.svg) Keep the form step separate from the clip. Failed validation or a failed save leaves the visitor on the current screen. In this demo, a talking clip plays once and holds its last frame until the next step; **Hear Nori** replays the current clip with sound. The idle loop is available in the source for a quieter resting state. These are website interaction states. Masko v1 creates the media; your app chooses which clip to show. [Copy the v1 requests](/docs/use-cases/web-onboarding#1-create-the-reference) for character creation, generation and file delivery. ## Make the animation set | Clip or moment | Performance or spoken line | Trigger | | -------------- | ------------------------------------------------------------------------- | ----------------------- | | Welcome | “Hi, I’m Nori. Let’s make a little space for your next big idea.” | Enter the first screen | | Guide | “Give your first project a name. One small step, and you’re ready to go.” | Workspace name accepted | | Done | “Your first project is ready. You’ve got this!” | First project created | Create a five-second idle loop from your approved image. Keep the camera still and the full character inside the frame. Then make the three talking clips below. ```text Gentle breathing, one friendly blink and a tiny paper-wing sway. Keep the full character centered and the camera still. End in the starting pose for a seamless loop. ``` [Animate an existing image](/docs/generate/animations#animate-an-existing-image) to avoid paying for a new pose when you already have the right one. Inspect the results before putting them in your interface. ## Give Nori a voice and record the lines In Studio, open **Context & References → Voice → Add a voice**. Try this description: ```text A calm, clear adult voice. Warm, lightly playful, unhurried conversational English. ``` Hear the samples and keep one. Each voice sample set costs 1 credit. For each line in the recipe table, create a **Talking animation** from the welcome pose. Add movements in brackets, such as `[waves gently, warm]`, and request a cost estimate before generating. For an API or coding agent, use the [talking tutorial](/docs/tutorials/make-it-talk) for voice samples, voice selection and job polling. Once the mascot has a voice, this request estimates one clip: ```typescript // Run on your server. Keep this helper out of browser code. async function masko(path: string, body: object, operationId: string) { const response = await fetch(`https://api.masko.ai/v1${path}`, { method: 'POST', headers: { Authorization: `Bearer ${process.env.MASKO_API_KEY}`, 'Content-Type': 'application/json', 'Idempotency-Key': operationId }, body: JSON.stringify(body) }); const result = await response.json(); if (!response.ok) throw new Error(result.error?.message ?? 'Request failed'); return result.data; } const request = { type: 'animation', item_id: welcomeItemId, speech: { script: '[waves gently, warm] Hi, I’m Nori. Let’s make a little space for your next big idea.' } }; const estimate = await masko( `/mascots/${mascotId}/generate`, { ...request, dry_run: true }, crypto.randomUUID() ); // Review estimate.estimate before sending the paid request. // Use a unique Idempotency-Key and the identical body on retries. ``` Generate your actual scripted lines from the table, not the example greeting above. Wait for the job and its WebM and HEVC files to complete before adding the result to the app. ## Get files that are ready to ship Download the transparent PNG, WebM and HEVC files into your project, or publish them to get stable CDN URLs. A completed MP4 alone is not proof that the transparent versions are ready: check the assets you intend to serve. Signed private URLs expire and should not be hardcoded into a shipped app. The source download uses `/website-use-cases/` for media. Copy that directory to your app’s `public/` folder, or change the URLs in `website-mascots.ts` to your published files. WebM serves Chrome, Firefox and Edge; HEVC with alpha serves Safari. ## Connect it to your web app Keep setup state in the app. Advance only after validation succeeds. In production, wait for the backend to create the workspace or project before changing the step; if it fails, keep the form open with a useful error. Put the clips in a [canvas](/docs/canvas/build) with one pose: its loop is the idle clip, and each line is an animation of that pose that starts on `action::` and the line's name. Release it, and your backend fetches its delivery ([Play a canvas](/docs/player/canvas)). The page then fires each line once, by name; the [Masko player](/docs/player) plays it when the loop on screen ends and goes back to idle. This small component shows the event wiring with local state. The source download includes the complete layout and production integration points. ```tsx import { useEffect, useRef, useState, type FormEvent } from 'react'; import { MaskoPlayer, type MaskoHandle } from '@masko/player/react'; const lines = ['welcome', 'guide', 'done']; const captions = [ 'Hi, I’m Nori. Let’s make a little space for your next big idea.', 'Give your first project a name. One small step, and you’re ready to go.', 'Your first project is ready. You’ve got this!' ]; // delivery: Nori's canvas release, fetched by your backend. export function SetupGuide({ delivery }) { const nori = useRef(null); const [step, setStep] = useState(0); const [workspace, setWorkspace] = useState(''); const [project, setProject] = useState(''); // Nori says the step's line once, when the loop on screen ends. useEffect(() => { nori.current?.fire(`action::${lines[step]}`); }, [step]); function submit(event: FormEvent) { event.preventDefault(); const name = step === 0 ? workspace : project; if (name.trim()) setStep((previous) => previous + 1); } return (

{captions[step]}

{step < 2 ? (
step === 0 ? setWorkspace(event.target.value) : setProject(event.target.value) } />
) : (

{workspace}: {project} is ready.

)}
); } ``` The downloaded demo contains the project form, back navigation, completion view and reset control. Put the spoken text next to the mascot, and keep the instruction beside the field. A screen reader can follow the flow without hearing the video. ## Use the full design [Download the React source and generated media](/examples/website-mascot-demos.zip). It contains all three independent designs. Choose **onboarding** for this tutorial: ```tsx import { WebsiteMascotDemo } from './WebsiteMascotDemo'; export default function Example() { return ; } ``` The archive includes the components, CSS module, media configuration and a README. Import the CSS module beside the components and keep your app’s existing React setup. The example plays each mascot with the Masko player, from a small canvas it builds from these clips in `website-mascot-delivery.ts`. In your app, play your own canvas release instead. Keep spoken lines visible as text. ## Check the finished experience Submit an empty or whitespace-only name: the step must stay put. Create a workspace, go back, and check that the name is preserved. Create the project and check that both names appear in the result. Replay each spoken line, mute it, then complete setup using only the keyboard. Test muted, with sound, with reduced motion, and with a keyboard. Check a narrow mobile viewport and both WebM and Safari’s HEVC playback. A failed media request should leave the still image or previous frame visible and offer a retry. ## Connect your real product Save setup to the signed-in account and restore the correct step after a reload. Keep essential instructions in text. Let returning users skip a guide they have already completed. ## Costs and what to measure Budget **1 credit for the reference image**, **10 for a five-second Standard idle loop from that image**, **1 for a voice sample set**, and **2 credits per second of talking**. Three talking clips have a five-second minimum each, so this recipe starts at about **42 credits**; the longer scripts in this example cost more. Use the talking estimate for your own lines. Exports and playback of downloaded or published files add no generation cost. The tutorial catalog shows estimates, not the cost of a visitor’s session. Compare setup completion, time to first project and next-day return rate with and without the guide. This demo illustrates the experience; it does not report a conversion lift. ## Ask Lovable to build your version ```text Build a project planning web app called Fold with a calm blue design. Use Masko to create Nori, a friendly paper manta ray. Add a three-step onboarding guide with captioned talking clips for welcome, the next setup step and completion. Let users name their workspace and create their first project. Keep sound optional and never cover the form. Follow https://masko.ai/docs/tutorials/web-onboarding-mascot. Use Masko v1 at https://api.masko.ai/v1 and inspect https://api.masko.ai/v1/openapi.json. Use real generated files, keep generation credentials on the server, and download or publish assets before shipping the app. ``` [Reference prompts and Masko v1 recipe](/docs/use-cases/web-onboarding) · [All website use cases](/docs/use-cases#website) --- ## Add a talking support mascot in the bottom right | Masko tutorial slug: tutorials/web-support-mascot url: https://masko.ai/docs/tutorials/web-support-mascot # Add a talking support mascot in the bottom right Build Leaf & Loom’s bottom-right support widget with Fern, a terracotta plant pot. A click opens help, the visitor chooses care or delivery, and a human handoff remains available. [Reference prompts and Masko v1 recipe](/docs/use-cases/web-support-mascot) · [Download the full React examples](/examples/website-mascot-demos.zip) ## What you will build A responsive web interface with a new brand character, working interactions and transparent video playback. This tutorial uses **Leaf & Loom**, a fictional product. The demo is free to try; generating your own assets spends your Masko credits. **What you need:** a React app, a Masko account, and a mascot’s published files or local downloads. Use Studio for generation, or keep a write API key on your server. Never ship the key in browser code. ## Create Fern for your brand ![Fern: approved character reference and animation recipe](/website-use-cases/fern-recipe.svg) Copy this reference prompt: ```text A friendly little terracotta plant pot with two jade leaves, large dark eyes, a small smiling mouth, short rounded arms and feet, warm clay texture, full character centered, soft 3D lighting, no text or extra props. ``` A little terracotta pot with jade leaves and a warm voice. Fern knows when to explain plant care and when to hand the conversation to a person. Create the reference in [Studio](/mascots/new), or follow [Create a mascot from text](/docs/create/from-text). Keep the approved image as the mascot’s reference so future poses share its identity. The downloaded examples include the completed demonstration media; replace the files when you make your own character. ## Map the interaction states ![Fern: website states and clips](/website-use-cases/fern-flow.svg) Keep panel visibility, selected topic and team contact as website state. **All help topics** returns to the menu. Closing or Escape returns focus to the launcher. Topic clips play once; the demo holds the last frame, and **Hear Fern** replays the line. Team contact uses the idle clip and a message form. These are website interaction states. Masko v1 creates the media; your app chooses which clip to show. [Copy the v1 requests](/docs/use-cases/web-support-mascot#1-create-the-reference) for character creation, generation and file delivery. ## Make the animation set | Clip or moment | Performance or spoken line | Trigger | | -------------- | -------------------------------------------------------------------------------------------------------------------------- | ---------------------- | | Greeting | “Hi, I’m Fern. Looking for plant care or delivery help?” | The visitor opens help | | Plant care | “Give your plant bright, indirect light. Check the soil before watering. Each plant comes with its own care card.” | Care selected | | Delivery | “Our example shop dispatches plants in two working days, packed with care. Your confirmation email has the tracking link.” | Delivery selected | Create a five-second idle loop from your approved image. Keep the camera still and the full character inside the frame. Then make the three talking clips below. ```text A tiny relaxed sway and a friendly blink; the jade leaves move gently. Keep the pot, arms and feet consistent. Full character in frame, still camera, seamless loop. ``` [Animate an existing image](/docs/generate/animations#animate-an-existing-image) to avoid paying for a new pose when you already have the right one. Inspect the results before putting them in your interface. ## Give Fern a voice and record the lines In Studio, open **Context & References → Voice → Add a voice**. Try this description: ```text A warm, practical adult voice with a gentle British accent, relaxed conversational pace. ``` Hear the samples and keep one. Each voice sample set costs 1 credit. For each line in the recipe table, create a **Talking animation** from the welcome pose. Add movements in brackets, such as `[waves gently, warm]`, and request a cost estimate before generating. For an API or coding agent, use the [talking tutorial](/docs/tutorials/make-it-talk) for voice samples, voice selection and job polling. Once the mascot has a voice, this request estimates one clip: ```typescript // Run on your server. Keep this helper out of browser code. async function masko(path: string, body: object, operationId: string) { const response = await fetch(`https://api.masko.ai/v1${path}`, { method: 'POST', headers: { Authorization: `Bearer ${process.env.MASKO_API_KEY}`, 'Content-Type': 'application/json', 'Idempotency-Key': operationId }, body: JSON.stringify(body) }); const result = await response.json(); if (!response.ok) throw new Error(result.error?.message ?? 'Request failed'); return result.data; } const request = { type: 'animation', item_id: welcomeItemId, speech: { script: '[waves gently, warm] Hi, I’m Fern. Looking for plant care or delivery help?' } }; const estimate = await masko( `/mascots/${mascotId}/generate`, { ...request, dry_run: true }, crypto.randomUUID() ); // Review estimate.estimate before sending the paid request. // Use a unique Idempotency-Key and the identical body on retries. ``` Generate your actual scripted lines from the table, not the example greeting above. Wait for the job and its WebM and HEVC files to complete before adding the result to the app. ## Get files that are ready to ship Download the transparent PNG, WebM and HEVC files into your project, or publish them to get stable CDN URLs. A completed MP4 alone is not proof that the transparent versions are ready: check the assets you intend to serve. Signed private URLs expire and should not be hardcoded into a shipped app. The source download uses `/website-use-cases/` for media. Copy that directory to your app’s `public/` folder, or change the URLs in `website-mascots.ts` to your published files. WebM serves Chrome, Firefox and Edge; HEVC with alpha serves Safari. ## Connect it to your web app Use a button as the launcher and keep the panel closed until the visitor chooses help. Fern appears beside the launcher when closed and inside the panel when opened. The widget stays inside the demo’s shop; on a real website, position the widget relative to the viewport with room for mobile safe areas. Put the clips in a [canvas](/docs/canvas/build) with one pose: its loop is the idle clip, and each line is an animation of that pose that starts on `action::` and the line's name. Release it, and your backend fetches its delivery ([Play a canvas](/docs/player/canvas)). The page then fires each line once, by name; the [Masko player](/docs/player) plays it when the loop on screen ends and goes back to idle. This small component shows the event wiring with local state. The source download includes the complete layout and production integration points. ```tsx import { useEffect, useRef, useState } from 'react'; import { MaskoPlayer, type MaskoHandle } from '@masko/player/react'; const answers = { welcome: 'Hi, I’m Fern. Looking for plant care or delivery help?', care: 'Give your plant bright, indirect light. Check the soil before watering. Each plant comes with its own care card.', delivery: 'Our example shop dispatches plants in two working days, packed with care. Your confirmation email has the tracking link.' }; // delivery: Fern's canvas release, fetched by your backend. export function ShopHelp({ delivery }) { const [open, setOpen] = useState(false); const [topic, setTopic] = useState('welcome'); const launcher = useRef(null); const fern = useRef(null); // Fern says the topic's line once, when the loop on screen ends. useEffect(() => { if (open) fern.current?.fire(`action::${topic}`); }, [open, topic]); function close() { setOpen(false); launcher.current?.focus(); } return (
{ if (event.key === 'Escape') close(); }} > {open && (

{answers[topic]}

)}
); } ``` The downloaded example includes a close control, Escape handling, focus returning to the launcher, topic buttons, captions and a local message preview. It never sends a customer message. Replace that preview with your support provider’s SDK or a server endpoint, and confirm successful delivery before telling the visitor the message was sent. The written answer is the source of truth. These talking clips contain prewritten lines. Your existing chatbot or help service supplies dynamic answers; Masko’s build-time connection does not turn those answers into live lip-synced speech. ## Use the full design [Download the React source and generated media](/examples/website-mascot-demos.zip). It contains all three independent designs. Choose **support** for this tutorial: ```tsx import { WebsiteMascotDemo } from './WebsiteMascotDemo'; export default function Example() { return ; } ``` The archive includes the components, CSS module, media configuration and a README. Import the CSS module beside the components and keep your app’s existing React setup. The example plays each mascot with the Masko player, from a small canvas it builds from these clips in `website-mascot-delivery.ts`. In your app, play your own canvas release instead. Keep spoken lines visible as text. ## Check the finished experience Open help with the keyboard, choose both topics, and check that the text and clip match. Close with Escape and confirm focus returns to the launcher. Try it on a narrow screen and verify product controls remain reachable. Preview a message: the page must clearly say it was not sent. Test muted, with sound, with reduced motion, and with a keyboard. Check a narrow mobile viewport and both WebM and Safari’s HEVC playback. A failed media request should leave the still image or previous frame visible and offer a retry. ## Connect your real product Replace the example care and delivery policies with your actual policies before publishing. Connect your support service, provide a human handoff, and keep a text fallback if video or sound cannot play. ## Costs and what to measure Budget **1 credit for the reference image**, **10 for a five-second Standard idle loop from that image**, **1 for a voice sample set**, and **2 credits per second of talking**. Three talking clips have a five-second minimum each, so this recipe starts at about **42 credits**; the longer scripts in this example cost more. Use the talking estimate for your own lines. Exports and playback of downloaded or published files add no generation cost. The tutorial catalog shows estimates, not the cost of a visitor’s session. Compare answered questions, successful support handoffs and purchase completion. A friendly mascot can support trust, while accurate answers and clear service policies do the work. ## Ask Lovable to build your version ```text Build a botanical ecommerce website called Leaf and Loom with forest green, cream and terracotta colors. Use Masko to create Fern, a friendly terracotta plant pot with jade leaves. Put Fern in the bottom right as a button that opens help. Add care and delivery topics with written answers and optional talking clips, plus a human support handoff. Keep checkout clear and sound off until clicked. Follow https://masko.ai/docs/tutorials/web-support-mascot. Use Masko v1 at https://api.masko.ai/v1 and inspect https://api.masko.ai/v1/openapi.json. Use real generated files, keep generation credentials on the server, and download or publish assets before shipping the app. ``` [Reference prompts and Masko v1 recipe](/docs/use-cases/web-support-mascot) · [All website use cases](/docs/use-cases#website)