Fork of DanielCheer/obsidian-web-viewer (MIT, 2026-04) with Lukas' first additions for the Hermes Wiki workflow. Additive customization layer (vault-custom.js) — keeps upstream-merge trivial via a one-line script tag in vault.html. Features added: 1. Current-page highlighting in 3D Graph — current node gold+glow, connected nodes light-blue, others dim to 20% opacity 2. Click-to-navigate on graph — Three.js raycaster triggers file load 3. Responsive layout — graph collapses below 1024px, tree below 768px 4. URL-based deep-linking via ?file=<path> query param 5. Server-side ?file= support in /api/vault/file/ endpoint Modified files: - server.py: +7 lines (Lukas-add: ?file= query param parsing) - vault.html: +1 line (script tag for vault-custom.js) New files: - vault-custom.js: 11KB, all customizations in one place under HermesCustom namespace - README.md: fork intro, quick start, customization guide - CHANGELOG.md: Lukas-additions tracking - docs/ARCHITECTURE.md: design rationale - docs/CUSTOMIZATIONS.md: feature spec - .gitignore: standard 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
96 lines
4.7 KiB
Markdown
96 lines
4.7 KiB
Markdown
# Architecture
|
|
|
|
## Why this fork exists
|
|
|
|
[DanielCheer/obsidian-web-viewer](https://github.com/DanielCheer/obsidian-web-viewer) is a great single-file Obsidian-vault viewer (server.py + vault.html, ~10 KB + 14 KB, Python stdlib only). But for Lukas' Hermes Wiki workflow — 245 Markdown files across 18 top-level folders, frequent cross-referencing via WikiLinks, mobile reading — three specific UX gaps needed fixing:
|
|
|
|
1. **3D Graph shows all nodes uniformly** — no indication of which node the user is currently reading or which nodes are connected to it
|
|
2. **Layout breaks on small screens** — the 3-panel grid (`280px 1fr 260px`) is too narrow on 13" laptops and unusable on phones
|
|
3. **Click-to-navigate from graph** — Three.js canvas accepts clicks but doesn't trigger navigation
|
|
|
|
## Design principles
|
|
|
|
### 1. Additive layer, not fork-and-modify
|
|
|
|
We modify **exactly one line** in `vault.html` (a `<script src="vault-custom.js"></script>` tag before `</body>`). Everything else — including the customizations themselves — lives in `vault-custom.js`.
|
|
|
|
Why:
|
|
- Upstream `git pull` conflicts are trivial to resolve (the one line is recognizable)
|
|
- Customizations are clearly separated from upstream code
|
|
- Reviewing customizations is reading one file, not diffing the whole repo
|
|
- Easier to upstream-merge back if Lukas' features prove generally useful
|
|
|
|
### 2. HermesCustom namespace
|
|
|
|
All custom code lives under `window.HermesCustom`. Methods are namespaced and self-documenting:
|
|
|
|
```js
|
|
window.HermesCustom = window.HermesCustom || {};
|
|
HermesCustom.highlightCurrentNode = function() { ... };
|
|
HermesCustom.setupGraphClickHandler = function() { ... };
|
|
HermesCustom.responsiveLayout = function() { ... };
|
|
```
|
|
|
|
This way the namespace is visible in DevTools and a future maintainer can see at a glance what's custom vs. upstream.
|
|
|
|
### 3. Server.py stays mostly upstream
|
|
|
|
We add **one** enhancement to `server.py`: a `?file=<path>` query parameter that returns the file directly (used by `HermesCustom.highlightCurrentNode` to know which file is open). This is a 5-line change that doesn't conflict with any upstream logic.
|
|
|
|
If upstream adds a similar feature, we drop our addition.
|
|
|
|
## File map
|
|
|
|
```
|
|
hermes-wiki-viewer/
|
|
├── server.py # obv-fork + 5 lines (file-query-param)
|
|
├── vault.html # obv-fork + 1 line (script tag for custom.js)
|
|
├── vault-custom.js # ALL Lukas-specific code
|
|
├── requirements.txt # PyYAML only (same as upstream)
|
|
├── README.md # this repo's entry point
|
|
├── LICENSE # MIT (inherited)
|
|
├── CHANGELOG.md # release notes for Lukas-additions
|
|
├── docs/
|
|
│ ├── ARCHITECTURE.md # you are here
|
|
│ └── CUSTOMIZATIONS.md # spec for each Lukas-feature
|
|
└── .gitignore # standard
|
|
```
|
|
|
|
## Why we keep `vault-custom.js` separate from `vault.html`
|
|
|
|
Embedding customizations into `vault.html` would mean:
|
|
- Every upstream update requires re-applying the entire diff
|
|
- Reviewing customizations requires diffing two HTML files
|
|
- Conflicts when upstream renames a function we override
|
|
|
|
A separate file means:
|
|
- The customizations are a stable, reviewable unit
|
|
- Upstream updates touch `vault.html` only, customizations are unchanged
|
|
- The one-line patch in `vault.html` is a clear "anchor point" that any reviewer can understand
|
|
|
|
## Why Python stdlib only (no Flask/FastAPI)
|
|
|
|
Upstream uses `http.server` from stdlib. We keep this. Adding a framework would:
|
|
- Inflate dependencies
|
|
- Require version-pinning for reproducibility
|
|
- Make the tool harder to deploy (anywhere with Python 3.8+ works)
|
|
|
|
The 5-line addition to `server.py` is plain stdlib `BaseHTTPRequestHandler` style.
|
|
|
|
## Tradeoffs we accepted
|
|
|
|
- **No build step.** Customizations are vanilla JS. No bundler, no TypeScript. Means no static type-checking, but means anyone can read and modify the code without toolchain setup.
|
|
- **No tests in CI.** We rely on manual testing for now. CI tests would add complexity that doesn't match the project's "simple tool" character. (Future: a small Playwright test for the graph highlighting.)
|
|
- **No auto-update from upstream.** When obv updates, Lukas has to `git pull upstream && git merge`. The one-line `vault.html` patch needs re-application if upstream modified it. This is acceptable for a personal side-project.
|
|
|
|
## Roadmap
|
|
|
|
See CHANGELOG.md for planned additions. Current priorities:
|
|
|
|
1. ✅ Current-page highlighting in 3D Graph
|
|
2. ✅ Click-to-navigate on graph
|
|
3. ✅ Responsive layout (1024px and 768px breakpoints)
|
|
4. ⏳ Backlinks panel (per-page incoming WikiLinks)
|
|
5. ⏳ Keyboard shortcuts (j/k for next/prev file, [/] for nav, g/G for graph focus)
|
|
6. ⏳ Light theme variant (currently Catppuccin-dark only)
|