Fish Audio
Generates one free S2.1 Pro voice clip for each scene.
FISH_STUDIO_APIKEYTeach a real idea through a familiar story world people already understand.
By Shaz · Updated July 2026
Before you start
Generates one free S2.1 Pro voice clip for each scene.
FISH_STUDIO_APIKEYFinds character, background, and instrumental music candidates only when a story world is not already packaged.
SERPER_API_KEYSetup, validation & inspection
node · ffmpeg · ffprobe · uvx · remotion
Typical run estimate
Usually $0 provider cost and 5-15 min with a packaged world
Estimates describe the saved recipe, not a price guarantee. Confirm current provider pricing and approve any spend before generation. Your coding agent may have its own fees or usage limits. Never paste API keys into chat.
Included assets
The published package includes its agent instructions, input contract, and quality rules, plus 24 viewable asset references below. Reference media teaches the recipe; it is not a new result for your input.

Characters · packaged asset

Characters · packaged asset

Characters · packaged asset

Characters · packaged asset

Characters · packaged asset

Characters · packaged asset

Characters · packaged asset

Characters · packaged asset

Characters · packaged asset

Characters · packaged asset

Characters · packaged asset

Characters · packaged asset

Backgrounds · packaged asset

Backgrounds · packaged asset

Backgrounds · packaged asset

Backgrounds · packaged asset

Backgrounds · packaged asset

Backgrounds · packaged asset

Backgrounds · packaged asset

Backgrounds · packaged asset

Backgrounds · packaged asset

Backgrounds · packaged asset

Backgrounds · packaged asset

