A CSS layout engine written in MoonBit, ported from Taffy.
Crater aims to provide layout computation similar to Yoga - calculating positions and dimensions of elements based on CSS properties like Flexbox and Grid, without requiring a full browser environment.
This library focuses purely on layout calculation - it computes the x, y, width, and height of each element in your tree. It does not handle:
- Font loading or text shaping
- Text rendering or measurement (uses approximate character-based sizing)
- Painting or drawing
- DOM manipulation
Layout algorithm tests ported from Taffy:
| Module | Passed | Total | Rate |
|---|---|---|---|
| Flexbox | 543 | 609 | 89.2% |
| Block | 204 | 226 | 90.3% |
| Grid | 268 | 331 | 81.0% |
| Total | 1015 | 1166 | 87.0% |
| Module | Passed | Total | Rate |
|---|---|---|---|
| CSS Parser | 332 | 332 | 100% |
| CSS Selector | 62 | 62 | 100% |
| CSS Media Query | 41 | 41 | 100% |
CSS tests from web-platform-tests:
| Module | Passed | Total | Rate |
|---|---|---|---|
| css-flexbox | 236 | 367 | 64.3% |
| css-grid | 26 | 39 | 66.7% |
| css-tables | 13 | 74 | 17.6% |
| css-display | 14 | 93 | 15.1% |
| css-sizing | 48 | 103 | 46.6% |
| css-position | 59 | 117 | 50.4% |
| css-overflow | 56 | 118 | 47.5% |
| css-contain | 125 | 315 | 39.7% |
| css-variables | 25 | 152 | 16.4% |
| Total | 602 | 1378 | 43.7% |
Run WPT tests:
npm run wpt:fetch-all # Fetch all WPT tests
npm run wpt:run-all # Run all WPT testsWPT target selection is configured in wpt.json.
- Added recursive module scan for
css-alignandcss-boxviarecursiveModules - Expanded
includePrefixesfor additional overflow/alignment coverage (scroll-,scrollbar-,scrollable-,text-overflow-,column-scroll-,targeted-column-scroll-,align-,place-) - Excludes JS harness tests (
testharness.js,check-layout-th.js, interpolation helpers) from layout-tree comparison runs
Check current enabled test counts:
npx tsx scripts/wpt-runner.ts --list- Flexbox - direction, wrap, wrap-reverse, alignment, grow/shrink
- CSS Grid - templates, auto-placement, areas, fr units, minmax, repeat
- Block layout - margin collapsing
- Inline layout - inline formatting context, inline-block
margin,padding,border- Percentage and fixed dimensions
min-width,max-width,min-height,max-height- Intrinsic sizing:
min-content,max-content,fit-content box-sizing: border-box
position: static,relative,absolute,fixedtop,right,bottom,left(inset properties)
gap(row-gap, column-gap)aspect-ratiooverflow-x,overflow-yvisibility: hidden(with child override)- CSS Variables (
--var,var()) calc()CSS function
- Accessible Name Computation - WAI-ARIA accname-1.2 algorithm
- ARIA Snapshot - Playwright-compatible YAML/JSON format
- Accessibility Tree - Full tree structure with roles, states, and
aria-ownssupport
HTML parser benchmarks (on Apple Silicon):
| Benchmark | Time |
|---|---|
| Simple HTML (100 elements) | ~27 µs |
| Large document (100 sections × 20 paragraphs) | ~5.2 ms |
| Attribute-heavy (200 elements, 6 attrs each) | ~390 µs |
| Table (100×20 cells) | ~990 µs |
Run benchmarks:
moon bench -p html- No font rendering: Text measurement uses approximate monospace character sizing
- No real text layout: Word wrapping is simplified
- Baseline alignment: Partial implementation
- Writing modes: Limited support for vertical text
- API Reference - Public interface documentation
moon add mizchi/crater// Parse HTML and render layout
///|
let html = "<div style=\"display: flex; width: 300px;\"><div style=\"flex: 1\">A</div><div style=\"flex: 2\">B</div></div>"
///|
let ctx = @renderer.RenderContext::default()
///|
let layout = @renderer.render(html, ctx)
// layout contains x, y, width, height for each elementApache-2.0