CodeMusings Logo CodeMusings

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)

  1. pt1 - First days with Rust, and how much less explicit it is than Go.
  2. pt2 - Fighting Rust over how to structure the thing. Unclear who won.
  3. pt3 - Named character references, finally done. They took far too long.
  4. pt4 - Character entities complete, so whole strings tokenize correctly.
  5. pt5 - More data states filled in, plus generated testcases to check them.
  6. pt6 - A test harness that runs the tokenizer against the html5 testsuite.
  7. pt7 - Over 5000 of 6000 token tests passing, with utf-8 as the sticking point.
  8. pt8 - The tokenizer passes all html5lib-tests and lands in main.
  9. pt9 - Tokenizer done, so on to tree construction.

Tree construction and the borrow checker (pt10-pt23)

  1. pt10 - Starting to get the hang of Rust. The borrow checker yells less.
  2. pt11 - Document tree generation runs straight into ownership problems.
  3. pt12 - An arena holding all nodes, referenced by node_id.
  4. pt13 - Still wrestling the borrow checker, with an LLM as a second pair of eyes.
  5. pt14 - First attempts at the adoption agency algorithm.
  6. pt15 - Something snapped and the borrow checker finally made sense.
  7. pt16 - A blog post on why this project exists, which blew up on Hacker News.
  8. pt17 - Still stuck on test 23 of the tree-construction tests.
  9. pt18 - Contributions start coming in, and my long-lived branch gets out of sync.
  10. pt19 - Test 23 defeated. The adoption agency works.
  11. pt20 - Filling in more tests, and struggling with Rust while doing it.
  12. pt21 - All 112 tests in test1.dat pass. Many files to go.
  13. pt22 - Parsing live documents from the actual web.
  14. pt23 - 99.89% of the tree-construction tests pass.

Network stack and CSS (pt24-pt30)

  1. pt24 - Designing the whole flow, and realising how much is still unwritten.
  2. pt25 - The DNS component is finished.
  3. pt26 - A week of yak shaving on the way to a http-to-rendertree pipeline.
  4. pt27 - A working css3 parser, at the cost of the previous one.
  5. pt28 - Porting csstree from JavaScript to Rust, which goes better than expected.
  6. pt29 - Real-life CSS parses, at the cost of ignoring the rest of the engine.
  7. pt30 - Tying the html parser and the css3 parser together.

First pixels (pt31-pt43)

  1. pt31 - "dive", a text-based user agent built with ratatui.
  2. pt32 - Tree-walking to get rudimentary text on screen.
  3. pt33 - Turning a CST into stylesheet structures usable for selectors.
  4. pt34 - Slower going, with the CSS system still far from finished.
  5. pt35 - Refactoring to break the cyclic dependency between html5 and css3.
  6. pt36 - The CSS3 and HTML5 crates finally work together.
  7. pt37 - Taking stock of the components, and thinking about event loops and async.
  8. pt38 - The v2 engine proof-of-concept merges into main.
  9. pt39 - We've got a browser: a standalone useragent that loads tabs and renders them.
  10. pt40 - Typography work, after the planning went sideways as usual.
  11. pt41 - Font manager setbacks: the font libraries are not interchangeable.
  12. pt42 - The render pipeline split into separate phases, tiling and painting included.
  13. pt43 - The rendering pipeline PoC turns html and css into actual pixels.

Putting it together (pt44-pt50)

  1. pt44 - Back at it after a quiet stretch, now with AI in the toolbox.
  2. pt45 - The big three merged: network stack, rendering pipeline and engine api.
  3. pt46 - Modularity pays off, with several browsers built on the same engine.
  4. pt47 - A new gosub.io, with a nautical theme.
  5. pt48 - The engine back in a useful state, with ModuleConfig and RenderConfig.
  6. pt49 - A refurbished Mac M1 to build and test on real hardware.
  7. pt50 - Cleanup, and a multi-process proof-of-concept.

On to the next fifty.

Nobody amused yet.