A lightweight offline desktop toolkit using webview with a Zig backend and Preact frontend: local Q&A chain notes with fuzzy search, an academic paper reader with reference/figure management, quizzes, todos, and PDF export throughout.
| Plugin | What it does |
|---|---|
| Chain Notes | Saves external AI chats as local question-and-answer records; fuzzy search, markdown-aware PDF/print export |
| Academic Paper | Two-column paper reader with citations, plus Reference Manager and Image Assets submenus |
| Quiz | Blender 3D and audio-programming decks with sessions and an editor |
| Todos | Local-first task list with filters |
| Disk Scanner | Storage usage mapping (mock UI, backend pending) |
| Audio Equalizer | Listening-profile controls (mock UI, backend pending) |
Details live in docs/: chain notes,
academic paper, backend, and
testing.
.
├── build.zig / build.zig.zon # Zig build, package manifest, test roots
├── src/
│ ├── main.zig # Entry point, WebView host, RPC context
│ ├── backend.zig # Domain logic, validation, PDF saving
│ ├── config.zig # Window title/size, debug mode, dev URL
│ └── backend/
│ ├── plugin.zig # Backend plugin registry + lifecycle hooks
│ ├── core_plugin.zig # Binding registration + canonical name list
│ ├── storage.zig # Versioned JSON note store (state.json)
│ ├── quiz_storage.zig # Versioned JSON quiz store (quizzes.json)
│ └── log.zig # Leveled logging
├── frontend-preact/ # Preact frontend (esbuild + StyleX)
│ ├── build.js # Bundle + single-file dist/index.html
│ └── src/
│ ├── App.jsx # Launcher, rail, submenus, window controls
│ ├── backend.js # window.* Zig bridge with browser mocks
│ ├── bindings.d.ts # Typed bridge declarations (21 bindings)
│ └── plugins/ # Tool UIs + shared modules
│ ├── chain-notes.jsx / qna.js
│ ├── note-search.js # fuzzysort adapter (+ benchmark engines)
│ ├── note-markdown.js # Markdown subset + print CSS reset
│ ├── note-pdf.js # jsPDF / pdf-lib / pdfmake adapter
│ ├── academic-paper.jsx / paper.js / paper-data.js / paper-pdf.js
│ ├── reference-manager.jsx / image-assets.jsx
│ └── quiz.jsx / quiz-data.js, todo.jsx, …
├── tools/ # check-deps.sh, install-frontend.sh, prepare-linux-libc.sh
├── docs/ # Feature and backend documentation
└── archive/svelte-view/ # Previous Svelte frontend (archived, not built)
- Zig 0.16.0+
- Node.js 18+ and npm
- Linux: GTK3 + WebKitGTK 4.1
- macOS: WebKit (built-in)
- Windows: WebView2 Runtime
The project compiles the bundled webview C/C++ sources with a C++11-capable system compiler; the native toolchain must be compatible with the pinned Zig release. Verify everything up front:
bash tools/check-deps.shsudo pacman -S webkit2gtk-4.1 gtk3sudo apt install libgtk-3-dev libwebkit2gtk-4.1-dev# Build and launch the GUI
./run.sh
# Build everything (frontend + backend) and run
zig build run
# Or step by step:
cd frontend-preact && npm ci && npm run build && cd ..
zig build
./zig-out/bin/webview-appbuild.zig builds the Preact bundle, stages the single-file HTML under src/
(Zig 0.16 only allows @embedFile inside the package tree), then compiles the
native binary with the HTML embedded. On Linux it also stages a cached libc
configuration that strips unsupported .sframe sections from startup objects
without touching system files.
zig build dev # frontend dev server (Preact shell + mocks)Inside the dev server the Zig bindings don't exist, so src/backend.js falls
back to in-browser mocks (notes and custom quiz decks persist to localStorage
when available).
zig build test --summary all # backend unit tests + all frontend checks
cd frontend-preact && npm test # bridge, quiz, Q&A, markdown, paper, search, PDF suites
cd frontend-preact && npm run benchmark:notes # fuzzy-search engines
cd frontend-preact && npm run benchmark:pdf # PDF engines (note + chain)
cd frontend-preact && npm run benchmark:paper # PDF engines (sample paper)See docs/testing.md for the full matrix.
- Frontend: Preact + esbuild + StyleX. The custom
single-file-htmlplugin inlines all JS/CSS intofrontend-preact/dist/index.html. - Backend: Zig compiles the webview library and embeds the built HTML.
RPCs are grouped into backend plugins (
src/backend/plugin.zig) instead of loose bindings; see docs/backend.md. - Communication: the frontend calls Zig functions via
window.*, which return Promises. Failures arrive as stable{code, message}envelopes. - Persistence: notes live in a versioned
state.jsonand custom quiz decks inquizzes.jsonunder the OS data dir; PDF exports are written to the user's Documents folder viasavePdf. - Launcher: the app starts as a workspace launcher with a fixed rail, expandable submenus (Tools, Quiz, Paper), and native window actions.
Create a Preact view and manifest under frontend-preact/src/plugins/ (see
contract.js), then register it in plugins/index.js and add its rail label
in src/App.jsx.
- Add a method to
Contextinsrc/main.zigand bind it insrc/backend/core_plugin.zig(+bound_names, tested for uniqueness). - Declare it in
frontend-preact/src/bindings.d.tsand wrap it infrontend-preact/src/backend.js(validation + mock fallback). - Extend
frontend-preact/check-bindings.cjs— CI fails on drift.
MIT