Skip to content

Commit 177f3ca

Browse files
committed
feat(editor): expose precise overlay and caption controls
1 parent 560ff93 commit 177f3ca

17 files changed

Lines changed: 603 additions & 58 deletions

‎docs/MCP.md‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,9 +147,15 @@ the MCP tool contract instead of guessing an opaque operation object.
147147

148148
Editor agents add a project-owned image overlay with `add_overlay`, then adjust
149149
its normalized position, width, opacity, rotation, and fades with
150-
`update_overlay`. Overlay clips live on their own visual track, may overlap the
150+
`update_overlay`. Use `replace_overlay_asset` with another project-owned image
151+
Asset to swap the artwork while preserving the clip's timing and transform.
152+
Overlay clips live on their own visual track, may overlap the
151153
base video, and remain subject to the same revision checks, Asset boundary, and
152-
durable timeline persistence as UI edits. Captions are composited after overlays.
154+
durable timeline persistence as UI edits. The UI also lets users drag an active
155+
overlay directly in the preview frame. Captions are composited after overlays.
156+
Use `update_caption` to tune one caption cue's normalized font size, maximum
157+
width, and bottom position without changing later cues; `set_caption_style`
158+
continues to select the shared visual preset.
153159

154160
For a newly connected Canvas node, append a `place_card` operation after its
155161
`upsert_card`. By default it places the target once to the right of the frames

‎docs/PRODUCT_PLAN_AND_STATUS.md‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,16 +112,17 @@ Codex / Claude Code / Other Agent
112112
- 非破坏式 trim、split、move、delete 和 ripple delete。
113113
- undo/redo。
114114
- 音量、静音、淡入和淡出。
115-
- 图片 Overlay 叠加,支持位置、宽度、透明度、旋转和淡入淡出;预览与 MP4 导出保持一致。
115+
- 图片 Overlay 叠加,支持在预览中直接拖动,并可精确调整位置、宽度、透明度、旋转和淡入淡出;预览与 MP4 导出保持一致。
116116
- 浏览器本地预览。
117117
- 选区派生 MP4。
118118
- BeatAPI 选区 AI redo。
119119
- Redo 结果作为 Take 保存、激活和恢复 Original。
120120
- 完整 Timeline H.264/AAC MP4 导出。
121-
- 字幕在 Overlay 之后绘制,确保字幕始终位于最终画面层。
121+
- 字幕在 Overlay 之后绘制,确保字幕始终位于最终画面层;单条字幕可独立调整字号、最大宽度和垂直位置,UI 与 MCP 共用同一操作。
122122
- 导出写回 Assets 和 Canvas Timeline Node。
123123
- 缺失素材、Clip 重叠和视频轨空隙诊断。
124124
- Editor 自动保存统一走 Command Kernel;并发写入使用 revision/CAS 和三方合并,不再用旧文档覆盖新版本。
125+
- 右侧栏是 Agent 中立的 Timeline Inspector,不内置或假装存在专有 Clip Agent;Codex、Claude Code、Cursor 等通用 Agent 通过 MCP 修改同一份 Timeline。
125126
- 同一次加入时间线使用稳定 Clip ID 和幂等键,重复点击、网络重试不会重复插入同一批 Clip。
126127
- Take 必须覆盖 Clip 时长;过短 Take 不可激活,诊断会阻止可能产生冻结尾帧的导出。
127128

