Knowledge Graph Obsidian Preset
One-click Obsidian demo preset, full-graph fit behavior, and admin persistence for Arcturus-Prime's Tendril-powered graph
Knowledge Graph Obsidian Preset
Arcturus-Prime now includes a dedicated Obsidian-style preset path for the KnowledgeGraph component, with both live and persistent workflows:
- Live apply:
Obsidian Presetbutton in the graph physics panel - Persistent apply:
Apply Obsidian Presetbutton in/admin/graph-settings
This is designed for demo quality: clean visual hierarchy, calmer motion, and reliable full-graph framing after settle.
Where it lives
| Surface | File |
|---|---|
| Graph runtime + UI | src/components/KnowledgeGraph.astro |
| Admin persistent preset | src/pages/admin/graph-settings.astro |
Preset behavior
The preset applies a tuned package of settings:
- Physics: center/repel/link/distance/damping, settle behavior, bounding box
- Styling: low-noise text and edge treatment for a cleaner Obsidian-like look
- Node sizing: compact min/max sizing and tag ratio
- Layout startup mode:
obsidian-circle(consumer-handled startup path) - Container: wider demo framing (
min(96vw, 1280px),16 / 10)
Fit and framing improvements
A dedicated helper now fits and centers the graph after key transitions:
- when physics settles
- when reset is clicked
- when fullscreen toggles
- when static layout modes are selected
- after Obsidian preset application
A zoom cap is also applied post-fit to avoid over-zooming dense graphs.
2026-03-01 follow-up: startup centering hardening
After the first Obsidian preset release, a real-world issue still appeared in some sessions: the graph loaded tiny in a corner and looked offset from center.
Root cause
Container dimensions (clientWidth, clientHeight) weren’t ready when enableObsidianMode() ran at initialization. The circle layout seeding depends on knowing the viewport size.
What changed (March 1, 2026)
- Triple-resize with delays: Startup now does multiple resize cycles with
setTimeoutdelays to ensure container dimensions are ready before applying the layout - Multiple fit passes: Calls
fitGraphForDemo()three times with increasing delays to handle CSS/viewport settling - Forced Obsidian by default: Blog (
/blog) and tag pages (/tag/*) now load with Obsidian circle layout automatically - no need to click the button
// Before: single call
enableObsidianMode();
// After: delayed multi-pass
setTimeout(() => {
graph.resize();
setTimeout(() => {
graph.resize();
enableObsidianMode();
}, 150);
}, 50);
User-visible result
- Graph starts centered and properly sized on page load
- Obsidian circle + dandelion visible immediately without clicking any buttons
- No more zoomed-out/corner view on fresh page load
Two Obsidian Layout Modes
obsidian-circle (Global View)
The original dandelion pattern:
- Center: highest-degree tag
- Inner ring: other major tags
- Outer rings: posts grouped by their primary tag anchor
- Best for: overview of entire knowledge base
obsidian-local (Local View) — New
Compact organic cluster like Obsidian’s actual local graph:
-
Center: Index node or highest-degree node
-
Inner ring: direct connections (1 hop) in tight cluster
-
Second ring: 2-hop connections grouped near their parents
-
Outer: remaining nodes
-
Best for: exploring local neighborhood of connected notes
-
Feels like: spider web around current note
Default: Blog and tag pages now use obsidian-local by default.
Layout and behavior correctness fixes
Initial layout now honors config
Graph initialization now reads config.layout.initialLayout instead of hardcoding a specific startup layout path.
Non-layout mode buttons no longer trigger invalid layout calls
Controls that use data-mode are handled as mode actions and no longer call setLayout(undefined).
Single-use tag filtering is config-driven
Tag filtering now follows behavior.filterSingleUseTags instead of being always-on.
Known technical nuance
Tendril’s current runtime physics loop is driven by global linkDistance. Per-edge length metadata is present but not fully authoritative in force calculation yet. To improve observed behavior, Arcturus-Prime maps spine/bridge slider values into a weighted global link distance at runtime.
For full per-edge spring realism, the next step is a library-level enhancement in @tendril/graph to use edge-specific length/weight during link force computation.