Integration: preview/rendering fixes and local build sync#155
Conversation
…:1 calibration (#40) Settings: - Restructure from single-page scroll to sidebar + detail layout (mirrors upstream SettingsView.swift): 180px sidebar with icon+label rows and an active capsule on the left edge. - 8 pane entries (General, Appearance, Import, AI, MCP Instructions, Storage, Notifications, About) — the 7-pane scope from the issue, with General and Appearance kept as separate panes (upstream merges them under "general" but OpenTake's existing split is preserved). - New MCPInstructionsPane: surfaces the built-in MCP server URL (http://127.0.0.1:19789/mcp) with copy button, plus one-line install commands for Claude Code, Codex, Cursor, and Claude Desktop. Mirrors upstream Help/MCPInstructionsPane.swift, consolidated into Settings per the issue. - New StoragePane: cache + search-index fields (simplified placeholder; runtime statistics require Rust commands not yet wired). - New NotificationsPane: generation-complete toggle (front-end-only for now). Home (1:1 calibration with upstream ProjectCard.swift / HomeView.swift): - ProjectCard: hover scale 1.02 -> 1.03 (match upstream). - ProjectCard: title moved inside the thumbnail with a 60px bottom gradient overlay (upstream pattern), replacing the below-card title. - ProjectCard: relative time (today / yesterday / N days ago / N weeks ago / N months ago) replaces the raw path display, using the existing RecentProject.openedAt timestamp. - ProjectCard: delete button rounded to a circle (upstream glassEffect pattern). - NewProjectCard: hover scale 1.02 -> 1.03. i18n: 30+ new keys (zh-CN + en) for MCP, Storage, Notifications, and relative-time strings. Closes #40.
…card) (#39) Adds an end-to-end "extract audio" path so users can save a video's soundtrack as a standalone audio file from the media panel. Backend (Rust): - opentake-media: `MediaEngine::extract_audio` + `extract_audio_file` helper drive ffmpeg via the existing `ffmpeg_path()` CLI wrapper. `-y -i <in> -vn` plus codec args picked by output extension: .m4a/.aac → AAC 192k, .mp3 → libmp3lame 192k, .wav → pcm_s16le. - src-tauri/media: new `extract_audio` Tauri command resolves a media id to its `MediaSource::External` absolute path, validates the file exists, then delegates to the engine. Returns the output path. - src-tauri/lib: register `media::extract_audio` in `generate_handler!`. Frontend (React/TS): - api.ts: `extractAudio(mediaId, outPath)` wrapper; rejects outside Tauri (no ffmpeg available). - MediaPanel.tsx: MediaCard gains a star-shaped "Extract Audio" button on the top-left, shown only when hovering a video that carries an audio track. Click opens a native save dialog (m4a/mp3/wav filters), invokes `extract_audio`, and surfaces a transient success/failure feedback message. `stopPropagation`+`preventDefault` keep the click from selecting the card. - i18n dict.ts: 6 new keys (zh-CN + en) for the button title, hint, success, failure, and no-audio messages. Closes #39.
Adds the standard clipboard shortcuts that were completely missing. Only
⌘C/⌘X/⌘V were absent — the unmodified C/V already switch tools (razor /
pointer), and the mod-prefixed branch had no handlers.
Frontend only:
- clipboardStore: new Zustand store holding deep snapshots of the selected
clips plus the source first-frame, so a paste can re-place the group
relative to the current playhead. UI-only, never persisted.
- editActions: copyClips / cutClips / pasteClipsAtPlayhead.
- copy: snapshot selected clips + their track index + min startFrame.
- cut: copy then deleteSelectedClips.
- paste: offset each clip's startFrame by `activeFrame - sourceFirstFrame`,
clear addLinkedAudio so the paste stands alone (mirrors upstream
`pasteClipsAtPlayhead` link re-reflection), and select the new clips.
Clips whose source track no longer exists are skipped.
- useKeyboardShortcuts: wire ⌘C / ⌘X / ⌘V inside the existing `if (mod)`
block — no conflict with the unmodified C/V tool switches.
- i18n: 4 new keys (zh-CN + en) for copy / cut / paste / clipboardEmpty.
Closes #94.
…oast Address review feedback on PR #105: 1. Rebased onto latest main (resolved import conflict: kept both trimToPlayheadEdits and useClipboardStore). 2. copyClips now expands link groups: if a selected clip has a linkGroupId, all linked companions are included in the clipboard (mirrors upstream copyClips), so a paste reproduces the video+audio pair. 3. pasteClipsAtPlayhead now re-establishes link groups after addClips: clips that shared a linkGroupId in the clipboard are re-linked via linkClips, preserving video+audio linkage. 4. Empty-clipboard paste now shows a toast (edit.clipboardEmpty) instead of silently doing nothing. Added toast mechanism to uiStore + Toast component in App.tsx.
…0624 # Conflicts: # web/src/i18n/dict.ts
# Conflicts: # src-tauri/src/lib.rs # src-tauri/src/media.rs # web/src/components/media/MediaPanel.tsx # web/src/i18n/dict.ts # web/src/lib/api.ts
- DrawOpts 新增 linkOffset 可选字段 - drawOffsetBadge() 绘制红色圆角 badge,白字 +N/-N 帧偏移 - paintTimeline 预计算 linkOffsetMap(同 linkGroupId 的 clip 间 startFrame 差值) - badge 位置: clip 右上角 trim handle 内侧 2px 边距 Port of ClipRenderer.swift:624-656 drawOffsetBadge. Closes #87
Upstream TimelineInputController.swift shows ALL interactive drag operations (razor, move, trimLeft, trimRight, timelineRange) pass includePlayhead=true. The only false case is external-drag-in (TimelineView.swift:948 applyExternalSnap), which OpenTake does not yet have.
…pOffsets Blockers: - Offset = (startFrame − trimStartFrame) − group_min, not raw startFrame - Group by linkGroupId, use min srcPos as ref (not pairwise ±) - Only non-earliest clips get badge (always +offset, never minus) - Remove break (correct for 3+ clip groups) Visual: - Color: rgb(255,71,71) (upstream #FF4747) - Remove white stroke (upstream has none) - Narrow clip guard: bx <= rect.x + 6 - Font weight: 600 (semibold) Tests: color + narrow clip guard
Rewrite the timeline preview/playback pipeline to upstream's single-surface model (VideoEngine.swift / PreviewView.swift): the engine owns playback, the view only renders. Removes the dual-surface / dual-clock stopgap that caused the reported pause-twitch, non-live scrub, and stutter. - previewEngine.ts: app-level single clock + shared element registry. One rAF authority; runs only while playing or scrubbing; auto-pauses at end. Replaces the playbackClock refcount + usePlaybackTicker + the in-component rAF. - Surface state machine = browser equivalent of upstream exact/interactiveScrub: PLAY and SCRUB use the cheap live <video>/<audio> stack (scrub live-seeks to the frame); SETTLED uses the high-fidelity Rust GPU composite. Drops the 140ms trailing debounce — the expensive composite now fires once, on settle. - Wire the long-unused isScrubbing through the ruler scrub (TimelineContainer, scrub branch only — editing gestures untouched) and the Preview scrub bar. - TimelinePlaybackLayer becomes a pure renderer (registers elements, no clock). - advancePlayhead extracted as a pure, unit-tested helper. Scope: full transform/crop/text compositing DURING playback still awaits the streaming engine (#53); this lands the faithful single-clock structure and fixes the three reported playback bugs. Rust composite_frame unchanged. Bump version 0.1.0 -> 0.1.1. tsc clean; 56 web tests pass (+4 engine tests).
…142) Two preview regressions: - Pause jumped back to the start. The composite targeted currentFrame, which the engine freezes at the play-start frame during playback (it only advances activeFrame), so the settled composite fetched frame 0. Target activeFrame — the live playhead — so the composite is the frame you paused on. useTimelineFrame now also returns which frame its url was rendered for; the composite is shown only once it has decoded the CURRENT frame, and the <video> backdrop (frozen on the pause frame) holds the picture until then — so pausing is correct instantly with no stale-frame flash. - Scrub-bar progress fill rendered as a tall cream bar down the preview's left edge: its absolute fill/handle escaped the (unpositioned) track. Add position:relative to contain them. Bump 0.1.1 -> 0.1.2. tsc clean; 56 tests pass.
Codex-authored changes addressing the upstream-consistency audit, brought onto the working branch. Compiles (tsc clean) and all 56 web tests pass. - Clipboard: copy/cut/paste clips (⌘C/⌘X/⌘V) + clipboardStore + empty toast. - Clip right-click context menu (ClipContextMenu) + editActions wiring. - Snap: stronger targets / includePlayhead / tolerance tweaks (snap.ts). - Clip helpers + types: new fields and edit helpers (clip.ts, types.ts). - Timeline interactions: drag/hit-test/canvas refinements (TimelineContainer, hitTest, timelineCanvas, clipRenderer incl. link-offset badge). - uiStore: transient toast; media-folder setter. HoverButton cursor: pointer. - Preview: position:relative on the stage (contains the scrub-bar fill, audit #10). Authored by Codex; reviewed for compile + tests only. Per-item correctness vs upstream is tracked in the audit issues filed alongside.
The transport play/pause button retained keyboard focus after a mouse click. On WebKit (Tauri WebView) a focused <button>'s Space activation fires on keyup, which the window keydown handler's preventDefault does not cancel — so Space toggled play TWICE (focused-button onClick + global shortcut), leaving isPlaying net-unchanged (the button never flipped to the paused state) and churning the engine (spurious playhead jump). onMouseDown preventDefault stops the button taking focus on click; Space is then handled solely by the global shortcut. onClick is unaffected; Tab focus (accessibility) is preserved.
ROOT CAUSE (thanks to the Codex audit): the paused-state GPU composite <img> (position:absolute; inset:0) had no pointerEvents:none, so it intercepted every mouse event over the preview area — the play/pause button "couldn't be pressed" and looked stuck (the icon WAS updating; the overlay just blocked the click and covered it). The state machine was never wrong (verified: togglePlay toggles isPlaying cleanly). - Composite <img>: pointerEvents:none. - <TimelinePlayback> surface: pointerEvents:none (same class of display-only layer). - Revert the earlier focus-prevention guess on HoverButton (wrong hypothesis; togglePlay was confirmed single-call/correct). The togglePlay rewind-from-end (uiStore) is intended replay behaviour and only fires at the timeline end; the perceived "jump to start" was a downstream effect of not being able to pause mid-timeline, resolved by the click fix.
Pause twitch + late-icon (#149, two-agent root-cause): the <video> backdrop freezes on its real-time decode frame F_video, but the engine's activeFrame lags by a tick, so the settled GPU composite was fetched for an EARLIER frame and, when it painted over the frozen video, the picture twitched back. The icon felt late because that twitch render was the one the user noticed. Fix: on the pause transition, snap activeFrame to the visual element's frozen frame (frameForSourceTime of its currentTime), so composeFrame == F_video and the composite paints the same picture — no jump, pause reads instant. Also adds docs/EDITING-ENGINE-PLAN.md: the editing-engine implementation map (ops layer is 1:1 with upstream; gaps are in the wiring layer), the linked-audio behaviour (upstream design — A1/A2 for video+audio is correct; "no-audio video" is a stale-cache or upstream-1:1-vs-deviation question for the user), and the A→B→C close-out plan over issues #145/#146/#147/#86/#87/#98. No probe.rs change: its channels-missing default is intentional (audio-only files report no channels in the test mock; flipping would drop real audio).
后端: - 新增 EditCommand::SwapMedia 变体,替换 clip 的 media_ref - 校验新媒体存在于 manifest,若时长不足自动截断 duration + 调整 trim_end - 保留所有编辑属性(transform/crop/keyframe tracks/grade/masks/effects/fade) - media_type 隐含 source_clip_type(spec "sync media_type" 场景) - 新增 EditRequest::SwapMedia DTO + into_command 映射 - 6 个单元测试:等长替换/较短截断/媒体不存在/同步 media_type/clip 不存在/undo 前端: - types.ts 新增 swapMedia EditRequest 变体 - editActions.ts 新增 swapMedia(clipId, mediaRef, options?) action - Inspector 新增「替换媒体」section + 内联媒体选择器 - i18n 中英文翻译 Closes #101
…ste' into integration/all-prs-20260625 # Conflicts: # web/src/components/preview/TimelinePlaybackLayer.tsx
…to integration/all-prs-20260625 # Conflicts: # web/src/components/preview/TimelinePlaybackLayer.tsx
…d hover parallax cards
…parallax-test # Conflicts: # web/src/components/home/HomeView.tsx
… modal dialog popup
…parallax-test # Conflicts: # web/src/App.tsx # web/src/components/settings/SettingsView.tsx
* feat(timeline): copy / cut / paste clips (⌘C / ⌘X / ⌘V) (#94) Adds the standard clipboard shortcuts that were completely missing. Only ⌘C/⌘X/⌘V were absent — the unmodified C/V already switch tools (razor / pointer), and the mod-prefixed branch had no handlers. Frontend only: - clipboardStore: new Zustand store holding deep snapshots of the selected clips plus the source first-frame, so a paste can re-place the group relative to the current playhead. UI-only, never persisted. - editActions: copyClips / cutClips / pasteClipsAtPlayhead. - copy: snapshot selected clips + their track index + min startFrame. - cut: copy then deleteSelectedClips. - paste: offset each clip's startFrame by `activeFrame - sourceFirstFrame`, clear addLinkedAudio so the paste stands alone (mirrors upstream `pasteClipsAtPlayhead` link re-reflection), and select the new clips. Clips whose source track no longer exists are skipped. - useKeyboardShortcuts: wire ⌘C / ⌘X / ⌘V inside the existing `if (mod)` block — no conflict with the unmodified C/V tool switches. - i18n: 4 new keys (zh-CN + en) for copy / cut / paste / clipboardEmpty. Closes #94. * fix(#94): rebase onto main + linkGroup re-mapping + empty-clipboard toast Address review feedback on PR #105: 1. Rebased onto latest main (resolved import conflict: kept both trimToPlayheadEdits and useClipboardStore). 2. copyClips now expands link groups: if a selected clip has a linkGroupId, all linked companions are included in the clipboard (mirrors upstream copyClips), so a paste reproduces the video+audio pair. 3. pasteClipsAtPlayhead now re-establishes link groups after addClips: clips that shared a linkGroupId in the clipboard are re-linked via linkClips, preserving video+audio linkage. 4. Empty-clipboard paste now shows a toast (edit.clipboardEmpty) instead of silently doing nothing. Added toast mechanism to uiStore + Toast component in App.tsx. --------- Co-authored-by: baiqing <lbx12309@icloud.com>
* feat(swap-media): 实现 SwapMedia 编辑命令,支持替换 clip 媒体 (#101) 后端: - 新增 EditCommand::SwapMedia 变体,替换 clip 的 media_ref - 校验新媒体存在于 manifest,若时长不足自动截断 duration + 调整 trim_end - 保留所有编辑属性(transform/crop/keyframe tracks/grade/masks/effects/fade) - media_type 隐含 source_clip_type(spec "sync media_type" 场景) - 新增 EditRequest::SwapMedia DTO + into_command 映射 - 6 个单元测试:等长替换/较短截断/媒体不存在/同步 media_type/clip 不存在/undo 前端: - types.ts 新增 swapMedia EditRequest 变体 - editActions.ts 新增 swapMedia(clipId, mediaRef, options?) action - Inspector 新增「替换媒体」section + 内联媒体选择器 - i18n 中英文翻译 Closes #101 * style: fix cargo fmt in command.rs and tests (#101) * fix: correct cargo fmt in command_apply.rs (#101) * fix: align trailing comment with 43 spaces (#101) * chore: trim playback whitespace * fix(swap-media): simplify DTO to 2-arg + frontend type-consistency filter (review #121) * fix(swap-media): singleLinkGroup gate + extract SwapMediaSection out of Inspector (#101) --------- Co-authored-by: baiqing <lbx12309@icloud.com>
* feat(inspector): live sampling + missing fields (crop/fade/flip) (#97) Backend (opentake-ops + src-tauri): - Extend ClipProperties with crop, fade_in/out_frames, fade_in/out_interpolation, flip_horizontal, flip_vertical - set_clip_properties writes new fields; fade clamps to clip duration; flip_* writes to transform.flip_* - ClipPropertiesDto mirrors fields with serde camelCase - 5 unit tests: crop sets+clears track, fade frames+interp, fade clamps, flip writes to transform, multiple fields at once Frontend (web): - clip.ts: 1:1 port of Rust Clip::*_at sampling methods (opacity/volume/ rotation/size/topLeft/crop), fadeMultiplier, db<->linear, generic sampleKeyframeTrack with number/AnimPair/Crop lerp - Inspector.tsx: read activeFrame from uiStore; show sampled values at playhead; switch to ReadOnlyValue + AnimatedHint when a track is active - 4 new sections: Position (top-left x/y), Crop (4 edge insets 0-1), Flip (2 checkboxes), Fade (in/out frames + interpolation selects) - Fade section appears on both video and audio tabs - types.ts: extend ClipPropertiesReq with camelCase fields - dict.ts: i18n keys for new sections (zh-CN + en) Closes #97 * style: fix cargo fmt import in command.rs (#97) * fix: add ..Default::default() for new ClipProperties fields (#97) * fix(#97): use clip.opacity/volume for editable fields, sampled* only for animated (review #122)
* feat(#93): add clip right-click context menu Closes #93. - New ClipContextMenu component with Split / Delete / Link-Unlink - TimelineContainer: onContextMenu hit-tests the clip, selects it if needed, and opens the menu; closes on outside click or Escape - i18n: contextMenu.split/delete/link/unlink (zh-CN + en) * fix(#93): menu cursor positioning + viewport flip; remove render-phase onClose() Blocking items from review: 1. Menu now follows cursor (x/y from onContextMenu -> ClipContextMenu left/top) with useLayoutEffect viewport-boundary flip (right/bottom overflow -> open left/up). 2. Removed onClose() call during render; clip-missing now returns null and reports close via useEffect (no parent setState mid-render). Minor items: - Added disabled placeholder items: Swap Media / Save as Media / Extract Audio. - Replaced key={i} with stable key={item.id}. - Replaced imperative onMouseEnter/Leave DOM mutation with CSS :hover. * fix(timeline): remove duplicate context menu handler * feat(inspector/swap-media): gate + picker modal for Swap Media entry Wire the Swap Media context-menu action in ClipContextMenu.tsx: - Availability gate: enabled only when the clip is non-text AND alone in its link group (SPEC §5.10 "非 text 且单链组" = upstream TimelineView.menu). Multi-clip link groups (e.g. linked A/V pairs) stay disabled to avoid desyncing partners. - On click, opens a media-picker modal pre-filtered by strict type equality (item.type === clip.mediaType, mirroring upstream isAssetCompatibleWithPendingSwap). Backend re-validates as a safety net. New files: - web/src/components/timeline/SwapMediaPicker.tsx: modal list of compatible library assets; calls edit.swapMedia() on selection; shows backend error message (e.g. type-mismatch refusal) inline; Esc-to-close. New helpers / state: - web/src/lib/clip.ts: isSingleLinkGroup(clip, timeline) helper. - web/src/store/uiStore.ts: pendingSwapClipId + setPendingSwapClipId. Touched: - web/src/components/timeline/ClipContextMenu.tsx: gate + open picker. - web/src/components/timeline/TimelineContainer.tsx: render SwapMediaPicker. - web/src/i18n/dict.ts: swapMedia.noCandidates (zh + en). - web/src/lib/types.ts: swapMedia EditRequest variant. - web/src/store/editActions.ts: 2-arg swapMedia wrapper around editApply. Pairs with feat-101-swap-media (the backend `replaceClipMediaRef( resetTrim=false)` route). tsc --noEmit + pnpm build green. * fix(#93): bind onContextMenu to content canvas (TS6133 unused) --------- Co-authored-by: baiqing <lbx12309@icloud.com>
* feat(timeline): 吸附迟滞+多探针 / 链接 offset 角标 / 音量橡皮筋 (#99) 1. 吸附迟滞 + 多探针 - snap.ts: findSnapDelta 扩展接受 currentlySnapped + probeOffsets, 返回 probeOffset,支持 sticky band 跨 pointer 事件保持 - TimelineContainer.tsx: 新增 snapStateRef 跨事件保持吸附状态; onPointerMove move 分支收集所有 companions 的 start+end 作为探针组, 改用 findSnapDelta(不再传 null);onPointerUp 清空 snapStateRef 2. 链接 offset 角标 - clip.ts: 新增 linkOffsetForClip 计算链接组内帧偏移(相对 lead clip) - clipRenderer.ts: 新增 drawOffsetBadge 绘制红色圆角徽章 "+N"/"-N" - timelineCanvas.ts: clip 绘制参数增加 linkOffset,调用 drawOffsetBadge 3. 音量橡皮筋 - clipRenderer.ts: 新增 drawVolumeEnvelope 绘制 volumeTrack 折线 + kf 圆点 (半径 5px,黄色填充白色边框);拖拽时 ghost dot 跟随光标 - hitTest.ts: 新增 audioVolumeKfHit 命中测试(8px 容差) - TimelineContainer.tsx: 新增 audioVolumeKf DragState + 拖拽逻辑; Cmd+click 空白处调 stampKeyframe - editActions.ts: moveKeyframe / stampKeyframe 实现为前端 wrapper (read-modify-write over setKeyframes,因后端仅暴露 SetKeyframes) 验证:pnpm tsc --noEmit 通过;pnpm build 通过;52 项测试全通过 * fix(pr-120): offset badge top-right + move drag excludes playhead (review #120) Two PR #120 review request-changes fixes, both for spec 5.7 / 5.4 1:1 port correctness: 1. drawOffsetBadge anchored to the right edge of the clip, just inside the right trim handle (ClipRenderer.swift:640-644). The old top-left position sat on top of the color strip and label, and the new width-guard reserves room for the trim handle so the badge never overlaps it. 2. Move drag no longer includes the playhead in the snap target set. The old collectTargets(timeline, excluded, activeFrame) made moving clips stick to the playhead, which felt like a bug. Pass null (the same exclusion the trim path uses) so a move only snaps to other clip edges and the playhead stays a passive reference. pnpm tsc --noEmit + pnpm build + pnpm test 52/52 green.
* feat(timeline): drag-drop new track + Option/Alt-drag duplicate (#98) Backend (Rust): - Add `opentake_ops::ops::duplicate::duplicate_clips` — deep-copies each clip (keyframe tracks / grade / chroma / masks / effects / text / transform / crop / fades via `Clip: Clone`), mints a fresh id, shifts `start_frame` by `offset_frames`, lands on `target_track_indexes[i]`, clears `link_group_id`, and clears the destination range overwrite-style first (mirrors `move_clips`). 11 unit tests cover original retention, link-group clearing, keyframe deep copy, grade/masks/effects deep copy, multi-track targets, relative spacing, overwrite blocking, frame clamping, missing-clip skip, incompatible-track skip, and text/transform. - Add `EditCommand::DuplicateClips` variant + `duplicate_clips_cmd` apply dispatch with validation (empty ids / length mismatch / missing clips) and the standard transact wrapper (snapshot -> mutate -> commit-if-changed -> version++). 7 command-level tests (creates copy, deep copies keyframes, clears link_group_id, missing clip errors, length mismatch errors, empty ids errors, undoable). - Add `EditRequest::DuplicateClips` DTO in `src-tauri/src/commands.rs` + `into_command` mapping (direct field pass-through). Frontend (React + TypeScript): - Add `duplicateClips` variant to `EditRequest` in `types.ts`. - Add `duplicateClips()` action in `editActions.ts` (applyAndRefresh). - `TimelineContainer.tsx`: add `isDuplicate` flag (Alt key detection at pointer-down), `DropTarget` discriminated union (`existing` | `newTrack`), `newTrackTypeFor` helper (audio -> "audio", else -> "video"). `onPointerMove` computes `dropTarget` (existing track via `trackAt`, or `newTrack` when below the last track bottom). `onPointerUp` branches: newTrack -> `edit.insertTrack` -> `forceRefresh` -> `edit.duplicateClips`/`moveClips` with the new track index; existing track -> group-floor-clamped move or duplicate. - `timelineCanvas.ts`: extend `DragPaint` move variant with `isDuplicate?` and `newTrackType?`. Render a dashed new-track drop indicator below the last track; render the ghost at the new-track Y when `newTrackType` is set; pass `isDuplicate` to `drawClip`. - `clipRenderer.ts`: add `isDuplicate?` to `DrawOpts`; draw a yellow "+" badge in the top-right corner when `ghost && isDuplicate` so the user sees the gesture will copy rather than move. Closes #98. * style: fix cargo fmt in duplicate.rs (#98) * fix: correct cargo fmt in duplicate.rs - split long assert lines (#98) * fix: split long assert/assert_eq lines for cargo fmt (#98) * fix: compile errors - rotation_track type + borrow conflict (#98) * style: fix cargo fmt - import wrap + assert_eq single line (#98) * style: fix import wrapping for cargo fmt (#98) * fix: clippy errors - remove redundant clone on Copy types (#98) * fix(#98): implement groupCounts/groupRemap for link group remapping (review #123)
# Conflicts: # crates/opentake-agent/src/mcp/dispatch.rs # web/src/components/preview/Preview.test.tsx # web/src/components/preview/Preview.tsx # web/src/components/preview/TimelinePlaybackLayer.tsx # web/src/components/preview/timelinePlayback.test.ts # web/src/components/preview/timelinePlayback.ts # web/src/components/preview/useTimelineFrame.ts # web/src/lib/fallback.test.ts # web/src/lib/fallback.ts # web/src/store/editActions.test.ts # web/src/store/editActions.ts
# Conflicts: # src-tauri/src/commands.rs # web/src/App.tsx # web/src/components/inspector/Inspector.tsx # web/src/components/preview/TimelinePlaybackLayer.tsx # web/src/components/timeline/ClipContextMenu.tsx # web/src/components/timeline/TimelineContainer.tsx # web/src/components/timeline/clipRenderer.ts # web/src/components/timeline/hitTest.ts # web/src/components/timeline/timelineCanvas.ts # web/src/lib/clip.ts # web/src/lib/types.ts # web/src/store/editActions.ts
|
Local review/verification before merge:\n\n- Confirmed the preview/rendering fix matches upstream Swift semantics: visual track 0 is topmost; frontend DOM playback and Rust render plan now agree.\n- Confirmed playback uses a single timeline clock with DOM media as followers, reducing the reported preview stutter path.\n- Confirmed the second overlapping video goes to a top overlay track and is covered by regression tests.\n- Local verification passed: cargo fmt, cargo clippy, cargo test --workspace, pnpm test, pnpm build, Tauri DMG build, installed app smoke test.\n\nThis PR intentionally supersedes #78, #79, #105, #108, #120, #121, #122, #123, #138, #139, and #144. Newer independent PRs (#152, #153, #154) are not closed by this integration unless separately reviewed. |
Summary
This integration PR consolidates the current local OpenTake work into
mainand makes the local/cloud codebase consistent.Key points:
track 0is topmost)1.0.0Verification
Already run locally before pushing:
cargo fmt --all --checkcargo clippy --workspace --all-targets -- -D warningscargo test --workspaceCI=1 corepack pnpm@10 -C web testCI=1 corepack pnpm@10 -C web build/Applications/OpenTake.appinstall smoke testSupersedes
This PR supersedes already-integrated open PRs:
It does not supersede newer independent work unless separately verified.