Skip to content

Commit 6fbf80a

Browse files
authored
Merge pull request gosub-io#927 from jaytaph/documentation-update
Documentation update
2 parents 253077b + bde3360 commit 6fbf80a

9 files changed

Lines changed: 644 additions & 515 deletions

File tree

.github/workflows/ci.yaml

Lines changed: 12 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -23,22 +23,12 @@ jobs:
2323
- uses: dtolnay/rust-toolchain@master
2424
with:
2525
toolchain: ${{ matrix.rust_version }}
26+
- uses: Swatinem/rust-cache@v2
27+
with:
28+
shared-key: ${{ matrix.rust_version }}
29+
cache-targets: "false"
2630
- name: Install dependencies
2731
run: sudo apt update -y && sudo apt install sqlite3 libsqlite3-dev libglib2.0-dev libcairo2-dev libgdk-pixbuf-2.0-dev libpango1.0-dev libgtk-4-dev -y
28-
- name: Cache cargo registry
29-
uses: actions/cache@v5
30-
with:
31-
path: ~/.cargo/registry
32-
key: ubuntu-24.04-cargo-registry-${{ matrix.rust_version }}-${{ hashFiles('**/Cargo.lock') }}
33-
restore-keys: |
34-
ubuntu-24.04-cargo-registry-${{ matrix.rust_version }}-
35-
- name: Cache cargo build
36-
uses: actions/cache@v5
37-
with:
38-
path: ${{ github.workspace }}/target
39-
key: ubuntu-24.04-cargo-target-test-${{ matrix.rust_version }}-${{ hashFiles('**/Cargo.lock') }}
40-
restore-keys: |
41-
ubuntu-24.04-cargo-target-test-${{ matrix.rust_version }}-
4232
- name: Build and test
4333
run: cargo test --locked --verbose --all --no-fail-fast --all-features --all-targets
4434

@@ -54,22 +44,12 @@ jobs:
5444
with:
5545
toolchain: ${{ matrix.rust_version }}
5646
components: clippy
47+
- uses: Swatinem/rust-cache@v2
48+
with:
49+
shared-key: ${{ matrix.rust_version }}
50+
cache-targets: "false"
5751
- name: Install dependencies
5852
run: sudo apt update -y && sudo apt install sqlite3 libsqlite3-dev libglib2.0-dev libcairo2-dev libgdk-pixbuf-2.0-dev libpango1.0-dev libgtk-4-dev -y
59-
- name: Cache cargo registry
60-
uses: actions/cache@v5
61-
with:
62-
path: ~/.cargo/registry
63-
key: ubuntu-24.04-cargo-registry-${{ matrix.rust_version }}-${{ hashFiles('**/Cargo.lock') }}
64-
restore-keys: |
65-
ubuntu-24.04-cargo-registry-${{ matrix.rust_version }}-
66-
- name: Cache cargo build
67-
uses: actions/cache@v5
68-
with:
69-
path: ${{ github.workspace }}/target
70-
key: ubuntu-24.04-cargo-target-clippy-${{ matrix.rust_version }}-${{ hashFiles('**/Cargo.lock') }}
71-
restore-keys: |
72-
ubuntu-24.04-cargo-target-clippy-${{ matrix.rust_version }}-
7353
- name: Run Clippy
7454
run: cargo clippy --locked --all --all-targets --all-features -- -D warnings
7555

@@ -80,6 +60,10 @@ jobs:
8060
- uses: dtolnay/rust-toolchain@stable
8161
with:
8262
components: rustfmt
63+
- uses: Swatinem/rust-cache@v2
64+
with:
65+
shared-key: stable
66+
cache-targets: "false"
8367
- name: Run fmt
8468
run: cargo fmt --check --all
8569

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2024 Gosub contributors
3+
Copyright (c) 2026 Gosub contributors
44
Copyright (c) 2023 Joshua Thijssen
55

66
Permission is hereby granted, free of charge, to any person obtaining a copy

README.md

Lines changed: 149 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
# Gosub: A new browser engine made from scratch
1+
# Gosub Browser Engine
22

