Cutlass Logo

Cutlass: Final Cut Pro XML Generated

Cutlass FCPXML Generation Framework

Welcome to the comprehensive documentation for the Cutlass FCPXML generation framework. This provides detailed guidance for working with Final Cut Pro XML files programmatically.

🚨 Critical First Reads

Before diving into development, you must read these essential documents:

📚 Wiki Navigation

Core Documentation

Quick Reference

  • Resource ID Management
  • Duration and Timing
  • Common Crash Patterns
  • Effect UID Verification

🛡️ Critical Architecture Rules

1. NO XML STRING TEMPLATES

NEVER EVER generate XML from hardcoded string templates:

❌ BAD: xml := "<video ref=\"" + videoRef + "\">" + content + "</video>"
❌ BAD: fmt.Sprintf("<asset-clip ref=\"%s\" name=\"%s\"/>", ref, name)
✅ GOOD: xml.MarshalIndent(&fcp.Video{Ref: videoRef, Name: name}, "", "    ")

All FCPXML generation MUST use the fcp.* structs in the fcp package.

2. CHANGE CODE NOT XML

NEVER EVER only change problem xml in an xml file, always change the code that generates it too

3. Images vs Videos Fundamentals

Media Type Asset Duration Format frameDuration Spine Element Effects Support
Images "0s" (timeless) NONE <video> Simple only
Videos Actual duration Required <asset-clip> Full support

🚨 Top Crash Patterns to Avoid

  1. AssetClip for imagesaddAssetClip:toObject:parentFormatID crash
  2. frameDuration on image formatsperformAudioPreflightCheckForObject crash
  3. Complex effects on images → Various import crashes
  4. Fictional effect UIDs → "invalid effect ID" crashes
  5. Non-frame-aligned durations → "not on edit frame boundary" errors

Resource ID Management

All IDs must be unique within the document:

// ✅ GOOD: Use ResourceRegistry pattern
registry := fcp.NewResourceRegistry(fcpxml)
tx := fcp.NewTransaction(registry)
defer tx.Rollback()

ids := tx.ReserveIDs(3)
assetID := ids[0]    // "r2"
formatID := ids[1]   // "r3"
effectID := ids[2]   // "r4"

// ❌ BAD: Hardcoded IDs cause collisions
assetID := "r1"  // Will conflict with other generators

Duration and Timing

All durations MUST use fcp.ConvertSecondsToFCPDuration():

// ✅ GOOD: Frame-aligned duration
duration := fcp.ConvertSecondsToFCPDuration(5.5)  // "132132/24000s"

// ❌ BAD: Decimal seconds cause drift
duration := "5.5s"  // Not frame-aligned

FCP uses 24000/1001 ≈ 23.976 fps timebase for frame alignment.

Effect UID Verification

ONLY use verified effect UIDs:

✅ Verified Working UIDs:

  • Gaussian Blur: FFGaussianBlur
  • Color Correction: FFColorCorrection
  • Text Title: .../Titles.localized/Basic Text.localized/Text.localized/Text.moti
  • Shape Mask: FFSuperEllipseMask

✅ Prefer built-in elements:

// Spatial transformations - always safe
video.AdjustTransform = &fcp.AdjustTransform{
    Position: "100 50",
    Scale:    "1.5 1.5",
}

// Cropping - always safe  
assetClip.AdjustCrop = &fcp.AdjustCrop{
    Mode: "trim",
    TrimRect: &fcp.TrimRect{Left: "0.1", Right: "0.9"},
}

Required Architecture Pattern

ALWAYS follow this pattern:

func GenerateMyFeature(inputFile, outputFile string) error {
    // 1. Use existing infrastructure  
    fcpxml, err := fcp.GenerateEmpty("")
    if err != nil {
        return fmt.Errorf("failed to create base FCPXML: %v", err)
    }
    
    // 2. Use proper resource management
    registry := fcp.NewResourceRegistry(fcpxml)
    tx := fcp.NewTransaction(registry)
    defer tx.Rollback()
    
    // 3. Add content using existing functions
    if err := fcp.AddImage(fcpxml, imagePath, duration); err != nil {
        return err
    }
    
    // 4. Apply animations (simple transforms only for images)
    imageVideo := &fcpxml.Library.Events[0].Projects[0].Sequences[0].Spine.Videos[0]
    imageVideo.AdjustTransform = createAnimation(duration, startTime)
    
    // 5. Commit and write
    if err := tx.Commit(); err != nil {
        return err
    }
    return fcp.WriteToFile(fcpxml, outputFile)
}

Package Structure

fcp/
├── types.go           # All FCPXML struct definitions
├── generator.go       # Core generation functions  
├── registry.go        # Resource ID management
├── transaction.go     # Transaction-based operations
├── ids.go            # ID generation utilities
└── *_test.go         # Comprehensive test patterns

Getting Started

  1. Read FCPXML Generation Best Practices
  2. Study the test files in fcp/*_test.go for proven patterns
  3. Validate your code with fcp.ValidateClaudeCompliance()
  4. Test imports in actual Final Cut Pro

Key Principle: Follow existing patterns in fcp/ package. If FCPXML generation requires more than 1 iteration to work, you're doing it wrong.

Cutlass excels at generating impressive content at unprecedented scale and speed.

Get Started with Cutlass