Skip to content

Export frame - #46

Open
PlkMarudny wants to merge 4 commits into
ronak-create:mainfrom
PlkMarudny:export-frame
Open

Export frame#46
PlkMarudny wants to merge 4 commits into
ronak-create:mainfrom
PlkMarudny:export-frame

Conversation

@PlkMarudny

@PlkMarudny PlkMarudny commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

image

This is a proposal, as rendering is affected (the one called "realtime" - it is disabled while frame is active).

Quite often the footage is, for example, horizontal, but a vertical reel must be produced. Abstracting out the video reframing done externally, for the manual process now one can set a project to 16x9, with a cropping frame 9x16. On ffmpeg export, this will be preserved. While making a composition (by a human), it is quite easy to manualy frame the source horizontal video, as it is visible, but dimmed ouside the frame area.

Type of change

  • Bug fix
  • New feature (GUI/composition)
  • Docs
  • Refactor / internal

How was it verified?

  • node --check server.js && node --check app.js && node --check mcp-server.js passes
  • Opened the editor and confirmed the change in preview
  • Confirmed the change in an export (fast or realtime), if it affects rendering
  • Updated CLAUDE.md / README.md if the schema, props, or API changed

Checklist

  • No new runtime dependencies added
  • Preview and export render identically (single compositor)
  • Commits are focused and messages are descriptive

Summary by CodeRabbit

  • New Features
    • Added export-frame controls to reframe compositions to different delivery aspect ratios, with a draggable overlay and presets.
    • Preview shows overscan outside the selected export area; the overlay updates during zoom/pan and monitor resizing.
    • Export-frame settings are saved/restored per project, and exports are cropped to the frame; realtime export is disabled while a frame is set (when applicable).
  • Documentation
    • Added guidance and a recipe for “Reframe horizontal → vertical,” explaining canvas vs delivery crop and exportFrame behavior.

= added 3 commits July 28, 2026 11:23
Introduce optional exportFrame crop in project.json so the composition canvas can differ from delivery size. Preview shows a dimmed overscan overlay with a draggable frame handle, aspect presets in the monitor, and Fast export crops JPEGs to the frame. Realtime export is disabled while a frame is set.
Move the caption inside the crop, add edge drag strips, and fix handle vertical alignment with 0.8/1/0.9 opacity states for normal, hover, and active drag.
@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 66afaeec-a314-43f0-917e-a7cc0e243962

📥 Commits

Reviewing files that changed from the base of the PR and between 446420b and 88eafbe.

📒 Files selected for processing (4)
  • CLAUDE.md
  • app.js
  • index.html
  • style.css
🚧 Files skipped from review as they are similar to previous changes (3)
  • style.css
  • index.html
  • CLAUDE.md

📝 Walkthrough

Walkthrough

Added optional exportFrame support across project persistence, MCP updates, Program Monitor controls, overscan overlay interaction, documentation, and JPEG export cropping. Export setup now adjusts engine availability based on the active crop and fast-export availability.

Changes

Export frame reframing

Layer / File(s) Summary
Project contract and persistence
CLAUDE.md, README.md, app.js, mcp-server.js
Documents exportFrame, persists it during project load/save, and permits it through setProject.
Monitor controls and overlay
app.js, index.html, style.css
Adds delivery-aspect presets, export-frame controls, a dimmed draggable overlay, and synchronization during monitor zoom, pan, and resize.
Cropped export path
app.js
Updates export engine state for active frames and encodes the selected crop for fast-export uploads.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant ProgramMonitor
  participant ProjectModel
  participant ExportSetup
  participant FastExport
  User->>ProgramMonitor: Select or drag export frame
  ProgramMonitor->>ProjectModel: Update project.exportFrame
  ProjectModel->>ExportSetup: Provide active crop
  ExportSetup->>FastExport: Update export engine state
  FastExport->>FastExport: Encode cropped preview JPEG
Loading

Possibly related PRs

  • ronak-create/FableCut#39: Both changes update Program Monitor overlay positioning and refresh behavior during zoom and pan.

Suggested reviewers: ur5fot, xusnitdinov

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title matches the main change: adding export-frame support.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

Actionable comments posted: 3

