| name | composition-editing |
| description | Build timeline-based video composition on the Lumen canvas — stitch, trim, split, reorder clips, add BGM, and render the final MP4 via a composition node. |
| trigger | composition, video composition, timeline, edit video, stitch, concat, final cut, trim, split, BGM,剪辑,剪辑成片,视频合成,拼接视频,合成视频,时间线,裁剪,分割,成片,导出视频,多镜头合成 |
Lumen Composition Editing
Use this skill whenever the user wants to edit, stitch, trim, split, reorder, or add BGM
to multiple video clips and export one final MP4.
Load canvas-core first if you have not already. Then follow this skill for all timeline work.
When To Use
- User asks to 剪辑 / 合成 / 拼接 / 成片 / 导出最终视频
- Workflow has 2+ video clips that must become one deliverable
- User wants trim, split, reorder, or BGM on a timeline
- Multi-scene UGC / product video needs a final assembly step
Do not skip the composition node when multiple scene videos exist. Generate scenes first,
then assemble with composition.
Composition Node Contract
{
"id": "composition-final",
"type": "lumenNode",
"position": { "x": 1200, "y": 120 },
"data": {
"kind": "composition",
"title": "最终成片",
"prompt": "",
"output": null,
"modelId": "lumen-composition",
"settings": {
"timeline": {
"clips": [],
"aspectRatio": "9:16",
"resolution": "720p",
"bgmVolume": 0.28
}
},
"status": "idle",
"error": null,
"progress": 0
}
}
Rules:
kind must be composition, modelId must be lumen-composition
prompt is not required — leave empty
- Timeline lives in
settings.timeline (edit state). Engine compiles it at run time.
- Node
output after success is a video URL (stored as video asset, not composition type)
Timeline Clip Fields
| Field | Meaning |
|---|
id | Stable clip id, e.g. clip-hook |
order | Sequence index (0, 1, 2…) |
sourceNodeId | Upstream video node id — preferred URL source at run time |
sourceUrlSnapshot | Optional URL snapshot; omit when upstream outputs will exist |
sourceIn | Trim in-point in seconds on source media |
duration | Used length after trim (seconds) |
volume | Clip volume 0–1 |
label | Optional display label |
URL resolution at run time: sourceNodeId output > sourceUrlSnapshot.
DAG Pattern
Each scene is a full shot chain; only the video nodes connect into composition:
text-script-scene-1 -> image-keyframe-scene-1 -> video-scene-1 ──┐
text-script-scene-2 -> image-keyframe-scene-2 -> video-scene-2 ──┼──> composition-final
text-script-scene-3 -> image-keyframe-scene-3 -> video-scene-3 ──┘
audio-bgm (optional) ─────────────────────────────────────────────> composition-final
Edges:
- Per scene:
text → image, image → video, optionally text → video
- Every scene
video node → composition (target handle)
- Optional one
audio node → composition for BGM
- Do not connect
text / image directly to composition
- Do not leave a global script node disconnected from scene videos
Full Canvas Example (2 scenes + final cut)
The JSON below shows the composition + timeline + video→composition edges only.
Each video-* node must also have its own upstream text-* script and image-* keyframe
nodes with edges into that video (see Multi-scene shot template in canvas-core).
{
"nodes": [
{
"id": "video-hook",
"type": "lumenNode",
"position": { "x": 600, "y": 80 },
"data": {
"kind": "video",
"title": "镜头1 Hook",
"prompt": "Close-up product reveal, energetic UGC, 9:16",
"output": null,
"modelId": "seedance-1.5-pro",
"settings": { "aspectRatio": "9:16", "duration": 5, "resolution": "720p" },
"status": "idle",
"error": null,
"progress": 0
}
},
{
"id": "video-cta",
"type": "lumenNode",
"position": { "x": 600, "y": 280 },
"data": {
"kind": "video",
"title": "镜头2 CTA",
"prompt": "Creator holding product, call to action, 9:16",
"output": null,
"modelId": "seedance-1.5-pro",
"settings": { "aspectRatio": "9:16", "duration": 4, "resolution": "720p" },
"status": "idle",
"error": null,
"progress": 0
}
},
{
"id": "composition-final",
"type": "lumenNode",
"position": { "x": 1000, "y": 180 },
"data": {
"kind": "composition",
"title": "最终成片",
"prompt": "",
"output": null,
"modelId": "lumen-composition",
"settings": {
"timeline": {
"clips": [
{
"id": "clip-hook",
"order": 0,
"sourceNodeId": "video-hook",
"sourceIn": 0,
"duration": 5,
"volume": 1,
"label": "Hook"
},
{
"id": "clip-cta",
"order": 1,
"sourceNodeId": "video-cta",
"sourceIn": 0,
"duration": 4,
"volume": 1,
"label": "CTA"
}
],
"aspectRatio": "9:16",
"resolution": "720p",
"bgmVolume": 0.28
}
},
"status": "idle",
"error": null,
"progress": 0
}
}
],
"edges": [
{ "id": "e-hook", "source": "video-hook", "target": "composition-final", "type": "lumenSmooth", "data": {} },
{ "id": "e-cta", "source": "video-cta", "target": "composition-final", "type": "lumenSmooth", "data": {} }
]
}
Split Same Source (advanced)
Two clips from one video node — different sourceIn / duration:
{
"clips": [
{ "id": "clip-a", "order": 0, "sourceNodeId": "video-main", "sourceIn": 0, "duration": 3, "volume": 1 },
{ "id": "clip-b", "order": 1, "sourceNodeId": "video-main", "sourceIn": 3, "duration": 2.5, "volume": 1 }
]
}
Engine keeps both segments even when URL is identical.
Agent Workflow (required order)
use_skill("canvas-core") if not loaded
use_skill("composition-editing") for this task
read_canvas — inspect existing nodes/outputs
write_canvas — save full canvas with composition node + settings.timeline + edges
run_canvas_node each upstream video (and audio if BGM) until output is saved
read_canvas — confirm upstream outputs exist
run_canvas_node("composition-final") — render final MP4
- Reply with the composition node's
output URL only after step 7 succeeds
Building Timeline From a Scene Plan
When creating N scenes, build N complete shot chains first, then stitch:
- For each scene
i in 1..N:
text-script-scene-i (scene-specific script / hook / VO beats)
image-keyframe-scene-i (reference frame / storyboard still)
video-scene-i (motion clip)
- Edges:
text → image, image → video, and optionally text → video
- Add one
composition-final node to the right
- Connect every
video-scene-i → composition-final
- Write one clip per scene in timeline
order matching playback order
- Set each clip
sourceNodeId to the matching video-scene-i id
- Set
duration to the intended used length (match or shorten scene video length)
- Set
aspectRatio / resolution on timeline (9:16 + 720p for short-video default)
Do not skip per-scene text and image nodes and wire bare video nodes straight into composition. Do not create one global script (e.g. "Retro Script") that is not connected to each scene's video chain.
If user wants BGM:
- Add
audio node with modelId: suno-music or fish-tts as appropriate
- Connect
audio → composition
- Tune
bgmVolume (default 0.28)
Editing an Existing Timeline
read_canvas
- Locate the
composition node and its settings.timeline
- Modify
clips (reorder, change sourceIn/duration, add/remove clips, split)
write_canvas with the complete canvas JSON
- Re-run composition only after upstream clips still have valid outputs
Run Preconditions
Composition will fail if:
timeline.clips is empty
- Any clip
sourceNodeId points to a video without output
- Timeline cannot compile to valid URLs
Before running composition, verify every referenced upstream video has data.output set.
Defaults
| Setting | Default | Notes |
|---|
aspectRatio | 9:16 | TikTok / Reels |
resolution | 720p | Faster first pass |
bgmVolume | 0.28 | When BGM connected |
clip volume | 1 | Full clip audio |
Use 1080p only when user explicitly asks for higher export quality.
Common Mistakes
- Putting clips only in
video node settings — timeline must be on composition.settings.timeline
- Running composition before upstream videos finish
- Forgetting edges from scene videos to composition
- Using
prompt on composition node (not needed)
- Claiming final video exists before
run_canvas_node succeeds on composition
- Creating only
video scene nodes + composition, with a disconnected global script and no per-scene text → image → video chains
- One script node for the whole project that does not connect to any video node — each clip needs its own script + reference image upstream