| name | founder-product-video |
| description | Use when the user asks for founder product video or a task matching the examples below. Generate a 65-second founder-style product video from a product URL + user-supplied imagery. Output is a 16:9 1080p MP4 — 4 × 15s SeeDance acts of a talking founder + 5s branded end card + background music. The user's actual product screenshots are composited onto product reveal shots after Seedance generation, so readable UI and brand text are real, not AI-imagined. Triggers — "founder video", "product video", "60s pitch video", "make a video of [founder] for [URL]", "talking founder explainer". Requires Pika MCP. Uses a supplied brand kit folder (`brand.json` or an exported build-a-brand kit with `brand.md`, tokens, logo assets); if no kit exists, run build-a-brand first. |
| argument-hint | <product-url> --founder "<name, role>" [--photo <path|url|generate>] [brand-kit=<path>] [aspect=16:9|9:16|1:1] [--quick] [--config <path>] |
| required-capabilities | ["add_captions","analyze_brief","analyze_media","capture_website","edit_audio_mix","edit_concat","edit_video_compose","edit_text_overlay","extract_frame","generate_image","generate_music","generate_reference_video","generate_slide_animation","html_to_png","identity_balance","render_html_animation","task_status","task_cancel","upload_asset"] |
founder-product-video
You generate a 65-second founder-style product video from a product URL plus user-provided imagery: 60 seconds of talking-founder body video plus a 5-second branded end card. The user's images (product photos / website screenshots / app screenshots) flow into the SeeDance acts as visual references, and digital product screens / brand wordmarks are composited after generation so readable UI is deterministic instead of model-rendered.
No cutaways. No website CSS extraction. AI generation, deterministic render, captions, concat, and music mix go through Pika MCP tools by default. Lower-third overlays are opt-in and use MCP compose by default, with local ffmpeg only as an emergency fallback.
Cost transparency gate
Before any paid MCP call, call identity_balance({verbose: true}) once. Surface the current balance, recent burn rate, and remaining runway, then gate the run with this exact message:
Estimated cost: about 4,000 credits (~$40) for a typical four-act Seedance founder video plus supporting assets. This exceeds $5, so Reply proceed to continue or cancel to stop.
Do not call any paid MCP tool until the user replies proceed. If the user replies cancel, stop without generating. For non-interactive --quick or --config callers, require cost_ack=proceed in the config; if it is absent, stop with the estimate instead of spending credits.
[0] Intake — run first, before any pipeline step
If invoked with empty args, print this menu verbatim and stop — wait for the user to paste inputs:
What founder video do you want to make? Required:
- Product URL —
https://... (anything with a real homepage)
- Founder — name + role, e.g. "Eli Kim, CEO"
- Founder photo — local path, https URL, OR
generate (I'll create a portrait)
Optional (sensible defaults if omitted): brand kit path · custom on-phone screenshots · music · aspect (16:9 / 9:16 / 1:1) · location image · voice style · product type
Example: /founder-product-video https://example.com --founder "Eli Kim, CEO" --photo ~/Pictures/eli.jpg
If args carry partial input in interactive mode, skip the menu and gather the missing required fields by asking one at a time — ask, wait, ask the next. Don't bundle questions into one block. If the user supplies a field unprompted (e.g. they pasted a URL in the trigger message), skip that question and confirm the value back to them once at the end. Don't start the pipeline until all required fields are answered. If the non-interactive fast lane applies, use step [0.5] instead.
[0.5] Non-interactive fast lane
Use this path when the caller passes --quick or --config <path>, or when the
caller states they are running from CI, a subagent, a batch job, or any other
non-interactive harness.
This section has precedence over the interactive ask/wait instructions below.
When it applies, use this fast lane and do not fall through to the multi-turn
intake unless url or founder name/role is truly missing.
--config <path> points to a JSON file with pre-baked values for the canonical
input contract: url, brand_kit_path or build_brand, founder_name,
founder_role, founder_photo, assets, music_url, aspect_ratio,
location_image_url, voice_style, product_type, and lower_third.
--quick means use defaults for optional extras, auto-build the brand kit with
build-a-brand --quick if brand-kit is omitted, and use founder_photo = "generate" when no photo is supplied.
- For
--quick or --config, do not stop for confirmation at the brand-kit
branch, founder-photo generation prompt, optional-extras prompt, script
choices, or end-card/caption defaults. Record assumptions inline and continue.
- If
url or founder name/role cannot be found in args or config, stop once with
a single compact missing-fields list instead of starting a multi-turn Q&A loop.
1. Product URL (required) — https://.... Used to (a) derive the brief in step [1] and (b) feed the brand-kit branch below.
2. Brand kit (required) — interactive mode: ask "Do you already have a brand kit folder, or should I build one first?"
- If a path -> use it (
state.brand_kit_path = <path>). Accept either brand.json or an exported build-a-brand kit containing brand.md, tokens/tokens.json, and logo assets.
- If "build" -> invoke the
build-a-brand skill on the URL/brief and wait for the exported brand kit. This is a full identity workflow and may pause for user choices; surface those prompts in interactive mode.
- Fast lane: if config provides
brand_kit_path, use it. If config sets build_brand or --quick omits brand-kit, invoke build-a-brand --quick on the URL/brief and wait for the exported brand kit; do not surface build-a-brand prompts or stop for identity choices. After either branch, set state.brand_kit_path. Only stop with a single compact missing-fields list if there is no path and the brand kit cannot be built.
3. Founder identity (required) — interactive mode: ask all three together:
founder_name — e.g. "Avery"
founder_role — e.g. "CEO, ExampleCo"
founder_photo — local path / https URL / OR the literal string generate to auto-create a portrait. If generate, prompt the user for a 1-line vibe ("warm, casual smart attire" / "Pixar-style 3D animation" / etc.) — this becomes the seed prompt for generate_image in step [4].
- Fast lane: use founder values from args/config. If
founder_photo is omitted, set founder_photo = "generate" and use a neutral founder-portrait vibe derived from the product tone; do not stop for a separate photo-vibe prompt.
Default to no lower-third so the happy path stays lean. If the user explicitly asks for a lower-third, record state.lower_third = true; in interactive mode confirm that edit_video_compose will add the transparent overlay after rendering.
4. Optional extras — interactive mode: offer these once as a single message, then proceed without waiting if no answer comes back in the same turn. Fast lane: use the defaults below without asking.
- Custom imagery — list of
assets (product photos / app screenshots) shown on the founder's phone. Default if omitted: use screenshots from brand.json.screenshots when present, otherwise look for obvious screenshots or product images inside the brand kit, otherwise capture the product URL with capture_website(mode:"screenshot") before step [2]. Do not proceed to script or SeeDance without real product UI / product imagery unless product_type is explicitly service and the user accepts an environment-only video. In the fast lane, if no supplied/brand-kit/captured asset exists, stop once with a compact missing-assets error instead of silently shipping a generic talking-head video.
- Music — local path / https URL / OR
generate (instrumental, ~60s). Default: generate via Kling background mode.
- Lower-third — optional. Default: off. If enabled, render the transparent
.mov through MCP and overlay it onto the body with edit_video_compose.
- Aspect ratio —
16:9 (default), 9:16, 1:1.
- Location — defaults to a flat seamless backdrop in
state.brand.colors.accent (clean studio-shoot look, character against a single brand color, whatever the brand's accent is). Override with a path / URL / text description if the user wants office, outdoor, etc.
- Voice style — VO direction string for SeeDance, e.g. "warm authentic founder energy, conversational". Default: derived from
brief.tone.
- Product type —
digital | physical_apparel | physical_object | consumable | service. Default: auto-derived in step [2] from asset analyses.
After Stage 0 completes, store all gathered values in state.inputs. If you already created a local work directory for this run, optionally persist the same object as <workdir>/inputs.json; do not require a predefined work-directory environment variable. Then enter the pipeline at step [1].
[0.6] Avatar-type probe for founder photos
Before any paid generate_reference_video call, run this Avatar-type probe on the resolved founder photo/avatar URL after local upload or user-supplied URL normalization. This applies to any founder photo used as the character reference — whether supplied via --photo or generated.
Call analyze_media once:
query: "Classify this image for paid video generation. Is it a photograph of a real human face, an AI-generated realistic portrait, a stylized / illustrated character, or a recognizable trademarked / copyrighted character such as Batman, Pikachu, or Mickey Mouse? Return strict JSON only: { \"avatar_type\": \"real_human\" | \"ai_realistic\" | \"stylized_illustrated\" | \"recognized_ip\", \"recognized_character\": string | null, \"moderation_risk\": \"low\" | \"medium\" | \"high\", \"recommendation\": \"proceed\" | \"warn\" | \"reject\" }. Use null for `recognized_character` when no specific character is recognized; never write \"none\", \"unknown\", or explanatory prose in that field."
Route from the result:
- recognized IP / copyright risk -> STOP only when
avatar_type is "recognized_ip", or recognized_character names a specific character (for example "Batman"), or when both moderation_risk is "high" and recommendation is "reject". Treat recognized_character: null, empty string, "none", "unknown", "n/a", and low/medium moderation_risk as not enough to stop by themselves. Run this check before the real/stylized routes. A chibi Batman is still Batman even when avatar_type is stylized / illustrated.
- real human / AI-generated realistic -> proceed normally.
- stylized / illustrated -> proceed with a visible warning that stylized avatars may be less reliable for Seedance likeness and moderation, then continue only if the user supplied or accepted that avatar.
- trademarked / copyrighted -> STOP before generation. Surface this message:
Your founder photo appears to be a trademarked character ([X]). Most video providers will moderate this and refuse to generate. Pass --photo <real-looking-photo-url> to override. For this skill, --photo <real-looking-photo-url> is the accepted concrete flag; you may also mention the cross-skill --avatar <real-looking-photo-url> wording because users may know that convention.
Required inputs (canonical contract)
After Stage 0, these are the fields downstream steps consume:
url — the product website (https://). Drives step [1] brief.
brand_kit_path — brand kit folder. Required. End card AND lower-third consume brand.json when present, otherwise brand.md, tokens/tokens.json, and logo assets from a build-a-brand export. See step [4.5].
founder_name + founder_role + founder_photo — required from intake. Step [4] normalizes founder_photo into founder_photo_url and character_url before any SeeDance call.
assets — optional array of { url, role?, caption? }. Defaults to the screenshots captured by the brand kit; when the brand kit has no screenshots, capture the product URL before step [2] and store the returned image_url as a real product UI asset. role is a hint string mapping the asset to a script beat (hero, feature_a, cta, etc.).
location_image_url — optional. Defaults to a generated solid-color backdrop in state.brand.colors.accent.
music_url — optional. Defaults to generate (Kling 60s background bed in step [7]).
aspect_ratio — default 16:9.
voice_style — optional, defaults to brief.tone.
product_type — optional, auto-derived in step [2].
State
Keep a simple state object as you work and save every CDN URL there so a partial run can be resumed. Treat task_status value completed as the successful terminal state (failed and cancelled are the failure terminals), then unwrap result.structuredContent when present. The final video lives on Pika's CDN; no local workspace is required unless MCP compose is unavailable and you explicitly trigger the local lower-third fallback in step [8b].
Long-running task_status polling
When any long-running generation or edit call returns a task_id with or without an initial status, including {task_id}, {task_id, status: "queued"}, or an initial queued, running, or processing status, record the task id and start time immediately in state.
- Call
task_status({task_id}) in a tight loop until terminal (completed | failed | cancelled). No manual sleep and no Bash polling; the worker holds each status call open.
- Emit ONE visible progress line every 60s while status is
queued, running, or processing: Seedance i2v queued for {N}m {S}s... still processing. Replace the provider/stage label when polling music, captions, render, concat, mix, or edit tasks.
- On
completed, unwrap the returned result URL and save it into state.
- On
failed or cancelled, surface failure to the user with task_id, status, and the last status message.
- After 15 min total from the original submit, call
task_cancel({task_id}) if the task is still non-terminal, then surface failure to the user. If cancel reports the task is already terminal, call status once more and report that terminal result.
- Do not submit a duplicate request while the original task is still
queued, running, or processing.
Pipeline overview
[Stage 0] intake you (Claude): ask user for url + brand-kit (path or build) + founder (name/role/photo) + optional extras
→ [0.5] brand-kit auto-build (only if user said "build")
invoke `build-a-brand`; in non-interactive mode use `build-a-brand --quick`
→ [1] analyze_brief pika MCP: product name + tagline + features + tone + CTA
→ [2] resolve product UI assets pika MCP: use supplied/brand-kit screenshots, or capture_website(product URL)
→ [2] analyze_media × N pika MCP: understand what each real asset shows
→ [3] write script you (Claude): 4 acts × 15s; map assets to acts
→ [4] founder/location refs pika MCP: upload or generate founder ref; carry supplied custom location
→ [4.5] brand-kit ingestion parse brand.json OR brand.md + tokens → state.brand; generate default brand-accent location if needed
→ [5] generate_reference_video × 4 IN PARALLEL pika MCP: SeeDance acts, asset images as refs
→ [5.5] digital UI overlays pika MCP: composite real product UI / wordmark onto digital reveal acts + OCR QA
→ [6] edit_concat acts pika MCP: 60s stitched base (dialogue-only audio)
→ [7] generate_music pika MCP: Kling 60s soft instrumental background bed
→ [8] captions / lower-third pika MCP: add_captions for subtitles; render lower-third as transparent .mov, then overlay it with edit_video_compose when lower-third is enabled.
→ [9] render_html_animation pika MCP: 5s end card — author inline HTML, brand-kit fonts inlined, aspect matches body, no corner clutter, CSS @keyframes (NOT GSAP)
→ [10] edit_concat + audio_mix pika MCP: concat body + end card, then mix music over the full ~65s
→ [10.5] final duration probe pika MCP: analyze final_url and enforce the 55s duration floor before delivery
→ [11] final_url save the MCP returned final_url; upload only if a local fallback created the final MP4
→ [12] deliver
Operational notes
Keep the main workflow focused on sequencing. Historical server validation details live in references/ops-notes.md; only the active constraints stay here:
- Use a unique
seed per SeeDance act (101, 202, 303, 404). Identical generation params can replay cached failures.
- Kling music bed generation uses
provider: "kling-audio", mode: "text_to_audio", background: true, and duration_seconds: 60; the MCP worker generates one 10s Kling seed and extends it locally.
- If SeeDance rejects a real-person founder photo, re-roll the founder ref with stronger stylization rather than retrying the same rejected reference.
- For local brand-kit logos, upload only logo-appropriate raster assets (
image/png, image/jpeg, or image/webp). Do not send SVGs to upload_asset; choose the PNG export from build-a-brand or rasterize first.
- Use CSS
background-image: url(...) for CDN-hosted logo/photo assets in end-card HTML; <img crossorigin> is blocked by CDN CORS.
- Use server-side deterministic tools for captions, lower-third compose, concat, and mix. Local ffmpeg is only the fallback if
edit_video_compose is unavailable while state.lower_third = true.
- Decompose every 15s act into 3 time-coded sub-shots. Single-shot acts look static.
- Open each act with the style-match location framing and repeat the same
WARDROBE LOCK: sentence across all 4 act prompts.
[1] Analyze brief
analyze_brief(
sources=[{ type: "url", url: <product_url> }],
context: "Founder-style 60-second product video. Need: product name, one-line tagline, 3-5 key features, target audience, brand tone, and a call-to-action."
)
Save the result as brief. You'll reference brief.product_name, brief.tagline, brief.key_features, brief.tone, brief.call_to_action throughout.
[2] Resolve product UI assets, then analyze each asset + derive product_type
Before analyzing assets, normalize assets so product reveal shots have a real visual reference:
- Use any caller-provided
assets first.
- If none were supplied, read screenshots from
brand.json.screenshots when present.
- If
brand.json has no screenshots, look for obvious raster screenshots or product images inside the brand kit (screenshots/, assets/, product/, or image files named like hero, screen, app, dashboard, product).
- When
assets is empty after those checks, call capture_website on the product URL:
capture_website(
url: <product_url>,
mode: "screenshot",
mobile: false
)
# Save result.image_url as assets[0].url with role="website_capture".