🤖 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 `@app.js`:
- Around line 5984-5996: Make manual export-frame repositioning
keyboard-operable by adding keyboard movement handling alongside the pointer
logic in app.js around the export-frame drag setup, updating and persisting
project.exportFrame with accessible, predictable step behavior. In index.html
around the existing export-frame UI, add or expose a focusable framing control
with appropriate accessible labels; apply the requested changes in both app.js
(lines 5984-5996) and index.html (lines 93-100).
- Around line 5713-5718: Update the active export-frame toggle branch around
state.exportFrameView so it only hides the overlay by setting
state.exportFrameView to false. Remove the project.exportFrame = null
assignment, while preserving syncExportFrameSel, updateMonitorRes, and
scheduleSave so the crop remains applied until “Full canvas” is explicitly
selected.

In `@CLAUDE.md`:
- Around line 157-160: Update the documented exportFrame example to use an
in-bounds 9:16 rectangle, such as x=405, y=0, w=405, h=720, within the 1280×720
canvas; keep the surrounding crop and coordinate guidance unchanged.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a2ae3019-37aa-4a81-908c-6cb177b97096

📥 Commits

Reviewing files that changed from the base of the PR and between 6ec153e and 446420b.

📒 Files selected for processing (6)
  • CLAUDE.md
  • README.md
  • app.js
  • index.html
  • mcp-server.js
  • style.css

Comment thread app.js
Comment thread app.js
Comment thread CLAUDE.md

@ronak-create ronak-create left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Nice feature and the plumbing is thorough — normalization/clamping, persistence through projectJSON(), the MCP setProject allowlist, keyboard nudge with an aria-label. Two blocking issues before this can land.

1. Odd crop dimensions produce a 0-byte export

fitExportFrameAspect() rounds without forcing even values. On the default 1280×720 canvas, clicking the new ⬒ Frame button takes the 9:16 branch and yields 405×720.

server.js pipes the JPEGs straight into libx264 -pix_fmt yuv420p with no scale/pad filter, so:

[libx264] width not divisible by 2 (405x720)
out.mp4 = 0 bytes

Reproduced against ffmpeg 8.0.1 with the exact pipeline the export uses (-f image2pipe -framerate 30 -i - -c:v libx264 -pix_fmt yuv420p). 608×1080 (9:16 on a 1920×1080 canvas) encodes fine, so it is specifically the default button on the default project size that breaks — and w: 405 is the value used in this PR's own CLAUDE.md example.

Either round to even in fitExportFrameAspect() and normalizeExportFrame() (w &= ~1), or add -vf "pad=ceil(iw/2)*2:ceil(ih/2)*2" in beginExport(). The client-side fix is probably better since the frame dimensions are user-visible in the monitor readout.

2. No ffmpeg + export frame set → silently uncropped output

openExportSetup() sets els.engineRealtime.disabled = true whenever a frame is set, but startChosenExport() only tests engineFast:

if (els.engineFast.checked && !els.engineFast.disabled) fastExport();
else startExport();

So when ffmpeg is unavailable and an export frame is set, both radios are disabled, yet the else branch still runs the realtime export — producing a full-canvas video with no crop. That contradicts the README line added here ("Realtime export is disabled while a frame is set"). Options: have startChosenExport() bail with a message when the chosen engine is disabled, or block setting an export frame at all when ffmpeg is missing.

Notes, not blockers

  • Merge conflict with #50, which removes the #monitorRes span this PR extends via updateMonitorRes(). Whichever lands second needs a rebase; if #50 goes first, updateMonitorRes() will throw on a null element during applyProject().
  • The box-shadow: 0 0 0 9999px dim is clipped by .monitor-stage { overflow: hidden }, so no spill — that part is fine.
  • The frame can be moved but not resized. Fine for a first pass given the aspect presets, just noting it in case it was meant to be resizable.

@ronak-create ronak-create mentioned this pull request Aug 4, 2026
11 tasks
@ronak-create

Copy link
Copy Markdown
Owner

Heads up — I merged #47 and #50, so this branch now needs a rebase on main, and for this PR it is more than a changelog fixup.

#50 removed the #monitorRes span entirely, replacing it with an FPS <select> in the same .panel-head-actions row. This PR extends that span via updateMonitorRes(), so the conflict is real: app.js, index.html, CLAUDE.md, README.md.

Worth deciding rather than mechanically resolving — after #50 the monitor header shows the aspect select (which already carries the dimensions) plus the FPS select, and there is no free-text readout left to hang 1920×1080 canvas → 608×1080 export on. Options I can see:

  • put the "→ W×H export" suffix into the export-frame select's own label, or
  • reinstate a small readout that only appears while an export frame is set, or
  • drop the readout and let the ⬒ Frame overlay be the only indication.

Your call — I do not have a strong preference, just flagging that updateMonitorRes() no longer has an element to write to.

The two blocking issues from my earlier review still stand independently of the rebase.

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