Fidelity
Fidelity
An honest account of what the renderer matches in a browser and what it does not.
The authoritative, per-page and per-phase assessment (five live pages, committed
golden PNGs, before/after deltas) lives in the engine’s
FIDELITY.md, and
the measured-vs-Chrome numbers in
bench/REPORT.md.
Measured vs headless Chrome
Windowed SSIM (1.0 = identical) over the common top-left region at 1024px width;
speed× = chrome_ms / webengine_ms (>1 = webengine faster). Timings include the
live network fetch, so they vary run to run.
| URL | SSIM | pixdiff % | speed× | note |
|---|---|---|---|---|
| example.com/ | 0.831 | 5.6 | 18.3 | near-parity; its JS cross-fade is not modelled |
| en.wikipedia.org/wiki/Go | 0.417 | 30.3 | 1.6 | live article; JS and rate-limited thumbnails |
| pkg.go.dev/net/http | 0.716 | 11.3 | 0.8 | large computed page |
| go.dev/blog/ | 0.700 | 16.6 | 0.45 | slower than Chrome |
| react.dev/ | 0.725 | 33.0 | 1.3 | SPA; hydration fails, so the static fallback renders |
| news.ycombinator.com/ | 0.615 | 13.7 | 1.75 | table layout; rotating front page |
| developer.mozilla.org/…/CSS | 0.606 | 18.1 | 3.3 | docs layout |
| github.com/golang/go | 0.637 | 14.2 | 2.0 | live repository counters |
| tailwindcss.com/ | 0.724 | 12.2 | 0.5 | sponsor carousel rotates; slower |
| caniuse.com/ | 0.660 | 18.0 | 0.8 | data grid |
Mean SSIM over the ten pages is ≈ 0.66. Summed over the run, webengine took 26.1 s and headless Chrome 26.3 s, so overall time is at parity, but the per-page spread is wide. The Wikipedia number is confounded by runtime JS chrome and by rate-limited image thumbnails.
Works today
- Full box-model layout: block/inline flow, floats + clear, flexbox, CSS
grid, tables (with
vertical-alignon cells; adisplay:blocktable keeps its grid, CSS 2.1 §17.2.1, engine v0.45.10;width: min-content | max-content | fit-content),position(relative/absolute/fixed/sticky), margin collapsing, greedy word-wrap, multi-column layout. - Effects and lists:
translate/rotate,filter,backdrop-filter,mask-image(a singleurl()mask).ul/ollist markers are generated in layout as a::markerbox, so every backend gets them as text (the raster canvas, the vector PDF, go-pdfkit/html2pdf):list-style-typedisc,circle,square,decimal,decimal-leading-zero,lower-/upper-alpha,lower-/upper-roman, a<string>andnone;list-style-positionoutside/inside;::markercolour, font andcontent; HTMLstart,reversed,valueandtype(engine v0.18.0). - Generated content and counters:
::before/::afterwith strings,counter()andcounters();counter-reset(withreversed()),counter-increment,counter-set, scoped and inherited per CSS Lists 3, and the implicitlist-itemcounter. CSS escapes ("\2022\00a0",.\31 0) are decoded in every string, identifier and selector. - CSS: cascade + specificity (inline > id > class > tag) + inheritance;
var()custom properties;@mediawidth queries; dark-mode (prefers-color-scheme); external<link>stylesheets; UA defaults. - Selectors: tag/class/id/compound, descendant + child + sibling (
~/+) combinators,:checked,:not()(the checkbox-hack that collapses MediaWiki dropdowns); unmodelled selectors reduce rather than drop the rule. - Colour & decoration: named/
#rgb/#rrggbb, modernrgb()/hsl(),background-color, linear/radial gradients (withbackground-size,background-positionandbackground-repeat, engine v0.45.10),background-image: url(), border + border-radius, box-shadow, group opacity. - Text: anti-aliased proportional text with real bold and italic faces
(no faux-bold); serif / sans / mono; complex scripts (Cyrillic, Vietnamese, …);
white-space: pre; the raster painter draws text at the exact size with a fractional pen and quarter-pixel glyph origins, so word positions agree with Chrome to within half a pixel (v0.45.12); the generic monospace has Go Mono bold, italic and bold italic (v0.45.12); variable fonts drawn at eachfont-weightthrough theirwghtaxis (v0.45.10; the bundled Inter and Lora regulars too, so 300 and 500 are their own weights); thefontshorthand (v0.45.11). TherenderCLI with-fileuses the file’s directory as its base, so a relative@font-facefont beside it loads. - Images:
<img>over http(s) +data:(PNG/JPEG) and SVG (oksvg/rasterx) via<img *.svg>,data:image/svg+xmland inline<svg>. - JavaScript: page scripts run via goja
against a real DOM, with
fetch()/XHR and read-back of real laid-out geometry (getBoundingClientRect,offset*,getComputedStyle). A settle-then-render loop re-cascades and re-lays-out after scripts mutate the DOM (including dynamically injected<script>/<style>/<link>), to a bounded fixpoint. The same JS-settled DOM drives the click hit-map.
Not supported yet (stated, not hidden)
conic-gradientis recognised but not painted.filterandmask-imageare modelled narrowly: a mask is a singleurl()stretched over the box.scaleandskeware not supported. SVG has no<filter>/<mask>/<pattern>/<text>/embedded<image>, and a per-page image budget caps very icon-heavy pages.::before/::aftertake strings,counter()andcounters();attr(),url()and the quote keywords are not supported, nor is@counter-styleorlist-style-image. A form control’s own::before/::afteris not drawn.- Rate-limited image hosts (Wikimedia) answer some requests with HTTP 429. The engine retries them and the renders are identical, but each retry adds about two seconds to that page.
- Large computed pages (pkg.go.dev, go.dev) render slower than Chrome — a perf gap, not a fidelity one.
- This is not a standards-complete browser and is not claimed to match Chromium pixel-for-pixel. It is an honest renderer whose gap to a browser is the roadmap, measured page by page rather than asserted.
How to read a render
example.com renders at near-parity. A JS-driven SPA (react.dev) renders its
gradients, SVG atoms and script-built content and lands around 0.73 SSIM. A large
computed docs page (pkg.go.dev) renders correctly but slower than Chrome. A modern
CMS page (Wikipedia) collapses its Vector-2022 chrome via the checkbox-hack and
mw.loader, but the SSIM stays noisy where runtime chrome and icon fonts differ —
the residual is documented, not hidden. The gap between these is exactly the
remaining-levers section of the roadmap.