Skip to content

feat(zoom): hold-to-preview button for zoom focus editing (prototype for #612)#613

Merged
siddharthvaddem merged 6 commits into
siddharthvaddem:mainfrom
auberginewly:feat/zoom-hold-preview
May 23, 2026
Merged

feat(zoom): hold-to-preview button for zoom focus editing (prototype for #612)#613
siddharthvaddem merged 6 commits into
siddharthvaddem:mainfrom
auberginewly:feat/zoom-hold-preview

Conversation

@auberginewly
Copy link
Copy Markdown
Contributor

@auberginewly auberginewly commented May 19, 2026

Draft prototype for #612.

What

When a zoom region is selected and paused, the editor shows the full un-zoomed frame so you can place the focus point. This adds a press-and-hold "Preview" button in the zoom controls: while held, the preview renders the selected zoom at the current focus + depth (before/after compare); on release it returns to the un-zoomed editing view.

Interaction is hold-to-preview (not a toggle): the zoomed view is shown only while the button is held, so it doubles as a quick before/after compare.

How

  • VideoPlayback: new transient isPreviewingZoom prop; shouldShowUnzoomedView now also requires !isPreviewingZoom, so the zoom transform is applied at the playhead while previewing. No change to focus-point math or the default editing view.
  • VideoEditor: isPreviewingZoom state wired down to VideoPlayback and to onZoomPreviewStart/End.
  • SettingsPanel: hold button in the zoom controls (pointer down/up/leave/cancel).
  • i18n: zoom.previewHold added across all 11 locales (i18n-check passes).

Open for maintainer direction (kept minimal on purpose)

  • Placement: settings-panel button (current) vs. an on-overlay button.
  • Optional: keyboard affordance / icon.

Test plan

  • Select a zoom, pause → full un-zoomed editing view (unchanged)
  • Press and hold Preview → zoomed result shows at current focus/depth
  • Release (or pointer leaves button) → back to un-zoomed editing view
  • Drag focus point, hold Preview again → reflects new focus
  • Play / export unaffected; npm test passes

Summary by CodeRabbit

Release Notes

  • New Features
    • Zoom preview button: users can now hold a button to temporarily preview their selected zoom effect on video playback, with support for both pointer and keyboard controls for accessibility
    • Multi-language support: zoom preview functionality is available across 13 languages including English, Spanish, French, Arabic, Japanese, Korean, Russian, Turkish, Vietnamese, Simplified Chinese, and Traditional Chinese

Review Change Stack

When a zoom region is selected and paused, the editor shows the full
un-zoomed frame for focus-point placement. This adds a press-and-hold
"Preview" button so editors can momentarily see the zoomed result at the
current focus + depth — like a before/after compare — without entering
playback.

- VideoPlayback: new transient isPreviewingZoom prop; shouldShowUnzoomedView
  now also requires !isPreviewingZoom, so the zoom transform is applied at
  the playhead while previewing
- VideoEditor: isPreviewingZoom state wired to VideoPlayback and to
  onZoomPreviewStart/End handlers
- SettingsPanel: hold button in the zoom controls (pointer down/up/leave/
  cancel)
- i18n: zoom.previewHold added across all 11 locales

Prototype for siddharthvaddem#612 — placement (panel vs overlay) and hold-vs-toggle still
open for maintainer direction.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 19, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2fd599c5-16b0-4092-98a5-d59145701c7d

📥 Commits

Reviewing files that changed from the base of the PR and between 259bfa9 and 85d0dea.

📒 Files selected for processing (3)
  • src/components/video-editor/SettingsPanel.tsx
  • src/components/video-editor/VideoEditor.tsx
  • src/components/video-editor/VideoPlayback.tsx

📝 Walkthrough

Walkthrough

Adds hold-to-preview gesture for zoom across three components: SettingsPanel renders a conditional button with pointer/keyboard/blur event handlers calling optional callbacks, VideoEditor tracks isPreviewingZoom state wired to those callbacks and passes it to VideoPlayback, and VideoPlayback suppresses unzoomed rendering during preview to keep selected zoom visible. Localization strings added across 11 locales.

Changes

Zoom Preview Hold-to-Preview Feature

Layer / File(s) Summary
SettingsPanel zoom preview button and callbacks
src/components/video-editor/SettingsPanel.tsx
Adds onZoomPreviewStart and onZoomPreviewEnd optional callbacks to SettingsPanelProps. Renders a conditional "hold-to-preview" button that triggers start on pointer down/space/enter key down, and end on pointer up/leave/cancel, blur, or key up.
VideoEditor state wiring
src/components/video-editor/VideoEditor.tsx
Adds non-undoable isPreviewingZoom state. Wires SettingsPanel callbacks to toggle the state and passes the flag down to VideoPlayback as a prop.
VideoPlayback preview-aware rendering
src/components/video-editor/VideoPlayback.tsx
Adds isPreviewingZoom?: boolean prop and syncs it to isPreviewingZoomRef via useEffect. Modifies the paused-state unzoomed view check in the PIXI ticker to also check !isPreviewingZoomRef.current, keeping the selected zoom visible during preview.
Zoom preview localization strings
src/i18n/locales/{ar,en,es,fr,ja-JP,ko-KR,ru,tr,vi,zh-CN,zh-TW}/settings.json
Adds zoom.previewHold translation key across all 11 locale files for the button label.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

The changes are straightforward: prop threading through three components, a small ref sync pattern, and repetitive i18n key additions. The button event handling is moderately detailed but follows standard React patterns. No complex logic or edge cases to reason through—mostly wiring and UI.

Possibly related issues

  • siddharthvaddem/openscreen#612: This PR directly implements the hold-to-preview feature for zoom that was described in the issue—adds the UI button, callbacks, state management, and localization strings to enable pressing and holding to preview the selected zoom effect.

Possibly related PRs

  • siddharthvaddem/openscreen#491: Both PRs modify VideoPlayback.tsx to change zoom behavior during playback (this one suppresses unzoomed view during preview; that one fixed zoom-sync initialization), so there's potential for interaction if landed in sequence.

Suggested reviewers

  • siddharthvaddem
  • FabLrc

Poem

hold down the space, zoom stays in place ✨
preview before you commit to the frame
buttons and refs, state flows just right
eleven translations light the zoom preview tonight 🔍

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning Description covers what/how/test plan and explains interaction model well, but is missing screenshots/video despite UI feature and the template requiring them. Add screenshot or video demonstrating the hold-to-preview button behavior to help reviewers understand the UX without running locally.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed Title accurately describes the main change—adding a hold-to-preview button for zoom controls—and references the related issue #612.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Make the label explicit about what holding previews (the zoom effect),
across all 11 locales.
@auberginewly auberginewly marked this pull request as ready for review May 19, 2026 02:54
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/video-editor/SettingsPanel.tsx`:
- Around line 947-958: The preview hold button should only render when both
lifecycle callbacks exist and must support keyboard users: change the render
condition from (onZoomPreviewStart || onZoomPreviewEnd) to (onZoomPreviewStart
&& onZoomPreviewEnd) and keep the pointer handlers
(onPointerDown/Up/Leave/Cancel) on the Button; additionally add keyboard
handlers onKeyDown (trigger onZoomPreviewStart for Space/Enter and guard against
repeat), onKeyUp and onBlur (trigger onZoomPreviewEnd) so the preview lifecycle
(start → end) is fully wired for keyboard and pointer input, referencing the
existing zoomEnabled, onZoomPreviewStart, onZoomPreviewEnd, and the Button
element that renders t("zoom.previewHold").
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0e4c6348-90b7-4c62-8039-470d6b3863c0

📥 Commits

Reviewing files that changed from the base of the PR and between 36ceca3 and 24ce67b.

📒 Files selected for processing (14)
  • src/components/video-editor/SettingsPanel.tsx
  • src/components/video-editor/VideoEditor.tsx
  • src/components/video-editor/VideoPlayback.tsx
  • src/i18n/locales/ar/settings.json
  • src/i18n/locales/en/settings.json
  • src/i18n/locales/es/settings.json
  • src/i18n/locales/fr/settings.json
  • src/i18n/locales/ja-JP/settings.json
  • src/i18n/locales/ko-KR/settings.json
  • src/i18n/locales/ru/settings.json
  • src/i18n/locales/tr/settings.json
  • src/i18n/locales/vi/settings.json
  • src/i18n/locales/zh-CN/settings.json
  • src/i18n/locales/zh-TW/settings.json

Comment thread src/components/video-editor/SettingsPanel.tsx Outdated
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 24ce67b5a7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

const hasSelectedZoom = selectedId !== null;
const shouldShowUnzoomedView = hasSelectedZoom && !isPlayingRef.current;
const shouldShowUnzoomedView =
hasSelectedZoom && !isPlayingRef.current && !isPreviewingZoomRef.current;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preview the selected zoom, not the playhead region

When the playhead is not inside the selected zoom (for example, clicking a zoom item only selects it; TimelineEditor does not seek), holding Preview disables the unzoomed edit guard but still relies on findDominantRegion(... currentTime ...). In that scenario the button previews no zoom or a different zoom at the playhead, while the settings panel is editing the selected zoom's focus/depth, so users cannot verify the selected region unless they manually seek into it first.

Useful? React with 👍 / 👎.

- VideoPlayback: while holding Preview, render the SELECTED zoom at full
  strength regardless of the playhead, instead of whatever findDominantRegion
  returns at currentTime (which is none/another zoom when the playhead is
  outside the selection). Uses getZoomScale/getRotation3D for the region's
  configured scale and 3D preset.
- SettingsPanel: require both onZoomPreviewStart && onZoomPreviewEnd to render
  the button (full lifecycle), and add keyboard support — Space/Enter keydown
  (repeat-guarded) starts preview, keyup/blur ends it.
…t frame

The a686fa0 override replaced findDominantRegion's resolved region with the
raw stored region (forcing strength=1 / transition=null). findDominantRegion
already resolves focus via getResolvedFocus — for focusMode:"auto" it
interpolates the cursor-followed focus from telemetry and applies clamp/blend/
transition. The override bypassed all of that, so previewing an auto-focus
zoom showed a stale static focus and an instant un-eased zoom that did not
match real playback/export.

Hold-to-preview now shows the natural zoom for the current playhead frame
(true before/after compare). The isPreviewingZoom flag is kept — it only
disables the un-zoomed editing guard so findDominantRegion's result is shown.
Previewing while the playhead is outside any zoom shows no zoom by design.
@auberginewly
Copy link
Copy Markdown
Contributor Author

Re: "Preview the selected zoom, not the playhead region" — reverted the selected-zoom override in b25c2c8.

The override (forcing region = raw selected region, strength = 1, transition = null) broke correctness: findDominantRegion already resolves focus via getResolvedFocus, which for focusMode: "auto" interpolates the cursor-followed focus from telemetry and applies clamp/blend/transition. Substituting the raw stored region made auto-focus zooms preview a stale static focus and an instant un-eased zoom that did not match real playback/export.

Hold-to-preview is intentionally scoped to the current playhead frame — a true before/after compare of how the zoom actually renders at that moment. When the playhead sits outside any zoom there is nothing to preview, which is acceptable: you preview while parked on the region you're editing. The isPreviewingZoom flag is kept; it only disables the un-zoomed editing guard so the natural findDominantRegion result is shown.

The keyboard a11y + && lifecycle-guard part of the earlier review is unaffected and remains in place.

@siddharthvaddem
Copy link
Copy Markdown
Owner

screen recording would be appreciated 🙏

@auberginewly
Copy link
Copy Markdown
Contributor Author

screen recording would be appreciated 🙏

Got it! Just like this — and I can preview what the zoomed-in version of the selected region looks like 👀https://github.com/user-attachments/assets/99950b12-5ea6-4e52-a4bc-a7ac00a07809

@siddharthvaddem siddharthvaddem merged commit fbd06fc into siddharthvaddem:main May 23, 2026
8 checks passed
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.

2 participants