Dumber, fully unfeatured unbloated browser for tiling WMs
Dumber is a minimalist browser and launcher companion focused on speed and simplicity. It ships a built‑in WebKitGTK (GTK4) window for navigation and a CLI with dmenu‑style launcher integration (rofi, fuzzel).
- Native GUI via WebKitGTK 6 (GTK4, CGO) with an embedded homepage UI.
- CLI that parses URLs, supports search shortcuts (e.g.,
g:query), and integrates with rofi/dmenu.
- Persistent history and per‑domain zoom levels (SQLite, XDG locations).
- Configurable via
config.json and environment variables, with live reload.
Wayland‑First
- Dumb on purpose, designed for Wayland window managers (Sway, Hyprland, River, Niri, etc..) it's a tiny companion that interact nicely with your launcher.
- Uses a native WebKitGTKdo i window; no external browser required and no X11/XWayland dependency.
- Optimized for dmenu‑style launchers (rofi, fuzzel, wofi) and keyboard‑driven workflows.
Status
- Very early stage, expect sharp edges and breaking changes, but it works well enough to browse and play with the launcher flows.
Features
- Built‑in browser window (no external browser needed)
- Custom
dumb:// scheme serving embedded frontend assets
- Keyboard and mouse controls: comprehensive shortcuts and gestures
- Persistent history with search and stats
- Per‑domain zoom persistence
- dmenu‑style launcher integration (rofi, fuzzel) with history and shortcut suggestions
Controls & Shortcuts
Keyboard Shortcuts
| Shortcut |
Action |
Notes |
| F12 |
Open Developer Tools |
WebKit inspector |
| Ctrl/Cmd+L |
Open Omnibox |
URL/search input with history |
| Ctrl/Cmd+F |
Find in Page |
Search text within current page |
| Ctrl/Cmd+= |
Zoom In |
Firefox-compatible zoom levels |
| Ctrl/Cmd++ |
Zoom In |
Alternative plus key |
| Ctrl/Cmd+- |
Zoom Out |
Works across keyboard layouts |
| Ctrl/Cmd+0 |
Reset Zoom |
Return to 100% zoom |
| Ctrl/Cmd+Shift+C |
Copy URL |
Copy current URL to clipboard with toast |
| Alt+← |
Navigate Back |
Go to previous page |
| Alt+→ |
Navigate Forward |
Go to next page |
Mouse Controls
| Action |
Result |
Notes |
| Ctrl+Scroll Up |
Zoom In |
Smooth zoom control |
| Ctrl+Scroll Down |
Zoom Out |
Smooth zoom control |
| Mouse Button 8 |
Navigate Back |
Side button (back) |
| Mouse Button 9 |
Navigate Forward |
Side button (forward) |
| Two-finger Swipe |
Back/Forward |
When supported by touchpad |
Omnibox/Find Mode (when active)
| Shortcut |
Action |
Notes |
| Escape |
Close overlay |
Exit omnibox or find mode |
| Enter |
Execute/Navigate |
Navigate to URL or jump to match |
| Shift+Enter |
Previous Match |
Find mode: go to previous match |
| Alt+Enter |
Center Match |
Find mode: center on match, keep open |
| ↑/↓ Arrow |
Navigate Results |
Browse suggestions/matches |
All zoom changes are automatically persisted per-domain and restored on next visit.
Quick Start
Prerequisites:
- Go 1.25+
- Node.js 20+ and npm (for building the embedded TypeScript frontend)
- For GUI build: WebKitGTK 6 and GTK4 dev packages (examples)
- Debian/Ubuntu:
libwebkitgtk-6.0-dev libgtk-4-dev build-essential
- Arch:
webkitgtk-6.0 gtk4 base-devel
Build options:
- GUI (default, recommended):
make build # builds frontend + Go with -tags=webkit_cgo
- Run:
./dist/dumber # opens the embedded homepage
- CLI‑only (no GUI, CGO disabled):
make build-no-gui
- Run:
./dist/dumber-no-gui version
Development:
make dev runs go run . (non‑CGO; GUI stubs log to console)
make test runs tests; make lint runs golangci‑lint
Install
Note: go install will not work for this project because the frontend assets must be built first and embedded into the binary. Use the build commands instead:
- GUI build (default, recommended):
- Ensure WebKit2GTK/GTK dev packages are installed (see prerequisites)
- Clone the repo and run
make build (builds frontend first, then Go with GUI support)
- The resulting
./dist/dumber binary includes the native GUI window
- CLI‑only (no native window):
- Clone the repo and run
make build-no-gui
- The resulting
./dist/dumber-no-gui binary runs CLI flows with GUI code stubbed
Usage
- Open a URL or search:
dumber browse https://example.com
dumber browse example.com # scheme auto‑added
dumber browse g:golang # Google search via shortcut
- Launch the GUI directly:
dumber # no args → opens GUI homepage
- Launcher integration (dmenu‑style examples):
- rofi:
dumber dmenu | rofi -dmenu -p "Browse: " | dumber dmenu --select
- fuzzel:
dumber dmenu | fuzzel --dmenu -p "Browse: " | dumber dmenu --select
- Clean up data and cache:
dumber purge # purge all data (with confirmation)
dumber purge --force # purge all data (no confirmation)
dumber purge -d -H -c # purge database and both caches
dumber purge --browser-data # purge WebKit data (cookies, etc.)
You can invoke dmenu mode in two ways:
- Subcommand (recommended):
dumber dmenu … and dumber dmenu --select
- Root flag (generate options only):
dumber --dmenu
Note: The root flag path only generates options; for processing a selection (--select), use the dmenu subcommand as the receiving command.
In GUI mode the app serves an embedded homepage via dumb://homepage, and frontend assets under dumb://app/....
Configuration
Dumber follows the XDG Base Directory spec:
- Config:
~/.config/dumber/config.json
- Data:
~/.local/share/dumber
- State:
~/.local/state/dumber (default DB lives here)
A default config.json is created on first run. Config changes are watched and applied at runtime when possible.
Complete Configuration Reference
Database Configuration
"database": {
"path": "~/.local/state/dumber/history.db",
"max_connections": 1,
"max_idle_time": "5m0s",
"query_timeout": "30s"
}
History Management
"history": {
"max_entries": 10000,
"retention_period_days": 365,
"cleanup_interval_days": 1
}
Search Shortcuts
"search_shortcuts": {
"g": { "url": "https://www.google.com/search?q=%s", "description": "Google search" },
"gh": { "url": "https://github.com/search?q=%s", "description": "GitHub search" },
"yt": { "url": "https://www.youtube.com/results?search_query=%s", "description": "YouTube search" },
"w": { "url": "https://en.wikipedia.org/wiki/%s", "description": "Wikipedia search" },
"ddg": { "url": "https://duckduckgo.com/?q=%s", "description": "DuckDuckGo search" },
"so": { "url": "https://stackoverflow.com/search?q=%s", "description": "Stack Overflow search" },
"r": { "url": "https://www.reddit.com/search?q=%s", "description": "Reddit search" },
"npm": { "url": "https://www.npmjs.com/search?q=%s", "description": "npm package search" },
"go": { "url": "https://pkg.go.dev/search?q=%s", "description": "Go package search" },
"mdn": { "url": "https://developer.mozilla.org/en-US/search?q=%s", "description": "MDN Web Docs search" }
}
"dmenu": {
"max_history_items": 20,
"show_visit_count": true,
"show_last_visited": true,
"history_prefix": "🕒",
"shortcut_prefix": "🔍",
"url_prefix": "🌐",
"date_format": "2006-01-02 15:04",
"sort_by_visit_count": true
}
Logging Configuration
"logging": {
"level": "info",
"format": "text",
"filename": "",
"max_size": 100,
"max_backups": 3,
"max_age": 7,
"compress": true
}
Appearance Settings
"appearance": {
"sans_font": "Fira Sans",
"serif_font": "Fira Sans",
"monospace_font": "Fira Code",
"default_font_size": 16
}
Rendering Mode (GPU/CPU)
"rendering_mode": "auto"
auto: Detect GPU availability and use GPU when available (default)
gpu: Force GPU acceleration (Vulkan/OpenGL via GTK4)
cpu: Force software rendering
Environment Variables
All config values can be overridden with environment variables using the DUMB_BROWSER_ prefix:
# Database
DUMB_BROWSER_DATABASE_PATH="./browser.db"
DUMB_BROWSER_DATABASE_MAX_CONNECTIONS=5
# Rendering mode (special variable name)
DUMBER_RENDERING_MODE="gpu"
# Dmenu settings
DUMB_BROWSER_DMENU_MAX_HISTORY_ITEMS=50
DUMB_BROWSER_DMENU_SHOW_VISIT_COUNT=false
# Logging
DUMB_BROWSER_LOGGING_LEVEL="debug"
DUMB_BROWSER_LOGGING_FORMAT="json"
CLI Flags
The browse command supports additional runtime flags:
dumber browse --rendering-mode=gpu https://example.com
Building With WebKitGTK 6 (GTK4)
- The GUI requires building with
-tags=webkit_cgo and CGO enabled.
- Ensure WebKitGTK 6 and GTK4 dev headers are installed (see prerequisites).
- Make targets handle both frontend and Go build steps:
make build-gui (CGO enabled)
make build (CGO enabled by default in the Makefile’s main build)
Without the native tag, a stub backend is used: you can still run CLI flows and see logs, but no native window is displayed.
WebKitGTK uses GStreamer for media playback. Install the following packages to ensure audio/video work correctly.
- Arch Linux:
sudo pacman -S gst-plugins-base gst-plugins-good gst-plugins-bad gst-plugins-ugly gst-libav gst-plugin-pipewire pipewire pipewire-pulse
- Optional hardware accel:
gstreamer-vaapi
- Debian/Ubuntu:
sudo apt install gstreamer1.0-tools gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-libav gstreamer1.0-pipewire
- Optional hardware accel:
gstreamer1.0-vaapi
Theme and Runtime Updates
- The homepage and pages respect your system’s light/dark preference.
- The app updates color‑scheme live when your GTK theme changes (no relaunch needed).
Project Structure
main.go: CLI/GUI entrypoint, dumb:// scheme, service wiring
internal/cli: Cobra commands (browse, dmenu, version)
internal/config: Viper‑backed config, XDG helpers, defaults
internal/db: SQLite schema init and sqlc‑generated queries
services: app services (parser/history/config/browser)
pkg/webkit: WebKit2GTK bindings (CGO and stub implementations)
frontend: TypeScript homepage UI bundled into the binary
Security & Privacy
- History and zoom settings are stored locally in SQLite under XDG state.
- The
tmp/ directory is ignored by Git and kept out of history.
Roadmap
- ✅ WebKitGTK 6 (GTK4) migration (GPU/Vulkan path complete)
- ✅ GPU rendering (Vulkan via GTK4 renderer) with graceful CPU fallback
- Full Vim-style motion and keyboard navigation across pages and UI
- Performance work: faster startup, lower memory, snappier UI
- Basic ad-block extension — because fuck ads
- Other shiny things I'm not yet aware of
License
This project is licensed under the MIT License. See LICENSE for details.
source
1# Dumber, fully unfeatured unbloated browser for tiling WMs
2
3<p align="center">
4 <img src="assets/logo.svg" alt="Dumber Logo" width="256" height="256" />
5</p>
6
7Dumber is a minimalist browser and launcher companion focused on speed and simplicity. It ships a built‑in WebKitGTK (GTK4) window for navigation and a CLI with dmenu‑style launcher integration (rofi, fuzzel).
8
9- Native GUI via WebKitGTK 6 (GTK4, CGO) with an embedded homepage UI.
10- CLI that parses URLs, supports search shortcuts (e.g., `g:query`), and integrates with rofi/dmenu.
11- Persistent history and per‑domain zoom levels (SQLite, XDG locations).
12- Configurable via `config.json` and environment variables, with live reload.
13
14## Wayland‑First
15- Dumb on purpose, designed for Wayland window managers (Sway, Hyprland, River, Niri, etc..) it's a tiny companion that interact nicely with your launcher.
16- Uses a native WebKitGTKdo i window; no external browser required and no X11/XWayland dependency.
17- Optimized for dmenu‑style launchers (rofi, fuzzel, wofi) and keyboard‑driven workflows.
18
19## Status
20- Very early stage, expect sharp edges and breaking changes, but it works well enough to browse and play with the launcher flows.
21
22## Features
23- Built‑in browser window (no external browser needed)
24- Custom `dumb://` scheme serving embedded frontend assets
25- Keyboard and mouse controls: comprehensive shortcuts and gestures
26- Persistent history with search and stats
27- Per‑domain zoom persistence
28- dmenu‑style launcher integration (rofi, fuzzel) with history and shortcut suggestions
29
30## Controls & Shortcuts
31
32### Keyboard Shortcuts
33| Shortcut | Action | Notes |
34|----------|--------|-------|
35| **F12** | Open Developer Tools | WebKit inspector |
36| **Ctrl/Cmd+L** | Open Omnibox | URL/search input with history |
37| **Ctrl/Cmd+F** | Find in Page | Search text within current page |
38| **Ctrl/Cmd+=** | Zoom In | Firefox-compatible zoom levels |
39| **Ctrl/Cmd++** | Zoom In | Alternative plus key |
40| **Ctrl/Cmd+-** | Zoom Out | Works across keyboard layouts |
41| **Ctrl/Cmd+0** | Reset Zoom | Return to 100% zoom |
42| **Ctrl/Cmd+Shift+C** | Copy URL | Copy current URL to clipboard with toast |
43| **Alt+←** | Navigate Back | Go to previous page |
44| **Alt+→** | Navigate Forward | Go to next page |
45
46### Mouse Controls
47| Action | Result | Notes |
48|--------|---------|-------|
49| **Ctrl+Scroll Up** | Zoom In | Smooth zoom control |
50| **Ctrl+Scroll Down** | Zoom Out | Smooth zoom control |
51| **Mouse Button 8** | Navigate Back | Side button (back) |
52| **Mouse Button 9** | Navigate Forward | Side button (forward) |
53| **Two-finger Swipe** | Back/Forward | When supported by touchpad |
54
55### Omnibox/Find Mode (when active)
56| Shortcut | Action | Notes |
57|----------|--------|-------|
58| **Escape** | Close overlay | Exit omnibox or find mode |
59| **Enter** | Execute/Navigate | Navigate to URL or jump to match |
60| **Shift+Enter** | Previous Match | Find mode: go to previous match |
61| **Alt+Enter** | Center Match | Find mode: center on match, keep open |
62| **↑/↓ Arrow** | Navigate Results | Browse suggestions/matches |
63
64All zoom changes are automatically persisted per-domain and restored on next visit.
65
66## Quick Start
67Prerequisites:
68- Go 1.25+
69- Node.js 20+ and npm (for building the embedded TypeScript frontend)
70- For GUI build: WebKitGTK 6 and GTK4 dev packages (examples)
71 - Debian/Ubuntu: `libwebkitgtk-6.0-dev libgtk-4-dev build-essential`
72 - Arch: `webkitgtk-6.0 gtk4 base-devel`
73
74Build options:
75- GUI (default, recommended):
76 - `make build` # builds frontend + Go with `-tags=webkit_cgo`
77 - Run: `./dist/dumber` # opens the embedded homepage
78- CLI‑only (no GUI, CGO disabled):
79 - `make build-no-gui`
80 - Run: `./dist/dumber-no-gui version`
81
82Development:
83- `make dev` runs `go run .` (non‑CGO; GUI stubs log to console)
84- `make test` runs tests; `make lint` runs golangci‑lint
85
86## Install
87**Note**: `go install` will not work for this project because the frontend assets must be built first and embedded into the binary. Use the build commands instead:
88
89- GUI build (default, recommended):
90 - Ensure WebKit2GTK/GTK dev packages are installed (see prerequisites)
91 - Clone the repo and run `make build` (builds frontend first, then Go with GUI support)
92 - The resulting `./dist/dumber` binary includes the native GUI window
93- CLI‑only (no native window):
94 - Clone the repo and run `make build-no-gui`
95 - The resulting `./dist/dumber-no-gui` binary runs CLI flows with GUI code stubbed
96
97## Usage
98- Open a URL or search:
99 - `dumber browse https://example.com`
100 - `dumber browse example.com` # scheme auto‑added
101 - `dumber browse g:golang` # Google search via shortcut
102- Launch the GUI directly:
103 - `dumber` # no args → opens GUI homepage
104- Launcher integration (dmenu‑style examples):
105 - rofi: `dumber dmenu | rofi -dmenu -p "Browse: " | dumber dmenu --select`
106 - fuzzel: `dumber dmenu | fuzzel --dmenu -p "Browse: " | dumber dmenu --select`
107- Clean up data and cache:
108 - `dumber purge` # purge all data (with confirmation)
109 - `dumber purge --force` # purge all data (no confirmation)
110 - `dumber purge -d -H -c` # purge database and both caches
111 - `dumber purge --browser-data` # purge WebKit data (cookies, etc.)
112
113### Dmenu mode invocation
114You can invoke dmenu mode in two ways:
115- Subcommand (recommended): `dumber dmenu` … and `dumber dmenu --select`
116- Root flag (generate options only): `dumber --dmenu`
117
118Note: The root flag path only generates options; for processing a selection (`--select`), use the `dmenu` subcommand as the receiving command.
119
120In GUI mode the app serves an embedded homepage via `dumb://homepage`, and frontend assets under `dumb://app/...`.
121
122## Configuration
123
124Dumber follows the XDG Base Directory spec:
125- Config: `~/.config/dumber/config.json`
126- Data: `~/.local/share/dumber`
127- State: `~/.local/state/dumber` (default DB lives here)
128
129A default `config.json` is created on first run. Config changes are watched and applied at runtime when possible.
130
131### Complete Configuration Reference
132
133#### Database Configuration
134```json
135"database": {
136 "path": "~/.local/state/dumber/history.db",
137 "max_connections": 1,
138 "max_idle_time": "5m0s",
139 "query_timeout": "30s"
140}
141```
142
143#### History Management
144```json
145"history": {
146 "max_entries": 10000,
147 "retention_period_days": 365,
148 "cleanup_interval_days": 1
149}
150```
151
152#### Search Shortcuts
153```json
154"search_shortcuts": {
155 "g": { "url": "https://www.google.com/search?q=%s", "description": "Google search" },
156 "gh": { "url": "https://github.com/search?q=%s", "description": "GitHub search" },
157 "yt": { "url": "https://www.youtube.com/results?search_query=%s", "description": "YouTube search" },
158 "w": { "url": "https://en.wikipedia.org/wiki/%s", "description": "Wikipedia search" },
159 "ddg": { "url": "https://duckduckgo.com/?q=%s", "description": "DuckDuckGo search" },
160 "so": { "url": "https://stackoverflow.com/search?q=%s", "description": "Stack Overflow search" },
161 "r": { "url": "https://www.reddit.com/search?q=%s", "description": "Reddit search" },
162 "npm": { "url": "https://www.npmjs.com/search?q=%s", "description": "npm package search" },
163 "go": { "url": "https://pkg.go.dev/search?q=%s", "description": "Go package search" },
164 "mdn": { "url": "https://developer.mozilla.org/en-US/search?q=%s", "description": "MDN Web Docs search" }
165}
166```
167
168#### Dmenu Integration
169```json
170"dmenu": {
171 "max_history_items": 20,
172 "show_visit_count": true,
173 "show_last_visited": true,
174 "history_prefix": "🕒",
175 "shortcut_prefix": "🔍",
176 "url_prefix": "🌐",
177 "date_format": "2006-01-02 15:04",
178 "sort_by_visit_count": true
179}
180```
181
182#### Logging Configuration
183```json
184"logging": {
185 "level": "info",
186 "format": "text",
187 "filename": "",
188 "max_size": 100,
189 "max_backups": 3,
190 "max_age": 7,
191 "compress": true
192}
193```
194
195#### Appearance Settings
196```json
197"appearance": {
198 "sans_font": "Fira Sans",
199 "serif_font": "Fira Sans",
200 "monospace_font": "Fira Code",
201 "default_font_size": 16
202}
203```
204
205#### Rendering Mode (GPU/CPU)
206```json
207"rendering_mode": "auto"
208```
209- `auto`: Detect GPU availability and use GPU when available (default)
210- `gpu`: Force GPU acceleration (Vulkan/OpenGL via GTK4)
211- `cpu`: Force software rendering
212
213### Environment Variables
214All config values can be overridden with environment variables using the `DUMB_BROWSER_` prefix:
215
216```bash
217# Database
218DUMB_BROWSER_DATABASE_PATH="./browser.db"
219DUMB_BROWSER_DATABASE_MAX_CONNECTIONS=5
220
221# Rendering mode (special variable name)
222DUMBER_RENDERING_MODE="gpu"
223
224# Dmenu settings
225DUMB_BROWSER_DMENU_MAX_HISTORY_ITEMS=50
226DUMB_BROWSER_DMENU_SHOW_VISIT_COUNT=false
227
228# Logging
229DUMB_BROWSER_LOGGING_LEVEL="debug"
230DUMB_BROWSER_LOGGING_FORMAT="json"
231```
232
233### CLI Flags
234The browse command supports additional runtime flags:
235```bash
236dumber browse --rendering-mode=gpu https://example.com
237```
238
239
240## Building With WebKitGTK 6 (GTK4)
241- The GUI requires building with `-tags=webkit_cgo` and CGO enabled.
242- Ensure WebKitGTK 6 and GTK4 dev headers are installed (see prerequisites).
243- Make targets handle both frontend and Go build steps:
244 - `make build-gui` (CGO enabled)
245 - `make build` (CGO enabled by default in the Makefile’s main build)
246
247Without the native tag, a stub backend is used: you can still run CLI flows and see logs, but no native window is displayed.
248
249## Media (GStreamer) Requirements
250
251WebKitGTK uses GStreamer for media playback. Install the following packages to ensure audio/video work correctly.
252
253- Arch Linux:
254 - `sudo pacman -S gst-plugins-base gst-plugins-good gst-plugins-bad gst-plugins-ugly gst-libav gst-plugin-pipewire pipewire pipewire-pulse`
255 - Optional hardware accel: `gstreamer-vaapi`
256- Debian/Ubuntu:
257 - `sudo apt install gstreamer1.0-tools gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-libav gstreamer1.0-pipewire`
258 - Optional hardware accel: `gstreamer1.0-vaapi`
259
260## Theme and Runtime Updates
261- The homepage and pages respect your system’s light/dark preference.
262- The app updates color‑scheme live when your GTK theme changes (no relaunch needed).
263
264## Project Structure
265- `main.go`: CLI/GUI entrypoint, `dumb://` scheme, service wiring
266- `internal/cli`: Cobra commands (`browse`, `dmenu`, `version`)
267- `internal/config`: Viper‑backed config, XDG helpers, defaults
268- `internal/db`: SQLite schema init and sqlc‑generated queries
269- `services`: app services (parser/history/config/browser)
270- `pkg/webkit`: WebKit2GTK bindings (CGO and stub implementations)
271- `frontend`: TypeScript homepage UI bundled into the binary
272
273## Security & Privacy
274- History and zoom settings are stored locally in SQLite under XDG state.
275- The `tmp/` directory is ignored by Git and kept out of history.
276
277## Roadmap
278- ✅ WebKitGTK 6 (GTK4) migration (GPU/Vulkan path complete)
279- ✅ GPU rendering (Vulkan via GTK4 renderer) with graceful CPU fallback
280- Full Vim-style motion and keyboard navigation across pages and UI
281- Performance work: faster startup, lower memory, snappier UI
282- Basic ad-block extension — because fuck ads
283- Other shiny things I'm not yet aware of
284
285## License
286This project is licensed under the MIT License. See `LICENSE` for details.