‎messages/en.json‎

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,11 @@
525525
"captions": {
526526
"text": "Caption text",
527527
"style": "Caption style",
528+
"currentCue": "Current caption",
529+
"currentCueHint": "This cue only",
530+
"fontScale": "Text size",
531+
"maxWidth": "Maximum width",
532+
"bottomOffset": "Position from bottom",
528533
"styles": {
529534
"classic": "Classic",
530535
"bold": "Bold",
@@ -542,6 +547,8 @@
542547
"activeHint": "Audio follows the timeline playhead and fades are applied during preview and export."
543548
},
544549
"overlay": {
550+
"dragLabel": "Move image overlay",
551+
"dragHint": "Drag to move · Arrow keys to nudge",
545552
"x": "Horizontal position",
546553
"y": "Vertical position",
547554
"width": "Width",
@@ -551,14 +558,13 @@
551558
"fadeOut": "Fade out"
552559
},
553560
"panel": {
554-
"title": "Clip Agent",
555-
"local": "Local",
556-
"subtitle": "Your editing workspace",
561+
"title": "Inspector",
562+
"subtitle": "Timeline properties",
557563
"properties": "Properties",
558564
"quickActions": "Clip actions",
559565
"exactHint": "Open Exact to edit source range, duration, and timeline position.",
560566
"welcomeTitle": "Edit with a clear workflow",
561-
"welcomeDescription": "Select a timeline clip to edit its properties here. Your source media stays local until an action explicitly needs BeatAPI.",
567+
"welcomeDescription": "Select a timeline clip to edit its properties here, or let any MCP-capable agent update the same timeline. Your source media stays local until an action explicitly needs BeatAPI.",
562568
"workflow": {
563569
"studio": {
564570
"title": "Start in Studio",

‎messages/ja.json‎

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,11 @@
525525
"captions": {
526526
"text": "字幕テキスト",
527527
"style": "字幕スタイル",
528+
"currentCue": "現在の字幕",
529+
"currentCueHint": "この字幕のみ",
530+
"fontScale": "文字サイズ",
531+
"maxWidth": "最大幅",
532+
"bottomOffset": "下端からの位置",
528533
"styles": {
529534
"classic": "クラシック",
530535
"bold": "ボールド",
@@ -542,6 +547,8 @@
542547
"activeHint": "音声はTimelineの再生ヘッドに追従し、プレビューと書き出し時にフェードが適用されます。"
543548
},
544549
"overlay": {
550+
"dragLabel": "画像オーバーレイを移動",
551+
"dragHint": "ドラッグで移動・矢印キーで微調整",
545552
"x": "水平位置",
546553
"y": "垂直位置",
547554
"width": "幅",
@@ -551,14 +558,13 @@
551558
"fadeOut": "フェードアウト"
552559
},
553560
"panel": {
554-
"title": "Clip Agent",
555-
"local": "ローカル",
556-
"subtitle": "編集ワークスペース",
561+
"title": "インスペクター",
562+
"subtitle": "Timelineのプロパティ",
557563
"properties": "プロパティ",
558564
"quickActions": "Clipの操作",
559565
"exactHint": "詳細設定を開き、ソース範囲、長さ、Timeline上の位置を編集します。",
560566
"welcomeTitle": "明確な流れで編集",
561-
"welcomeDescription": "TimelineのClipを選択すると、ここでプロパティを編集できます。BeatAPIが明示的に必要な操作を行うまで、ソースメディアはローカルに保持されます。",
567+
"welcomeDescription": "TimelineのClipを選択すると、ここでプロパティを編集できます。MCP対応の汎用Agentも同じTimelineを更新できます。BeatAPIが明示的に必要な操作を行うまで、ソースメディアはローカルに保持されます。",
562568
"workflow": {
563569
"studio": {
564570
"title": "Studioから始める",

‎messages/zh.json‎

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,11 @@
525525
"captions": {
526526
"text": "字幕文案",
527527
"style": "字幕样式",
528+
"currentCue": "当前字幕",
529+
"currentCueHint": "仅调整这一句",
530+
"fontScale": "文字大小",
531+
"maxWidth": "最大宽度",
532+
"bottomOffset": "距底部位置",
528533
"styles": {
529534
"classic": "经典描边",
530535
"bold": "短视频粗体",
@@ -542,6 +547,8 @@
542547
"activeHint": "音频跟随时间线播放头,淡入淡出会同时应用于预览和导出。"
543548
},
544549
"overlay": {
550+
"dragLabel": "移动叠加图片",
551+
"dragHint": "拖动移动 · 方向键微调",
545552
"x": "水平位置",
546553
"y": "垂直位置",
547554
"width": "宽度",
@@ -551,14 +558,13 @@
551558
"fadeOut": "淡出"
552559
},
553560
"panel": {
554-
"title": "片段助手",
555-
"local": "本地",
556-
"subtitle": "你的剪辑工作区",
561+
"title": "属性检查器",
562+
"subtitle": "时间线属性",
557563
"properties": "片段属性",
558564
"quickActions": "片段操作",
559565
"exactHint": "展开精确参数,可以修改素材范围、持续时间和时间线位置。",
560566
"welcomeTitle": "按清晰流程完成剪辑",
561-
"welcomeDescription": "选择时间线片段后,可在这里编辑参数。除非某个操作明确需要 BeatAPI,否则源素材始终保留在本地。",
567+
"welcomeDescription": "选择时间线片段后,可在这里编辑参数;任何支持 MCP 的通用 Agent 也能修改同一条时间线。除非某个操作明确需要 BeatAPI,否则源素材始终保留在本地。",
562568
"workflow": {
563569
"studio": {
564570
"title": "从 Studio 开始",

‎src/components/editor/video-editor-workspace.test.ts‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,37 @@ import { createTimelineDocument } from '@/core/editor/timeline-document';
55
import { applyEditorOperations } from '@/core/commands/editor-commands';
66
import {
77
findVisualClipAtTimelineTime,
8+
moveOverlayInPreview,
89
PROJECT_TIMELINE_EXTERNAL_POLL_INTERVAL_MS,
910
shouldPersistTimelineDocument,
1011
timelineDocumentsEqualForPersistence,
1112
} from './video-editor-workspace';
1213

14+
test('overlay preview dragging maps pixels to normalized frame coordinates', () => {
15+
assert.deepEqual(
16+
moveOverlayInPreview({
17+
originX: 0.5,
18+
originY: 0.25,
19+
deltaX: 100,
20+
deltaY: 50,
21+
frameWidth: 500,
22+
frameHeight: 1000,
23+
}),
24+
{ x: 0.7, y: 0.3 }
25+
);
26+
assert.deepEqual(
27+
moveOverlayInPreview({
28+
originX: 0.98,
29+
originY: 0.02,
30+
deltaX: 100,
31+
deltaY: -100,
32+
frameWidth: 500,
33+
frameHeight: 1000,
34+
}),
35+
{ x: 1, y: 0 }
36+
);
37+
});
38+
1339
test('does not echo a remotely loaded timeline back through UI autosave', () => {
1440
const remote = createTimelineDocument({
1541
projectId: 'project-1',

0 commit comments

Comments
 (0)