Project¶
Project loading, saving, and creation for Camtasia .cmproj bundles.
- class camtasia.project.Project(file_path, encoding=None)[source]¶
Bases:
objectMain entry-point for interacting with Camtasia projects.
A Camtasia project is a macOS bundle directory (.cmproj) containing a project.tscproj JSON file, media assets, and recordings.
- Parameters:
- property history: ChangeHistory¶
Undo/redo history for this project.
- track_changes(description='edit')[source]¶
Context manager that records a reversible change.
Usage:
with project.track_changes("add intro"): track.add_clip(...) project.undo() # reverts the block
- Return type:
_ChangeTracker
- property edit_rate: int¶
The editing tick rate (ticks per second).
Default is 705,600,000 — divisible by 30fps, 60fps, 44100Hz, 48000Hz.
- property authoring_client: AuthoringClient | None¶
Details about the software used to edit the project.
- property media_bin: MediaBin¶
The project’s media bin (sourceBin).
- clone_track(source_track_name, new_track_name)[source]¶
Clone a track with all its clips and effects.
- Return type:
- property total_duration_formatted: str¶
MM:SS string.
Returns
H:MM:SSwhen the duration is one hour or more, otherwiseM:SS.- Type:
Total duration as HH
- property all_clips: list[tuple[Track, BaseClip]]¶
All clips across all tracks as (track, clip) tuples, including nested clips.
- property all_groups: list[tuple[Track, Group]]¶
All Group clips across all tracks as (track, group) tuples.
- clips_between(range_start_seconds, range_end_seconds)[source]¶
Return all clips across all tracks that fall within the time range.
- replace_all_media(old_source_id, new_source_id)[source]¶
Replace all references to one media source with another. Returns count.
- Return type:
- property longest_clip: tuple[Track, BaseClip] | None¶
The longest clip across all tracks, or None if empty.
- property shortest_clip: tuple[Track, BaseClip] | None¶
The shortest clip across all tracks, or None if empty.
- property average_clip_duration_seconds: float¶
Average clip duration across all tracks, or 0.0 if empty.
- search_clips(*, clip_type=None, min_duration_seconds=None, max_duration_seconds=None, has_effects=None, has_keyframes=None, on_track=None)[source]¶
Search for clips matching the given criteria.
All criteria are AND-combined. None means ‘any value’.
- classmethod from_template(template_path, output_path)[source]¶
Create a new project by copying an existing one as a template.
Copies the entire .cmproj bundle to the output path and loads it.
- Return type:
- classmethod new(output_path, title='Untitled', width=1920, height=1080)[source]¶
Create a brand new empty project at the given path.
- Return type:
- classmethod merge_projects(projects, output_path, title='Merged Project')[source]¶
Merge multiple projects into one by concatenating their timelines.
Each project’s tracks are appended sequentially. Media bins are merged.
- Return type:
- batch_apply(operation, *, clip_type=None, on_track=None)[source]¶
Apply an operation to matching clips. Returns count of clips modified.
- Return type:
- replace_media_path(old_path_fragment, new_path_fragment)[source]¶
Replace a path fragment in all source bin entries. Returns count changed.
- Return type:
- validate()[source]¶
Check for common project issues.
- Return type:
- Returns:
A list of
ValidationIssueinstances (may be empty).
- validate_schema()[source]¶
Validate the project data against the Camtasia JSON Schema.
This is a stricter check than validate() — it verifies the project structure matches the schema derived from 93 TechSmith sample projects.
- Return type:
- repair()[source]¶
Remove stale transitions that reference non-existent clips. Returns counts of fixes applied.
- save()[source]¶
Write the current project state to disk.
Matches Camtasia’s
NSJSONSerializationJSON formatting to avoid parser crashes with.trecscreen recordings.- Return type:
- import_media(file_path, **kwargs)[source]¶
Import a media file into the project’s source bin.
Detects media type from the file extension and passes appropriate defaults so that pymediainfo is not required.
- Parameters:
- Return type:
Media- Returns:
The newly created Media entry.
- Raises:
ValueError – Unknown file extension.
- import_shader(shader_path)[source]¶
Import a .tscshadervid shader with effectDef parsing.
Reads the shader JSON, converts effectDef entries (hex colors to RGBA floats), and sets sourceTracks metadata for Camtasia. Reuses existing media if already imported.
- Return type:
Media
- import_trec(trec_path)[source]¶
Import a .trec screen recording with full stream metadata.
Uses pymediainfo to probe the multi-track container and build correct source bin entries with all stream metadata.
- Parameters:
- Return type:
Media- Returns:
The Media entry.
- Raises:
ImportError – pymediainfo not installed.
- health_check()[source]¶
Run comprehensive project health check.
Returns dict with: - healthy: bool (True if no errors) - errors: list of error messages - warnings: list of warning messages - structural_issues: list from timeline.validate_structure() - statistics: dict from statistics()
- Return type:
- compact()[source]¶
Run all cleanup operations and validate.
Removes orphaned media, empty tracks, and validates the result.
- Return type:
- Returns:
Summary dict with counts of items cleaned.
- Raises:
ValueError – If validation finds errors after cleanup.
- total_duration_seconds()[source]¶
Total timeline duration in seconds.
- Return type:
- Returns:
Duration in seconds, delegated to the timeline.
- export_frame(video_path, timestamp_seconds, output_path=None)[source]¶
Extract a single frame from a video file as a PNG image.
Uses ffmpeg to extract the frame. If output_path is None, saves to the project’s media directory with an auto-generated name.
- Parameters:
- Return type:
- Returns:
Path to the extracted PNG file.
- Raises:
RuntimeError – If ffmpeg exits with a non-zero return code.
- export_frame_and_import(video_path, timestamp_seconds)[source]¶
Extract a frame from video and import it into the project media bin.
- find_media_by_extension(ext)[source]¶
Find all media entries with the given file extension.
- Return type:
list[Media]
- add_gradient_background(duration_seconds, color0=(0.16, 0.16, 0.16, 1.0), color1=(0.0, 0.0, 0.0, 1.0), track_index=1)[source]¶
Create a gradient shader background on the specified track.
Adds a sourceBin entry for the gradient shader and places a VMFile clip on the given track.
- Parameters:
- Return type:
- Returns:
The created clip.
- add_progressive_disclosure(image_file_paths, start_seconds=0.0, per_step_seconds=5.0, fade_in_seconds=0.5, fade_out_seconds=0.0, track_name_prefix='Prog')[source]¶
Place images on separate tracks for progressive visual accumulation.
Each image gets its own track so all previous images remain visible when a new one appears. Each image fades in and stays visible until the end of the sequence.
- Parameters:
image_file_paths (
list[Path|str]) – Ordered list of image file paths.start_seconds (
float) – When the first image appears.per_step_seconds (
float) – Time between each image appearing.fade_in_seconds (
float) – Fade-in duration for each image.fade_out_seconds (
float) – Fade-out duration for the last image (0 = no fade).track_name_prefix (
str) – Prefix for auto-generated track names.
- Return type:
- Returns:
List of placed image clips.
- add_four_corner_gradient(shader_path, duration_seconds, track_name='Background')[source]¶
Import and place a 4-corner animated gradient shader background.
Reuses an existing
.tscshadervidsource if one is already in the media bin; otherwise imports from shader_path.
- add_voiceover_sequence(vo_files, pauses=None, track_name='Audio')[source]¶
Import voiceover files and place them sequentially on an audio track.
- Parameters:
- Returns:
float, ‘duration’: float, ‘clip’: AMFile}``.
- Return type:
- add_voiceover_sequence_v2(audio_file_paths, track_name='Voiceover', start_seconds=0.0, gap_seconds=0.0)[source]¶
Import and place multiple audio files sequentially on a track.
Each audio file is imported into the source bin, its duration is read from the source bin metadata, and the resulting clip is placed end-to-end (with an optional gap) on the named track.
- Parameters:
- Return type:
- Returns:
The list of placed audio clips.
- add_image_sequence(image_file_paths, track_name='Images', start_seconds=0.0, per_image_seconds=5.0, fade_seconds=0.5)[source]¶
Import and place multiple images sequentially with fade animations.
Each image is imported into the source bin and placed on the named track for the specified duration. Optional fade-in and fade-out animations are applied to each clip.
- Parameters:
image_file_paths (
list[Path|str]) – Paths to image files to import.track_name (
str) – Name of the track to place clips on.start_seconds (
float) – Timeline position for the first image.per_image_seconds (
float) – Display duration per image.fade_seconds (
float) – Fade-in and fade-out duration (0 to disable).
- Return type:
- Returns:
The list of placed image clips.
- export_all(output_dir)[source]¶
Export project in all available formats.
Creates: report.md, report.json, timeline.json, markers.srt, timeline.edl
Returns dict mapping format name to output path.
- remove_all_effects()[source]¶
Remove all effects from all clips. Returns count removed.
- Return type:
- save_with_history()[source]¶
Save the project and persist undo history to a sidecar file.
- Return type:
- diff_from(other)[source]¶
Return JSON Patch operations showing differences from another project.
Useful for comparing two versions of the same project.
- diff_summary(other)[source]¶
Human-readable summary of differences from another project.
- Return type:
- move_all_clips_to_track(source_track_name, target_track_name)[source]¶
Move all clips from one track to another by name.
- add_title_card(title_text, start_seconds=0.0, duration_seconds=5.0, track_name='Titles', font_name='Helvetica Neue', font_weight='Bold', font_size=72.0, font_color=(1.0, 1.0, 1.0), fade_seconds=0.5)[source]¶
Add a text title card to the timeline.
Creates a callout clip on the named track with the given text and styling. Optionally applies fade-in and fade-out transitions.
- Parameters:
title_text (
str) – The text to display on the title card.start_seconds (
float) – Timeline position where the title card begins.duration_seconds (
float) – How long the title card is visible.track_name (
str) – Name of the track to place the title card on.font_name (
str) – Font family name.font_weight (
str) – Font weight (e.g. ‘Bold’, ‘Regular’).font_size (
float) – Font size in points.font_color (
tuple[float,float,float]) – RGB color as a tuple of floats in [0.0, 1.0].fade_seconds (
float) – Duration of fade-in and fade-out. Pass 0 to skip.
- Return type:
- Returns:
The created callout clip.
- add_background_music(audio_path, volume=0.3, fade_in_seconds=2.0, fade_out_seconds=3.0, track_name='Background Music')[source]¶
Import and place background music spanning the full timeline.
The audio is placed at the start and trimmed to match the timeline duration. Volume is reduced and fades are applied.
- Return type:
- mute_all_groups()[source]¶
Mute every Group clip in the project.
- Return type:
- Returns:
The number of Group clips that were muted.
- add_subtitle_track(subtitle_entries, track_name='Subtitles', font_size=36.0, font_color=(1.0, 1.0, 1.0))[source]¶
Add subtitle text entries to a dedicated track.
Each entry is placed as a callout clip at the specified time and duration. All subtitles share the same font size and color.
- Parameters:
subtitle_entries (
list[tuple[float,float,str]]) – List of (start_seconds, duration_seconds, text) tuples, one per subtitle line.track_name (
str) – Name of the track to place subtitles on.font_size (
float) – Font size in points for all subtitle clips.font_color (
tuple[float,float,float]) – RGB color as a tuple of floats in [0.0, 1.0].
- Return type:
- Returns:
List of created callout clips in the same order as the input.
- add_callout_sequence(callout_entries, track_name='Callouts', font_size=24.0, fade_seconds=0.3)[source]¶
Add a sequence of timed callout annotations.
- Parameters:
- Return type:
- Returns:
List of created callout clips.
- add_lower_third(title_text, subtitle_text='', start_seconds=0.0, duration_seconds=5.0, track_name='Lower Thirds', fade_seconds=0.5)[source]¶
Add a lower-third title overlay.
Creates a callout positioned in the lower portion of the frame with title and optional subtitle text.
- Return type:
- add_section_divider(title_text, at_seconds, duration_seconds=3.0, track_name='Section Dividers', fade_seconds=0.5)[source]¶
Add a section divider title card at the specified time.
Creates a full-screen text callout that serves as a visual separator between sections of the video.
- Return type:
- add_end_card(title_text='Thank You', subtitle_text='', duration_seconds=5.0, track_name='End Card', fade_seconds=1.0)[source]¶
Add an end card at the end of the timeline.
- Return type:
- export_project_report(output_path)[source]¶
Export a comprehensive project report as a markdown file.
Includes: project summary, track listing, clip inventory, effect usage, transition listing, and validation results.
- Return type:
- apply_color_grade(brightness=0.0, contrast=0.0, saturation=0.0, clip_types=None)[source]¶
Apply color adjustment to all video/image clips.
- Parameters:
- Return type:
- add_zoom_to_region(clip, start_seconds, duration_seconds, scale=2.0, center_x=0.5, center_y=0.5)[source]¶
Add a zoom-in animation to a clip at a specific time.
Creates scale and translation keyframes that zoom into a region of the clip, hold, then zoom back out.
- Return type:
- normalize_audio(target_gain=1.0)[source]¶
Set all audio clips to the same gain level. Returns count adjusted.
- Return type:
- static convert_audio_to_wav(input_path, output_path=None, sample_rate=48000)[source]¶
Convert an audio file to PCM WAV format using ffmpeg.
This is recommended before importing audio into Camtasia projects, especially for compressed formats (MP3, AAC) that may have unreliable duration metadata.
- Parameters:
- Return type:
- Returns:
Path to the converted WAV file.
- Raises:
FileNotFoundError – If ffmpeg is not installed.
subprocess.CalledProcessError – If conversion fails.
- import_and_convert_audio(audio_path, sample_rate=48000)[source]¶
Convert audio to WAV (if needed) and import into the project.
Automatically converts compressed audio formats to PCM WAV before importing to avoid duration metadata issues.
- Return type:
- build_from_screenplay_file(screenplay_path, audio_dir, track_name='Voiceover', gap_seconds=0.5)[source]¶
Parse a screenplay file and build the voiceover timeline.
Reads the screenplay markdown, finds matching audio files in audio_dir, and places them sequentially on the timeline.
- Parameters:
- Return type:
- Returns:
Dict with ‘clips’ (placed clips), ‘total_duration’ (seconds), ‘sections’ (parsed screenplay sections).
- add_watermark(image_path, opacity=0.3, track_name='Watermark')[source]¶
Add a watermark image that spans the entire timeline.
The image is placed on its own track with reduced opacity.
- Return type:
- add_countdown(seconds=3, track_name='Countdown', per_number_seconds=1.0)[source]¶
Add a countdown (3, 2, 1) at the start of the timeline.
- apply_to_all_clips(operation, clip_filter=None)[source]¶
Apply an operation to all clips, optionally filtered.
- solo_track(track_name)[source]¶
Solo a track by name (mute all others). Returns True if found.
- Return type:
- remove_orphaned_media()[source]¶
Remove media bin entries not referenced by any clip.
- Return type:
- Returns:
Number of media entries removed.
- extract_audio_track(output_path, track_name=None)[source]¶
Export audio clips from a track as a list of file references.
Returns a text file listing all audio source files on the track. If track_name is None, exports from all tracks.
- Return type:
- timeline_to_dict()[source]¶
Export the timeline structure as a clean dict for serialization.
Returns a simplified representation of the timeline suitable for JSON export, debugging, or comparison.