beat-fx build contract
Interface contract for the effect scripts and Fusion macros in this skill. Every script/macro author MUST follow this so the pieces compose.
Mission
Reusable effect and timing helpers for DaVinci Resolve. The authored edit chooses targets, timing, and treatment; helpers implement those choices. Defaults and macros are optional building blocks, not a genre specification.
Environment facts (verified 2026-08-02)
- DaVinci Resolve Studio 21.0.3.7 at
/Applications/DaVinci Resolve/DaVinci Resolve.app. External scripting WORKS (run scripts from Bash under system python3). - System python3 at
/opt/homebrew/bin/python3.uvandffmpegon PATH. - The
davinci-resolve-mcpserver (repo:~/dev/davinci-resolve-mcp) is connected. Its docs are the API reference of record:~/dev/davinci-resolve-mcp/docs/SKILL.md, plusdocs/,examples/. - More hard-won API recipes:
~/.claude/skills/davinci-resolve-scripting/SKILL.md. Probe the current edition and connection; the installed skill covers external and menu routes.
Two-process rule
- Scripts that TOUCH RESOLVE run under system python3, stdlib only (fusionscript.so must load; no third-party deps, no uv-managed python).
- Scripts with heavy deps (librosa etc.) run under uv with PEP 723 inline
metadata (
# /// script) and NEVER import DaVinciResolveScript. They exchange data with Resolve-side scripts via JSON files.
Layout
scripts/— CLI entry points (both kinds).lib/resolve_boot.py— shared connection bootstrap. Use it; don't re-derive.connect(),current_context(),timeline_fps().macros/— Fusion.settingmacro sources, namedBeatFX_<Name>.setting.
Script conventions
- Pure ASCII source (Resolve's in-app loader chokes on curly quotes/em-dashes).
- argparse CLI; every mutating script supports
--dry-run(print plan, touch nothing). Default target: current project + current timeline. - Log every action to stdout AND append to
/tmp/beatfx.log(in-app runs don't surface stdout). On error: traceback to both, exit nonzero. - Frame math: always via
timeline_fps(); never hardcode fps. Timeline record frames start at the timeline start timecode (usually 01:00:00:00 -> frame 3600*fps) — checktimeline.GetStartFrame().
Idempotency & ownership
- Everything a script creates is tagged so re-runs clean up ONLY their own work:
- markers:
customDatastarting with"beatfx:" - media pool: bin named
BeatFX - timelines the verify flow creates: name prefix
beatfx-
- markers:
- Re-run behavior: delete/replace own artifacts, never touch anything else.
- NEVER delete or modify user media, user markers, or user timelines.
Beat grid interchange format
beat_grid.py writes markers AND a JSON sidecar other scripts may consume:
/tmp/beatfx_grid.json:
{"fps": 30.0, "timeline": "name", "start_frame": 108000,
"beats": [{"frame": 108012, "sec": 0.4, "downbeat": true}],
"bpm": 120.0}
- Beat markers: color
Blue, customDatabeatfx:beat. - Downbeat markers: color
Red, customDatabeatfx:downbeat. - Marker frameId values are relative to timeline start (GetStartFrame offset already subtracted) — that is what AddMarker expects.
Fusion macros
- Plain-text
.settingfiles, group/macro namedBeatFX_<Name>, exposing a small number of published controls (e.g. Intensity, DurationFrames). - Install target (applier script copies if missing):
~/Library/Application Support/Blackmagic Design/DaVinci Resolve/Fusion/Templates/Edit/Effects/BeatFX/(appears in Edit page Effects Library under Effects > BeatFX). - Each macro ships with
scripts/apply_<name>.pythat applies it to timeline items at/around beat markers via the scripting API. Research the reliable application path in the MCP repo docs (fusion_comp / timeline_item_fusion tools,docs/,api_truthfacts) — do not guess one API call and hope.
Verification
Test helper math and graph construction offline where possible, then verify the changed behavior in a short live Deliver render. File-only tests do not prove that a Fusion graph renders correctly. Serialize work against the one shared Resolve instance; if work is delegated, keep parallel workers offline and assign live mutation to a single operator.
Documentation duty
Each deliverable ends with a short header comment: what it does, args, example invocation. Anything you discovered the hard way (API quirk, wrong-page failure, property name) goes in your final report so it lands in SKILL.md.
