Norn/README.md
2026-08-27 00:09:09 +02:00

254 lines
6.8 KiB
Markdown

# Norn
React-first graph viewer for Epiphany typed graph state.
The live package is `web/norn-viewer`. It is what clients and agents
should reach for when they want to render `architecture`, `dataflow`, and typed
cross-links in a UI.
The older .NET generator, MSAGL SVG renderer, and MCP server still exist as support
tools for note exports and legacy inspection. They are not competing client surfaces.
Do not make consumers choose between engines like this repo is a sad little trade
show booth.
## React Viewer
```powershell
cd E:\Projects\Norn\web\norn-viewer
npm install
npm run dev
```
```tsx
import { NornViewer } from "@gamecult/norn-viewer";
import type { NornGraphsState } from "@gamecult/norn-viewer";
export function GraphScreen({ state }: { state: NornGraphsState }) {
return (
<NornViewer
state={state}
layoutMode="combined-force"
motion={{ strength: 1.05, flow: 1.1, orbit: 0.85 }}
performance="fast"
/>
);
}
```
The public viewer API is intentionally coarse:
- `layoutMode`: `layered`, `stress`, `force`, or `combined-force`
- `motion`: viewer-owned force tuning for Rust-solver combined-force layouts
- `performance`: `quality`, `balanced`, `fast`, or explicit `simulationBudgetMs` realtime knobs
- `selection`, `focusSelection`, `expandedNode`, and callbacks for app integration
- typed state and event payloads
Norn owns graph layout, viewport motion, selection, focus, inspection, and the
interaction boundary of expanded node articles. Consumers own graph meaning and
article content. When an expanded article fills a node surface, Norn derives wheel
and drag behavior from that surface's committed article geometry; consumers do not
need product-specific classes or data attributes to make the article scrollable.
## What It Does
The support generator:
- scans markdown notes under a vault folder
- resolves Obsidian wikilinks and regular markdown note links
- optionally starts from an entry note and keeps only reachable notes
- classifies notes into `source-tree` and `control-flow` graph families
- lays out each family as its own graph partition
- reports cross-links that still jump between those families
- runs Microsoft Automatic Graph Layout
- writes:
- `manifest.json`
- `source-tree.svg`
- `source-tree.msagl.svg`
- `source-tree.rich.svg`
- `source-tree.json`
- `control-flow.svg`
- `control-flow.msagl.svg`
- `control-flow.rich.svg`
- `control-flow.json`
- `cross-links.json`
- `warnings.txt`
## CLI Usage
Run from source:
```powershell
dotnet run --project . -- `
--vault-root "E:\Projects\Aetheria-Economy\Aetheria\Source Tree Map" `
--entry-note "Source Tree Map" `
--renderer rich `
--output-dir ".\out\source-tree-map"
```
After packing as a .NET tool:
```powershell
norn `
--vault-root "E:\Projects\Aetheria-Economy\Aetheria\Source Tree Map" `
--entry-note "Source Tree Map" `
--renderer rich `
--output-dir ".\out\source-tree-map"
```
## MCP Usage
The MCP server exposes one tool:
- `generate_obsidian_graph_layout`
### Run From Source
Use this in an MCP client config when you want to launch the server straight from the repo:
```json
{
"mcpServers": {
"norn": {
"command": "dotnet",
"args": [
"run",
"--project",
"E:\\Projects\\Norn\\Norn.csproj",
"--",
"--mcp"
]
}
}
}
```
### Pack As A .NET Tool
Build the package:
```powershell
dotnet pack . -c Release -o .\nupkg
```
Install it from the local package output:
```powershell
dotnet tool install --global --add-source .\nupkg Norn
```
Then point your MCP client at the installed command:
```json
{
"mcpServers": {
"norn": {
"command": "norn",
"args": ["--mcp"]
}
}
}
```
### MCP Tool Arguments
- `vaultRoot`: path to the Obsidian vault folder
- `entryNote`: optional entry note name or relative note path
- `outputDir`: optional output directory, defaults to `./out`
- `layout`: `sugiyama` or `mds`
- `renderer`: `msagl` or `rich`
- `includeUnreachable`: keep notes that are not reachable from the entry note
### MCP Tool Result
The tool writes `manifest.json`, primary partition SVGs, raw `.msagl.svg` variants, custom `.rich.svg` variants, partition JSON files, `cross-links.json`, and `warnings.txt`, then returns:
- output paths for each partition
- seed note IDs used for traversal
- total note and edge counts
- per-partition node and edge counts
- warnings
- the resolved entry note ID, if one was used
## Graph Families
By default, notes whose basename contains `Control Flow` land in the `control-flow` partition, and everything else lands in `source-tree`.
You can override that with frontmatter on a note:
```yaml
---
norn-family: control-flow
---
```
or:
```yaml
---
norn-families:
- source-tree
- control-flow
---
```
Supported keys:
- `norn-family`
- `norn-families`
- `graph-family`
- `graph-families`
If your chosen `entryNote` is itself one of the explicit family roots, the generator also seeds traversal from any sibling family roots it can find.
- `Source Tree Map` will also pull in `Control Flow Map`
- `Control Flow Map` will also pull in `Source Tree Map`
That keeps structurally separated note graphs from vanishing just because they no longer link to each other directly.
## Layout Modes
- `sugiyama`: layered, better for hierarchy-heavy note trees
- `mds`: force-ish spread, better when the graph is cross-linked chaos
`mds` is the closest MSAGL-native approximation to the Obsidian or Kamada-Kawai vibe. It is not a named Kamada-Kawai mode.
## Renderer Modes
- `msagl`: the stock MSAGL SVG, useful as the plain baseline
- `rich`: a custom SVG renderer that consumes MSAGL graph geometry and semantic metadata, then draws something with more visual hierarchy and less beige despair
## Support Tool: Norn Viewer Demo
The web-side viewer package lives under `web/norn-viewer/`.
It consumes the typed Epiphany graph state shape directly:
- `graphs.architecture`
- `graphs.dataflow`
- `graphs.links`
and packages:
- Rust hybrid solver layout through bundled WASM
- zoom and pan
- zoom-gated label and detail pop-in
- node, edge, and code-ref inspection
- typed cross-link browsing between architecture and dataflow
- combined-force motion tuning for clients that want the lively overview
Run it locally with:
```powershell
cd E:\Projects\Norn\web\norn-viewer
npm install
npm run dev
```
## Notes
- unresolved and ambiguous links are written to `warnings.txt`
- node IDs in the partition `.json` files are relative note paths without `.md`
- the current implementation estimates label sizes instead of using a platform text measurer, because this is a generator, not a cathedral
- `source-tree.svg` and `control-flow.svg` are the primary outputs for the selected renderer
- raw MSAGL output is always preserved as `*.msagl.svg`
- the custom renderer currently emits `*.rich.svg` from MSAGL geometry, not from post-processing the stock SVG