feat(timeline): enumerate the timeline's native formats instead of one drifting "native" - #150
Merged
Merged
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
…e drifting "native" The ratio picker's "native" entry resolved to whichever clip had the largest pixel area, so on a multi-clip project it silently meant "the biggest clip's format" and flipped the whole project's output shape whenever a clip was added or removed — adding a 4K portrait rush switched everything to portrait with no UI feedback. The picker now enumerates the distinct native shapes of the clips actually on the timeline (deduped by reduced ratio, so 1080p and 4K are one "16:9" entry) and the user picks one explicitly. The selection is stored as a concrete "W:H" token and can no longer drift. Native shapes annotate the preset rows with an "Original" badge rather than duplicating them, so the common case (every clip same format) gains no extra row; only shapes with no preset equivalent (an ultrawide "64:27") get a row of their own. - AspectRatio opens from a closed union to a parsed "W:H" type. "native" is kept as a legacy value so saved projects still open, and resolves to the row it currently means — re-picking it self-migrates the document off it. - New lib/ai-edition/document/outputFormat.ts is the single owner of output geometry. Deletes the duplicated referenceAssetDims/pickOutputDims in sceneDescription.ts and rawReferenceSource/EXPORT_ASPECT in ExportDialog.tsx, which had to agree by construction rather than by comment. - Fixes a preview/export divergence: PreviewCanvas resolved "native" through bare getAspectRatioValue, which answers the hardcoded 16/9 fallback, so a project saved with "native" over portrait footage framed the preview 16:9 while the compositor received a portrait output. - Corrects the comment at sceneDescription.ts claiming nothing writes legacyEditor.aspectRatio: patchEditorSettings does, there is no separate editorSettings store, and ExportDialog was reading the right field all along. It now reads through getEditorSettings so it cannot drift if storage moves. - Persistence validators accept any well-formed ratio; a preset-membership test would have reset non-preset selections to 16:9 on load. Output *resolution* still follows the largest used asset — only the shape is pinned. Verified: 518 tests pass, no new tsc errors, app boots clean.
Enumerating the timeline's native shapes made non-preset ratios selectable,
and that widened the domain `pickOutputDims` rounds over. The seven fixed
presets all divide a normal capture's long side evenly (3840 goes to 2160,
2880, 2400, ...), so bare `Math.round` was safe by accident, not by design.
An "Original" token is not. Taken from one clip and applied to a
differently-shaped reference it lands anywhere: picking the shape of a
1366x768 capture ("683:384") while a 4K clip is the reference by pixel area
gives 3840/(683/384) = 2158.946, which rounds to an odd 3840x2159. H.264's
4:2:0 chroma plane is half-resolution on both axes, so an odd axis has no
valid subsampling -- the encoder rejects it or silently pads. `SceneOutput`
is a bare u32 pair with no validation, so the odd value reaches the encoder.
The docstring already claimed alignment with `calculateSourceDimensions`
(mp4ExportSettings.ts) while omitting the part of that convention that makes
its output encodable: it evens the base and then searches downward in steps
of two until the derived side is even too. Snap both axes here instead, at
the single choke point this module exists to be. Nearest-even moves the
realised shape by a fraction of a pixel; being encodable at all wins.
Covered by the concrete mixed-timeline case above plus a sweep asserting
both axes stay even across every preset, three odd-capture tokens and
legacy "native" -- the presets pass unclamped, which is precisely why this
stayed latent, so the sweep has to include the odd shapes to mean anything.
EtienneLescot
force-pushed
the
claude/trusting-wing-a70920
branch
from
July 24, 2026 16:42
bf3d32a to
7b716f1
Compare
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.
Le problème
L'entrée « native » du sélecteur de ratio se résolvait vers le clip ayant la plus grande surface en pixels :
Sur un projet multi-clips, ça voulait donc dire « le format du plus gros clip », en silence :
La solution
Le menu énumère les formats natifs distincts des clips réellement présents sur la timeline et l'utilisateur en choisit un explicitement. La sélection est persistée en token concret
"W:H"et ne peut plus dériver.Déduplication par ratio réduit, pas par taille : 1920×1080 et 3840×2160 sont une seule entrée
16:9. On choisit une forme, pas une résolution.UX
Plutôt que d'ajouter une liste « Original » qui doublonnerait les presets, les formats natifs annotent les lignes existantes :
Original. Aucune ligne en plus, aucune décision en plus.Original · N— deux badges disent immédiatement « ta timeline est mixte, voilà qui est quoi ».64:27, taille de capture atypique)Original, étiquetée avec ses dimensions.Contenu
AspectRatios'ouvre d'une union fermée à un type"W:H"parsé."native"est conservé comme valeur legacy pour que les projets sauvegardés s'ouvrent, et il surligne la ligne qu'il désigne aujourd'hui — la re-sélectionner réécrit le document en token concret, donc les vieux projets se migrent d'eux-mêmes.lib/ai-edition/document/outputFormat.ts, propriétaire unique de la géométrie de sortie. Supprime les copies dupliquéesreferenceAssetDims/pickOutputDims(sceneDescription.ts) etrawReferenceSource/EXPORT_ASPECT(ExportDialog.tsx), qui devaient s'accorder par construction et non par commentaire.PreviewCanvasrésolvait"native"viagetAspectRatioValuenu, qui renvoie le fallback 16/9 codé en dur. Un projet sauvegardé en « native » sur du portrait cadrait donc la preview en 16:9 pendant que le compositeur recevait unoutputportrait.sceneDescription.tsaffirmant que rien n'écritlegacyEditor.aspectRatio:patchEditorSettingsl'écrit, il n'y a pas de storeeditorSettingsséparé, etExportDialoglisait le bon champ depuis le début. La lecture passe désormais pargetEditorSettingspour ne pas pouvoir dériver si le stockage bouge.Hors périmètre — à noter
La résolution de sortie suit toujours le plus gros clip utilisé ; seule la forme est figée. Depuis
7d7ec31a(rasterise at the output geometry), ça pèse davantage qu'avant :outputdimensionnerender_size, donc la résolution à laquelle le compositeur rastérise réellement, et non plus un simple rescale final depuis une cible 1080p fixe. Ajouter un rush 4K fait donc rastériser chaque frame en 4K. Figer la résolution comme la forme l'est maintenant est une décision distincte, volontairement non prise ici.Vérifications
"native"legacy et stabilité à l'ajout/retrait de clip.tsc: une seule erreur restante, pré-existante et intacte (PlayheadOverlay, non touché par ce commit).