Rust · from scratch · no browser dependencies
Kaleidoscope is a browser engine in Rust: it parses HTML into a DOM, parses CSS into rules, applies the cascade, lays out boxes, and paints pixels. The whole pipeline, small enough to read end to end. Edit the HTML or CSS below and watch it render, live, right here.
Edit the HTML in the left box and the CSS in the right box, then press Render to run the full parse, cascade, layout, and paint pipeline onto the canvas. Use Toggle box outlines to see the layout tree drawn over the render, the Try chips to load ready-made examples, and Download PNG to save the painted result.
No browser engine borrowed, no rendering library included. Every stage below runs the same way in the Rust binary and in the JavaScript powering the demo above.
A tolerant tokenizer and tree builder turns tags, attributes, text, and comments into a DOM tree. Unclosed tags recover instead of failing.
Selectors (type, id, class, universal, descendant), declarations, lengths, and colors become a stylesheet of rules in source order.
Rules are matched against every node and sorted by specificity then source order. An inline style attribute always wins, and color and font-size inherit down the tree.
Each box takes its containing block's width, stacks its children vertically, and derives its own height, honoring margin, border, and padding.
The layout tree becomes a display list of solid rectangles, rasterized with integer alpha compositing into a pixel buffer, then written as a dependency-free PNG or PPM.
// the box model equation layout.rs solves for every box
width + padding + border + margin = containing block width
The CLI builds the same pipeline as this page. Point it at an HTML file and a stylesheet, and it writes a PNG or PPM image or prints the layout tree with exact pixel coordinates for every box.
kaleidoscope render page.html --css style.css --width 800 -o out.png kaleidoscope layout page.html --css style.css --width 800
layout prints the box tree, one line per box, with the tag name and the exact pixel coordinates layout solved for it. This is the real output for the bundled example at a 800px viewport:
$ kaleidoscope layout examples/sample.html --css examples/sample.css --width 800
html x=0.0 y=0.0 width=800.0 height=240.0
body x=0.0 y=0.0 width=800.0 height=240.0
div x=8.0 y=8.0 width=300.0 height=40.0
#text x=8.0 y=8.0 width=300.0 height=19.2
div x=16.0 y=72.0 width=200.0 height=60.0
#text x=16.0 y=72.0 width=200.0 height=19.2
div x=16.0 y=164.0 width=200.0 height=60.0
#text x=16.0 y=164.0 width=200.0 height=19.2
An MCP server exposes a render_html tool that turns HTML and CSS into a PNG. An AI agent can generate markup and see the result without a headless browser. Kaleidoscope boots in milliseconds and uses a couple of megabytes, where a headless Chromium needs seconds and hundreds of megabytes.
kaleidoscope snapshot --html "<div style='background:teal;height:40px'></div>" \
--css "div{display:block}" --width 200 --height 80
# prints a base64 PNG, the same bytes the MCP tool returns
Kaleidoscope is not trying to render the whole web. It is trying to be the one engine you can follow end to end. The comparison is about comprehensibility, not coverage.
Modern Rust, about 2,000 lines. One render path you can read in an afternoon, with a live demo. Maintained.
Tens of millions of lines of C++. Ships the real web, not something a person reads end to end.
Rust, research-grade and parallelized. Powerful, but hard to trace a single render path through.
The classic teaching engine that inspired this space, now an unmaintained tutorial.