plugins/video-editing/skills/final-cut-pro/SKILL.md
Apple Final Cut Pro FCPXML format reference. Covers project structure, timeline creation, clip references, effects, and transitions. Use when generating FCP projects or understanding FCPXML structure.
npx skillsauth add madappgang/claude-code final-cut-proInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
plugin: video-editing updated: 2026-01-20
Production-ready patterns for generating FCPXML projects compatible with Final Cut Pro 10.4+.
| FCP Version | FCPXML Version | Key Features | |-------------|----------------|--------------| | 10.4+ | 1.8+ | Compound clips, roles | | 10.5+ | 1.9 | Enhanced color | | 10.6+ | 1.10 | HDR support | | 10.7+ | 1.11 | Object tracking |
Recommendation: Use version 1.9 for broad compatibility.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE fcpxml>
<fcpxml version="1.9">
<resources>
<!-- Media references -->
<format id="r1" name="FFVideoFormat1080p24"
frameDuration="1/24s" width="1920" height="1080"/>
<asset id="a1" name="clip1" src="file://{ABSOLUTE_PATH}/clip1.mov"
start="0s" duration="120s" hasVideo="1" hasAudio="1">
<media-rep kind="original-media" src="file://{ABSOLUTE_PATH}/clip1.mov"/>
</asset>
</resources>
<library location="file://{USER_MOVIES}/MyLibrary.fcpbundle/">
<event name="Event 2024-01-15">
<project name="My Project">
<sequence format="r1" duration="300s">
<spine>
<!-- Timeline clips go here -->
</spine>
</sequence>
</project>
</event>
</library>
</fcpxml>
Define the timeline format (resolution, frame rate):
<!-- 1080p @ 24fps -->
<format id="r1" name="FFVideoFormat1080p24"
frameDuration="1/24s" width="1920" height="1080"/>
<!-- 4K @ 30fps -->
<format id="r2" name="FFVideoFormat4KUHD30p"
frameDuration="1001/30000s" width="3840" height="2160"/>
<!-- 1080p @ 29.97fps (NTSC) -->
<format id="r3" name="FFVideoFormat1080p2997"
frameDuration="1001/30000s" width="1920" height="1080"/>
Reference media files:
<asset id="a1" name="Interview_001"
src="file://{ABSOLUTE_PATH}/interview.mov"
start="0s" duration="600s"
hasVideo="1" hasAudio="1"
format="r1">
<media-rep kind="original-media"
src="file://{ABSOLUTE_PATH}/interview.mov"/>
</asset>
<spine>
<!-- First clip: starts at 0, uses full duration -->
<asset-clip name="Interview Opening"
ref="a1"
offset="0s"
start="0s"
duration="30s"/>
<!-- Second clip: starts after first (offset=30s) -->
<asset-clip name="B-Roll"
ref="a2"
offset="30s"
start="10s"
duration="15s"/>
<!-- Third clip: starts at 45s -->
<asset-clip name="Interview Conclusion"
ref="a1"
offset="45s"
start="120s"
duration="20s"/>
</spine>
Key timing attributes:
offset - Position on timeline (where clip starts in sequence)start - In-point within source mediaduration - How long the clip plays<spine>
<asset-clip ref="a1" offset="0s" duration="30s"/>
<!-- 5 second gap -->
<gap name="Gap" offset="30s" duration="5s"/>
<asset-clip ref="a2" offset="35s" duration="30s"/>
</spine>
<spine>
<asset-clip ref="a1" offset="0s" duration="30s"/>
<!-- Cross dissolve between clips -->
<transition name="Cross Dissolve"
offset="29s"
duration="2s">
<filter-video ref="r10" name="Cross Dissolve"/>
</transition>
<asset-clip ref="a2" offset="29s" duration="30s"/>
</spine>
<spine>
<!-- Main video (layer 0) -->
<asset-clip ref="a1" offset="0s" duration="60s">
<!-- Picture-in-picture on layer 1 -->
<asset-clip ref="a2" offset="10s" duration="15s" lane="1">
<adjust-transform position="200 150" scale="0.3 0.3"/>
</asset-clip>
</asset-clip>
</spine>
<title name="Chapter Title"
offset="0s"
duration="5s"
ref="r5">
<text>
<text-style ref="ts1">Welcome to the Video</text-style>
</text>
</title>
<asset-clip ref="a1" offset="0s" duration="120s">
<!-- To-do marker -->
<marker start="15s" duration="1/24s" value="TODO: Add B-roll here"/>
<!-- Chapter marker -->
<chapter-marker start="30s" duration="1/24s" value="Chapter 2: Setup"/>
<!-- Standard marker -->
<marker start="45s" duration="1/24s" value="Key moment"/>
</asset-clip>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE fcpxml>
<fcpxml version="1.9">
<resources>
<!-- Timeline format -->
<format id="r1" name="FFVideoFormat1080p24"
frameDuration="1/24s" width="1920" height="1080"/>
<!-- Title effect -->
<effect id="r10" name="Basic Title" uid=".../Titles.localized/Bumper:Opener.localized/Basic Title.localized/Basic Title.moti"/>
<!-- Media assets -->
<asset id="a1" name="clip_001"
src="file://{ABSOLUTE_PATH}/clip1.mov" start="0s" duration="120s"
hasVideo="1" hasAudio="1" format="r1">
<media-rep kind="original-media" src="file://{ABSOLUTE_PATH}/clip1.mov"/>
</asset>
<asset id="a2" name="clip_002"
src="file://{ABSOLUTE_PATH}/clip2.mov" start="0s" duration="90s"
hasVideo="1" hasAudio="1" format="r1">
<media-rep kind="original-media" src="file://{ABSOLUTE_PATH}/clip2.mov"/>
</asset>
</resources>
<library location="file://{USER_MOVIES}/MyLibrary.fcpbundle/">
<event name="Import Event">
<project name="Assembled Project" uid="generated-uuid-here">
<sequence format="r1" duration="180s" tcStart="0s" tcFormat="NDF">
<spine>
<!-- Opening title -->
<gap name="Title Gap" offset="0s" duration="5s">
<title ref="r10" offset="0s" duration="5s" lane="1">
<text>
<text-style ref="ts1" font="Helvetica" fontSize="72" fontColor="1 1 1 1">
Project Title
</text-style>
</text>
</title>
</gap>
<!-- First clip -->
<asset-clip name="Opening" ref="a1"
offset="5s" start="10s" duration="60s">
<!-- Fade in -->
<adjust-volume>
<keyframe time="0s" value="0dB"/>
</adjust-volume>
</asset-clip>
<!-- Cross dissolve -->
<transition name="Cross Dissolve"
offset="64s" duration="2s"/>
<!-- Second clip -->
<asset-clip name="Middle Section" ref="a2"
offset="64s" start="0s" duration="90s"/>
</spine>
</sequence>
</project>
</event>
</library>
</fcpxml>
| Frame Rate | frameDuration | |------------|---------------| | 24 fps | 1/24s | | 25 fps | 1/25s | | 30 fps | 1/30s | | 29.97 fps | 1001/30000s | | 23.976 fps | 1001/24000s | | 60 fps | 1/60s |
FCPXML uses rational time notation:
30s (30 seconds)24/24s (24 frames at 24fps = 1 second)1001/30000s (for NTSC timing)def frames_to_fcpxml_time(frames, fps=24):
"""Convert frame count to FCPXML time string."""
if fps == 29.97:
return f"{frames * 1001}/30000s"
elif fps == 23.976:
return f"{frames * 1001}/24000s"
else:
return f"{frames}/{fps}s"
def seconds_to_fcpxml_time(seconds):
"""Convert seconds to FCPXML time string."""
return f"{seconds}s"
Before importing FCPXML:
xmllint --noout project.fcpxml
grep -oP 'src="file://[^"]+' project.fcpxml | while read src; do
path="${src#src=\"file://}"
[[ -f "$path" ]] || echo "Missing: $path"
done
testing
A test skill for validation testing. Use when testing skill parsing and validation logic.
tools
--- name: bad-skill description: This skill has invalid YAML in frontmatter allowed-tools: [invalid, array, syntax prerequisites: not-an-array --- # Bad Skill This skill has malformed frontmatter that should fail parsing. The YAML has: - Unclosed array bracket - Wrong type for prerequisites (should be array, not string)
tools
Plugin release process for MAG Claude Plugins marketplace. Covers version bumping, marketplace.json updates, git tagging, and common mistakes. Use when releasing new plugin versions or troubleshooting update issues.
testing
Fetch trending programming models from OpenRouter rankings. Use when selecting models for multi-model review, updating model recommendations, or researching current AI coding trends. Provides model IDs, context windows, pricing, and usage statistics from the most recent week.