fix(layout): resolve viewport units against the real viewport and run the cascade - #156
Merged
LeadcodeDev merged 1 commit intoAug 9, 2026
Conversation
… the cascade Five confirmed audit findings on CSS→taffy translation and intrinsic sizing. - `vw`/`vh` were resolved against a hardcoded 1920x1080 and `em`/`rem` against a hardcoded 16px, because both production layout sites passed `ConversionContext::default()` while the real dimensions sat in scope one line away. On a 1080x1920 vertical video — a routine format here — `50vw` came out 960px instead of 540px, a 78% error. A shared `viewport_conversion_context` now builds the context from the real viewport; at 1920x1080 it is bit-identical to the old default, so the common case does not move. - The CSS cascade was never executed. `cascade::inherit_from` was correct and tested, but nothing called it: `color` and `font-*` set on a container reached no child. It is now applied in `build_child` after position and before timeline states and animations, so an own value still beats an inherited one. - `box-sizing`, `justify-items` and `justify-self` were declared by the schema and never translated. They are now. `order` cannot be — taffy has no style-level reordering primitive, its `order` is source order assigned during layout — so it warns instead of vanishing, once per process rather than once per node per frame. - The default-size guard for components with no intrinsic measurer wrote a hardcoded width *and* height, each gated only by `is_none()` on its own axis, so an explicit `aspect-ratio` was overwritten: `width: 400` with `aspect-ratio: 16/9` produced height 80 instead of 225. The other axis is now derived from the ratio when one axis is explicit. - `rules/html-css-mental-model.md` taught `margin-top` / `margin-left` and `padding: [32, 48]`. `CssStyle` has `deny_unknown_fields` and only `margin: Edges`, so those forms fail deserialization and drop the whole component from the video. This is a rule read by the LLMs that generate scenarios: it was actively teaching them to write JSON that deletes components. Verified by running the CLI, not by reading the struct. Cascade and aspect-ratio both change how existing scenarios could render, so both were checked against every shipped example: no node inherits a property it was missing, and no example uses `aspect-ratio`. Tests: full workspace green on this branch alone.
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.
Round 4, vague A — lot layout, 5 constats vérifiés.
vw/vhrésolus contre un 1920×1080 codé en dur,em/remcontre 16 px. Sur une vidéo verticale 1080×1920 — un format courant ici —50vwvalait 960 px au lieu de 540, soit 78 % d'erreur.cascade::inherit_frométait correct et testé, mais personne ne l'appelait :coloretfont-*posés sur un conteneur n'atteignaient aucun enfant.box-sizing,justify-items,justify-self,orderacceptés par le schéma, jamais traduits vers taffy, sans un mot.aspect-ratioécraséwidth: 400+aspect-ratio: 16/9donnait une hauteur de 80 px au lieu de 225.margin-topDétails
Unités de viewport. Les deux sites de layout de production passaient
ConversionContext::default()alors que les dimensions réelles étaient dans la portée, une ligne plus haut. Unviewport_conversion_contextpartagé construit désormais le contexte depuis le viewport réel. À 1920×1080 il est bit-à-bit identique à l'ancien défaut : le cas le plus fréquent ne bouge pas.Cascade. Appliquée dans
build_childaprès la position et avant les états de timeline et les animations — une valeur propre continue donc de battre une valeur héritée.order. taffy n'a aucune primitive de réordonnancement au niveau du style (sonorderest l'ordre source, assigné pendant le layout) : le traduire est structurellement impossible. Il avertit donc au lieu de disparaître — une fois par processus, pas une fois par nœud et par frame.to_taffy_styletourne à chaque frame ; uneprintln!non gardé aurait imprimé la même ligne un millier de fois par rendu.Documentation.
CssStyleportedeny_unknown_fieldset n'expose quemargin: Edges. Les formesmargin-topetpadding: [32, 48]que la règle montrait font échouer la désérialisation et retirent le composant de la vidéo. C'est un document lu par les LLM qui génèrent les scénarios : il leur apprenait activement à produire du JSON qui supprime des composants. Vérifié en exécutant la CLI, pas en lisant la struct.Risque de régression sur l'existant
La cascade et l'
aspect-ratiochangent tous deux le rendu possible de scénarios existants. Les deux ont été confrontés à tous les exemples livrés : aucun nœud n'hérite d'une propriété qui lui manquait, aucun exemple n'utiliseaspect-ratio,box-sizing,justify-items,justify-selfniorder.Hors périmètre — constaté, non causé ici
examples/ferriskey-presentation.jsonéchouerustmotion validate(gradient_text, largeur naturelle 404 px pour 400 px disponibles). J'ai vérifié : le chemin de mesure, le validateur et le fichier d'exemple sont identiques àmain, et l'échec se reproduit àc229ec0avec le même chiffre. Il précède tout le chantier. Suivi séparément.Vérification
cargo test --workspacesur cette branche seule : intégralement vert.