HTML Animation Render (Simple)
Render a composition spec into a finished video (mp4): a video base track + custom HTML animation particles composited in one render. Built for full-screen opaque cut-ins / short clips / pure HTML animation (no long base track running through, or particles that fully cover the base) — lighter and faster. The visual vocabulary is not predefined or enumerated — you author the particles freely, as long as they follow the seekable HTML-animation format. Materials are referenced by composition.assets.file_id.
Which endpoint?
- This endpoint · Simple: particles are full-screen opaque cut-ins / short clips / pure HTML animation (no long base track running through) → use this, lighter and faster.
- HTML Animation Render (Layered): you have one long base track running through the whole piece (talking head / B-roll) with transparent particles overlaid on top, not covering the subject → use the layered endpoint.
- Both endpoints take the exact same input spec; pick by your scene.
Particle Format (Important)
Each custom HTML particle must be a self-contained, seekable HTML animation:
- Its root element must be wrapped in a
<template>:<template><div data-composition-id=...>…</div></template>, otherwise the particle cannot be parsed and the whole render fails; - It must declare its own
data-composition-id/data-width/data-height; - Its animation must be registered on a frame-seekable timeline (recommended: GSAP
gsap.timeline({paused:true})registered onwindow.__timelines). - ⚠️ A particle using only plain CSS
animation-delaywithout a registered timeline cannot be rendered frame-by-frame and will freeze at the animation's end state. Author particles in a seekable format.
Create Task
Basics
| Item | Value |
|---|---|
| Method | POST |
| Path | /task/html_render_simple |
| Content-Type | application/json |
| Auth | Authorization header (API Key directly) |
| Billing | By output duration (minutes) |
Request Body
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
composition | object | Yes | — | Composition spec, see below |
render | object | No | {} | fps (defaults to composition.fps or 30) / quality (draft/standard/high, default high) / output_format (mp4/webm/qtrle, default mp4) |
render object
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
fps | number | No | composition.fps or 30 | Render frame rate |
quality | string | No | high | draft / standard / high |
output_format | string | No | mp4 | Output mode (see below): mp4 = composite base + particles into a finished video → .mp4; webm = render the transparent particle layer only (beats-only) as VP8-alpha WebM → .webm; qtrle = render the transparent particle layer only (beats-only) as QuickTime Animation (qtrle, argb) alpha MOV → .mov |
output_format modes
mp4(default): the base track and particles are composited into one finished video (.mp4). A video base is processed outside the particle renderer; a composition without a video base keeps the single-pass path.webm: renders only the transparent particle layer (beats-only) as a VP8-alpha WebM (.webm). The base tracks do not participate in the composite (they stay local) — the WebM is meant to be decoded in the client browser via WebCodecs/mediabunny and composited natively on the client over the local base track.qtrle: renders only the transparent particle layer (beats-only) as a QuickTime Animation (qtrle, argb) alpha MOV (.mov), for import into JianYing as a transparent overlay material (JianYing only reliably ingests qtrle; webm / ProRes-alpha show a black background in JianYing).- Transparent-layer modes (
webm/qtrle):composition.tracksmay be empty (mp4still requires at least 1 track;webm/qtrlerelax this); the base tracks are not written into the output, and the output duration equals the end of the last beat.
composition object
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
video_size | object | Yes | — | {"width":w,"height":h} |
fps | number | No | 30 | Output frame rate |
duration | number | No | auto | Output duration (s); derived from max track/particle end if omitted |
assets | object | Yes | — | Material refs, must contain file_id: {asset_name: platform_file_id} (base tracks and any file_id-referenced particles) |
tracks | array | Yes | — | Base tracks (video/audio), at least 1 for mp4; may be empty under the transparent-layer modes (render.output_format = webm / qtrle), where the base does not enter the output |
beats | array | No | [] | Custom HTML animation particle overlays |
tracks[] base-track object
| Field | Type | Required | Description |
|---|---|---|---|
type | string | Yes | video or audio |
asset | string | Yes | Asset name (key in assets.file_id) |
track_index | number | Yes | Layer (higher = front; no overlap within a layer) |
start | number | Yes | Start time on the output timeline (s) |
duration | number | No | Duration (s); optional for video/audio |
muted | boolean | No | Video only, default true |
volume | number | No | Audio only, default 1.0 |
beats[] particle object
| Field | Type | Required | Description |
|---|---|---|---|
id | string | No | Unique identifier |
start | number | Yes | Enter time (s) |
duration | number | Yes | On-screen duration (s) |
track_index | number | Yes | Overlay layer (z-order) |
opaque | boolean | No | Whether the particle is full-screen opaque (covers the base). For simple scenes usually true (full-screen cut-in); pure HTML animation may also be transparent |
html | string | one of | Inline: the particle HTML source directly in the field (self-contained, one call) |
html_asset | string | one of | Reference: the particle HTML is uploaded; put its key in assets.file_id |
Each particle must provide either
html(inline) orhtml_asset(file_id reference).
Request Example
curl -X POST https://api.ai-mcn.tv:10000/task/html_render_simple \
-H "Authorization: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"composition": {
"video_size": {"width": 1920, "height": 1080},
"fps": 30,
"duration": 5.0,
"assets": {"file_id": {"base": "78246108192718854"}},
"tracks": [
{"type": "video", "asset": "base", "track_index": 0, "start": 0, "duration": 5.0, "muted": true}
],
"beats": [
{"id": "b1", "start": 0.5, "duration": 4.0, "track_index": 10, "opaque": true,
"html": "<template><div data-composition-id=\"p1\" data-width=\"1920\" data-height=\"1080\">...particle HTML with a GSAP timeline registration...</div></template>"}
]
},
"render": {"fps": 30, "quality": "high"}
}'
Success Response
{"code": 200, "msg": "success", "data": {"task_id": "537489015178500", "task_type": "html_render_simple", "status": "queued"}}
Query Task Result
| Item | Value |
|---|---|
| Method | GET |
| Path | /task/html_render_simple/{task_id} |
| Auth | Authorization header |
Response (output_result)
| Field | Type | Description |
|---|---|---|
file_id | string | Output file ID |
download_url | string | Download path |
duration | number | Output duration (s) |
video_size | object | {"width":w,"height":h} |
The output file depends on
render.output_format:mp4→ the composited finished video (.mp4);webm/qtrle→ the transparent particle layer only (.webm/.mov), to be composited over your local base track on the client / imported into JianYing — not a composited mp4.
Error Codes
| Code | HTTP | Description | Fix |
|---|---|---|---|
6013 | 400 | Missing composition | Provide required params |
6016 | 400 | Invalid spec (particle missing html/html_asset, too many clips, duration ≤ 0, render out of range) | Fix per response |
6004 | 404 | A file in assets.file_id does not exist | Check file ID / upload |
6014 | 400 | Base-track material type mismatch | Check material type |
6502 | 401 | Auth failed | Check Authorization header |
6201 / 6202 | 402 | Quota / balance insufficient | Top up |
Limits
- Output format:
render.output_formatmust be one ofmp4/webm/qtrle(defaultmp4); any other value is rejected as out-of-rangerender. Under the transparent-layer modes (webm/qtrle) the base does not enter the output,composition.tracksmay be empty, and the output is the beats-only transparent particle layer (.webm/.mov). - Base-track fitting (
mp4): If the base track andcomposition.video_sizehave different aspect ratios, the base is scaled proportionally and padded to fit the canvas; it is not cropped. - Base-track audio (
mp4):muteddefaults totruefor a video base track, so its audio is silent unless you explicitly setmuted: false. A separatetype: "audio"track is unaffected. - Base-track trimming limitation (
mp4): Only the first video track is used. Itsstart/durationare applied, butmedia_startand later video tracks are not applied to source trimming or assembly. - Audio timeline limitation (
mp4with a video base): A separate audio track takes precedence, but only the first one is used; itsstart/duration/media_start/volumeand additional audio tracks are not applied. Whenmuted: falseuses the video base's original audio, that audio is not shifted or trimmed by the video track's timeline fields. - Particles must be seekable: each particle must be wrapped in a
<template>, declaredata-composition-id, and register a frame-seekable timeline (see "Particle Format"); plain-CSS particles without registration will freeze. - Clip cap: base tracks + particles ≤ 200.
- Billed by output duration (minutes); frame-by-frame rendering, so render time scales with duration/complexity — poll every 5–10 s.
- Best for: full-screen opaque cut-ins / short clips / pure HTML animation; for a long base track running through the piece + transparent particle overlays (subject on camera + graphics that don't cover them), use HTML Animation Render (Layered).
- Complementary to timeline render: use Timeline Render for single-track hard cuts; use this for a video base + custom animation particles.