Make Video
You are the director. You design the video as a JSON scene plan ("props"), then a remote
render service turns it into a real MP4 (1080p H.264). Rendering takes about 10 seconds of
wall time per 1 second of video, and jobs may queue, so tell the user the video is being
rendered and that it takes a few minutes.
Credentials
Read the file render-token.json in this skill's own directory (next to this SKILL.md).
It contains {"url": ..., "token": ...}. Use them below. If the file is missing or the API
returns 401, tell the user to reinstall the make-video skill from the dashboard Skills page
(that regenerates the token). Never print the token into chat.
Daily limits by plan (the API enforces them): Lite 2 videos/day, Pro 10 videos/day. Free
trials do not include video rendering. If the API returns 429 with a limit message,
explain it to the user rather than retrying.
Render API
- Submit:
curl -s -X POST <url>/jobs -H "Authorization: Bearer <token>" \
-H 'Content-Type: application/json' --data @props-body.json
where props-body.json is {"composition":"Explainer","props":{...}} — schema below.
Returns {"jobId":"<id>"}.
- Poll every 30-60s (never faster):
curl -s <url>/jobs/<jobId> -H "Authorization: Bearer <token>"
-> {"status":"queued|running|done|failed","progress":0-100,"error":...}
If failed: read the error, fix the props, resubmit once. Two failures: show the user
the error and stop.
- Download when done:
curl -s -o video.mp4 <url>/jobs/<jobId>/video -H "Authorization: Bearer <token>"
Save into the workspace, then send the file to the user in the chat.
Props schema (composition "Explainer")
Top level: {"theme":"flat-motion-graphics","cuts":[...],"overlays":[],"captions":[],"audio":{}}
Each cut plays sequentially. Cut fields: id (slug), type, in_seconds, out_seconds,
plus type-specific fields. Keep total duration 20-90 seconds, 3-8 seconds per cut.
Reliable cut types:
- hero_title: {"text","subtitle","backgroundColor"} — opening/closing card
- section_title: {"text"} — divider
- text_card / callout: {"text","subtitle"} — body copy
- quote: {"text","attribution"}
- stat_card / stat_reveal: {"label","value","suffix"} — big numbers
- kpi_grid: {"items":[{"label","value"}]}
- bar_chart / line_chart / pie_chart: {"title","data":[{"label","value"}]}
- comparison: {"title","left":{"label","items":[...]},"right":{"label","items":[...]}}
- terminal_scene: {"title","lines":["$ command","output"]}
Set "source":"" on all of the above. Fields you are unsure about: leave out.
AI-generated footage (optional)
A cut with a non-empty "source" URL (public .jpg/.png or .mp4) renders that media
full-screen instead of its text layout. If your instance has image or video generation
available (for example a fal API key in your config), you can generate assets first and
reference their URLs as cut sources. Default to cheap models (e.g. FLUX schnell for
stills); use expensive video models only when the user explicitly asks and accepts the
cost. 1-3 assets per video is plenty. Confirm each URL returns 200 before submitting.
If you have no media generation available, make a clean text/stat/chart video instead —
do not fail the request.
Rules
- Design 5-10 cuts that tell one clear story: hook -> 3-6 points -> closing card.
- Prefer stats/charts when the user's content has numbers; text cards otherwise.
- Always deliver the actual MP4 file into the chat, not a link.
- Clean up temp files; keep only the final mp4 in the workspace.