Skip to content

fix(export): stop counting letterbox rows as an upscale - #229

Merged
EtienneLescot merged 1 commit into
release/v1.8.0from
fix/export-upscale-badge
Aug 3, 2026
Merged

fix(export): stop counting letterbox rows as an upscale#229
EtienneLescot merged 1 commit into
release/v1.8.0from
fix/export-upscale-badge

Conversation

@EtienneLescot

@EtienneLescot EtienneLescot commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator

Reported from the export dialog: with a 1920x1032 window capture on the timeline, the Source tile reads 1920 × 1080.

That number is right — it is the output frame, and the smallest 16:9 frame holding a 1920-wide source without shrinking it is 1920x1080. The source's real 1032 was never lost either: it is what makes the 720p tile read as a downscale. So the size SSOT is fine.

What was wrong is next to it: 1080p and Source resolve to the exact same 1920x1080 frame, and only one of them carries the "Upscale" warning.

before after
720p 1280 × 720 1280 × 720
1080p 1920 × 1080 · Upscale 1920 × 1080
Source 1920 × 1080 1920 × 1080

The badge compared short sides (1080 > 1032), which counts the letterbox rows a non-16:9 source gets in a 16:9 project as if they were stretched pixels. Those 48 rows are wallpaper; the clip is contain-fitted and still renders at 1:1.

wouldUpscale() now asks the contain-fit question the compositor actually answers:

min(out.w / src.w, out.h / src.h) > 1

A source whose shape matches the project ratio is unaffected — which is why a full-screen capture never showed this and a window capture did. A tier that genuinely stretches the source (1280x720 → 1080p, scale 1.5) is still flagged.

The q.value !== "source" exemption is gone: Source's frame is the source's long side at the project ratio, so its contain scale is never above 1 and the general test covers it. The MEDIUM_SHORT_SIDE/HIGH_SHORT_SIDE constants (duplicated from mp4ExportSettings.ts) and the write-only targetShortSide field they fed go with it.

Verification

  • src/lib/exporter/mp4ExportSettings.test.ts — 8/8, two new cases: the reported 1920x1032 @ 16:9 (all three tiers unflagged) and a real stretch that must stay flagged.
  • src/components/ai-edition/ExportDialog.test.ts — 8/8.
  • biome check clean on the three files (also via the pre-commit hook).
  • Not exercised in the running app: it needs a real 1920x1032 window recording loaded in the editor. The unit test replays that exact case.

tsc --noEmit reports one pre-existing unrelated error, src/i18n/loader.ts: Cannot find module 'i18next' — the local node_modules predates that dependency and needs an npm install.

Summary by CodeRabbit

  • Bug Fixes
    • Improved export quality warnings by accurately accounting for letterboxed video dimensions.
    • Prevented false upscale warnings when source footage fits within the selected output without enlargement.
    • Continued warning users when genuinely smaller source footage would be enlarged during export.
    • Updated quality handling consistently across medium, good, and source export options.

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The export flow now uses contain-fit output dimensions to detect upscaling. The dialog removes fixed target-size metadata and applies the shared check to all quality tiers. Tests cover letterboxed captures and genuine source upscaling.

Changes

Upscale detection

Layer / File(s) Summary
Contain-fit upscale helper and coverage
src/lib/exporter/mp4ExportSettings.ts, src/lib/exporter/mp4ExportSettings.test.ts
Adds Dims and the exported wouldUpscale helper. Tests cover letterboxed captures and smaller sources.
Export dialog warning integration
src/components/ai-edition/ExportDialog.tsx
Removes fixed target short-side metadata and uses wouldUpscale for quality warnings, including the Source tier.

Estimated code review effort: 2 (Simple) | ~15 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
Title check ✅ Passed The title clearly identifies the export bug and the correction for letterbox rows being counted as an upscale.
Description check ✅ Passed The description clearly explains the bug, implementation, affected behavior, and verification, but it does not complete the template checkboxes or related-issue field.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/export-upscale-badge

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/components/ai-edition/ExportDialog.tsx (1)

409-417: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add a same-package test for the ExportDialog upscale badge path.

src/components/ai-edition/ExportDialog.test.ts does not cover willUpscale(dims, smallestSource) or qualityUpscaleWarning, while the exported badge uses wouldUpscale on the dialog’s tier output dimensions. Add integration coverage for the letterboxed source case and a genuine upscale case across the relevant quality options.

🤖 Prompt for 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.

In `@src/components/ai-edition/ExportDialog.tsx` around lines 409 - 417, Add
same-package integration tests in ExportDialog.test.ts covering the exported
upscale badge path that calls wouldUpscale(dims, smallestSource), including a
letterboxed source case that remains unflagged and a genuine upscale case that
is flagged. Exercise the relevant quality options and verify
qualityUpscaleWarning behavior using the dialog’s tier output dimensions.

Source: Coding guidelines

🤖 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.

Nitpick comments:
In `@src/components/ai-edition/ExportDialog.tsx`:
- Around line 409-417: Add same-package integration tests in
ExportDialog.test.ts covering the exported upscale badge path that calls
wouldUpscale(dims, smallestSource), including a letterboxed source case that
remains unflagged and a genuine upscale case that is flagged. Exercise the
relevant quality options and verify qualityUpscaleWarning behavior using the
dialog’s tier output dimensions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: e04c0496-2993-482a-9a92-ac78c92ab642

📥 Commits

Reviewing files that changed from the base of the PR and between e383f9b and ee28154.

📒 Files selected for processing (3)
  • src/components/ai-edition/ExportDialog.tsx
  • src/lib/exporter/mp4ExportSettings.test.ts
  • src/lib/exporter/mp4ExportSettings.ts

A 1920x1032 window capture in a 16:9 project exports into a 1920x1080 frame:
the 48 extra rows are wallpaper, and the clip itself still renders at 1:1. The
export dialog decided whether a tier upscaled by comparing short sides, so it
read those rows as stretched pixels and flagged "1080p - Upscale" on the exact
frame the "Source" tier produced unflagged, since both tiers resolve to the
same 1920x1080 there. The two tiles sat side by side with identical dimensions
and different warnings.

wouldUpscale() now asks the contain-fit question the compositor actually
answers: min(out.w/src.w, out.h/src.h) > 1. Nothing changes for a source whose
shape matches the project ratio, which is why a full-screen capture never
showed this and a window capture did.

That also makes the "Source" exemption provable instead of asserted - its
frame is the source's long side at the project ratio, so its contain scale is
never above 1 - and the general test now covers it. The exemption goes, and
with it the MEDIUM_SHORT_SIDE/HIGH_SHORT_SIDE constants duplicated from
mp4ExportSettings and the write-only targetShortSide field they fed.
@EtienneLescot
EtienneLescot force-pushed the fix/export-upscale-badge branch from ee28154 to 85b0ab7 Compare August 3, 2026 06:28
@EtienneLescot
EtienneLescot changed the base branch from main to release/v1.8.0 August 3, 2026 06:28
@EtienneLescot
EtienneLescot merged commit 3b0847b into release/v1.8.0 Aug 3, 2026
16 checks passed
@EtienneLescot
EtienneLescot deleted the fix/export-upscale-badge branch August 3, 2026 07:08
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