Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -1052,6 +1052,44 @@ highlight color, others get the base text color.
and point size from the selected Motion title's CHChannelText channel. `verify_captions()`
walks connected titles on the timeline and checks text/fontSize against the expected style.

## Undo History Palette

A floating palette that shows every action pushed onto FCP's undo stack, including
actions registered before the panel was opened. Redo entries (done-then-undone) are
shown greyed-out below the current state. Click any row to undo or redo to that state.

```
history.show() # open the Undo History palette
history.hide() # close it
history.get() # return full history + cursor position
history.jumpToIndex(index=-1) # undo/redo to a specific index (-1 = pristine)
history.clear() # clear SpliceKit's buffer (does NOT touch FCP undo stack)
```

`history.get()` returns:
```json
{
"entries": [
{ "index": -1, "name": "(Pristine)", "timestamp": "", "isCurrent": false },
{ "index": 0, "name": "Blade", "timestamp": "14:32:01", "isCurrent": false },
{ "index": 1, "name": "Add Marker", "timestamp": "14:32:05", "isCurrent": true },
{ "index": 2, "name": "Trim Start", "timestamp": "14:32:09", "isCurrent": false }
],
"cursor": 1,
"canUndo": true,
"canRedo": true,
"visible": true
}
```

Entries at indices > cursor are redo-available (greyed in the UI).
The palette tracks up to 100 entries in a ring buffer.

**Implementation note**: history is captured by observing `NSUndoManagerDidCloseUndoGroupNotification`
with per-manager nesting depth tracking — only the outermost group close (depth 0→1→0) produces an
entry, so nested FCP transactions don't generate spurious rows. Recording is suppressed during
undo/redo replay so redo-stack registrations aren't mistaken for new user actions.

## Lua Scripting

SpliceKit embeds a Lua 5.4 VM directly in FCP's process. Scripts use the `sk`
Expand Down
16 changes: 12 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ braw-prototype: $(BRAW_IMPORT_EXEC) $(BRAW_DECODER_EXEC) $(BRAW_CLI_BIN)
braw-raw-processor: $(BRAW_RAWPROC_EXEC)
@echo "Staged: $(BRAW_RAWPROC_BUNDLE)"

deploy: $(OUTPUT) $(SILENCE_DETECTOR) $(STRUCTURE_ANALYZER) $(MIXER_APP) braw-prototype vp9-prototype mkv-prototype
deploy: $(OUTPUT) $(SILENCE_DETECTOR) $(STRUCTURE_ANALYZER) $(MIXER_APP) vp9-prototype mkv-prototype

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Removing braw-prototype from deploy prerequisites masks BRAW build/copy failures

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At Makefile, line 383:

<comment>Removing `braw-prototype` from deploy prerequisites masks BRAW build/copy failures</comment>

<file context>
@@ -380,7 +380,7 @@ braw-prototype: $(BRAW_IMPORT_EXEC) $(BRAW_DECODER_EXEC) $(BRAW_CLI_BIN)
 	@echo "Staged: $(BRAW_RAWPROC_BUNDLE)"
 
-deploy: $(OUTPUT) $(SILENCE_DETECTOR) $(STRUCTURE_ANALYZER) $(MIXER_APP) braw-prototype vp9-prototype mkv-prototype
+deploy: $(OUTPUT) $(SILENCE_DETECTOR) $(STRUCTURE_ANALYZER) $(MIXER_APP) vp9-prototype mkv-prototype
 	@echo "=== Deploying SpliceKit to modded FCP ==="
 		@rm -rf "$(FW_DIR)"
</file context>

