Repository navigation
GRID: grid layout on web, iOS and Android (engine, fixtures, place-* shorthands) - #253
Merged
Merged
Conversation
…s, the units.ts grid helpers and the G-P differential test grid.ts from grid-g1a-engine (df45f80, ae4abde, cdcc301): Blink 145's grid placement, ranges and sets, track sizing, item placement, content and self alignment, container intrinsic sizes and the first baseline, with 21 grid plants on Ctx.gridFaults (layoutWithGridFaults). The G-P differential test runs every horizontal-tb environment of the frozen Chrome 145 grid corpus (docs/research/grid-spike/probe). Changes for today's master: - units.ts: the grid's saturating float helpers are clampedFloatMul and clampedFloatDiv (master's floatMul and floatDiv round without saturating); the duplicate FLOAT_MAX and FLOAT_EPSILON are dropped. - gutters resolve calc() gaps with resolveLength (a calc gap reaches the engine now), an indefinite basis counting as 0. - layoutContents takes bfcLineOffset 0 for a grid item (a formatting context root). - a replaced grid item is refused (grid-replaced) until replaced grid items are proven. - normal block-axis self-alignment of an item with an aspect ratio is start (aspect-ratio reaches the engine now; the corpus case a-stretch-aspect proves it in all 8 environments). - rt-hit.ts and the inline tests build Ctx with NO_GRID_FAULTS. - environment.ts: grid px track sizes and fit-content() limits clamp to the CSS length range like every other px length, also at DPR 1 (review of #197), with a saturation test. - the G-P pins: the three DPR 2.625 known mismatches now match (KNOWN_MISMATCHES is empty), aspect-ratio cases match (hand 1256 -> 1272 matched), and a calc gap with a percentage is owned by CALC-p (the compiler refuses it everywhere).
…egen: fixed point after 2 passes): the translated engine with grid.ts
…-engine-v2): seven grid fixtures in ltr and rtl (placement, named areas, fr, intrinsic, alignment, sizing, nested) in the per-feature grid group; reject-display-grid moves to a grid in a column flex container and reject-grid-justify-items to an unproven block context; the tests that pinned display: grid as refused now pin display: inline-grid
… regen: fixed point after 3 passes): the grid fixtures' captures, emitted CSS and vectors, the profiles (+256 rows per target, none lost or changed), the north-star messages, the Tailwind sweep (+1 supported utility per target) and the WPT expectations
…opped or rescued rules (DRAGON_PIN_WRITE=1; only new lines, every existing pin unchanged)
…play: inline-grid (display: grid is proven now); same intent
…track_collection.cc, grid_track_sizing_algorithm.cc, grid_layout_algorithm.cc and layout_utils.cc (grid.ts and units.ts ports, the G-P deviation reference), and grid.ts on grid_area.h, fetched at 145.0.7632.6 with their sha256 and located ranges
…ine ports entries
…heavy-lease.sh pnpm regen: fixed point after 3 passes)
# Conflicts: # packages/dragon/test/media-wiring.test.ts # packages/dragon/test/s5.test.ts # packages/parity/test/fixture-reader.test.ts
… grid-g1a-fixtures-v2 (/tmp/heavy-lease.sh pnpm regen: fixed point after 3 passes)
…d on master) is display: inline-grid; same intent, an unsupported value
…-v2 (/tmp/heavy-lease.sh pnpm regen: fixed point after 3 passes)
…ter 2c48409) into grid-g1a-fixtures-v2 (/tmp/heavy-lease.sh pnpm regen: fixed point after 3 passes)
…k 145 (shorthands_custom.cc PlaceContent/PlaceItems/PlaceSelf::ParseShorthand): each part parses as its own longhand, so the longhand rules and refusals apply; place-content's lone baseline gives justify-content start. align-content: last baseline is invalid, as in Chrome (ConsumeFirstBaseline). place-computed.test is the dual computed check against Chrome over every one- and two-value combination of 26 alignment words for each shorthand, with three planted faults each caught on every item. Three fixtures in ltr and rtl: grid-self-values (every justify-items and align-items value, justify-self and align-self auto and center/end, legacy inheritance), grid-place, and grid-template-shorthands (grid-template, grid, the none values, spans on end lines)
…after 3 passes): the three fixtures' captures, emitted CSS and vectors, the profiles (+72 rows per target, none lost or changed) and the derived outputs
…flicts: unsupported.ts keeps INL1a's five inline codes and GRID's three, and drops master's grid-layout placeholder (the engine replaces it); intrinsic.ts sizes a grid container first, then INL1a's strut path; native-support.ts and line-breaks.ts take INL1a's placeIfcLines over its hoisted Ctx, which gains grid_NO_GRID_FAULTS, and the Kotlin imports are the union; grid.test.ts takes both imports (its local column span helper is renamed colSpan beside INL1a's span); inline.test.ts takes INL1a's call with gridFaults. Composition: buildGrid throws on any inline-level child (inline box or br), as INL1a's flex.ts does, instead of skipping it; INL1a's inline-box, inline-box-placelines and parity inline tests give their Ctx gridFaults
…ng_utils.cc (chrome-ports)
…ngine-v2 (/tmp/heavy-lease.sh pnpm regen: fixed point after 3 passes)
…ures-v2. parity.test.ts's row-key test takes the union of the text contexts (GRID's grid item contexts and INL1a's text-in-inline and text-beside-inline) and keeps GRID's grid box contexts
#203) into grid-g1a-engine-v2. Conflict: rt-hit.ts imports keep GRID's NO_GRID_FAULTS and OVFL's isScrollContainer beside resolveBorder. Master's grid input (input.ts, validate.ts) is unchanged here; the engine reads it as is. Generated files keep the merge result until the CI regen Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WSkSiXMPXTAsNpS9BD9LDR
…iner by name (hitRefusal and hitTableOf's HitError): Blink paints grid items atomically in order-modified document order (css-grid-2 §9), which the hit table does not model, and on master layout refused every grid so no grid ever reached it. The compiler's R13 hit-model check refuses interaction rules on native in a case with a grid container whose display compiles (hitUnmodelledGrid; package GRID hit model). Tests: rt-hit.test (a grid program throws the named HitError and hitRefusal names it; the same tree as block flow is unaffected) and interaction.test (native refusal, web and non-grid unaffected, the hitUnmodelledNotRefused plant) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WSkSiXMPXTAsNpS9BD9LDR
Commands: pnpm regen --skip lanes-host --skip tw-sweep (macos-26) and pnpm regen --only lanes-host (xcode-27), alternated to a fixed point, then pnpm regen --only tw-sweep (macos-26). Base: 26d73e7 Run: https://github.com/compiled-run/dragoncss/actions/runs/37940805954
…/master b97cf50) into grid-g1a-fixtures-v2 Conflicts (both sides' intent kept): - media-wiring.test: master's @unknown-thing enclosing at-rule with G1a's display: inline-grid probe. - s5.test: G1a's inline-grid probe with master's CSS-wide keyword list (list-item, revert, revert-layer) plus grid. - seams.test: master's OVFL reject retargets and G1a's reject-display-grid retarget; the milestone-1 specs but reject-display-grid hash to 7725fc41 (master's specs with reject-display-grid left out). - fixture-reader.test: RETARGETED_AFTER_BASE holds both reject-display-grid (G1a) and reject-overflow-single-axis (OVFL). Composition with #212's grid hit refusal (rt-hit.ts hitRefusal): the hit lane now leaves out the 14 G1a fixture cases by name (hit-refusals-grid.ts GRID_OUT and GRID_REASON, judged by hit-report.test and lanes.test in the exact union). Generated files keep the merge result until the CI regen. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WSkSiXMPXTAsNpS9BD9LDR
Commands: pnpm regen --skip lanes-host --skip tw-sweep (macos-26) and pnpm regen --only lanes-host (xcode-27), alternated to a fixed point, then pnpm regen --only tw-sweep (macos-26). Base: 73dc191 Run: https://github.com/compiled-run/dragoncss/actions/runs/37950823661
…sedCases) and after HitError's "hit test: " prefix (caseHitTable throws it), as INLINE_REASON does; still anchored at the end Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WSkSiXMPXTAsNpS9BD9LDR
…inline-grid (display: grid is proven on web now, and the test pins that it decides true); same intent Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WSkSiXMPXTAsNpS9BD9LDR
…'s new Ctx call after merging origin/master) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DhER59LA5E9S5yeL8xkRHf
…mum height (ratioFinalBlockSize, as block and flex do), proven by the new grid-aspect-ratio fixture; scroll-decidable refuses a grid container as overflow.ts does Review findings on #253: the grid branch of block.ts used the ratio height as final, so content taller than the ratio overflowed where Chrome grows the grid (css-sizing-4 automatic minimum). undecidedScrollContainers now mirrors overflowOf's grid refusal; the scroll-decidable test gains a grid child shape and fails without the rule. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DhER59LA5E9S5yeL8xkRHf
… template shorthands) into the grid branch
Commands: pnpm regen --skip lanes-host --skip tw-sweep (macos-26) and pnpm regen --only lanes-host (xcode-27), alternated to a fixed point, then pnpm regen --only tw-sweep (macos-26). Base: f5b5622 Run: https://github.com/compiled-run/dragoncss/actions/runs/38043547657
…claude/native-grid-h62uxx
Commands: pnpm regen --skip lanes-host --skip tw-sweep (macos-26) and pnpm regen --only lanes-host (xcode-27), alternated to a fixed point, then pnpm regen --only tw-sweep (macos-26). Base: 6d95f7b Run: https://github.com/compiled-run/dragoncss/actions/runs/38049194088
- grid-corpus.ts: the compiler's refusal of a grid scroll container on native (scroll-decidable mirrors overflow.ts) is owned by G-OVF; the corpus pins move overflow-auto 24 to grid-scroll-overflow 16 and safe-alignment +8 on today's master (OVFL-B landed), matched unchanged at 1272. - hit-refusals-grid.ts: GRID_OUT names the G1c fixtures and grid-aspect-ratio, which the hit lane refuses as grid containers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DhER59LA5E9S5yeL8xkRHf
… hit-report and lanes tests take the union of the stacking and grid hit refusals
Commands: pnpm regen --skip lanes-host --skip tw-sweep (macos-26) and pnpm regen --only lanes-host (xcode-27), alternated to a fixed point, then pnpm regen --only tw-sweep (macos-26). Base: dd32b45 Run: https://github.com/compiled-run/dragoncss/actions/runs/38054908669
Commands: pnpm regen --skip lanes-host --skip tw-sweep (macos-26) and pnpm regen --only lanes-host (xcode-27), alternated to a fixed point, then pnpm regen --only tw-sweep (macos-26). Base: 285a0ef Run: https://github.com/compiled-run/dragoncss/actions/runs/38061188038
Commands: pnpm regen --skip lanes-host --skip tw-sweep (macos-26) and pnpm regen --only lanes-host (xcode-27), alternated to a fixed point, then pnpm regen --only tw-sweep (macos-26). Base: e0e98ce Run: https://github.com/compiled-run/dragoncss/actions/runs/38068030567
thejackshelton
pushed a commit
that referenced
this pull request
Oct 10, 2026
…XTURES pin to the batch Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JzUCRZ7PRctKowaJ7qRxYa
thejackshelton
pushed a commit
that referenced
this pull request
Oct 10, 2026
Catch up with #253 (grid): the hit-report and lanes unions hold both GRID_OUT and VISIBILITY_OUT, each with its reason. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012dJVP4456dCkJKMJUUf3xG
thejackshelton
pushed a commit
that referenced
this pull request
Oct 10, 2026
grid-aspect-ratio, grid-place, grid-self-values and grid-template-shorthands (and their -rtl variants) came in with #253 without pins, so pixel-reference failed for ios and android once the regen produced their PNGs. Written with DRAGON_PIN_WRITE=1; additions only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AnXuaNziRHaTgQDqijdmBC
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.
Requested by Jack · project thread
Before:
display: gridand everygrid-*property were refused on web, iOS and Android (the engine had no grid layout; the compiler's grid input and lowering were already on master from #197).After: grid containers and grid items lay out on all three targets. The layout engine gains
grid.ts, a port of Blink 145 grid layout, and seven Chrome-compared grid fixtures (ltr and rtl) back the grid support rows, sogrid-template-*,grid-area/grid-row/grid-column,grid-auto-*, the gaps and grid alignment become supported on iOS and Android through the translated engine (lanelinux-dragon-layout).This PR lands #212 (engine), #246 (fixtures, stacked on #212) and the G1c branch (place-content, place-items and place-self; every self-alignment value; the template shorthands) together, caught up with today's master. Both had passed their own CI and test-file runs; see their bodies for the full details, which this PR carries unchanged.
How: branch from #246's head
0a786aed15(which already contains #212's land-ready head), mergeorigin/master03ba583 (no textual conflicts), and one fix for master's newscrollRangesWithFaults(overflow.tsbuilds aCtx, which now needsgridFaults: NO_GRID_FAULTS). Then a CI regen.Supersedes
Review fixes (Claude correctness review; Macroscope skipped)
block.ts: a grid container withaspect-rationow keeps its content-based minimum height (ratioFinalBlockSize, as block and flex do). Proven by the newgrid-aspect-ratiofixture (ltr and rtl), which matches Chrome.scroll-decidable.ts: the compiler now refuses a native scroll container whose engine range would be refused for a grid container, asoverflow.tsdoes. Without it a grid withoverflow: autoreached the nativefatalError. The test gains a grid child shape and fails without the rule.grid-corpus.ts: that refusal is owned by G-OVF. The hand-corpus pins moveoverflow-auto24 togrid-scroll-overflow16 plussafe-alignment+8 (OVFL-B landed on master);matchedstays 1272.hit-refusals-grid.ts:GRID_OUTnames the G1c fixtures andgrid-aspect-ratio.What passed (head 57be38a, master 7882845 merged in, CI regen run 38068030567)
pnpm typecheck: pass.vitest run packages/dragon packages/layout, 128 files and 2980 tests pass. The only failing file isnative-backends.test(no swiftc or kotlinc locally), which passes on CI below.pnpm ci:test-filesrun 38074580587: 20 Chrome files pass, among them parity (573), native-host (363), grid-computed, all grid-corpus files, grid-fuzz, place-computed, hit-report, hit-lanes, chrome-ports, registry-claims, android-profile, fixture-reader and dist.native-backendspasses (13).lanes.test: 380 pass, 2 fail. P5 is the device step pending (ios layout-vectors-device: not run, as on master). The device-hit case fails onalias-paint, which ALIAS-2: -webkit-transform, -webkit-transform-origin and the -webkit- corner radii #249 added on master and which this PR does not touch.checks: pass.🤖 Generated with Claude Code
https://claude.ai/code/session_01DhER59LA5E9S5yeL8xkRHf
Generated by Claude Code