3-
This repository holds the Gosub browser engine. It will become a standalone library that can be used by other projects
4-
but will ultimately be used by the Gosub browser user-agent. See the [About](#about) section for more information.
3+
An embeddable, async browser engine written in Rust.
54

65
Join us at our development [Zulip chat](https://chat.developer.gosub.io)!
76

@@ -12,163 +11,213 @@ If you are interested in contributing to Gosub, please check out the [contributi
1211

1312
## About
1413

15-
This repository is part of the Gosub browser engine project. This is the main engine that holds the following components:
14+
Gosub is a modular, embeddable browser engine. The primary entry point is `GosubEngine` in the
15+
[`gosub_engine`](crates/gosub_engine) crate. You provide a render backend and a compositor; the
16+
engine owns a multi-zone/tab model, an async networking stack, cookie and storage isolation per
17+
zone, and an event bus. Your user-agent (UA) drives everything via `TabCommand` and reacts to
18+
`EngineEvent`.
1619

17-
- HTML5 tokenizer / parser
18-
- CSS3 tokenizer / parser
19-
- Document tree
20-
- Several APIs for connecting to javascript
21-
- Configuration store
22-
- Networking stack
23-
- Rendering engine
24-
- JS bridge
20+
**Core components:**
2521

26-
More will follow as the engine grows. The idea is that this engine will receive some kind of stream of bytes (most likely
27-
from a socket or file) and parse this into a valid HTML5 document tree and CSS stylesheets.
28-
From that point, it can be fed to a renderer engine that will render the document tree into a window, or it can be fed
29-
to a more simplistic engine that will render it in a terminal. JS can be executed on the document tree and the document
30-
tree can be modified by JS.
22+
| Crate | Role |
23+
|---|---|
24+
| `gosub_engine` | `GosubEngine` — the unified entry point |
25+
| `gosub_html5` | HTML5 tokenizer / parser |
26+
| `gosub_css3` | CSS3 tokenizer / parser |
27+
| `gosub_net` | Networking stack (async, streaming, per-zone) |
28+
| `gosub_taffy` | Layout engine (Taffy/flexbox) |
29+
| `gosub_cairo` | Cairo / GTK4 render backend |
30+
| `gosub_vello` | Vello / wgpu render backend |
31+
| `gosub_js` | JS bridge |
32+
| `gosub_config` | Configuration store |
3133

3234

3335
## Status
3436

35-
> This project is in its infancy. There is no usable browser yet. However, you can look at simple html pages and parse
36-
> them into a document tree and do some initial rendering.
37+
The engine is under active development. What works today:
3738

38-
We can parse HTML5 and CSS3 files into a document tree or the respective css tree. This tree can be shown in the terminal
39-
or be rendered in a very unfinished renderer. Our renderer cannot render everything yet, but it can render simple html
40-
pages, sort of.
39+
- **Multi-zone / multi-tab model** — zones isolate cookies and storage; tabs are controlled via `TabCommand`
40+
- **Async networking** — streaming HTTP fetcher with priority queues, inflight coalescing, redirect handling, and per-zone cookie isolation
41+
- **Event-driven UA interface**`EngineEvent` (navigation, resource, redraw) flows out; `TabCommand` / `EngineCommand` flow in
42+
- **HTML5 and CSS3 parsing** — spec-compliant parsers for both
43+
- **Pluggable render backends** — Null (headless), Cairo (GTK4), Vello (wgpu)
4144

42-
We already implemented other parts of the engine, for a JS engine, networking stack, a configuration store and other
43-
things however these aren't integrated yet. You can try these out by running the respective binary.
45+
What is still in progress:
4446

45-
We can render a part for our own [site](https://gosub.io):
47+
- Full page layout and rendering pipeline (the render backends receive geometry but pixel-perfect output is incomplete)
48+
- JavaScript execution integration
49+
- Accessibility tree
4650

47-
![Gosub.io](resources/images/current_progress.png)
4851

52+
## Quick start
4953

50-
## How to run
54+
Add `gosub_engine` to your `Cargo.toml`:
5155

52-
<details>
53-
<summary> Installing dependencies </summary>
56+
```toml
57+
[dependencies]
58+
gosub_engine = { git = "https://github.com/gosub-io/gosub-engine", package = "gosub_engine" }
59+
tokio = { version = "1", features = ["full"] }
60+
```
5461

55-
This project uses [cargo](https://doc.rust-lang.org/cargo/) and [rustup](https://www.rust-lang.org/tools/install). First
56-
you must install `rustup` at the link provided. After installing `rustup`, run:
62+
Then drive the engine from async code:
63+
64+
```rust
65+
use std::sync::{Arc, RwLock};
66+
use gosub_engine::{EngineConfig, GosubEngine, EngineError};
67+
use gosub_engine::render::{DefaultCompositor, Viewport};
68+
use gosub_engine::render::backends::null::NullBackend;
69+
use gosub_engine::events::{EngineEvent, TabCommand};
70+
use gosub_engine::storage::{StorageService, InMemoryLocalStore, InMemorySessionStore, PartitionPolicy};
71+
use gosub_engine::cookies::DefaultCookieJar;
72+
use gosub_engine::zone::{ZoneConfig, ZoneServices};
73+
use gosub_engine::tab::TabDefaults;
74+
75+
#[tokio::main]
76+
async fn main() -> Result<(), EngineError> {
77+
let backend = NullBackend::new().expect("backend");
78+
let mut engine = GosubEngine::new(
79+
Some(EngineConfig::default()),
80+
Arc::new(backend),
81+
Arc::new(RwLock::new(DefaultCompositor::default())),
82+
);
83+
engine.start().expect("start");
84+
85+
let mut events = engine.subscribe_events();
86+
87+
let services = ZoneServices {
88+
storage: Arc::new(StorageService::new(
89+
Arc::new(InMemoryLocalStore::new()),
90+
Arc::new(InMemorySessionStore::new()),
91+
)),
92+
cookie_store: None,
93+
cookie_jar: Some(DefaultCookieJar::new().into()),
94+
partition_policy: PartitionPolicy::None,
95+
};
96+
let mut zone = engine.create_zone(ZoneConfig::default(), services, None)?;
97+
98+
let tab = zone.create_tab(TabDefaults {
99+
viewport: Some(Viewport::new(0, 0, 1280, 800)),
100+
..Default::default()
101+
}, None).await?;
102+
103+
tab.send(TabCommand::Navigate { url: "https://example.com".into() }).await?;
104+
105+
while let Ok(ev) = events.recv().await {
106+
match ev {
107+
EngineEvent::Navigation { tab_id, event } => println!("[{tab_id}] {event:?}"),
108+
EngineEvent::Redraw { tab_id, .. } => println!("[{tab_id}] frame ready"),
109+
_ => {}
110+
}
111+
}
112+
113+
engine.shutdown().await?;
114+
Ok(())
115+
}
116+
```
57117

58-
If you want to use a specific version of rust:
118+
See [`examples/hello-world.rs`](examples/hello-world.rs) for a fuller walkthrough, and
119+
[`examples/multi-tab.rs`](examples/multi-tab.rs) for a 25-tab stress test with a live progress UI.
59120

60-
```bash
61-
$ rustup toolchain install 1.82
62-
$ rustup default 1.82
63-
$ rustc --version
64-
rustc 1.82.0 (f6e511eec 2024-10-15)
65-
```
66121

67-
or you can use the latest version:
122+
## Running the examples
123+
124+
<details>
125+
<summary>Installing dependencies</summary>
126+
127+
This project uses [cargo](https://doc.rust-lang.org/cargo/) and [rustup](https://www.rust-lang.org/tools/install).
128+
Install `rustup`, then:
68129

69130
```bash
70-
$ rustup default stable
71-
$ rustc --version
72-
rustc 1.92.0 (ded5c06cf 2025-12-08)
73-
(or a higher version if available)
131+
rustup default stable
74132
```
75133

76-
You also should have following OS packages installed:
134+
For the GTK4-based examples you also need these OS packages (Ubuntu / Debian):
77135

78136
```
79-
make
80-
gcc
81-
g++
82-
libglib2.0-dev
83-
libcairo2-dev
84-
libpango1.0-dev
85-
libgdk-pixbuf-2.0-dev
86-
libgraphene-1.0-dev
87-
libgtk-4-dev
137+
make gcc g++
138+
libglib2.0-dev libcairo2-dev libpango1.0-dev
139+
libgdk-pixbuf-2.0-dev libgraphene-1.0-dev libgtk-4-dev
88140
libsqlite3-dev
89141
```
90142

91-
or equivalent for non-ubuntu based systems.
92-
93-
94-
Once Rust is installed, run this command to pre-build the dependencies:
143+
Clone and build:
95144

96145
```bash
97-
$ git clone https://github.com/gosub-io/gosub-engine.git
98-
$ cd gosub-engine
99-
$ cargo build --release
146+
git clone https://github.com/gosub-io/gosub-engine.git
147+
cd gosub-engine
148+
cargo build
100149
```
101150
</details>
102151

152+
### Engine examples (no GUI required)
103153

104-
You can run the following binaries (these will not output much useful information yet, as the engine is still in development):
154+
| Command | Description |
155+
|---|---|
156+
| `cargo run --example hello-world` | Single tab — navigate a URL, stream events to stdout |
157+
| `cargo run --example multi-tab` | 25 tabs navigating random sites; live progress bars via `indicatif` |
105158

106-
| Command | Type | Description |
107-
|----------------------------------------|------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
108-
| `cargo run -r --bin config-store` | bin | A simple test application of the config store for testing purposes |
109-
| `cargo run -r --bin css3-parser` | bin | Show a parsed css tree from an url |
110-
| `cargo run -r --bin display-text-tree` | bin | A simple parser that will try and return a textual presentation of the website |
111-
| `cargo run -r --bin gosub-parser` | bin | The actual html5 parser/tokenizer that allows you to convert html5 into a document tree. |
112-
| `cargo run -r --bin html5-parser-test` | test | A test suite that tests all html5lib tests for the treebuilding |
113-
| `cargo run -r --bin parser-test` | test | A test suite for the parser that tests specific tests. This will be removed as soon as the parser is completely finished as this tool is for developement only. |
114-
| `cargo run -r --bin run-js` | bin | Run a JS file (Note: console and event loop are not yet implemented) |
159+
### GUI examples
115160

116-
For running the binaries, take a look at a quick introduction at [/docs/binaries.md](/docs/binaries.md)
161+
| Command | Description |
162+
|---|---|
163+
| `cargo run --example gtk-cairo` | GTK4 / Cairo window |
164+
| `cargo run --example egui-vello` | egui / Vello / wgpu window |
117165

118-
There are also a bit more advanced examples that can be run that will try and display some graphics:
166+
### Component tools (individual crate testing)
119167

120-
| Command | Description |
121-
|--------------------------------------------|--------------------------------------------------------------|
122-
| `cargo run --example gtk-renderer <url>` | A GUI based on GTK4 / Cairo that displays a webpage |
123-
| `cargo run --example vello-renderer <url>` | A GUI based on Winit / Vello that displays a webpage |
124-
| `cargo run --example html5-parser` | A simple example that displays a dom tree from a html source |
168+
| Command | Description |
169+
|---|---|
170+
| `cargo run --bin gosub-parser` | HTML5 parser / tokenizer — prints a document tree |
171+
| `cargo run --bin css3-parser` | CSS3 parser — prints a CSS tree from a URL |
172+
| `cargo run --bin display-text-tree` | Text-only render of a page |
173+
| `cargo run --bin config-store` | Config store smoke test |
174+
| `cargo run --bin run-js` | Run a JS file (event loop not yet implemented) |
175+
| `cargo run --bin html5-parser-test` | html5lib tree-builder test suite |
176+
| `cargo run --bin parser-test` | Parser development test runner |
125177

178+
For more detail on the component tools see [/docs/binaries.md](/docs/binaries.md).
126179

127-
## Benchmark and test suites
128180

129-
To run the tests and benchmark suite, do:
181+
## Tests and benchmarks
130182

131183
```bash
132184
make test
133185
cargo bench
134-
ls target/criterion/report
135-
index.html
186+
# open target/criterion/report/index.html
136187
```
137188

138-
## Wasm
139189

140-
Our engine can also be compiled to WebAssembly. You need to use WasmPack for this. To build the Wasm version, run:
190+
## WebAssembly
191+
192+
The engine can be compiled to WebAssembly via `wasm-pack`:
141193

142194
```bash
143195
wasm-pack build --target web
144196
```
145197

146-
Afterwards you need to serve the small useragent around the wasm version in the `wasm/` directory. You can do this by
198+
Then serve the thin UA wrapper in `wasm/`:
147199

148200
```bash
149201
cd wasm
150-
npm run dev # you can also use `bun run dev`
151-
```
202+
bun run dev # or: npm run dev
203+
```
152204

153-
To use this demo, you need to enable webgpu in chromium and disable the same origin policy.
205+
To run the demo you need a Chromium with WebGPU enabled:
154206

155207
```bash
156-
chromium --disable-web-security --enable-features=Vulkan --enable-unsafe-webgpu --user-data-dir=/tmp/chromium-temp-profile
157-
```
158-
159-
This command works on Linux only, if someone uses Windows or macOS, please open an PR!
160-
161-
And then you have it! A browser in a browser:
208+
# Linux only — PRs welcome for Windows / macOS
209+
chromium --disable-web-security --enable-features=Vulkan \
210+
--enable-unsafe-webgpu --user-data-dir=/tmp/chromium-temp-profile
211+
```
162212

163213
![Browser in browser](resources/images/browser-wasm-hackernews.png)
164214

165215

166-
## Contributing to the project
167-
168-
We welcome contributions to this project but the current status makes that we are spending a lot of time researching,
169-
building small proof-of-concepts and figuring out what needs to be done next. Much time of a contributor at this stage
170-
of the project will be non-coding.
216+
## Contributing
171217

172-
We do like to hear from you if you are interested in contributing to the project and you can join us currently at
218+
We welcome contributions. Because the engine is still taking shape, a lot of work is exploratory
219+
— building proofs-of-concept, reading specs, and making architectural decisions — rather than
220+
pure coding.
173221

174-
our [Zulip chat](https://chat.developer.gosub.io)!
222+
Join us on [Zulip](https://chat.developer.gosub.io) or [Discord](https://chat.gosub.io) before
223+
diving in; it will save you time and help us keep things coordinated.

0 commit comments

Comments
 (0)