@echo "=== Deploying SpliceKit to modded FCP ==="
@rm -rf "$(FW_DIR)"
@mkdir -p "$(FW_DIR)/Versions/A/Resources"
Expand All @@ -394,9 +394,11 @@ deploy: $(OUTPUT) $(SILENCE_DETECTOR) $(STRUCTURE_ANALYZER) $(MIXER_APP) braw-pr
@cd "$(FW_DIR)/Versions" && ln -sfn A Current
@cd "$(FW_DIR)" && ln -sfn Versions/Current/SpliceKit SpliceKit
@cd "$(FW_DIR)" && ln -sfn Versions/Current/Resources Resources
@# Create Info.plist if missing
@test -f "$(FW_DIR)/Versions/A/Resources/Info.plist" || \
printf '<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "https://www.apple.com/DTDs/PropertyList-1.0.dtd">\n<plist version="1.0"><dict><key>CFBundleIdentifier</key><string>com.splicekit.SpliceKit</string><key>CFBundleName</key><string>SpliceKit</string><key>CFBundleVersion</key><string>1.0.0</string><key>CFBundlePackageType</key><string>FMWK</string><key>CFBundleExecutable</key><string>SpliceKit</string></dict></plist>' \
@# Always write Info.plist with the current SPLICEKIT_VERSION so the patcher
@# version check (CFBundleShortVersionString comparison) never triggers a
@# spurious "update available" prompt after a manual make deploy.
@mkdir -p "$(FW_DIR)/Versions/A/Resources"
@printf '<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "https://www.apple.com/DTDs/PropertyList-1.0.dtd">\n<plist version="1.0"><dict><key>CFBundleIdentifier</key><string>com.splicekit.SpliceKit</string><key>CFBundleName</key><string>SpliceKit</string><key>CFBundleShortVersionString</key><string>$(SPLICEKIT_VERSION)</string><key>CFBundleVersion</key><string>$(SPLICEKIT_VERSION)</string><key>CFBundlePackageType</key><string>FMWK</string><key>CFBundleExecutable</key><string>SpliceKit</string></dict></plist>' \
> "$(FW_DIR)/Versions/A/Resources/Info.plist"
@# Add privacy usage descriptions for transcript, LiveCam, and palette voice dictation.
@/usr/libexec/PlistBuddy -c "Set :NSSpeechRecognitionUsageDescription 'SpliceKit uses speech recognition for transcript editing and command palette voice dictation inside Final Cut Pro.'" "$(MODDED_APP)/Contents/Info.plist" 2>/dev/null || /usr/libexec/PlistBuddy -c "Add :NSSpeechRecognitionUsageDescription string 'SpliceKit uses speech recognition for transcript editing and command palette voice dictation inside Final Cut Pro.'" "$(MODDED_APP)/Contents/Info.plist" 2>/dev/null || true
Expand Down Expand Up @@ -451,11 +453,13 @@ deploy: $(OUTPUT) $(SILENCE_DETECTOR) $(STRUCTURE_ANALYZER) $(MIXER_APP) braw-pr
@mkdir -p "$(MODDED_APP)/Contents/PlugIns/Codecs"
@rm -rf "$(MODDED_APP)/Contents/PlugIns/Codecs/SpliceKitVP9Decoder.bundle"
@cp -R "$(VP9_DECODER_BUNDLE)" "$(MODDED_APP)/Contents/PlugIns/Codecs/SpliceKitVP9Decoder.bundle"
@xattr -rc "$(MODDED_APP)/Contents/PlugIns/Codecs/SpliceKitVP9Decoder.bundle" 2>/dev/null || true
@echo "VP9 decoder bundle copied into FCP.app/Contents/PlugIns"
@$(MAKE) mkv-prototype
@mkdir -p "$(MODDED_APP)/Contents/PlugIns/FormatReaders"
@rm -rf "$(MODDED_APP)/Contents/PlugIns/FormatReaders/SpliceKitMKVImport.bundle"
@cp -R "$(MKV_IMPORT_BUNDLE)" "$(MODDED_APP)/Contents/PlugIns/FormatReaders/SpliceKitMKVImport.bundle"
@xattr -rc "$(MODDED_APP)/Contents/PlugIns/FormatReaders/SpliceKitMKVImport.bundle" 2>/dev/null || true
@echo "MKV/WebM format reader copied into FCP.app/Contents/PlugIns"
@if [ "$(ENABLE_BRAW_RAW_PROCESSOR)" = "1" ]; then \
$(MAKE) braw-raw-processor; \
Expand All @@ -464,6 +468,7 @@ deploy: $(OUTPUT) $(SILENCE_DETECTOR) $(STRUCTURE_ANALYZER) $(MIXER_APP) braw-pr
cp -R "$(BUILD_DIR)/braw-prototype/Extensions/SpliceKitBRAWRAWProcessor.appex" "$(MODDED_APP)/Contents/Extensions/SpliceKitBRAWRAWProcessor.appex"; \
echo "Opt-in BRAW RAW processor copied into FCP.app/Contents/Extensions"; \
fi
@xattr -rc "$(MODDED_APP)/Contents/PlugIns" 2>/dev/null || true
@sign_identity=$$(security find-identity -v -p codesigning 2>/dev/null | awk '/"Apple Development:/ { print $$2; exit } /"Developer ID Application:/ && developer == "" { developer = $$2 } /[0-9]+\) [0-9A-F]+ "/ && first == "" { first = $$2 } END { if (developer != "") print developer; else if (first != "") print first }'); \
if [ -n "$$sign_identity" ]; then \
echo "Using signing identity: $$sign_identity"; \
Expand All @@ -480,6 +485,9 @@ deploy: $(OUTPUT) $(SILENCE_DETECTOR) $(STRUCTURE_ANALYZER) $(MIXER_APP) braw-pr
if [ -d "$(MODDED_APP)/Contents/PlugIns/Codecs/SpliceKitVP9Decoder.bundle" ]; then \
codesign --force --sign "$$sign_identity" "$(MODDED_APP)/Contents/PlugIns/Codecs/SpliceKitVP9Decoder.bundle"; \
fi; \
if [ -d "$(MODDED_APP)/Contents/PlugIns/FormatReaders/SpliceKitMKVImport.bundle" ]; then \
codesign --force --sign "$$sign_identity" "$(MODDED_APP)/Contents/PlugIns/FormatReaders/SpliceKitMKVImport.bundle"; \
fi; \
if [ -d "$(MODDED_APP)/Contents/Extensions/SpliceKitBRAWRAWProcessor.appex" ]; then \
appex_sign_id="$(BRAW_RAWPROC_SIGN_ID)"; \
if [ -n "$$appex_sign_id" ]; then \
Expand Down
7 changes: 7 additions & 0 deletions Sources/SOURCES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@ SpliceKitSentry.m
SpliceKitTranscriptPanel.m
SpliceKitTranscriptDiagnostics.m
SpliceKitCaptionPanel.m
SpliceKitUndoHistoryPanel.m
SpliceKitCommandPalette.m
SpliceKitDebugUI.m
SpliceKitPreferencesPane.m
SpliceKitStructureBlocks.m
SpliceKitSectionsBar.m
SpliceKitTimelineOverview.m
Expand All @@ -36,9 +38,14 @@ SpliceKitLuaPanel.m
SpliceKitPlugins.m
SpliceKitMixerPanel.m
SpliceKitSidebarCoalesce.m
SpliceKitReplaceAtPlayhead.m
SpliceKitClipLock.m
SpliceKitTimelineInteractionSuspend.m
SpliceKitTimelinePlayheadOverlay.m
SpliceKitTimelineTabs.m
SpliceKitTimecodeBarShortcuts.m
SpliceKitTimelinePerfMode.m
SpliceKitWaveformExpand.m
SpliceKitURLImport.m
SpliceKitLiveCam.m
SpliceKitVisionPro.m
Expand Down
8 changes: 8 additions & 0 deletions Sources/SpliceKit.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,10 @@ void SpliceKit_removeViewerPinchZoom(void);
void SpliceKit_setViewerPinchZoomEnabled(BOOL enabled);
BOOL SpliceKit_isViewerPinchZoomEnabled(void);

