AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Capcut Editor

skill-duckyman-ai-agent-skills-capcut-editor · by duckyman-ai

>

No reviews yet
0 installs
31 views
0.0% view→install

Install

$ agentstack add skill-duckyman-ai-agent-skills-capcut-editor

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access Used
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-duckyman-ai-agent-skills-capcut-editor)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
2mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Capcut Editor? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

CapCut Desktop Project Skill

Programmatically read, create, and modify CapCut desktop (macOS) project files.

Important Limitation

Only locally-created projects can be read/written. Projects downloaded from CapCut's template library have encrypted draft_info.json files (base64-encoded with proprietary ByteDance encryption) and cannot be modified. Always check by attempting json.loads() — if it fails, the project is encrypted.

Project Location

BASE = ~/Movies/CapCut/User Data/Projects/com.lveditor.draft/

Quick Reference

Read references/draft-schema.md for the complete JSON schema with field descriptions and time conversion rules.

Commands

List all projects

python3 -c "
import json, os
base = os.path.expanduser('~/Movies/CapCut/User Data/Projects/com.lveditor.draft')
with open(os.path.join(base, 'root_meta_info.json')) as f:
    data = json.load(f)
for d in data['all_draft_store']:
    name = d.get('draft_name', d['draft_fold_path'].split('/')[-1])
    dur = d.get('tm_duration', 0)
    secs = dur / 1000000 if dur else 0
    print(f'{name:30s}  {secs:>6.1f}s  {d[\"draft_fold_path\"]}')
"

Check if a project is readable (not encrypted)

python3 -c "
import json, os
base = os.path.expanduser('~/Movies/CapCut/User Data/Projects/com.lveditor.draft')
path = os.path.join(base, 'PROJECT_NAME', 'draft_info.json')
try:
    with open(path) as f: json.load(f)
    print('READABLE (plain JSON)')
except:
    print('ENCRYPTED (template project — cannot modify)')
"

Read project summary

python3 -c "
import json, os
base = os.path.expanduser('~/Movies/CapCut/User Data/Projects/com.lveditor.draft')
with open(os.path.join(base, 'PROJECT_NAME', 'draft_info.json')) as f:
    d = json.load(f)
print(f'ID: {d[\"id\"]}')
print(f'Duration: {d[\"duration\"]/1000000:.1f}s')
print(f'FPS: {d[\"fps\"]}')
print(f'Canvas: {d[\"canvas_config\"][\"width\"]}x{d[\"canvas_config\"][\"height\"]}')
tracks = d.get('tracks', [])
print(f'Tracks: {len(tracks)}')
for i, t in enumerate(tracks):
    segs = t.get('segments', [])
    print(f'  Track {i}: {t[\"type\"]} ({len(segs)} segments)')
mats = d.get('materials', {})
for k, v in mats.items():
    if isinstance(v, list) and len(v) > 0:
        print(f'  materials.{k}: {len(v)}')
"

Create a new project from scratch

python3 scripts/create-project.py  [--width 1920] [--height 1080] [--fps 30]

View and edit clips

# Show full timeline overview (tracks, segments, timing, transforms)
python3 scripts/edit-clips.py  --info

# Scale clips (1.0 = 100%, 1.5 = 150%)
python3 scripts/edit-clips.py  --scale 1.2 --clips 0 5 10
python3 scripts/edit-clips.py  --scale 1.1 --range 3-19

# Speed (0.5 = half speed, 2.0 = double)
python3 scripts/edit-clips.py  --speed 2.0 --clips 5
python3 scripts/edit-clips.py  --speed 0.5 --all

# Volume (0.0 = mute, 1.0 = normal, 2.0 = double)
python3 scripts/edit-clips.py  --volume 0 --range 0-2
python3 scripts/edit-clips.py  --mute --all

# Rotate/flip/opacity
python3 scripts/edit-clips.py  --rotate 90 --clips 2
python3 scripts/edit-clips.py  --flip-h --clips 3
python3 scripts/edit-clips.py  --opacity 0.8 --clips 0

# Trim clip to first N seconds
python3 scripts/edit-clips.py  --trim 3.5 --clips 0

# Split clip at position (seconds from clip start)
python3 scripts/edit-clips.py  --split 2.5 --clips 0

# Remove clips
python3 scripts/edit-clips.py  --remove --clips 10 11 12

