Fifty parts of Gosub Browser Progress
2026-08-01 · 6 hours ago
Fifty parts of Gosub Browser Progress
Part 50 went up this week, which felt like a good moment to look back at the whole series. Three years, from "I don't know Rust and I don't know how browsers work" to a modular engine with a multi-process proof-of-concept.
Here is the whole thing, one line per part. It reads a bit like a changelog of the project, and a bit like a changelog of me learning Rust.
It started here: The one where he is writing a browser... - the announcement, including the tiny issue that I didn't know Rust yet.
Tokenizer (pt1-pt9)
- pt1 - First days with Rust, and how much less explicit it is than Go.
- pt2 - Fighting Rust over how to structure the thing. Unclear who won.
- pt3 - Named character references, finally done. They took far too long.
- pt4 - Character entities complete, so whole strings tokenize correctly.
- pt5 - More data states filled in, plus generated testcases to check them.
- pt6 - A test harness that runs the tokenizer against the html5 testsuite.
- pt7 - Over 5000 of 6000 token tests passing, with utf-8 as the sticking point.
- pt8 - The tokenizer passes all html5lib-tests and lands in main.
- pt9 - Tokenizer done, so on to tree construction.
Tree construction and the borrow checker (pt10-pt23)
- pt10 - Starting to get the hang of Rust. The borrow checker yells less.
- pt11 - Document tree generation runs straight into ownership problems.
- pt12 - An arena holding all nodes, referenced by node_id.
- pt13 - Still wrestling the borrow checker, with an LLM as a second pair of eyes.
- pt14 - First attempts at the adoption agency algorithm.
- pt15 - Something snapped and the borrow checker finally made sense.
- pt16 - A blog post on why this project exists, which blew up on Hacker News.
- pt17 - Still stuck on test 23 of the tree-construction tests.
- pt18 - Contributions start coming in, and my long-lived branch gets out of sync.
- pt19 - Test 23 defeated. The adoption agency works.
- pt20 - Filling in more tests, and struggling with Rust while doing it.
- pt21 - All 112 tests in test1.dat pass. Many files to go.
- pt22 - Parsing live documents from the actual web.
- pt23 - 99.89% of the tree-construction tests pass.
Network stack and CSS (pt24-pt30)
- pt24 - Designing the whole flow, and realising how much is still unwritten.
- pt25 - The DNS component is finished.
- pt26 - A week of yak shaving on the way to a http-to-rendertree pipeline.
- pt27 - A working css3 parser, at the cost of the previous one.
- pt28 - Porting csstree from JavaScript to Rust, which goes better than expected.
- pt29 - Real-life CSS parses, at the cost of ignoring the rest of the engine.
- pt30 - Tying the html parser and the css3 parser together.
First pixels (pt31-pt43)
- pt31 - "dive", a text-based user agent built with ratatui.
- pt32 - Tree-walking to get rudimentary text on screen.
- pt33 - Turning a CST into stylesheet structures usable for selectors.
- pt34 - Slower going, with the CSS system still far from finished.
- pt35 - Refactoring to break the cyclic dependency between html5 and css3.
- pt36 - The CSS3 and HTML5 crates finally work together.
- pt37 - Taking stock of the components, and thinking about event loops and async.
- pt38 - The v2 engine proof-of-concept merges into main.
- pt39 - We've got a browser: a standalone useragent that loads tabs and renders them.
- pt40 - Typography work, after the planning went sideways as usual.
- pt41 - Font manager setbacks: the font libraries are not interchangeable.
- pt42 - The render pipeline split into separate phases, tiling and painting included.
- pt43 - The rendering pipeline PoC turns html and css into actual pixels.
Putting it together (pt44-pt50)
- pt44 - Back at it after a quiet stretch, now with AI in the toolbox.
- pt45 - The big three merged: network stack, rendering pipeline and engine api.
- pt46 - Modularity pays off, with several browsers built on the same engine.
- pt47 - A new gosub.io, with a nautical theme.
- pt48 - The engine back in a useful state, with ModuleConfig and RenderConfig.
- pt49 - A refurbished Mac M1 to build and test on real hardware.
- pt50 - Cleanup, and a multi-process proof-of-concept.
On to the next fifty.
Nobody amused yet.