// Clip locking: right-click → "Lock/Unlock Clip", ⌥L shortcut, and RPC methods.
// Locked clips cannot be moved, trimmed, deleted, or cut.
void SpliceKit_installClipLock(void);

// Adds a right-click "Favorite" option in the effect browser.
void SpliceKit_installEffectFavoritesSwizzle(void);

Expand Down Expand Up @@ -216,11 +220,15 @@ void SpliceKit_installTimelinePerformanceMode(void);
void SpliceKit_setTimelinePerformanceModeEnabled(BOOL enabled);
BOOL SpliceKit_isTimelinePerformanceModeEnabled(void);

// Expands audio waveform to fill full clip height when video thumbnails are hidden.
void SpliceKit_installWaveformExpand(void);

// Swizzles pasteAnchored: and paste: to handle FCPXML on the pasteboard.
// When FCPXML is detected, imports it into a temp project, converts to native
// clipboard format, and then lets the original paste proceed. Includes caching,
// screen freeze to hide the project switch, and playhead restoration.
void SpliceKit_installFCPXMLPasteSwizzle(void);
void SpliceKit_installPasteOverwriteMenuItem(void);

// Shared FCPXML-to-native conversion function. Checks if the pasteboard has
// FCPXML, converts it to native proFFPasteboardUTI format (using cache if
Expand Down
Loading