# Move clip from index to index
python3 scripts/edit-clips.py  --move 5 --to 10

# Reset transforms
python3 scripts/edit-clips.py  --reset --clips 0 1 2

Edit audio tracks

# Audio tracks shown in --info output
python3 scripts/edit-clips.py  --info

# Volume (0.0=mute, 1.0=normal)
python3 scripts/edit-clips.py  --audio-track --volume 0.5 --all
python3 scripts/edit-clips.py  --audio-track --mute --clips 0

# Move audio segment to align with video (seconds from timeline start)
python3 scripts/edit-clips.py  --audio-track --position 10.5 --clips 0

# Select which audio track (0=first, 1=second, etc.)
python3 scripts/edit-clips.py  --audio-track --track-index 2 --volume 0.8 --all

# Speed up/slow down audio
python3 scripts/edit-clips.py  --audio-track --speed 1.5 --clips 0

# Trim audio to first N seconds
python3 scripts/edit-clips.py  --audio-track --trim 5.0 --clips 0

# Remove audio segment
python3 scripts/edit-clips.py  --audio-track --remove --clips 2

# Fade in/out (seconds)
python3 scripts/edit-clips.py  --audio-track --fade-in 0.5 --clips 0
python3 scripts/edit-clips.py  --audio-track --fade-out 1.0 --clips 0

Add video effects (zoom, blur, sparkle, etc.)

# List built-in effect shortcuts (20 effects)
python3 scripts/add-effect.py --list-effects

# Scan ALL cached effects (404+ downloaded effects)
python3 scripts/add-effect.py --scan-cache

# Add Zoom Lens to all clips
python3 scripts/add-effect.py  --effect zoom-lens --all

# Add Sparkle to specific clips
python3 scripts/add-effect.py  --effect sparkle --clips 0 5 10

# Add any cached effect by ID (from --scan-cache)
python3 scripts/add-effect.py  --effect-id 7399469087174233349 --all

# Add Blur to a range with custom parameters
python3 scripts/add-effect.py  --effect blur --range 3-19 --speed 0.02 --param-range 0.06

# Remove all effects
python3 scripts/add-effect.py  --clear

Add transitions between clips

# List available transitions
python3 scripts/add-transition.py --list

# Add transition between two adjacent clips
python3 scripts/add-transition.py  --between 19 20

# Add transitions between all consecutive clips
python3 scripts/add-transition.py  --all-gaps

# Add at specific gaps with custom duration
python3 scripts/add-transition.py  --gaps 2 5 10 --duration 0.5

# Remove all transitions
python3 scripts/add-transition.py  --clear

Add color grading (HSL)

# Show current color settings per clip
python3 scripts/add-color.py  --info

# Custom HSL values (hue: -180~180, sat: -100~100, light: -100~100)
python3 scripts/add-color.py  --hsl --hue 10 --saturation 20 --lightness -5 --clips 0 1 2
python3 scripts/add-color.py  --hsl --saturation 30 --all

# Presets
python3 scripts/add-color.py  --preset warm --all
python3 scripts/add-color.py  --preset vivid --range 0-10
python3 scripts/add-color.py  --preset moody --all

# Available presets: warm, cool, vivid, moody, vintage, fade
# Remove all color grading
python3 scripts/add-color.py  --clear

Add text overlays

# Single text
python3 scripts/add-text.py  --text "Hello" --start 0 --duration 5 --y -0.65 --size 14

# With a specific font
python3 scripts/add-text.py  --text "สวัสดี" --font sarabun-bold --size 14
python3 scripts/add-text.py  --text "Hello" --font /full/path/to/font.ttf

# List available font aliases
python3 scripts/add-text.py --list-fonts

# From a JSON file
python3 scripts/add-text.py  --from-file texts.json

# Remove all text
python3 scripts/add-text.py  --clear

JSON file format (supports font field):

[
  {"text": "Opening title", "start": 0, "duration": 4.5, "y": -0.65, "size": 14, "font": "thai"},
  {"text": "Subtitle", "start": 5.4, "duration": 2, "y": 0.7, "size": 10, "font": "sarabun-bold"}
]