Backgrounds · packaged asset
Examples
6 saved examples for this recipe—not 6 separate Repos. Each example keeps its original version and provenance.
From input to output
From the published SKILL.md. The agent follows the packaged runtime and its approval gates.
Step 01
Read this file, requirements.json, worlds/<world>.json, layouts.json, scene-contract.json, prompts/script-system.md, and quality.json.
Step 02
Run npm run smoke, then run check. If either fails, stop and report the exact missing local requirement. If check reports a missing key, ask the user to add the named key to .env.local. Never ask them to paste a secret into chat and never print its value.
Step 03
Run init, then write 12–18 short scene records in the new run's scene-plan.json.
Step 04
Use only packaged role names, backgrounds, layout IDs, and assets. Do not invent character coordinates.
Step 05
Run validate before any media call. Fix every validation error first.
Step 06
Show the user the scene plan, scene count, cast, and estimated duration. If any media call may cost money, ask once for approval covering no more than three total render attempts.
Step 07
Run render --approve-loop for the first attempt. Later attempts use render without that flag.
Step 08
Run inspect. Look at the full video and contact sheet. Record only concrete problems in quality-report.json.
Step 09
Fix only the problems you found. Do not rewrite good scenes. Render and inspect again when needed.
Step 10
Run finalize only when every automatic and human review check passes.
Proof & quality
The examples above are saved reference outputs. They are not evidence that a new input has passed the quality checks.
These are the acceptance criteria in quality.json—not a claim that every pictured example passed the current version. Inspect each new output before finalizing.
Open the package
Actual files from the published v1.2.0-experiment package. Expand any file to inspect the instructions, requirements, or evidence before sending the Repo to your agent.
# Cartoon Explainer Turn a real lesson into a short conversation between familiar characters. A curious lead asks the obvious questions, an expert explains the idea through the story world, and a third character adds tension or a joke. This package is the first Wiggly Format repository experiment. It contains the instructions, inputs, assets, prompts, scene slots, renderer, audio rules, quality checks, and exact run records needed to recreate its outputs. An agent can operate the package without an OpenRouter planning call. Start with `SKILL.md`; it explains how to check requirements, create and validate a scene plan, request one render-loop approval, inspect the result, and stop after three attempts. ## Start from the public Wiggly Repo 1. Download and unzip the **Runnable Format Kit**. 2. Open its `v3` folder and run `npm install`. 3. Run `npm run smoke`. This free local test proves the renderer, assets, FFmpeg, Remotion, and audio mix work. 4. Copy `.env.example` to `.env.local` and add the requested key values. 5. Tell Claude or Codex: “Read `public/format-repositories/otaku-explainer-v1/SKILL.md` and use the packaged renderer. Do not rebuild it.” The kit contains the real runner, renderer, dependencies, rules, layouts, and required assets. A fresh agent may write a new scene plan or story-world pack, but it must not recreate the renderer or timing pipeline. ## Formula 1. Open with a question that names the confusing idea. 2. Explain it one step at a time through story-world objects and actions. 3. Let the challenger introduce a believable mistake, warning, or joke. 4. Correct the mistake and complete the lesson. 5. End with the lead character saying the core idea back in one simple line. Each scene uses the same visual grammar: a slowly panning story-world background, two or three grounded character cutouts, one visible speaker, one speech bubble, and an optional short callout. Scene writers choose lesson roles and an approved layout. `worlds/*.json` maps the roles to characters and voices, while `layouts.json` owns the coordinates. This keeps a new topic from inventing a new renderer. ## Agent commands From `v3`: ```bash npm run smoke npm run prototype:otaku -- check npm run prototype:otaku -- init --run=<run-id> --topic="<topic>" --world=naruto npm run prototype:otaku -- validate --run=<run-id> npm run prototype:otaku -- render --run=<run-id> --approve-loop npm run prototype:otaku -- inspect --run=<run-id> npm run prototype:otaku -- finalize --run=<run-id> ``` The Fish key stays in `v3/.env.local`. Serper is needed only when a run adds a new story world. `SKILL.md` tells the agent how to research lore, choose voices, source and inspect assets, and create the world pack without adding another command or changing the renderer. The package never needs OpenRouter, Replicate, a GPU, image generation, or video generation. ## Proof runs The Format page discovers every packaged world from `worlds/*.json`, every scene plan from `scenes/*.json`, and every finished proof from `outputs/*.run.json`. These files are the source of truth; the README and page do not maintain separate lists. Every proof uses the same scene contract and `renderer/OtakuFormatRenderer.tsx`. The tracked videos, contact sheets, run records, and quality reports show whether the agent loop works across topics and story worlds. ## Editing Assets and deterministic scene values can be replaced without regenerating the script. Changing a prompt or instruction marks the package **Needs rerun**, because an old output must never pretend to reflect a new prompt.
--- name: otaku-explainer-format description: Use the Cartoon Explainer Format to make a short story-world lesson video without asking the user to explain how the Format works. --- # Cartoon Explainer Agent Loop You are operating a complete runnable Wiggly Format Kit. The user supplies a topic and chooses a packaged story world. This folder supplies the cast, voices, backgrounds, layouts, renderer, runner, audio rules, and quality checks. ## Use the packaged runtime Do not rebuild, replace, translate, or imitate the renderer. Run the renderer and runner already included in this kit. A different framework or a new scene-timing loop is a failed use of the Format, even when its final video looks similar. If you received the public Wiggly Repo URL, download and unzip the **Runnable Format Kit** first. Open its `v3` folder, run `npm install`, copy `.env.example` to `.env.local`, and add only the missing key values. Then follow the commands below. The renderer deliberately adds a soft glow around the active speaker. This hides rough transparent-image edges and makes the speaker obvious. Preserve that behavior. ## Commands Run commands from the downloaded kit's `v3` folder: ```bash npm run smoke npm run prototype:otaku -- check npm run prototype:otaku -- init --run=<run-id> --topic="<topic>" --world=naruto npm run prototype:otaku -- validate --run=<run-id> npm run prototype:otaku -- render --run=<run-id> --approve-loop npm run prototype:otaku -- inspect --run=<run-id> npm run prototype:otaku -- finalize --run=<run-id> ``` Run `npm run smoke` first. It makes a tiny local test video and verifies the packaged renderer, assets, FFmpeg, Remotion, and audio mix without calling Fish or any paid provider. `--approve-loop` records permission for one initial render and up to two focused improvement renders without storing secrets. If the configured voice model is free and the user already asked the agent to make the video, that request is enough; do not interrupt them for another approval. Ask first when a provider may charge money. ## Required loop 1. Read this file, `requirements.json`, `worlds/<world>.json`, `layouts.json`, `scene-contract.json`, `prompts/script-system.md`, and `quality.json`. 2. Run `npm run smoke`, then run `check`. If either fails, stop and report the exact missing local requirement. If `check` reports a missing key, ask the user to add the named key to `.env.local`. Never ask them to paste a secret into chat and never print its value. 3. Run `init`, then write 12–18 short scene records in the new run's `scene-plan.json`. 4. Use only packaged role names, backgrounds, layout IDs, and assets. Do not invent character coordinates. 5. Run `validate` before any media call. Fix every validation error first. 6. Show the user the scene plan, scene count, cast, and estimated duration. If any media call may cost money, ask once for approval covering no more than three total render attempts. 7. Run `render --approve-loop` for the first attempt. Later attempts use `render` without that flag. 8. Run `inspect`. Look at the full video and contact sheet. Record only concrete problems in `quality-report.json`. 9. Fix only the problems you found. Do not rewrite good scenes. Render and inspect again when needed. 10. Run `finalize` only when every automatic and human review check passes. ## Add a story world When the user asks for a story world that is not packaged: 1. Run `check --needs-new-assets`. Ask for missing key names without exposing their values. 2. Research the show's characters, relationships, locations, and lore. Record the sources you used. 3. Map one character to each lesson role: learner, guide, and challenger. Keep the renderer, layouts, and scene contract unchanged. 4. Search Fish Audio's public models for each character, audition available samples, and record the chosen model IDs and why they fit. 5. Use Serper to find full-body character cutouts and wide backgrounds. Follow `prompts/image-search.md`; prefer existing transparent assets and use local cleanup when needed. 6. Source one quiet instrumental track using the music procedure below. 7. Add the inspected files and provenance to `assets.json`, then create `worlds/<world>.json` with the cast, voices, backgrounds, useful lore, claims to avoid, and selected music. 8. Validate the new world before rendering. If it requires special renderer, runner, layout, or schema code, stop: the Format is not portable yet. Do not generate images unless the user separately approves it. Do not add an automated world-building workflow; the agent performs and documents this work. ### Source story-world music 1. Search Serper for `"<story world> background music instrumental"` and inspect the top three credible results. 2. Prefer an exact official or studio instrumental over a cover, remix, or re-orchestration unless the Format calls for one. 3. Download audio with `uvx yt-dlp --no-playlist -x --audio-format mp3 --audio-quality 0 <url>`. 4. Use FFprobe and FFmpeg to check duration, loudness, clipping, and trailing silence. Remove dead air, normalize with `loudnorm=I=-14:TP=-1.5:LRA=11`, and use a one-second crossfade when looping the track to the video length. 5. Verify that the loop has no silent seam and dialogue remains clear. If you cannot hear the candidates, do not claim that you auditioned them: use metadata and technical checks, then show the user playable options when taste affects the decision. 6. Record `localPath`, `sourceUrl`, `volume`, and `selectionReason` in the world pack. Keep the Format's default music when no candidate passes. ## Good result A passing result: - teaches the topic accurately in language a nontechnical viewer can repeat; - sounds like a natural conversation, not a lecture pasted into character mouths; - uses a story-world analogy that stays consistent; - keeps every visible character grounded; - fits every line inside the speech bubble; - assigns the right voice to the active speaker; - uses a clean music loop that stays below the dialogue; and - leaves a clear final takeaway. ## Failure rules - Never render an invalid plan. - Never rebuild the packaged renderer or write a substitute timing/rendering pipeline. - Scene duration comes from the actual voice file. Never add arbitrary silence after a voice clip. - Use the full-length music bed prepared by the runner. Never loop a short track with a hard seam. - Never exceed three attempts for one run. - Never silently change providers or generate replacement images or video. - If the packaged world lacks an asset, stop and explain what is missing. Use Serper only after the user approves sourcing a new asset. - If attempt three still fails, stop and explain the blocker. Do not mark the run finished. - Do not expose, copy, log, or store API key values.
{
"environment": [
{
"name": "FISH_STUDIO_APIKEY",
"requiredFor": ["render"],
"description": "Generates one free S2.1 Pro voice clip for each scene."
},
{
"name": "SERPER_API_KEY",
"requiredFor": ["new-story-world-assets"],
"description": "Finds character, background, and instrumental music candidates only when a story world is not already packaged."
}
],
"localTools": [
{ "name": "node", "requiredFor": ["check", "init", "validate", "render", "inspect", "finalize"] },
{ "name": "ffmpeg", "requiredFor": ["render", "inspect", "new-story-world-assets"] },
{ "name": "ffprobe", "requiredFor": ["render", "inspect", "new-story-world-assets"] },
{ "name": "uvx", "requiredFor": ["new-story-world-assets"] },
{ "name": "remotion", "requiredFor": ["render"] }
],
"notUsed": [
"OpenRouter",
"Replicate",
"GPU",
"image generation",
"video generation"
],
"secretPolicy": "Read keys from the downloaded kit's v3/.env.local. Never write secret values to plans, logs, reports, or run records."
}
{
"fields": [
{
"id": "topic",
"label": "What should the characters explain?",
"type": "text",
"required": true
},
{
"id": "storyWorld",
"label": "Which story world should teach it?",
"type": "story-world",
"required": true,
"source": "worlds/*.json"
}
],
"defaults": {
"topic": "Compilers versus interpreters",
"storyWorld": "naruto"
}
}
{
"characters": [
{
"id": "naruto",
"label": "Naruto",
"localPath": "assets/images/naruto-clean.png",
"postprocess": "remove-white-and-trim",
"searchQuery": "Naruto Uzumaki full body transparent png render",
"sourcePage": "https://www.pngitem.com/middle/hJmTRwx_naruto-naruto-shippuden-anime-naruto-render-hd-png/",
"sourceUrl": "https://www.pngitem.com/pimgs/m/487-4873619_naruto-naruto-shippuden-anime-naruto-render-hd-png.png"
},
{
"id": "kakashi",
"label": "Kakashi",
"localPath": "assets/images/kakashi-alpha.png",
"searchQuery": "Kakashi Hatake full body transparent png render",
"sourcePage": "https://freepngimg.com/png/32495-kakashi-hd",
"sourceUrl": "https://freepngimg.com/save/32495-kakashi-hd/900x2332"
},
{
"id": "orochimaru",
"label": "Orochimaru",
"localPath": "assets/images/orochimaru-clean.png",
"postprocess": "remove-white-and-trim",
"searchQuery": "Orochimaru full body transparent png render",
"sourcePage": "https://www.pngitem.com/middle/iJbimTT_renders-de-naruto-y-naruto-shippuden-naruto-orochimaru/",
"sourceUrl": "https://www.pngitem.com/pimgs/m/282-2823667_renders-de-naruto-y-naruto-shippuden-naruto-orochimaru.png"
},
{
"id": "yugi",
"label": "Yugi",
"localPath": "assets/images/yugi-clean.png",
"postprocess": "remove-checkerboard-and-trim",
"searchQuery": "Yami Yugi full body transparent png render",
"sourcePage": "https://www.pngaaa.com/detail/4492094",
"sourceUrl": "https://image.pngaaa.com/94/4492094-middle.png"
},
{
"id": "kaiba",
"label": "Kaiba",
"localPath": "assets/images/kaiba-clean.png",
"postprocess": "remove-checkerboard-and-trim",
"searchQuery": "Seto Kaiba full body transparent png render",
"sourcePage": "https://www.pngaaa.com/detail/4354853",
"sourceUrl": "https://image.pngaaa.com/853/4354853-middle.png"
},
{
"id": "joey",
"label": "Joey",
"localPath": "assets/images/joey.webp",
"searchQuery": "Joey Wheeler full body transparent png render",
"sourcePage": "https://all-worlds-alliance.fandom.com/wiki/Joey_Wheeler",
"sourceUrl": "https://static.wikia.nocookie.net/all-worlds-alliance/images/d/d2/JoeyWheelerMD.png/revision/latest/scale-to-width-down/340?cb=20200516064401"
},
{
"id": "danny-phantom",
"label": "Danny Phantom",
"localPath": "assets/images/danny-phantom.webp",
"searchQuery": "Danny Phantom full body transparent png render",
"sourcePage": "https://dannyphantom.fandom.com/wiki/Danny_Phantom_(character)",
"sourceUrl": "https://static.wikia.nocookie.net/dpwikia/images/3/3c/Render-_Danny_Phantom_stock_image.png/revision/latest?cb=20250529003148"
},
{
"id": "tucker-foley",
"label": "Tucker Foley",
"localPath": "assets/images/tucker-foley.webp",
"searchQuery": "Tucker Foley full body transparent png render",
"sourcePage": "https://dannyphantom.fandom.com/wiki/Tucker_Foley",
"sourceUrl": "https://static.wikia.nocookie.net/dpwikia/images/a/ac/Render-_Tucker_Foley.png/revision/latest?cb=20250529003317"
},
{
"id": "vlad-plasmius",
"label": "Vlad Plasmius",
"localPath": "assets/images/vlad-plasmius.webp",
"searchQuery": "Vlad Plasmius full body transparent png render",
"sourcePage": "https://dannyphantom.fandom.com/wiki/Vlad_Plasmius",
"sourceUrl": "https://static.wikia.nocookie.net/dpwikia/images/6/67/Render-_Vlad_Plasmius_pose.png/revision/latest?cb=20260610224348"
},
{
"id": "spongebob",
"label": "SpongeBob SquarePants",
"localPath": "assets/images/spongebob.webp",
"searchQuery": "SpongeBob full body transparent PNG stock art",
"sourcePage": "https://spongebob.fandom.com/wiki/SpongeBob_SquarePants_(character)/gallery",
"sourceUrl": "https://static.wikia.nocookie.net/spongebob/images/5/5f/SpongeBobStockArt-2D.png/revision/latest?cb=20251102074746"
},
{
"id": "sandy-cheeks",
"label": "Sandy Cheeks",
"localPath": "assets/images/sandy-cheeks.png",
"searchQuery": "Sandy Cheeks full body spacesuit transparent PNG render",
"sourcePage": "https://commons.wikimedia.org/wiki/File:Sandy_Cheeks_(transparent).png",
"sourceUrl": "https://upload.wikimedia.org/wikipedia/commons/thumb/9/95/Sandy_Cheeks_%28transparent%29.png/500px-Sandy_Cheeks_%28transparent%29.png"
},
{
"id": "plankton",
"label": "Plankton",
"localPath": "assets/images/plankton.webp",
"searchQuery": "Plankton full body transparent PNG stock art",
"sourcePage": "https://spongebob.fandom.com/wiki/Sheldon_J._Plankton/gallery",
"sourceUrl": "https://static.wikia.nocookie.net/spongebob/images/7/7a/Laughton.png/revision/latest?cb=20221113005908"
}
],
"backgrounds": [
{
"id": "konoha",
"label": "Konoha",
"localPath": "assets/images/bg-konoha.jpg",
"searchQuery": "Naruto Konoha village background no characters",
"sourcePage": "https://www.peakpx.com/en/hd-wallpaper-desktop-fzdbf",
"sourceUrl": "https://w0.peakpx.com/wallpaper/589/265/HD-wallpaper-konohagakure-anime-naruto-the-leaf-village.jpg"
},
{
"id": "naruto-forest",
"label": "Forest",
"localPath": "assets/images/bg-naruto-forest.jpg",
"searchQuery": "Naruto forest background no characters",
"sourcePage": "https://www.pinterest.com/ideas/naruto-backgrounds/941180977477/",
"sourceUrl": "https://s-media-cache-ak0.pinimg.com/originals/ed/ed/05/eded05d47a6e14ef62a7c275589f16bb.jpg"
},
{
"id": "training-ground",
"label": "Training ground",
"localPath": "assets/images/bg-training-ground.jpg",
"searchQuery": "Naruto training ground background no characters",
"sourcePage": "https://sketchfab.com/3d-models/training-field-naruto-stage-glb-c6cd7082ee864ec984b11f8cdaeefa64",
"sourceUrl": "https://media.sketchfab.com/models/c6cd7082ee864ec984b11f8cdaeefa64/thumbnails/f612af92dae545d2be1ec358e21e2b23/1e62e315d3684beab34923a07f51edd6.jpeg"
},
{
"id": "duel-arena",
"label": "Duel arena",
"localPath": "assets/images/bg-duel-arena.jpg",
"searchQuery": "Yu-Gi-Oh duel arena background no characters",
"sourcePage": "https://yugioh.fandom.com/wiki/Dueling_Arena",
"sourceUrl": "https://static.wikia.nocookie.net/yugioh/images/c/ce/DuelingArena-EN-Anime-DM.png/revision/latest?cb=20080930233413"
},
{
"id": "duel-club",
"label": "Duel club",
"localPath": "assets/images/bg-duel-club.jpg",
"searchQuery": "Yu-Gi-Oh classroom background no characters",
"sourcePage": "https://yugioh.fandom.com/wiki/Duel_Club",
"sourceUrl": "https://static.wikia.nocookie.net/yugioh/images/d/d0/Dc.png/revision/latest/scale-to-width-down/1200?cb=20170903092444"
},
{
"id": "domino-city",
"label": "Domino City",
"localPath": "assets/images/bg-domino-city.jpg",
"searchQuery": "Yu-Gi-Oh city background no characters",
"sourcePage": "https://backgrounds.gallery/backgrounds/753/1150640-Paradise%20City",
"sourceUrl": "https://steamcdn-a.akamaihd.net/steamcommunity/public/images/items/1150640/cacb64095456a03c8e04e9e886d938c1f504d29c.jpg"
},
{
"id": "amity-park",
"label": "Amity Park",
"localPath": "assets/images/bg-amity-park.webp",
"searchQuery": "Danny Phantom Amity Park street background no characters wide",
"sourcePage": "https://dannyphantom.fandom.com/wiki/Amity_Park",
"sourceUrl": "https://static.wikia.nocookie.net/dpwikia/images/c/c0/S01e16_AP_welcome_sign.png/revision/latest?cb=20160627025704"
},
{
"id": "fenton-lab",
"label": "Fenton lab",
"localPath": "assets/images/bg-fenton-lab.webp",
"searchQuery": "Danny Phantom Fenton lab background no characters",
"sourcePage": "https://dannyphantom.fandom.com/wiki/Fenton_Portal",
"sourceUrl": "https://static.wikia.nocookie.net/dpwikia/images/f/fe/S01e04_Fenton_Ghost_Portal.png/revision/latest?cb=20160428225359"
},
{
"id": "ghost-zone",
"label": "Ghost Zone",
"localPath": "assets/images/bg-ghost-zone.jpg",
"searchQuery": "Danny Phantom Ghost Zone landscape ground background no characters wide",
"sourcePage": "https://www.ign.com/wikis/nick-all-star-brawl/Ghost_Zone",
"sourceUrl": "https://oyster.ignimgs.com/mediawiki/apis.ign.com/nick-all-star-brawl/1/19/Ghost_Zone.jpg"
},
{
"id": "bikini-bottom",
"label": "Bikini Bottom",
"localPath": "assets/images/bg-bikini-bottom.webp",
"searchQuery": "SpongeBob Bikini Bottom city background no characters wide",
"sourcePage": "https://spongebob.fandom.com/wiki/Bikini_Bottom",
"sourceUrl": "https://static.wikia.nocookie.net/spongebob/images/2/26/Bubbletown_002.png/revision/latest/scale-to-width-down/1200?cb=20181028171458"
},
{
"id": "sandy-treedome",
"label": "Sandy's treedome",
"localPath": "assets/images/bg-sandy-treedome.webp",
"searchQuery": "Sandy treedome exterior background no characters wide",
"sourcePage": "https://spongebob.fandom.com/wiki/Sandy_Cheeks%27_treedome",
"sourceUrl": "https://static.wikia.nocookie.net/spongebob/images/f/f2/Sandy%2C_Help_Us%21_002.png/revision/latest/scale-to-width-down/1200?cb=20231007030731"
},
{
"id": "boating-school",
"label": "Mrs. Puff's Boating School",
"localPath": "assets/images/bg-boating-school.webp",
"searchQuery": "Mrs. Puff Boating School exterior background no characters wide",
"sourcePage": "https://spongebob.fandom.com/wiki/Mrs._Puff%27s_Boating_School",
"sourceUrl": "https://static.wikia.nocookie.net/spongebob/images/1/12/Lighthouse_Louie_001.png/revision/latest?cb=20200527190216"
}
]
}
{
"checks": [
{ "id": "same-renderer", "label": "Every proof uses the same renderer and scene contract." },
{ "id": "bubble-fit", "label": "Every line fits inside its speech bubble." },
{ "id": "grounded-characters", "label": "Feet or lower body meet a believable ground line." },
{ "id": "background-pan", "label": "Every scene has visible right-to-left background movement." },
{ "id": "voice-match", "label": "The active speaker uses the assigned Fish Audio voice." },
{ "id": "music-balance", "label": "Music has no vocals, clipping, or dead loop gap and stays below the dialogue." },
{ "id": "simple-language", "label": "A nontechnical viewer can repeat the lesson after watching." },
{ "id": "world-fit", "label": "The analogy uses objects and behavior from the selected story world." }
]
}
{
"provider": "fish-audio",
"model": "s2.1-pro-free",
"dialogue": {
"format": "wav",
"sampleRate": 44100,
"speed": 1.08
},
"music": {
"localPath": "assets/audio/background-music.mp3",
"volume": 0.1,
"loop": false,
"preparation": "The runner trims or crossfades the packaged track into one full-length music bed for each video."
}
}
{
"id": "otaku-explainer",
"version": "1.2.0-experiment",
"title": "Cartoon Explainer",
"description": "Familiar characters explain a real idea through their own story world.",
"status": "experimental",
"canvas": { "width": 720, "height": 1280, "fps": 30 },
"components": [
"instructions",
"user-inputs",
"fixed-assets",
"ai-generated-content",
"scene-slots",
"renderer",
"audio",
"quality-checks",
"final-output"
],
"renderer": "renderer/OtakuFormatRenderer.tsx",
"sceneContract": "scene-contract.json",
"sourceReference": "assets/reference/reference.mp4"
}
{
"name": "wiggly-otaku-explainer-format-kit",
"private": true,
"version": "1.0.0",
"type": "module",
"engines": {
"node": ">=22"
},
"scripts": {
"check:kit": "node kit-smoke.mjs",
"smoke": "tsx scripts/smoke-otaku-format.ts",
"prototype:otaku": "tsx scripts/otaku-format.ts",
"prototype:otaku:render": "tsx scripts/render-otaku-proofs.ts",
"test": "tsx tests/otaku-format-runtime.test.ts && node kit-smoke.mjs"
},
"dependencies": {
"@remotion/bundler": "4.0.473",
"@remotion/media": "4.0.473",
"@remotion/renderer": "4.0.473",
"react": "19.0.1",
"react-dom": "19.0.1",
"remotion": "4.0.473",
"tsx": "4.20.6"
}
}
{
"layouts": {
"two-balanced": [
{ "x": 8, "bottom": 2, "width": 52, "rotate": -1 },
{ "x": 56, "bottom": 3, "width": 41, "rotate": 0 }
],
"two-first-focus": [
{ "x": 8, "bottom": 2, "width": 58, "rotate": -2 },
{ "x": 60, "bottom": 3, "width": 36, "rotate": 0 }
],
"two-second-focus": [
{ "x": 8, "bottom": 3, "width": 45, "rotate": 0 },
{ "x": 52, "bottom": 2, "width": 47, "rotate": 1 }
],
"three-balanced": [
{ "x": 2, "bottom": 2, "width": 38, "rotate": -2 },
{ "x": 33, "bottom": 3, "width": 37, "rotate": 0 },
{ "x": 64, "bottom": 2, "width": 35, "rotate": 2 }
]
}
}
# Cartoon Explainer Format — morning report ## Result The Wiggly Repo successfully taught an agent to make a new lesson, research a new story world, assemble its world pack, and produce a finished video without changing the renderer, runner, layouts, or scene contract. | Proof | What changed | Scenes | Length | Attempts | Result | |---|---|---:|---:|---:|---| | Naruto explains compilers vs interpreters | Close rebuild of the reference | 18 | 1:14 | 1 | Pass | | Naruto explains MCP | New lesson, same story world | 15 | 1:03 | 1 | Pass | | Yu-Gi-Oh explains compilers vs interpreters | Same lesson, packaged world swap | 18 | 1:04 | 1 | Pass | | Naruto explains APIs | Agent-operated control run | 15 | 1:08 | 1 | Pass | | Danny Phantom explains APIs | Agent-researched world swap | 15 | 1:10 | 1 | Pass | | SpongeBob explains EVs | New world and new lesson | 15 | 1:02 | 2 | Pass | The Danny proof is the important result: the agent started with no Danny pack, researched the show and lore, selected voices, sourced and inspected six assets, wrote the lesson, validated it, rendered it, inspected it, and finalized it through the Repo instructions. The SpongeBob proof goes one step further: the agent changed both the story world and the lesson while keeping the renderer, runner, layouts, and scene contract unchanged. The first attempt exposed a short music loop; the second attempt changed only that asset and passed. ## Cross-world proof ### Naruto control  [Watch Naruto explain APIs](outputs/naruto-apis.mp4) The run used Naruto as learner, Kakashi as guide, and Orochimaru as challenger. All automatic and creative checks passed. ### Danny Phantom portability test  [Watch Danny Phantom explain APIs](outputs/danny-apis.mp4) The lesson maps the Fenton Portal to an API doorway, portal commands to requests, controls to endpoints, returned results to responses, details to parameters, and access keys to authentication. Danny, Tucker, and Vlad stay inside their intended lesson roles. ### SpongeBob portability test  [Watch SpongeBob explain EVs](outputs/spongebob-evs.mp4) SpongeBob learns how an electric boatmobile works, Sandy explains the battery, controller, inverter, motor, charging, and regenerative braking, and Plankton proposes a bad shortcut for Sandy to correct. The run used the existing layouts without adding SpongeBob-specific renderer code. ## New world evidence ### Selected voices | Role | Character | Fish voice ID | Why it was selected | |---|---|---|---| | Learner | Danny Phantom | `14f06ac475944bb7a0ef5cc958f07462` | Highest-use English result with a youthful, energetic sample | | Guide | Tucker Foley | `e3e1212180ee4f87ab0730db54d1a8e2` | Public English result with a friendly, energetic sample | | Challenger | Vlad Plasmius | `23231b8547f04d79bebc51bb2a23b5ab` | Exact English result with an appropriately confident delivery | ### Selected assets - Character cutouts: Danny, Tucker, and Vlad from their documented Danny Phantom Wiki pages. - Backgrounds: Amity Park, the Fenton lab and portal, and a Ghost Zone stage with visible ground. - Every query, source page, source URL, and local path is recorded in `assets.json`. - The canonical character files already had clean transparency, so no AI image generation or custom cleanup system was needed. ## What the Repo handled - Reported the required key names and local tools without exposing secret values. - Enforced 12–18 scenes, short dialogue, approved layouts, valid roles, valid backgrounds, and a three-attempt ceiling before media spending. - Mapped lesson roles to world-specific characters and Fish voices. - Turned role-based scenes into the existing renderer's character positions. - Generated a contact sheet and technical report after each render. - Refused finalization until every automatic and creative check passed. ## What the agent still decided - Which story-world idea best explains the lesson. - Which search results are clean enough to use. - Which Fish voice sounds closest to each character. - How to write natural dialogue and pace the lesson. - Whether the finished video is honestly good enough to finalize. Those are useful agent decisions, not missing framework code. ## Checks completed - Both new videos are 720×1280 H.264 with AAC audio. - Naruto API: 68.3 seconds; Danny API: 69.8 seconds. - Every scene has voice audio; speech bubbles fit; characters are grounded; the API lesson is accurate. - Existing Naruto and Yu-Gi-Oh proofs remain in the package. - Production `/create`, `/builder`, `/share`, `AdScene`, `AdRenderSurface`, and the Format registry remain untouched. ## Cost and boundaries Fish used the free developer voice model. Asset discovery stayed below the 20-search Serper cap. No OpenRouter, Replicate, GPU, image generation, AI video generation, or MCP was used. ## Honest limits - Page edits are still a local prototype; changing a file on the page does not write it back to disk or start a render. - Voice selection remains subjective even when public samples and usage data are available. - The agent can assemble a world pack, but a person should still review likeness, asset quality, and the story analogy before publishing.
{
"authoredScene": {
"id": "stable string",
"speakerRole": "learner | guide | challenger",
"visibleRoles": "two or three unique lesson roles; the speaker must be included",
"layout": "approved id from layouts.json",
"dialogue": "speech bubble and voice text, at most 100 characters",
"background": "background id approved by the selected world pack",
"estimatedDurationMs": "2000 to 8000",
"callout": {
"label": "optional short label, at most 14 characters",
"theme": "neutral | question | warm | cool | violet | gold"
}
},
"materializedScene": {
"speaker": "character asset id resolved from speakerRole",
"characters": "concrete placements resolved from visibleRoles and layout",
"voice": "Fish voice resolved from the selected world pack"
},
"run": {
"input": "exact topic and packaged story world",
"approval": "one approval covering at most three render attempts",
"provenance": "format, version, plan hash, world pack, layout file, and runner version",
"audio": "one generated clip per scene plus fixed music",
"inspection": "technical checks plus agent-reviewed creative checks",
"output": "final MP4 path"
}
}
Run it with a coding agent
The agent reads this version’s instructions, checks the requirements, and walks you through the approved workflow. Review the inputs and estimate before starting.
Typical run
Usually $0 provider cost and 5-15 min with a packaged world
You provide
The topic to explain · A packaged story world
Output
One vertical explainer MP4, usually 60-75 seconds