Honor sizing-probe verdicts in height emission; pin lottie mount heights

- heightFlows() bails when the capture probe proved a height authored-
  explicit (hAuto=false, hFill=false), so circular parent/child flow
  reasoning can no longer drop 100vh heroes to 0px; the probe verdict now
  vetoes the drop through both OR'd paths at the call site
- Space-distributing flex columns (space-between/around/evenly, center,
  flex-end) disqualify the content-driven read - the box height is load-
  bearing for the distribution
- Lottie mounts pin their captured per-viewport height like other replaced
  content, so aspect-fit runtime svgs can't inflate past the captured box
- DittoLottie forwards the placeholder's data-cid onto the runtime svg/
  canvas so the media stays addressable after the swap

240 tests pass (9 new), typecheck clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Samraaj Bath
2026-07-03 23:43:36 -07:00
co-authored by Claude Fable 5
parent 6a930d57b1
commit d5a713d31f
6 changed files with 209 additions and 7 deletions
+4 -1
View File
@@ -2539,7 +2539,10 @@ export function generateApp(input: GenerateInput, tokensCss: string): { pageTsx:
const mode = input.humanizeMode ?? "tailwind";
// Tailwind mode (default): translate each node's exact decls to utility classes.
// CSS mode: dedup into shared semantic CSS classes. Both fidelity-neutral.
const tw = humanize && mode === "tailwind" ? buildTailwind(ir, assetMap, input.colorVar, { interaction: input.interaction, reflow: input.reflow }) : undefined;
// Lottie mount boxes are pinned to their captured height (replaced-like) so the runtime player's
// aspect-sized svg fills a definite box instead of inflating. The spec item cid IS the mount cid.
const lottieMounts = new Set(lottieSpec.items.map((it) => it.cid));
const tw = humanize && mode === "tailwind" ? buildTailwind(ir, assetMap, input.colorVar, { interaction: input.interaction, reflow: input.reflow, lottieMounts }) : undefined;
const classMap = humanize && mode === "css" ? buildClassMap(ir, assetMap, input.colorVar, input.primitives, input.tokenResolver) : undefined;
const cleanRecipeClass = recipeResponsiveClassCleaner(ir, input.recipeReport, { tailwind: !!tw });
const classOf = tw ? (cid: string) => cleanRecipeClass(cid, tw.classOf.get(cid)) : classMap ? (cid: string) => classMap.classOf.get(cid) : undefined;