Built-in font aliases: default, en, th/thai, noto, noto-thai, capcut/capcut-bold/capcut-medium, sarabun/sarabun-bold/sarabun-light/sarabun-med/sarabun-thin, thsarabun/thsarabun-new, db-helv-med/db-helv-bold. Or pass any full path to a .ttf/.otf file.

Create project manually

The create-project.py script handles everything. Alternatively, create manually:

  1. Generate 3 separate UUIDs: project_json_id, timeline_id, draft_id
  2. Create the folder structure (22 files total — see below)
  3. CapCut MUST be closed — it overwrites root_meta_info.json on launch

Required file structure (22 files)

PROJECT_NAME/
├── draft_info.json                          # Main project data
├── draft_info.json.bak                      # Backup (identical to draft_info.json)
├── draft_meta_info.json                     # Project metadata (plain JSON)
├── draft_settings                           # INI format settings
├── draft_agency_config.json                 # Resolution/agency config
├── draft_biz_config.json                    # Empty file (0 bytes)
├── performance_opt_info.json                # Performance optimization
├── timeline_layout.json                     # UI layout with timeline UUID
├── attachment_pc_common.json                # PC-specific attachments
├── template-2.tmp                           # Full draft_info copy
├── common_attachment/
│   └── attachment_pc_timeline.json          # Timeline reference lines config
└── Timelines/
    ├── project.json                         # Timeline registry (separate id!)
    ├── project.json.bak                     # Backup
    └── {timeline_id}/                       # Named with timeline_id UUID
        ├── draft_info.json                  # Same content as root draft_info.json
        ├── draft_info.json.bak
        ├── attachment_editing.json          # Edit state
        ├── attachment_pc_common.json        # Same as root level
        ├── template.tmp                     # Draft info with canvas w/h = 0
        ├── template-2.tmp                   # Full draft_info copy
        └── common_attachment/
            ├── attachment_action_scene.json
            ├── attachment_gen_ai_info.json
            ├── attachment_pc_timeline.json
            └── attachment_script_video.json

UUID scheme

CapCut uses 3 separate UUIDs for each project:

| UUID | Used in | Notes | |------|---------|-------| | project_json_id | Timelines/project.jsonid | Separate from timeline | | timeline_id | Timelines/project.jsonmain_timeline_id, draft_info.jsonid, timeline folder name | The primary project UUID | | draft_id | root_meta_info.jsondraft_id, draft_meta_info.jsondraft_id | Registry identifier |

Key parameters

  • canvas_config.width/height — 1080×1920 for 9:16 portrait, 1920×1080 for 16:9 landscape
  • fps — 30.0 (standard)
  • create_time / update_time — microseconds (0 for blank project)
  • tm_draft_create / tm_draft_modified — microseconds (Unix timestamp × 1,000,000)

Register in rootmetainfo.json

When creating a project, add an entry to all_draft_store in root_meta_info.json:

import json, os, uuid, time

BASE = os.path.expanduser("~/Movies/CapCut/User Data/Projects/com.lveditor.draft")
dst = os.path.join(BASE, "PROJECT_NAME")
meta_path = os.path.join(BASE, "root_meta_info.json")

with open(meta_path) as f:
    meta = json.load(f)

meta["all_draft_store"].insert(0, {
    "cloud_draft_cover": False,
    "cloud_draft_sync": False,
    "draft_cloud_last_action_download": False,
    "draft_cloud_purchase_info": "",
    "draft_cloud_template_id": "",
    "draft_cloud_tutorial_info": "",
    "draft_cloud_videocut_purchase_info": "",
    "draft_cover": os.path.join(dst, "draft_cover.jpg"),
    "draft_fold_path": dst,
    "draft_id": str(uuid.uuid4()).upper(),
    "draft_is_ai_shorts": False,
    "draft_is_cloud_temp_draft": False,
    "draft_is_invisible": False,
    "draft_is_web_article_video": False,
    "draft_json_file": os.path.join(dst, "draft_info.json"),
    "draft_name": "PROJECT_NAME",
    "draft_new_version": "",
    "draft_root_path": BASE,
    "draft_timeline_materials_size": 4106,
    "draft_type": "",
    "draft_web_article_video_enter_from": "",
    "streaming_edit_draft_ready": True,
    "tm_draft_cloud_completed": "",
    "tm_draft_cloud_entry_id": -1,
    "tm_draft_cloud_modified": 0,
    "tm_draft_cloud_parent_entry_id": -1,
    "tm_draft_cloud_space_id": -1,
    "tm_draft_cloud_user_id": -1,
    "tm_draft_create": int(time.time() * 1_000_000),
    "tm_draft_modified": int(time.time() * 1_000_000),
    "tm_draft_removed": 0,
    "tm_duration": 0,
})

