3D Graph
Understand the 3D interactive graph, its architecture, and how to customize it.
The 3D interactive graph is the flagship feature of Grafos. It visualizes your content as a force-directed network where every page is a node and every link between pages is an edge.
Overview
The graph is built on three layers:
-
Data layer — the pre-build step scans all markdown files, extracts wikilinks and standard links, and writes
graph.jsonto the.grafos/cache. This file contains an array of nodes (one per page) and an array of edges (one per link). -
Physics layer — the d3-force-3d library runs a force simulation that positions nodes in 3D space. Linked nodes attract each other, unlinked nodes repel, and the simulation converges to a stable layout. This runs in a Web Worker to keep the main thread free for rendering.
-
Rendering layer — Three.js with React Three Fiber draws the graph. Nodes are instanced spheres (one draw call for all nodes), edges are
BufferGeometrylines, and labels are SDF (signed distance field) text rendered by@react-three/drei. The camera supports orbit controls for rotation, zoom, and pan.
The result is a smooth, interactive 3D visualization that runs at 60fps even with hundreds of nodes.
Local Graph
The local graph appears in the sidebar on every content page. It shows a filtered view centered on the current page:
- The current page is highlighted with a larger node and distinct color
- Neighboring pages up to a configurable depth are shown
- Edges between visible nodes are drawn
- Clicking a node navigates to that page
The depth is controlled in configuration:
graph: {
localDepth: 2, // Show nodes within 2 hops of the current page
}
A depth of 1 shows only direct neighbors. A depth of 2 shows neighbors of neighbors. Higher values show more of the graph but can become cluttered for densely connected sites.
The local graph is useful for discovering related content. When reading a page, glancing at the graph shows what else is connected and helps readers find their next page to visit.
Global Graph
The global graph shows every page in your site as a single interconnected network. It is available in two forms:
- Full page — the
/graphroute renders the graph as a full-screen experience - Modal — pressing
Cmd+G(orCtrl+Gon Windows/Linux) opens the graph as a modal overlay from any page
In the global view, all nodes and edges are visible. The force simulation spreads them out to reveal clusters and connections. You can:
- Rotate the graph by dragging
- Zoom in and out with the scroll wheel
- Click a node to navigate to that page
- Hover a node to see its title and highlight its connections
Nodes that you have previously visited are tracked in localStorage and rendered with a muted color, helping you identify unvisited pages.
Press Cmd+G from any page to open the global graph without navigating away. Press Escape to close it.
Web Worker
The force simulation is computationally expensive, especially for large graphs. Grafos offloads it to a Web Worker so it never blocks the main thread.
The architecture works as follows:
- The main thread sends graph data (nodes and edges) to the worker
- The worker initializes a d3-force-3d simulation with the configured forces
- On each simulation tick, the worker posts updated node positions back to the main thread
- The main thread updates the Three.js scene with the new positions
This separation means the graph stays interactive (camera controls, hover, click) even while the simulation is actively running. On low-powered devices, the simulation may take longer to converge, but the UI never freezes.
The forces applied by the simulation:
- Charge — nodes repel each other to prevent overlap. Controlled by
graph.physics.charge. - Link — linked nodes attract toward a target distance. Controlled by
graph.physics.linkDistance. - Center — a gentle force that pulls the entire graph toward the origin to prevent drift.
Customization
You can customize the visual appearance of the graph in configuration:
graph: {
localDepth: 2,
nodeColor: '#6366f1', // Default node color
edgeColor: '#4b5563', // Edge color
labelSize: 12, // Label text size in pixels
physics: {
charge: -120, // Repulsion strength (more negative = stronger)
linkDistance: 60, // Target distance between linked nodes
},
}
Individual pages can override the default node color in their frontmatter:
---
title: Important Page
graph:
color: '#ef4444'
---
To exclude a page from the graph entirely:
---
title: Hidden Page
graph:
exclude: true
---
The current page is always rendered with the accent color and a larger radius so it stands out in both the local and global views. The accent color is controlled by the --grafos-accent CSS variable. See theme for details on customizing colors.
The backlinks data comes from the same that powers the graph visualization. The graph stores edges as pairs. To find backlinks for a page, Grafos filters for all edges where matches the current page slug and returns the corresponding source pages.
- 3D Interactive Graph — force-directed graph visualization with local and global views, instanced rendering, and Web Worker physics. See graph for details. - Full-text Search — client-side search powered by MiniSearch with a Cmd+K keyboard shortcut and fuzzy matching. See search for details. - Wikilinks — Obsidian-compatible link syntax including page links, aliased links, heading links, and block embeds. See wikilinks for details. - Backlinks — automatic bidirectional link tracking that shows which pages link to the current page. See backlinks for details. - Syntax Highlighting — code blocks highlighted by Shiki with support for dozens of languages and themes. - LaTeX Math — inline and block math expressions rendered by KaTeX through remark-math and rehype-katex. - Callouts — Obsidian-style callout blocks for tips, warnings, notes, and other admonitions. - Table of Contents — automatically generated from page headings with scroll-tracking and smooth navigation. - Dark Mode — dark by default with a toggle that persists in localStorage and renders flash-free via an inline head script. - On-demand OG Images — social sharing images generated at request time through a Next.js API route, not at build time. - Plugin System — extend the markdown pipeline, graph data, and page layout with reusable plugins. See plugins for details. - Tailwind CSS v4 Preset — theming through CSS custom properties with a custom Tailwind preset for consistent styling. See theme for details.
From here, explore the configuration guide to customize your site, or dive into the feature guides for the graph, search, and wikilinks systems.