browser/engine: host Chrome to display list (spike)
Host side only. Python 3 stdlib, plus PIL (installed) for images and compare.
Run#
python3 render.py https://example.com/ --out dl.json --png shot.png --images imgs/
python3 compare.py dl.json shot.png --img-dir imgs/ --out-dir cmp/
python3 suite.py OUTDIR # ten spike URLs on one Chrome
python3 selftest.py OUTDIR # click, type, wheel scroll, resizeChrome 156.0.8078.48 from /Applications/Google Chrome.app, --headless=new,
throwaway profile in the scratchpad, 1440x900, DPR 1. Only our own process tree is killed.
Display list JSON#
{url, title, width, height, # cssContentSize from Page.getLayoutMetrics
clips: [[x,y,w,h,parentClip]], # overflow hidden/scroll/auto/clip
items: [...]} # paint order; rects in document CSS pxbox:r,ffill#rrggbb[aa],b{w:[t,r,b,l], c},radtext:rline box,sASCII,uoriginal Unicode (only if non-ASCII),fs,fw,col,it,ul,ffimg:r,srcabsolute (null for svg),nat[w,h],bg,localfile after--imageslink:r,href.ctl:r,tag,type,val,ph.media:r,tagoopacity (product down the DOM),cclip index
Measurements (1440x900, light scheme forced)#
| page | DL s | items | JSON KB (gz) | lines KB | non-ASCII text items | fidelity | render CPU s |
|---|---|---|---|---|---|---|---|
| example.com | 0.99 | 24 | 5.8 (1.6) | 2.5 | 16 | 0.875 | 0.36 |
| wikipedia Oscilloscope | 1.33 | 2277 | 294.1 (52.9) | 200.0 | 47 | 0.690 | 0.86 |
| news.ycombinator | 0.80 | 692 | 70.8 (9.4) | 44.3 | 2 | 0.789 | 0.17 |
| MDN Web/HTML | 1.19 | 570 | 62.4 (11.8) | 40.8 | 4 | 0.535 | 0.45 |
| github linux | 1.25 | 682 | 72.2 (10.2) | 46.7 | 1 | 0.891 | 1.09 |
| 1.34 | 21 | 13.5 (4.7) | 12.4 | 3 | 0.941 | 0.83 | |
| bbc.com/news | 1.27 | 637 | 71.2 (13.1) | 44.7 | 7 | 0.097 | 1.23 |
| react.dev | 1.20 | 1039 | 117.1 (15.0) | 69.4 | 14 | 0.769 | 0.52 |
| google "temple os" | 1.41 | 15 | 1.7 (0.6) | 0.9 | 0 | 0.953 | 0.80 |
| maps.google.com | 2.70 | 58 | 13.3 (1.5) | 10.4 | 6 | 0.067 | 2.08 |
Chrome startup 0.32 s. Tree RSS about 1 GB idle, 2.1 GB peak. Images: wikipedia 5/78 (47 KB), BBC 11/30 (594 KB), maps 26/26 (1.06 MB). Fidelity = share of 16x16 tiles within 12.
Bytes#
Text dominates: Wikipedia text is 225 KB of 294 KB (u duplicate, inline ff, per-line r).
Fixes: u only when needed; style table; merge lines of a paragraph; integer coords; cull offscreen.
Worked#
- Stdlib CDP over WebSocket; DOMSnapshot gives lines, boxes, paint order at once.
- Click on the example.com link navigated to iana.org. Typing filled the Wikipedia search box (snapshot shows the value); Enter navigated.
- Wheel:
scrollY800, rects unchanged (document space). Resize to 800 px reflowed text.
Did not work or is missing#
- Consent and bot walls: BBC Terms of Use dialog is not painted (score 0.097). Reddit serves "Prove your humanity". Google returned an almost empty page (title is the URL).
- Canvas and WebGL (maps): only media boxes, so the map is unpainted. Fallback: screenshot tiles.
- SVG not rasterised (count only). CSS gradients counted, not emitted (85 GitHub, 34 react.dev).
- Wikipedia 0.69 and MDN 0.535 fidelity not investigated yet (painter is rough).
- Light scheme forced; host is in dark appearance.
--disable-extensionsused instead of the literal--disable-extensions-except nothing.
CDP methods#
Page. (navigate, lifecycle, getLayoutMetrics, captureScreenshot, getFrameTree, getResourceContent), DOMSnapshot.captureSnapshot, DOM.resolveNode, Runtime., Emulation.*, Input.dispatchMouseEvent/KeyEvent.
Next steps#
- Text run merging and a style table, target under 100 KB on Wikipedia.
- Viewport culling and streaming of the rest of the page.
- Screenshot-tile fallback for canvas, video, WebGL and SVG.
- Consent-wall detection before capture.
- Per-item diff to explain the Wikipedia and MDN fidelity gap.