feat(inspector): keyframe editing UI + fine-grained backend commands (#95)#119
Merged
Merged
Conversation
…ppergb#95) Backend (Rust): - Add 4 EditCommand variants: StampKeyframe, RemoveKeyframe, MoveKeyframe, SetKeyframeInterpolation (absolute timeline frames, converted to clip-relative internally) - stamp_keyframe samples the clip current value via raw_opacity_at / top_left_at / size_at / crop_at / rotation_at / volume_track.sample - move_keyframe validates target frame is within clip range (half-open) - 12 unit tests covering happy paths + error paths Tauri boundary: - Add 4 EditRequest variants + into_command mappings Frontend (React + TypeScript): - Add 4 EditRequest types + 4 editActions functions - New KeyframesPanel.tsx: ruler + per-property rows + playhead overlay - New KeyframesLaneRow.tsx: draggable diamonds + right-click menu (delete / set interpolation) + stamp/clear buttons + snap to playhead - Wire Inspector.tsx: render panel when keyframesOpen === true - Fix clipRenderer.ts: drawKeyframeMarkers now includes volumeTrack - 14 i18n keys (zh-CN + en) Closes appergb#95
appergb
approved these changes
Jun 23, 2026
appergb
left a comment
Owner
There was a problem hiding this comment.
审核通过 ✅(自动审核流程 · 主控亲审 + 路线裁决)
实现 issue #95 关键帧编辑:后端 4 个细粒度 EditCommand(StampKeyframe/RemoveKeyframe/MoveKeyframe/SetKeyframeInterpolation)+ 前端 Inspector KeyframesPanel/KeyframesLaneRow 菱形可拖编辑。
- 命令 apply 语义正确(亲读核对):clip 相对帧
rel=frame-start_frame、半开区间clip.contains校验、move 的『目标越界/被占用』守卫、Volume stamp 取 0.0 dB(unity 正确)、SetInterp 仅设 interpolation_out 对齐上游 per-keyframe out-interp。12 后端单测覆盖全部命令与边界。 - 真接线非死代码,Inspector 在 keyframesOpen 渲染 KeyframesPanel(补齐消费缺口),每属性一行 + 拖动/删除/盖章/改插值。
- 符号逐一在 main 存在且匹配,序列化兼容;不碰 #91 媒体重写区;CI 双绿。
- 路线裁决:关键帧采用本 PR 的『后端命令』路线(更接近上游 1:1、走真命令+undo),优于 #120 的纯前端 read-modify-write。先合本 PR 确立该路线。
follow-up(非阻塞):① clipRenderer 把 volumeTrack 加入时间线菱形集,上游仅渲染 5 个视觉轨——与 #120 的音量包络 dot 并存时音频 clip 音量关键帧可能重复渲染,rebase #120 时一并按上游收口;② KeyframesLaneRow 拖拽吸附基于 mousedown 时的 activeFrame 快照(交互细节)。
This was referenced Jun 23, 2026
appergb
pushed a commit
to cuic19053-hue/OpenTake
that referenced
this pull request
Jun 24, 2026
…ppergb#120-123 request-changes
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Closes #95 — adds keyframe editing UI + fine-grained backend commands.
Before: the Inspector had a dead diamond toggle button that did nothing. Keyframes were read-only on the timeline (yellow diamonds). Users could not add, delete, move, or change interpolation.
After: clicking the diamond button opens a full keyframe editing panel with per-property rows, draggable diamonds, right-click context menu, and stamp/clear buttons.
How
Backend (Rust) — 4 new EditCommand variants:
StampKeyframeframeand upserts a keyframe. Usesraw_opacity_at(notopacity_at) to avoid double fade,top_left_atfor position,size_atfor scale.RemoveKeyframeframe. Clears track toNonewhen empty.MoveKeyframeSetKeyframeInterpolationinterpolation_out(Linear/Smooth/Hold).All commands use absolute timeline frames (public API), converted to clip-relative internally. Each returns
affected_clip_idsto trigger frontend refresh.Tauri boundary: 4
EditRequestvariants +into_commandmappings, reusingKeyframePropertyDtoand domainInterpolation.Frontend (React + TypeScript):
KeyframesPanel.tsx— ruler + per-property rows (video: 5 rows, audio: 1 row) + panel-wide playhead overlayKeyframesLaneRow.tsx— HTML div diamonds (rotate 45deg, not SVG — avoids percentage coordinate issues), drag with window listeners + snap to playhead (±5 frames), right-click context menu (delete / set interpolation), stamp/clear buttonsInspector.tsx— renders<KeyframesPanel>whenkeyframesOpen === trueclipRenderer.ts— fix:drawKeyframeMarkersnow includesvolumeTrack(was missing)Key design decisions:
transform: rotate(45deg)instead of SVG polygons (SVGpointscan't take percentage strings;viewBox + preserveAspectRatio="none"distorts diamonds)useRefcleanup to prevent window listener leaks on unmount[startFrame, startFrame + duration - 1](half-open clip range)Testing
pnpm tsc --noEmit— passpnpm build— passcargo test/cargo clippy— pending CI (no local Rust toolchain)Limitations
SetClipPropertiesstill clears keyframe tracks when setting opacity/volume scalars. The UI to disable scalar sliders for animated properties will be handled in [inspector] 三段式 live 预览缺失 + 字段不全(位置/裁剪/翻转/fade) #97 (Inspector three-section live preview).