if isinstance(meta.get("draft_ids"), int):
    meta["draft_ids"] += 1

with open(meta_path, "w") as f:
    json.dump(meta, f, separators=(",", ":"))

Add a video clip to a project

  1. Generate UUIDs for: segment, video material, canvas material, speed material,

placeholderinfo, soundchannelmapping, vocalseparation, material_color

  1. Add a video material to materials.videos with the video file path and metadata
  2. Add a canvas_color material to materials.canvases
  3. Add entries to materials.speeds, materials.placeholder_infos,

materials.sound_channel_mappings, materials.vocal_separations, materials.material_colors

  1. Add a segment to the target video track with:
  • material_id → video material UUID
  • extra_material_refs → [speeduuid, canvasuuid, placeholderuuid, soundch_uuid,

vocalsepuuid, materialcoloruuid]

  • target_timerange → { start: cumulative position, duration: clip length in μs }
  • source_timerange → { start: 0, duration: clip length in μs }
  1. Update duration at the project root level

Add an audio track

  1. Generate UUIDs for: segment, audio material, audio_fade, beats, speed,

placeholderinfo, soundchannelmapping, vocalseparation

  1. Add audio material to materials.audios
  2. Add entries to materials.audio_fades, materials.beats, materials.speeds,

materials.placeholder_infos, materials.sound_channel_mappings, materials.vocal_separations

  1. Either add a new track of type: "audio" or add segment to existing audio track
  2. Segment clip should be null for audio

Add a text overlay

  1. Generate UUID for: segment and text material
  2. Add text material to materials.texts with:
  • content — JSON-encoded string with text and styles array
  • font_size, text_color, alignment, line_max_width
  1. Add segment to a type: "text" track (create one if needed)
  • source_timerange should be null for text
  • clip.transform.y controls vertical position (e.g., 0.7 = lower third)

Text content field format

import json
content = json.dumps({
    "text": "Your text here",
    "styles": [{
        "fill": {
            "content": {
                "solid": {"color": [1.0, 1.0, 1.0]},
                "render_type": "solid"
            }
        },
        "range": [0, len("Your text here")],
        "strokes": [{
            "width": 0.06,
            "content": {
                "solid": {"color": [0, 0, 0]},
                "render_type": "solid"
            }
        }],
        "size": 15,
        "font": {
            "path": "/Applications/CapCut.app/Contents/Resources/Font/SystemFont/en.ttf",
            "id": ""
        }
    }]
})

Colors in styles are [R, G, B] normalized 0.0-1.0 (not hex).

Add video effects (zoom, blur, sparkle, etc.)

Video effects are placed on type: "effect" tracks and reference entries in materials.video_effects. Each segment on an effect track matches the timing of a video clip it applies to. Multiple effects can share one track via separate segments.

Structure:

  1. Create a video_effect material in materials.video_effects
  2. Create a segment on an effect track with target_timerange matching the video clip
  3. The segment's material_id points to the video_effect entry
import uuid, os

CACHE_BASE = "/Users/admin/Library/Containers/com.lemon.lvoverseas/Data/Movies/CapCut/User Data/Cache/effect"

def gen_uuid():
    return str(uuid.uuid4()).upper()

# Create a video effect material
effect_id = "7399465441057328389"  # Zoom Lens
effect_hash = "60a68556b7df52cc36d20d1f565b4569"
effect_path = os.path.join(CACHE_BASE, effect_id, effect_hash)

mat_id = gen_uuid()
video_effect = {
    "id": mat_id,
    "effect_id": effect_id,
    "resource_id": effect_id,
    "name": "Zoom Lens",
    "type": "video_effect",
    "path": effect_path,
    "adjust_params": [
        {"name": "effects_adjust_speed", "value": 0.01, "default_value": 0.33},
        {"n

…

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [duckyman-ai](https://github.com/duckyman-ai)
- **Source:** [duckyman-ai/agent-skills](https://github.com/duckyman-ai/agent-skills)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.