Skip to content

Add export-video: render the current timeline to ProRes 422 .mov #10

Description

@RichardBray

Summary

Add a camkit export-video command that renders the current timeline to a
.mov using Apple ProRes 422. Today camkit can mix the timeline's audio
(export-audio) but has no way to produce the finished video — that step is
still a manual Camtasia GUI export (Share ▸ Export ▸ Local File ▸ ProRes 422).
This command closes the last manual gap in the rough-cut → cleanup → render
pipeline.

Why this must go through Camtasia (read before designing)

camkit's design principle is "no ffmpeg re-encoding — Camtasia stays the
final renderer
" (see README). A pure-ffmpeg render is not viable here and
should not be attempted:

  • The timeline composites effects, transitions, and injected Dynamic Caption
    callouts that only Camtasia's engine knows how to render.
  • Screen recordings (.trec) carry a tscc2 video stream that ffmpeg cannot
    decode
    (this is already documented in packages/cli/src/media.ts — audio is
    readable, the video stream is not).

So export-video must drive Camtasia to render, not rebuild the frame
itself.

Feasibility risk — PROBE FIRST, then report

@camkit/darwin (packages/darwin/src/index.ts) already documents that
Camtasia's AppleScript suite is partially broken on 2026.1.3: document
list / open / close-with-save are verified working, but media-element access
fails with AppleEvent -10000
and some project properties are inaccessible.
Whether an export/render verb works is unverified.

The first task is a spike, not code. In order:

  1. Inspect the scripting definition for an export/batch-export command:
    sdef /Applications/Camtasia.app | less        # or open CamtasiaGo.sdef in the bundle
    Look for any export, render, share, or produce verb and its
    parameters (codec/preset, destination). If one exists, try it via
    osascript against a throwaway .cmproj and confirm it can be told to use
    ProRes 422.
  2. If no scripting verb works, fall back to UI scripting via System
    Events
    (drive the Share/Export menu + the export dialog). This needs
    Accessibility permission and is brittle across Camtasia versions — gate it
    behind the same assertDarwin() and document the version it was verified on,
    matching the existing convention in index.ts.
  3. If neither is feasible, do not ship a fake. Instead update this issue
    / the README with findings and implement a camkit export-video that prints
    clear manual instructions (the exact Share ▸ Export ▸ ProRes 422 steps) and
    exits non-zero, so the command exists as a documented stub. Report back
    before doing more.

Proposed interface (if scripting works)

camkit export-video [--project PATH] [--out FILE] [--codec prores422] [--preset NAME]
  • --out FILE — output path; default ./<project>.mov (mirror how
    export-audio derives its default name via bundleName(...) in
    cmdExportAudio).
  • --codec — default prores422; structure it so prores4444/h264 can be
    added later, but only prores422 is required for v1.
  • Render the timeline as-is (run after rebuild, same contract as
    export-audio). macOS-only; throw the standard "macOS-only" error elsewhere.
  • Respect that Camtasia must have the project open (or open it) to render —
    reuse camtasiaDocPaths() / openProject() from @camkit/darwin.

Where the code goes (follow CONTRIBUTING boundaries)

  • Anything that shells out to Camtasia/osascript → @camkit/darwin
    (packages/darwin/src/index.ts), throwing on non-darwin.
  • Arg parsing, default-path logic, console output → @camkit/cli
    (packages/cli/src/camkit.ts): add cmdExportVideo, register it in
    COMMANDS, add a HELP["export-video"] entry and a one-line summary in
    printHelp's summaries map.
  • Keep @camkit/core out of this — there's no pure timeline math here.

Acceptance criteria

  • Spike findings recorded (which AppleScript/UI path works on the current
    Camtasia version) in the PR description and/or index.ts doc comment.
  • camkit export-video produces a playable ProRes 422 .mov of the current
    timeline, or — if Camtasia can't be scripted — a documented stub that
    prints exact manual steps and exits non-zero.
  • camkit export-video --help and the top-level help list the command.
  • README updated (Packages/CLI section + Prerequisites if Accessibility
    permission is needed).
  • bun test and bun run typecheck pass.
  • Verified manually against a real .cmproj; note the verification in the PR
    (per CONTRIBUTING).

Relationship to the other issues

This is the render half of the pipeline. Putting the rendered footage back
into a project as media is a separate mechanism (pure JSON + ffprobe, no
Camtasia render) — tracked in the companion "import media" issue. They were
considered for merging but use different machinery; keep them separate. Both are
features and should land under the new release flow (the release issue),
bumping the minor version.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    p3Priority 3

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions