Skip to content

修复加文本覆写现有轨 + center-only transform 无 auto-fit(#194 #195)#205

Merged
appergb merged 4 commits into
betafrom
fix/194-add-texts-auto-track
Jul 6, 2026
Merged

修复加文本覆写现有轨 + center-only transform 无 auto-fit(#194 #195)#205
appergb merged 4 commits into
betafrom
fix/194-add-texts-auto-track

Conversation

@appergb

@appergb appergb commented Jul 6, 2026

Copy link
Copy Markdown
Owner

概述

修复两个 add_texts(MCP 工具)/ addTextClip(Toolbar "T" 按钮)的 bug:

上游对照

位置 文件
MCP 工具 addTexts ToolExecutor+Texts.swift:42-157parseAddTextTransform 在 18-40 行)
UI 按钮 addTextClip() EditorViewModel+MediaLibrary.swift:518-558
批量放置 placeTextClips() EditorViewModel+MediaLibrary.swift:454-516

三态行为表(add_textstrackIndex

每条 entry 的 trackIndex 行为 对应 EditCommand
全部省略 新建 1 条顶层视频轨(index 0),全部文本落这条轨,单事务 AddTextsAutoTrack(新增)
全部指定 直接落到指定轨,覆写重叠区(同 add_clips AddTexts(既有)
部分省略 拒绝,报错:Mixed trackIndex: N of M entries omitted trackIndex. Either set it on every entry or omit it on every entry (to auto-create a shared new track).(与上游文案一致)

transform 解析(resolve_text_transform,1:1 port parseAddTextTransform

输入 行为
省略整个 transform center (0.5, 0.5) + 按文本自然尺寸 auto-fit
只给 {centerX, centerY} 该 center + auto-fit(lower-third 场景:只重新定位,不用手算 box)
全部四项 {centerX, centerY, width, height} 完全按指定值,不测量
其他组合(如只给 width、或只给 centerX) 拒绝,报错文案与上游一致

Auto-fit 复用 add_captions 已有的度量路径 opentake_domain::TextLayout::natural_size,按 90% 画布宽度换行(与 ADD_TEXT_MAX_TEXT_WIDTH_RATIO / CAPTION_MAX_TEXT_WIDTH_RATIO 同一比例,上游 parseAddTextTransform 里硬编码同一个 0.9)——不是新发明的度量机制。

关于 #195 "顺带核实" 项的结论

issue 原文怀疑"省略整个 transform 时实测渲染位置对应 centerY≈0.9(caption 式),与工具文档 'Omit transform to center + auto-fit' 不符"。对照上游源码 EditorViewModel+MediaLibrary.swift:460TextClipSpec.transform doc comment:"When nil the box is auto-fit to content and centered on the canvas")以及 493 行实现(Transform(topLeft: ((1-w)/2,(1-h)/2), width: w, height: h),即几何居中),确认工具文档("center")是对的,上游行为也是 center——add_texts 省略 transform 时用 (0.5, 0.5)。真机 ~0.9 的观察应该是修复前旧代码 Transform::default()(identity 全画布 + 未 auto-fit)叠加渲染细节导致的视觉偏移,不是不同的"预期默认值"。本 PR 的实现(center 0.5/0.5 + auto-fit)与上游一致,无需改文档。

add_captions 是另一个独立工具,其 center_y 默认 0.9(字幕贴底),与 add_texts 的 center 默认互不影响,二者常量也各自独立命名(ADD_TEXT_MAX_TEXT_WIDTH_RATIO vs CAPTION_MAX_TEXT_WIDTH_RATIO)。

改动范围

  • crates/opentake-ops/src/command.rs — 新增 EditCommand::AddTextsAutoTrack + TextAutoTrackEntry,单事务插入顶层轨 + 放置全部文本;6 个单测(新轨@0、原轨零变化、undo 单步回滚含新轨、空 entries 报错、非法 duration/startFrame 报错、同批重叠覆写语义)。
  • crates/opentake-agent/src/mcp/dispatch.rsadd_texts dispatch 按 trackIndex 全省略/全指定/混合三态路由;resolve_text_transform + auto_fit_text_transform 实现 [HIGH][ops] add_texts 只传 center 时 auto-fit 缺失(box 落 1.0×1.0 全画布;上游 TextLayout.naturalSize) #195 的 auto-fit;8 个单测覆盖三态路由 + 4 种 transform 形状。
  • src-tauri/src/commands.rsEditRequest::AddTextsAutoTrack + TextAutoTrackEntryDto,camelCase serde;serde round-trip 测试守卫 IPC 边界契约。
  • web/src/lib/types.tsTextAutoTrackEntryReq 镜像 Rust DTO。
  • web/src/store/editActions.ts — Toolbar "T" 的 addTextClip() 改走 addTextsAutoTrack,替换原来的 firstVisualTrackIndex 覆写路径。
  • web/src/store/editActions.test.ts — 4 个新测试覆盖 addTextClip(新轨/空时间线/选中新 clip/连续两次各建各的轨)。

验证

  • cargo fmt --all --check:绿
  • cargo clippy --workspace --all-targets -- -D warnings:绿,零告警
  • cargo test --workspace:全绿(含本 PR 新增的 15 个 Rust 单测)
  • pnpm -C web build:绿
  • pnpm -C web test:44 个测试文件、498 个测试全绿

Fixes #194
Fixes #195

baiqing added 4 commits July 6, 2026 22:29
Adds a variant that always inserts a fresh top video track (index 0) and
places every text entry there in one undoable transaction, instead of
writing into whatever track the caller already has at index 0.

1:1 port of upstream's addTexts all-omitted-trackIndex path
(ToolExecutor+Texts.swift:114-121) and addTextClip
(EditorViewModel+MediaLibrary.swift:519-558), both of which unconditionally
create a new top track rather than reusing an existing one — the gap #194
reports: an existing top track can hold unrelated video/image content that
the straight AddTexts path would clear_region over.

Entries within the batch still overwrite each other on overlap in
start-frame order, matching AddTexts/upstream placeTextClips. Empty
entries is an error (a caller mistake), not a no-op like AddCaptions.
)

add_texts dispatch now inspects trackIndex across the whole entries batch:
- all omitted -> AddTextsAutoTrack (shared new top track, #194 fix)
- all set -> existing AddTexts (explicit tracks, overwrite as before)
- mixed -> rejected with upstream's exact error text, since a new track
  at index 0 would shift any explicit indices

Also fixes #195: a center-only transform ({centerX, centerY} with no
width/height) used to fall through to Transform::default(), filling in
identity width/height = 1.0 (full canvas). It now auto-fits the box to the
measured text via opentake_domain::TextLayout::natural_size, wrapped at
90% of canvas width — the same measurement path add_captions already
uses, and the same 0.9 ratio upstream's parseAddTextTransform hardcodes
(ToolExecutor+Texts.swift:38). Omitting transform entirely also auto-fits,
centered at (0.5, 0.5) — matches upstream's placeTextClips/addTextClip,
which explicitly center + auto-fit a nil transform
(EditorViewModel+MediaLibrary.swift:460-493). Passing all four transform
fields still overrides without measuring.
New EditRequest::AddTextsAutoTrack variant + TextAutoTrackEntryDto,
camelCase serde (startFrame/durationFrames/textStyle) matching the
TypeScript EditRequest union and TextAutoTrackEntryReq mirror. Includes a
serde round-trip test guarding the camelCase contract, same pattern as
the existing addCaptions guard — this repo's #1 bug class is a DTO field
that silently fails to deserialize because the wire format didn't match.
The Toolbar "T" button's addTextClip used to reuse the first existing
visual track (or create one only if none existed at all), so a top
video/image track's content could get overwritten by addTexts' clip
placement. It now always calls addTextsAutoTrack, mirroring upstream
addTextClip's unconditional insertTrack(at: 0, type: .video)
(EditorViewModel+MediaLibrary.swift:519-558) — each call creates its own
new top track rather than caching or reusing one.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant