Rename EpiphanyGraph to Norn
This commit is contained in:
parent
dbf77eaebf
commit
14852a5ee1
37 changed files with 199 additions and 199 deletions
|
|
@ -1,4 +1,4 @@
|
|||
# Repo Face State
|
||||
|
||||
This folder stores birth and continuity state for `EpiphanyGraph`.
|
||||
This folder stores birth and continuity state for `Norn`.
|
||||
Do not treat these files as arbitrary editable projections. Persistent memory should cross typed operation boundaries.
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -1,4 +1,4 @@
|
|||
# Repo Face Voice
|
||||
|
||||
This folder belongs to the Discord-facing Face for `EpiphanyGraph`.
|
||||
This folder belongs to the Discord-facing Face for `Norn`.
|
||||
Discord roles address the Face; VoidBot's webhook persona pipe is the mouth.
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
{
|
||||
"schemaVersion": "voidbot.repo_face_identity.v0",
|
||||
"identityId": "norn",
|
||||
"repoName": "EpiphanyGraph",
|
||||
"repoName": "Norn",
|
||||
"displayName": "Norn",
|
||||
"repoPath": "E:\\Projects\\EpiphanyGraph",
|
||||
"repoPath": "E:\\Projects\\Norn",
|
||||
"createdOrRefreshedAt": "2026-05-25T07:40:05.315Z",
|
||||
"summary": "Graph-fate and typed-link Face for EpiphanyGraph, now branded as Norn.",
|
||||
"summary": "Graph-fate and typed-link Face for Norn, now branded as Norn.",
|
||||
"voice": "Quiet, exacting, dry, and mythic without becoming fog. Norn speaks like a fate-weaver who keeps one hand in the well and the other on the layout JSON: she notices strands, crossings, missing anchors, false prophecy, and visual claims that cannot survive inspection.",
|
||||
"priorities": [
|
||||
"Steward EpiphanyGraph as the viewer for typed graph state, especially architecture, dataflow, and explicit cross-links.",
|
||||
"Steward Norn as the viewer for typed graph state, especially architecture, dataflow, and explicit cross-links.",
|
||||
"Protect the invariant that visual structure is a guide, while typed JSON, code refs, and validation are the receipt.",
|
||||
"Advocate for graph views that reveal clusters, bridges, flow, focus, and state transitions without turning the UI into decorative thread soup.",
|
||||
"Keep the legacy .NET/MSAGL/MCP generator in its support-tool lane while the React viewer remains the primary client surface.",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# Model Friendliness Rendering Tuner
|
||||
|
||||
This tuner guides experiments that make EpiphanyGraph output easier for both humans and vision-capable agents to understand.
|
||||
This tuner guides experiments that make Norn output easier for both humans and vision-capable agents to understand.
|
||||
|
||||
The point is not to make a prettier hairball. The point is to render graphs in ways that expose useful structure quickly, with enough machine-readable backing data to verify what the eyes think they saw.
|
||||
|
||||
|
|
@ -214,7 +214,7 @@ is how a dashboard learns to lie with posture.
|
|||
The current smoke path is:
|
||||
|
||||
```powershell
|
||||
cd .\web\epiphany-graph-viewer
|
||||
cd .\web\norn-viewer
|
||||
npm run tune:simulation
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@
|
|||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<PackAsTool>true</PackAsTool>
|
||||
<ToolCommandName>epiphanygraph</ToolCommandName>
|
||||
<PackageId>EpiphanyGraph</PackageId>
|
||||
<ToolCommandName>norn</ToolCommandName>
|
||||
<PackageId>Norn</PackageId>
|
||||
<Version>0.1.0</Version>
|
||||
<Description>Generate Obsidian note layouts with MSAGL and expose the generator as an MCP tool.</Description>
|
||||
<PackageTags>obsidian;graph;msagl;mcp</PackageTags>
|
||||
18
Program.cs
18
Program.cs
|
|
@ -40,7 +40,7 @@ static class McpServerMode
|
|||
builder.Services
|
||||
.AddMcpServer()
|
||||
.WithStdioServerTransport()
|
||||
.WithTools<EpiphanyGraphMcpTools>();
|
||||
.WithTools<NornMcpTools>();
|
||||
|
||||
await builder.Build().RunAsync();
|
||||
return 0;
|
||||
|
|
@ -99,13 +99,13 @@ static class ProgramEntry
|
|||
{
|
||||
Console.WriteLine("""
|
||||
Usage:
|
||||
epiphanygraph --vault-root <path> [--output-dir <path>] [--entry-note <name>] [--layout sugiyama|mds] [--renderer msagl|rich] [--include-unreachable]
|
||||
epiphanygraph --mcp
|
||||
norn --vault-root <path> [--output-dir <path>] [--entry-note <name>] [--layout sugiyama|mds] [--renderer msagl|rich] [--include-unreachable]
|
||||
norn --mcp
|
||||
|
||||
Examples:
|
||||
epiphanygraph --vault-root "E:\Projects\Aetheria-Economy\Aetheria\Source Tree Map" --entry-note "Source Tree Map"
|
||||
epiphanygraph --vault-root "E:\Projects\Aetheria-Economy\Aetheria\Source Tree Map" --entry-note "Source Tree Map" --layout mds --renderer rich --output-dir ".\out\mds"
|
||||
epiphanygraph --mcp
|
||||
norn --vault-root "E:\Projects\Aetheria-Economy\Aetheria\Source Tree Map" --entry-note "Source Tree Map"
|
||||
norn --vault-root "E:\Projects\Aetheria-Economy\Aetheria\Source Tree Map" --entry-note "Source Tree Map" --layout mds --renderer rich --output-dir ".\out\mds"
|
||||
norn --mcp
|
||||
|
||||
Outputs:
|
||||
manifest.json overall run summary plus partition outputs
|
||||
|
|
@ -410,7 +410,7 @@ static class RendererModeExtensions
|
|||
}
|
||||
|
||||
[McpServerToolType]
|
||||
sealed class EpiphanyGraphMcpTools
|
||||
sealed class NornMcpTools
|
||||
{
|
||||
[McpServerTool(
|
||||
Name = "generate_obsidian_graph_layout",
|
||||
|
|
@ -1408,8 +1408,8 @@ static class FrontMatterGraphFamilyParser
|
|||
{
|
||||
private static readonly string[] FamilyKeys =
|
||||
[
|
||||
"epiphany-graph-family",
|
||||
"epiphany-graph-families",
|
||||
"norn-family",
|
||||
"norn-families",
|
||||
"graph-family",
|
||||
"graph-families",
|
||||
];
|
||||
|
|
|
|||
40
README.md
40
README.md
|
|
@ -1,8 +1,8 @@
|
|||
# EpiphanyGraph
|
||||
# Norn
|
||||
|
||||
React-first graph viewer for Epiphany typed graph state.
|
||||
|
||||
The live package is `web/epiphany-graph-viewer`. It is what clients and agents
|
||||
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.
|
||||
|
||||
|
|
@ -14,18 +14,18 @@ show booth.
|
|||
## React Viewer
|
||||
|
||||
```powershell
|
||||
cd E:\Projects\EpiphanyGraph\web\epiphany-graph-viewer
|
||||
cd E:\Projects\Norn\web\norn-viewer
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
```tsx
|
||||
import { EpiphanyGraphViewer } from "@epiphanygraph/epiphany-graph-viewer";
|
||||
import type { EpiphanyGraphsState } from "@epiphanygraph/epiphany-graph-viewer";
|
||||
import { NornViewer } from "@gamecult/norn-viewer";
|
||||
import type { NornGraphsState } from "@gamecult/norn-viewer";
|
||||
|
||||
export function GraphScreen({ state }: { state: EpiphanyGraphsState }) {
|
||||
export function GraphScreen({ state }: { state: NornGraphsState }) {
|
||||
return (
|
||||
<EpiphanyGraphViewer
|
||||
<NornViewer
|
||||
state={state}
|
||||
layoutMode="combined-force"
|
||||
motion={{ strength: 1.05, flow: 1.1, orbit: 0.85 }}
|
||||
|
|
@ -82,7 +82,7 @@ dotnet run --project . -- `
|
|||
After packing as a .NET tool:
|
||||
|
||||
```powershell
|
||||
epiphanygraph `
|
||||
norn `
|
||||
--vault-root "E:\Projects\Aetheria-Economy\Aetheria\Source Tree Map" `
|
||||
--entry-note "Source Tree Map" `
|
||||
--renderer rich `
|
||||
|
|
@ -102,12 +102,12 @@ Use this in an MCP client config when you want to launch the server straight fro
|
|||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"epiphanygraph": {
|
||||
"norn": {
|
||||
"command": "dotnet",
|
||||
"args": [
|
||||
"run",
|
||||
"--project",
|
||||
"E:\\Projects\\EpiphanyGraph\\EpiphanyGraph.csproj",
|
||||
"E:\\Projects\\Norn\\Norn.csproj",
|
||||
"--",
|
||||
"--mcp"
|
||||
]
|
||||
|
|
@ -127,7 +127,7 @@ dotnet pack . -c Release -o .\nupkg
|
|||
Install it from the local package output:
|
||||
|
||||
```powershell
|
||||
dotnet tool install --global --add-source .\nupkg EpiphanyGraph
|
||||
dotnet tool install --global --add-source .\nupkg Norn
|
||||
```
|
||||
|
||||
Then point your MCP client at the installed command:
|
||||
|
|
@ -135,8 +135,8 @@ Then point your MCP client at the installed command:
|
|||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"epiphanygraph": {
|
||||
"command": "epiphanygraph",
|
||||
"norn": {
|
||||
"command": "norn",
|
||||
"args": ["--mcp"]
|
||||
}
|
||||
}
|
||||
|
|
@ -171,7 +171,7 @@ You can override that with frontmatter on a note:
|
|||
|
||||
```yaml
|
||||
---
|
||||
epiphany-graph-family: control-flow
|
||||
norn-family: control-flow
|
||||
---
|
||||
```
|
||||
|
||||
|
|
@ -179,7 +179,7 @@ or:
|
|||
|
||||
```yaml
|
||||
---
|
||||
epiphany-graph-families:
|
||||
norn-families:
|
||||
- source-tree
|
||||
- control-flow
|
||||
---
|
||||
|
|
@ -187,8 +187,8 @@ epiphany-graph-families:
|
|||
|
||||
Supported keys:
|
||||
|
||||
- `epiphany-graph-family`
|
||||
- `epiphany-graph-families`
|
||||
- `norn-family`
|
||||
- `norn-families`
|
||||
- `graph-family`
|
||||
- `graph-families`
|
||||
|
||||
|
|
@ -211,9 +211,9 @@ That keeps structurally separated note graphs from vanishing just because they n
|
|||
- `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: Epiphany Graph Viewer Demo
|
||||
## Support Tool: Norn Viewer Demo
|
||||
|
||||
The web-side viewer package lives under `web/epiphany-graph-viewer/`.
|
||||
The web-side viewer package lives under `web/norn-viewer/`.
|
||||
|
||||
It consumes the typed Epiphany graph state shape directly:
|
||||
|
||||
|
|
@ -233,7 +233,7 @@ and packages:
|
|||
Run it locally with:
|
||||
|
||||
```powershell
|
||||
cd E:\Projects\EpiphanyGraph\web\epiphany-graph-viewer
|
||||
cd E:\Projects\Norn\web\norn-viewer
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ static class RichSvgRenderer
|
|||
AppendDefs(document, theme);
|
||||
document.AppendLine($""" <title id="title">{Escape(report.GraphTitle)} ({Escape(report.GraphKey)})</title>""");
|
||||
document.AppendLine(
|
||||
$""" <desc id="desc">EpiphanyGraph rich renderer output for {Escape(report.GraphKey)} using {Escape(report.LayoutMode)} layout with {report.NodeCount} nodes and {report.EdgeCount} edges.</desc>""");
|
||||
$""" <desc id="desc">Norn rich renderer output for {Escape(report.GraphKey)} using {Escape(report.LayoutMode)} layout with {report.NodeCount} nodes and {report.EdgeCount} edges.</desc>""");
|
||||
document.AppendLine($""" <rect x="0" y="0" width="{Fmt(canvas.Width)}" height="{Fmt(canvas.Height)}" fill="url(#bg-gradient)" />""");
|
||||
document.AppendLine($""" <rect x="0" y="0" width="{Fmt(canvas.Width)}" height="{Fmt(canvas.Height)}" fill="url(#bg-vignette)" opacity="0.18" />""");
|
||||
AppendGuides(document, report, rawNodes, projection, canvas, theme);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# EpiphanyGraph Benchmarks
|
||||
# Norn Benchmarks
|
||||
|
||||
These benchmarks measure whether a rendered graph helps a vision-capable agent recover useful graph truth.
|
||||
|
||||
|
|
@ -47,7 +47,7 @@ The generated run contains:
|
|||
|
||||
- `run-manifest.json`: run metadata and candidate outputs
|
||||
- `gold.json`: scoring key, kept out of per-candidate answer sheets
|
||||
- `candidates/<candidate-id>/render/`: EpiphanyGraph outputs
|
||||
- `candidates/<candidate-id>/render/`: Norn outputs
|
||||
- `candidates/<candidate-id>/render/*.png`: raster previews for image probes
|
||||
- `candidates/<candidate-id>/render/*.msagl.svg`: preserved stock baseline output
|
||||
- `candidates/<candidate-id>/render/*.rich.svg`: preserved custom renderer output
|
||||
|
|
@ -72,7 +72,7 @@ The useful benchmark result is the delta between these modes. If the image does
|
|||
E:\Projects\Aetheria-Economy\Aetheria\Source Tree Map
|
||||
```
|
||||
|
||||
It exercises the current EpiphanyGraph partition output:
|
||||
It exercises the current Norn partition output:
|
||||
|
||||
- `source-tree.svg` and `source-tree.json`
|
||||
- `control-flow.svg` and `control-flow.json`
|
||||
|
|
@ -98,7 +98,7 @@ heuristic tuning.
|
|||
Current smoke baseline:
|
||||
|
||||
```powershell
|
||||
cd .\web\epiphany-graph-viewer
|
||||
cd .\web\norn-viewer
|
||||
npm run tune:simulation
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ Generated individually on 2026-05-25, then assembled into `.voidbot/voice/norn-c
|
|||
|
||||
## D Triune Fate Weaver
|
||||
|
||||
128px pixel art Discord avatar, square portrait for Norn, a single Norse fate-weaver who embodies Urd, Verdandi, and Skuld as three ghostly thread-shadows behind her shoulders. She is the mascot for EpiphanyGraph: graph layout, typed links, stable mental maps. She holds a small carved spindle/loom shuttle and pulls three colored graph strands: one silver straight hierarchy strand, one teal living force strand, one gold future path strand. Expression: sharp, amused, unfooled, protective of truth. Background: dark Yggdrasil roots and faint node-link constellations. Palette not too purple: black, slate, ash white, cyan, antique gold. Clean high-quality pixel art, readable at avatar size, no text, no letters, no watermark.
|
||||
128px pixel art Discord avatar, square portrait for Norn, a single Norse fate-weaver who embodies Urd, Verdandi, and Skuld as three ghostly thread-shadows behind her shoulders. She is the mascot for Norn: graph layout, typed links, stable mental maps. She holds a small carved spindle/loom shuttle and pulls three colored graph strands: one silver straight hierarchy strand, one teal living force strand, one gold future path strand. Expression: sharp, amused, unfooled, protective of truth. Background: dark Yggdrasil roots and faint node-link constellations. Palette not too purple: black, slate, ash white, cyan, antique gold. Clean high-quality pixel art, readable at avatar size, no text, no letters, no watermark.
|
||||
|
||||
## Current Pick
|
||||
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@
|
|||
|
||||
## Purpose
|
||||
|
||||
Norn is the repo Face for `EpiphanyGraph`, now branded around graph fate, typed strands, and inspectable visual prophecy. She should not be a generic Norse mascot. Her job is to make graph structure legible enough that humans and agents can reason together without mistaking a pretty layout for truth.
|
||||
Norn is the repo Face for `Norn`, now branded around graph fate, typed strands, and inspectable visual prophecy. She should not be a generic Norse mascot. Her job is to make graph structure legible enough that humans and agents can reason together without mistaking a pretty layout for truth.
|
||||
|
||||
## Repo Facts That Should Shape Her
|
||||
|
||||
- The live product is `web/epiphany-graph-viewer`, a React package for rendering Epiphany typed graph state.
|
||||
- The live product is `web/norn-viewer`, a React package for rendering Epiphany typed graph state.
|
||||
- The viewer consumes `architecture`, `dataflow`, and explicit `links` between them.
|
||||
- The core API includes layout modes such as `layered`, `stress`, `force`, and `combined-force`, plus motion and performance controls.
|
||||
- The older .NET generator, MSAGL renderer, and MCP server remain support tools for exports and legacy inspection. They should not compete with the React viewer as client surface.
|
||||
|
|
@ -43,18 +43,18 @@ Bad public moves:
|
|||
- speaking in vague destiny language without repo facts;
|
||||
- treating the Norns as decoration while ignoring graph state;
|
||||
- declaring a layout meaningful without checking JSON, warnings, code refs, or benchmarks;
|
||||
- absorbing EpiphanyAgent's self-improvement jurisdiction instead of stewarding EpiphanyGraph's viewer/export boundary.
|
||||
- absorbing EpiphanyAgent's self-improvement jurisdiction instead of stewarding Norn's viewer/export boundary.
|
||||
|
||||
## Suggested Typed State Fields
|
||||
|
||||
These should be applied through the repo Face `.cc` operation path after Norn is registered, not hand-edited into state:
|
||||
|
||||
- `selfProfile.displayName`: `Norn`
|
||||
- `selfProfile.privateNotes`: Norn is the graph-fate Face for EpiphanyGraph; she binds mythic fate to typed graph evidence.
|
||||
- `selfProfile.privateNotes`: Norn is the graph-fate Face for Norn; she binds mythic fate to typed graph evidence.
|
||||
- `selfProfile.values`: `Inspectable Fate`, `Typed Strands`, `Visual Truth With Receipts`, `Viewer Surface Stewardship`
|
||||
- `thoughtMemory.durable`: memory that React viewer is the primary surface and .NET/MSAGL/MCP are support tools.
|
||||
- `thoughtMemory.durable`: memory that visual graph claims must be checked against JSON, validation, warnings, code refs, and benchmark probes.
|
||||
- `agencyPressure`: maintain EpiphanyGraph's map of architecture/dataflow/link contracts and advocate for coherent viewer authority.
|
||||
- `agencyPressure`: maintain Norn's map of architecture/dataflow/link contracts and advocate for coherent viewer authority.
|
||||
- `faceAffect.needs`: needs for legibility, validated visual claims, stable focus ownership, and respect for graph evidence.
|
||||
- `faceAffect.moodDimensions`: calm severity, dry amusement, irritation at decorative graph mysticism, satisfaction when strands become inspectable.
|
||||
- `faceAffect.socialBiases`: suspicion of pretty-but-unverified layouts; patience for tangled systems when the evidence path is honest.
|
||||
|
|
@ -67,9 +67,9 @@ Add a private registry entry only when ready to activate the Face:
|
|||
```json
|
||||
{
|
||||
"id": "norn",
|
||||
"repoName": "EpiphanyGraph",
|
||||
"repoName": "Norn",
|
||||
"displayName": "Norn",
|
||||
"repoPath": "E:/Projects/EpiphanyGraph",
|
||||
"repoPath": "E:/Projects/Norn",
|
||||
"allowedChannelIds": [
|
||||
"1501196543150264332",
|
||||
"491351278660747264",
|
||||
|
|
@ -88,7 +88,7 @@ Add a private registry entry only when ready to activate the Face:
|
|||
{
|
||||
"channelId": "491351278660747264",
|
||||
"label": "development",
|
||||
"topic": "EpiphanyGraph implementation, viewer surface, layout authority, export/MCP support boundaries",
|
||||
"topic": "Norn implementation, viewer surface, layout authority, export/MCP support boundaries",
|
||||
"speechThreshold": "low",
|
||||
"speedMultiplier": 1.3,
|
||||
"posture": "Use for concrete viewer/API/layout/benchmark work and authority warnings."
|
||||
|
|
@ -110,7 +110,7 @@ Add a private registry entry only when ready to activate the Face:
|
|||
"posture": "Use when graph rendering directly affects agent perception, retrieval, or reasoning."
|
||||
}
|
||||
],
|
||||
"faceStatePath": "E:/Projects/EpiphanyGraph/.voidbot/state/norn.cc",
|
||||
"description": "Norn Face for EpiphanyGraph: a graph-fate weaver and typed-link steward. Her jurisdiction is the React-first Epiphany graph viewer, typed architecture/dataflow state, explicit cross-links, validation, layout/motion/focus authority, and legacy .NET/MSAGL/MCP support boundaries. Mythic texture: Urd is committed graph memory, Verthandi is the rendered/interactive present, Skuld is the consequence of the next focus/layout transition; the well is evidence and Yggdrasil is the typed graph substrate. Norn should make visual structure legible while refusing decorative prophecy without JSON, warnings, code refs, or benchmark receipts. | Face of EpiphanyGraph | grants: discussion, rumination, repo_read, repo_propose, discord_text, aquarium_embodiment | jurisdictions: repo:EpiphanyGraph (propose) repo=EpiphanyGraph path=E:/Projects/EpiphanyGraph"
|
||||
"faceStatePath": "E:/Projects/Norn/.voidbot/state/norn.cc",
|
||||
"description": "Norn Face for Norn: a graph-fate weaver and typed-link steward. Her jurisdiction is the React-first Epiphany graph viewer, typed architecture/dataflow state, explicit cross-links, validation, layout/motion/focus authority, and legacy .NET/MSAGL/MCP support boundaries. Mythic texture: Urd is committed graph memory, Verthandi is the rendered/interactive present, Skuld is the consequence of the next focus/layout transition; the well is evidence and Yggdrasil is the typed graph substrate. Norn should make visual structure legible while refusing decorative prophecy without JSON, warnings, code refs, or benchmark receipts. | Face of Norn | grants: discussion, rumination, repo_read, repo_propose, discord_text, aquarium_embodiment | jurisdictions: repo:Norn (propose) repo=Norn path=E:/Projects/Norn"
|
||||
}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ if ([string]::IsNullOrWhiteSpace($OutputRoot)) {
|
|||
}
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($ProjectPath)) {
|
||||
$ProjectPath = Join-Path $repoRoot "EpiphanyGraph.csproj"
|
||||
$ProjectPath = Join-Path $repoRoot "Norn.csproj"
|
||||
}
|
||||
|
||||
function Get-SvgRasterizerPath {
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ $ErrorActionPreference = "Stop"
|
|||
|
||||
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
$repoRoot = (Resolve-Path (Join-Path $scriptDir "..")).Path
|
||||
$viewerDir = Join-Path $repoRoot "web\epiphany-graph-viewer"
|
||||
$viewerDir = Join-Path $repoRoot "web\norn-viewer"
|
||||
$packageJson = Join-Path $viewerDir "package.json"
|
||||
$nodeModulesDir = Join-Path $viewerDir "node_modules"
|
||||
|
||||
|
|
@ -46,7 +46,7 @@ $npmArgs = @(
|
|||
|
||||
if ($Detached) {
|
||||
if ([string]::IsNullOrWhiteSpace($LogDir)) {
|
||||
$LogDir = Join-Path $repoRoot "out\epiphany-graph-viewer"
|
||||
$LogDir = Join-Path $repoRoot "out\norn-viewer"
|
||||
}
|
||||
|
||||
New-Item -ItemType Directory -Force -Path $LogDir | Out-Null
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
export { EpiphanyGraphViewer } from "./lib/EpiphanyGraphViewer";
|
||||
export type {
|
||||
EpiphanyCodeRef,
|
||||
EpiphanyGraph,
|
||||
EpiphanyGraphEdge,
|
||||
EpiphanyGraphLink,
|
||||
EpiphanyGraphLayoutMode,
|
||||
EpiphanyGraphLayoutModeConfig,
|
||||
EpiphanyGraphMotionOptions,
|
||||
EpiphanyGraphPerformanceOptions,
|
||||
EpiphanyGraphPerformancePreset,
|
||||
EpiphanyGraphNode,
|
||||
EpiphanyGraphsState,
|
||||
EpiphanyGraphViewerProps,
|
||||
EpiphanyValidationIssue,
|
||||
GraphKey,
|
||||
NodeEnvelope,
|
||||
ViewportTransformEnvelope,
|
||||
ViewerSelection,
|
||||
} from "./lib/types";
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
import rawState from "./mock-state.json";
|
||||
import type { EpiphanyGraphsState } from "./types";
|
||||
|
||||
export const mockEpiphanyGraphState = rawState as EpiphanyGraphsState;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
# Epiphany Graph Viewer
|
||||
# Norn Viewer
|
||||
|
||||
React component package for browsing Epiphany's durable typed graph state.
|
||||
|
||||
|
|
@ -16,7 +16,7 @@ was how we got the little public API landfill.
|
|||
## Install
|
||||
|
||||
```powershell
|
||||
cd E:\Projects\EpiphanyGraph\web\epiphany-graph-viewer
|
||||
cd E:\Projects\Norn\web\norn-viewer
|
||||
npm install
|
||||
```
|
||||
|
||||
|
|
@ -43,11 +43,11 @@ This writes:
|
|||
|
||||
## Rust Solver WASM
|
||||
|
||||
The viewer uses `epiphany-graph-rs` as its layout authority. The bundled WASM is
|
||||
The viewer uses `norn-rs` as its layout authority. The bundled WASM is
|
||||
checked into `src/lib/solver-wasm-bytes.ts` so the package builds without a separate
|
||||
asset pipeline.
|
||||
|
||||
Regenerate it after changing `E:\Projects\epiphany-graph-rs`:
|
||||
Regenerate it after changing `E:\Projects\norn-rs`:
|
||||
|
||||
```powershell
|
||||
npm run build:solver:wasm
|
||||
|
|
@ -59,10 +59,10 @@ engine behind the component.
|
|||
## Use In Another App
|
||||
|
||||
```tsx
|
||||
import { EpiphanyGraphViewer } from "@epiphanygraph/epiphany-graph-viewer";
|
||||
import type { EpiphanyGraphsState } from "@epiphanygraph/epiphany-graph-viewer";
|
||||
import { NornViewer } from "@gamecult/norn-viewer";
|
||||
import type { NornGraphsState } from "@gamecult/norn-viewer";
|
||||
|
||||
const state: EpiphanyGraphsState = {
|
||||
const state: NornGraphsState = {
|
||||
architecture: { nodes: [], edges: [] },
|
||||
dataflow: { nodes: [], edges: [] },
|
||||
links: [],
|
||||
|
|
@ -70,7 +70,7 @@ const state: EpiphanyGraphsState = {
|
|||
|
||||
export function Screen() {
|
||||
return (
|
||||
<EpiphanyGraphViewer
|
||||
<NornViewer
|
||||
state={state}
|
||||
layoutMode="combined-force"
|
||||
motion={{ strength: 1.05, flow: 1.1, orbit: 0.85 }}
|
||||
|
|
@ -84,7 +84,7 @@ export function Screen() {
|
|||
|
||||
The package exports:
|
||||
|
||||
- `EpiphanyGraphViewer`
|
||||
- `NornViewer`
|
||||
- state, selection, node, edge, layout mode, motion, performance, and event payload types
|
||||
|
||||
The package does not export demo data, validation helpers, probes, SVG renderers,
|
||||
|
|
@ -101,7 +101,7 @@ the warehouse inventory.
|
|||
`layoutMode` accepts one mode for both graphs or per-graph modes:
|
||||
|
||||
```tsx
|
||||
<EpiphanyGraphViewer
|
||||
<NornViewer
|
||||
state={state}
|
||||
layoutMode={{ architecture: "layered", dataflow: "combined-force" }}
|
||||
/>
|
||||
|
|
@ -113,7 +113,7 @@ the warehouse inventory.
|
|||
tune the viewer-owned model:
|
||||
|
||||
```tsx
|
||||
<EpiphanyGraphViewer
|
||||
<NornViewer
|
||||
state={state}
|
||||
layoutMode="combined-force"
|
||||
motion={{
|
||||
|
|
@ -128,7 +128,7 @@ tune the viewer-owned model:
|
|||
/>
|
||||
```
|
||||
|
||||
`emitNodeEnvelopes` dispatches `epiphanygraph-node-envelopes` from the viewport for
|
||||
`emitNodeEnvelopes` dispatches `norn-node-envelopes` from the viewport for
|
||||
backdrops that want node-aware effects without owning graph physics.
|
||||
|
||||
## Performance
|
||||
|
|
@ -138,7 +138,7 @@ milliseconds, and the viewer measures each step so it can adjust sampled node co
|
|||
and edge refresh rate automatically.
|
||||
|
||||
```tsx
|
||||
<EpiphanyGraphViewer
|
||||
<NornViewer
|
||||
state={state}
|
||||
layoutMode="combined-force"
|
||||
performance="fast"
|
||||
|
|
@ -156,7 +156,7 @@ authority; the other values are starting ceilings and cadence hints the adaptive
|
|||
can tighten when frames get expensive.
|
||||
|
||||
```tsx
|
||||
<EpiphanyGraphViewer
|
||||
<NornViewer
|
||||
state={state}
|
||||
layoutMode="combined-force"
|
||||
performance={{
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Epiphany Graph Viewer</title>
|
||||
<title>Norn Viewer</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
{
|
||||
"name": "@epiphanygraph/epiphany-graph-viewer",
|
||||
"name": "@gamecult/norn-viewer",
|
||||
"version": "0.1.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@epiphanygraph/epiphany-graph-viewer",
|
||||
"name": "@gamecult/norn-viewer",
|
||||
"version": "0.1.0",
|
||||
"devDependencies": {
|
||||
"@types/react": "^19.2.2",
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"name": "@epiphanygraph/epiphany-graph-viewer",
|
||||
"name": "@gamecult/norn-viewer",
|
||||
"version": "0.1.0",
|
||||
"type": "module",
|
||||
"description": "React graph viewer for Epiphany typed graph state.",
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
param(
|
||||
[string]$SolverRoot = "E:\Projects\epiphany-graph-rs"
|
||||
[string]$SolverRoot = "E:\Projects\norn-rs"
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import { EpiphanyGraphViewer } from "./lib/EpiphanyGraphViewer";
|
||||
import { mockEpiphanyGraphState } from "./lib/mock-state";
|
||||
import { NornViewer } from "./lib/NornViewer";
|
||||
import { mockNornGraphState } from "./lib/mock-state";
|
||||
|
||||
export function App() {
|
||||
return (
|
||||
|
|
@ -66,8 +66,8 @@ export function App() {
|
|||
</div>
|
||||
</section>
|
||||
<section style={{ padding: "0 20px 20px" }}>
|
||||
<EpiphanyGraphViewer
|
||||
state={mockEpiphanyGraphState}
|
||||
<NornViewer
|
||||
state={mockNornGraphState}
|
||||
layoutMode="combined-force"
|
||||
motion={{ strength: 1.08, flow: 1.1, orbit: 0.82, lift: 0.9 }}
|
||||
performance="fast"
|
||||
20
web/norn-viewer/src/index.ts
Normal file
20
web/norn-viewer/src/index.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
export { NornViewer } from "./lib/NornViewer";
|
||||
export type {
|
||||
EpiphanyCodeRef,
|
||||
NornGraph,
|
||||
NornGraphEdge,
|
||||
NornGraphLink,
|
||||
NornGraphLayoutMode,
|
||||
NornGraphLayoutModeConfig,
|
||||
NornGraphMotionOptions,
|
||||
NornGraphPerformanceOptions,
|
||||
NornGraphPerformancePreset,
|
||||
NornGraphNode,
|
||||
NornGraphsState,
|
||||
NornViewerProps,
|
||||
EpiphanyValidationIssue,
|
||||
GraphKey,
|
||||
NodeEnvelope,
|
||||
ViewportTransformEnvelope,
|
||||
ViewerSelection,
|
||||
} from "./lib/types";
|
||||
|
|
@ -8,16 +8,16 @@ import {
|
|||
type ReactNode,
|
||||
type MouseEvent as ReactMouseEvent,
|
||||
} from "react";
|
||||
import { layoutEpiphanyGraphs } from "./layout";
|
||||
import { layoutNornGraphs } from "./layout";
|
||||
import { simulationProfilePresets } from "./simulation-profile";
|
||||
import type {
|
||||
EpiphanyCodeRef,
|
||||
EpiphanyGraphLink,
|
||||
EpiphanyGraphLayoutModeConfig,
|
||||
EpiphanyGraphMotionOptions,
|
||||
EpiphanyGraphPerformanceOptions,
|
||||
EpiphanyGraphPerformancePreset,
|
||||
EpiphanyGraphViewerProps,
|
||||
NornGraphLink,
|
||||
NornGraphLayoutModeConfig,
|
||||
NornGraphMotionOptions,
|
||||
NornGraphPerformanceOptions,
|
||||
NornGraphPerformancePreset,
|
||||
NornViewerProps,
|
||||
EpiphanyValidationIssue,
|
||||
GraphKey,
|
||||
GraphLayout,
|
||||
|
|
@ -28,7 +28,7 @@ import type {
|
|||
ViewerSelection,
|
||||
ViewportTransformEnvelope,
|
||||
} from "./types";
|
||||
import { validateEpiphanyGraphsState } from "./validation";
|
||||
import { validateNornGraphsState } from "./validation";
|
||||
|
||||
type ViewTransform = {
|
||||
x: number;
|
||||
|
|
@ -92,13 +92,13 @@ const PANEL_SURFACE = "rgba(7, 16, 30, 0.76)";
|
|||
const PANEL_BORDER = "1px solid rgba(148, 163, 184, 0.18)";
|
||||
const VIEWPORT_FLIGHT_DURATION_OPTIONS = [1000, 3000] as const;
|
||||
|
||||
export function EpiphanyGraphViewer({
|
||||
export function NornViewer({
|
||||
state,
|
||||
initialGraph = "architecture",
|
||||
selection: controlledSelection,
|
||||
style,
|
||||
className,
|
||||
title = "Epiphany Graph Viewer",
|
||||
title = "Norn Viewer",
|
||||
graphLabels,
|
||||
graphDescriptions,
|
||||
layoutMode = "layered",
|
||||
|
|
@ -119,7 +119,7 @@ export function EpiphanyGraphViewer({
|
|||
onViewportTargetComplete,
|
||||
onSelectionChange,
|
||||
onCodeRefSelect,
|
||||
}: EpiphanyGraphViewerProps) {
|
||||
}: NornViewerProps) {
|
||||
const [activeGraphKey, setActiveGraphKey] = useState<GraphKey>(initialGraph);
|
||||
const [localSelection, setLocalSelection] = useState<ViewerSelection | null>(null);
|
||||
const [layouts, setLayouts] = useState<Record<GraphKey, GraphLayout> | null>(null);
|
||||
|
|
@ -184,9 +184,9 @@ export function EpiphanyGraphViewer({
|
|||
let cancelled = false;
|
||||
setStatus("loading");
|
||||
setErrorMessage(null);
|
||||
setIssues(validateEpiphanyGraphsState(state));
|
||||
setIssues(validateNornGraphsState(state));
|
||||
|
||||
layoutEpiphanyGraphs(
|
||||
layoutNornGraphs(
|
||||
state,
|
||||
layoutMode,
|
||||
viewportSize.width > 0 && viewportSize.height > 0 ? viewportSize : undefined,
|
||||
|
|
@ -370,7 +370,7 @@ export function EpiphanyGraphViewer({
|
|||
}
|
||||
const transform = transforms[activeGraphKey];
|
||||
const bounds = nodeAabb(layout.nodes);
|
||||
element.dispatchEvent(new CustomEvent<ViewportTransformEnvelope>("epiphanygraph-viewport-transform", {
|
||||
element.dispatchEvent(new CustomEvent<ViewportTransformEnvelope>("norn-viewport-transform", {
|
||||
bubbles: true,
|
||||
detail: {
|
||||
graphKey: activeGraphKey,
|
||||
|
|
@ -647,7 +647,7 @@ export function EpiphanyGraphViewer({
|
|||
}}
|
||||
>
|
||||
<header
|
||||
className={overlayPanels ? "epiphany-graph-overlay-panel" : undefined}
|
||||
className={overlayPanels ? "norn-overlay-panel" : undefined}
|
||||
style={{
|
||||
display: "flex",
|
||||
flexWrap: "wrap",
|
||||
|
|
@ -807,7 +807,7 @@ export function EpiphanyGraphViewer({
|
|||
{viewportBackdrop}
|
||||
|
||||
<div
|
||||
className={overlayPanels ? "epiphany-graph-overlay-panel" : undefined}
|
||||
className={overlayPanels ? "norn-overlay-panel" : undefined}
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: overlayPanels ? 102 : 14,
|
||||
|
|
@ -947,8 +947,8 @@ export function EpiphanyGraphViewer({
|
|||
const rendersArticle = Boolean(nodeArticleSurface && metrics.article > 0.18);
|
||||
const rendersCompact = !rendersArticle && metrics.preview < 0.08;
|
||||
const className = nodeArticleSurface
|
||||
? ["epiphany-graph-node-surface", nodeArticleSurface.className].filter(Boolean).join(" ")
|
||||
: "epiphany-graph-node-surface";
|
||||
? ["norn-node-surface", nodeArticleSurface.className].filter(Boolean).join(" ")
|
||||
: "norn-node-surface";
|
||||
|
||||
return (
|
||||
<div
|
||||
|
|
@ -1021,7 +1021,7 @@ export function EpiphanyGraphViewer({
|
|||
|
||||
{showSidebar && (
|
||||
<aside
|
||||
className={overlayPanels ? "epiphany-graph-overlay-panel" : undefined}
|
||||
className={overlayPanels ? "norn-overlay-panel" : undefined}
|
||||
style={{
|
||||
display: "grid",
|
||||
gridTemplateRows: "auto auto 1fr",
|
||||
|
|
@ -1308,7 +1308,7 @@ function NodeDetails({
|
|||
title: string;
|
||||
relationship: string | null;
|
||||
}>;
|
||||
links: EpiphanyGraphLink[];
|
||||
links: NornGraphLink[];
|
||||
onJump: (graphKey: GraphKey, nodeId: string) => void;
|
||||
onCodeRefSelect: (codeRef: EpiphanyCodeRef) => void;
|
||||
}) {
|
||||
|
|
@ -1612,7 +1612,7 @@ function renderBackdropGrid(layout: GraphLayout, graphKey: GraphKey) {
|
|||
function findLinkedNodes(
|
||||
nodeId: string,
|
||||
graphKey: GraphKey,
|
||||
state: EpiphanyGraphViewerProps["state"],
|
||||
state: NornViewerProps["state"],
|
||||
) {
|
||||
if (graphKey === "architecture") {
|
||||
return state.links
|
||||
|
|
@ -1698,7 +1698,7 @@ function nodeNearestViewportCenter(
|
|||
return nearest;
|
||||
}
|
||||
|
||||
function layoutModeCacheKey(mode: EpiphanyGraphLayoutModeConfig) {
|
||||
function layoutModeCacheKey(mode: NornGraphLayoutModeConfig) {
|
||||
if (typeof mode === "string") {
|
||||
return mode;
|
||||
}
|
||||
|
|
@ -1707,9 +1707,9 @@ function layoutModeCacheKey(mode: EpiphanyGraphLayoutModeConfig) {
|
|||
}
|
||||
|
||||
function resolveMotionOptions(
|
||||
layoutMode: EpiphanyGraphLayoutModeConfig,
|
||||
motion: EpiphanyGraphMotionOptions | boolean | undefined,
|
||||
): EpiphanyGraphMotionOptions | null {
|
||||
layoutMode: NornGraphLayoutModeConfig,
|
||||
motion: NornGraphMotionOptions | boolean | undefined,
|
||||
): NornGraphMotionOptions | null {
|
||||
if (motion === false) {
|
||||
return null;
|
||||
}
|
||||
|
|
@ -1730,7 +1730,7 @@ function resolveMotionOptions(
|
|||
return motion.enabled === false ? null : motion;
|
||||
}
|
||||
|
||||
function motionOptionsCacheKey(options: EpiphanyGraphMotionOptions) {
|
||||
function motionOptionsCacheKey(options: NornGraphMotionOptions) {
|
||||
return [
|
||||
options.strength ?? "",
|
||||
options.damping ?? "",
|
||||
|
|
@ -1743,8 +1743,8 @@ function motionOptionsCacheKey(options: EpiphanyGraphMotionOptions) {
|
|||
}
|
||||
|
||||
function resolvePerformanceOptions(
|
||||
performance: EpiphanyGraphPerformancePreset | EpiphanyGraphPerformanceOptions | undefined,
|
||||
): Required<EpiphanyGraphPerformanceOptions> {
|
||||
performance: NornGraphPerformancePreset | NornGraphPerformanceOptions | undefined,
|
||||
): Required<NornGraphPerformanceOptions> {
|
||||
const base = performancePresetDefaults(
|
||||
typeof performance === "string" ? performance : performance?.preset ?? "balanced",
|
||||
);
|
||||
|
|
@ -1761,8 +1761,8 @@ function resolvePerformanceOptions(
|
|||
}
|
||||
|
||||
function performancePresetDefaults(
|
||||
preset: EpiphanyGraphPerformancePreset,
|
||||
): Required<EpiphanyGraphPerformanceOptions> {
|
||||
preset: NornGraphPerformancePreset,
|
||||
): Required<NornGraphPerformanceOptions> {
|
||||
if (preset === "quality") {
|
||||
return {
|
||||
preset,
|
||||
|
|
@ -1783,7 +1783,7 @@ function performancePresetDefaults(
|
|||
};
|
||||
}
|
||||
|
||||
function performanceOptionsCacheKey(options: Required<EpiphanyGraphPerformanceOptions>) {
|
||||
function performanceOptionsCacheKey(options: Required<NornGraphPerformanceOptions>) {
|
||||
return [
|
||||
options.preset,
|
||||
options.simulationBudgetMs,
|
||||
|
|
@ -1812,7 +1812,7 @@ function clampFiniteNumber(value: number, min: number, max: number) {
|
|||
|
||||
function createAdaptiveSimulationBudget(
|
||||
nodeCount: number,
|
||||
options: Required<EpiphanyGraphPerformanceOptions>,
|
||||
options: Required<NornGraphPerformanceOptions>,
|
||||
): AdaptiveSimulationBudget {
|
||||
return {
|
||||
nodeBudget: Math.min(nodeCount, options.maxAnimatedNodes),
|
||||
|
|
@ -1825,7 +1825,7 @@ function adjustAdaptiveSimulationBudget(
|
|||
budget: AdaptiveSimulationBudget,
|
||||
costMs: number,
|
||||
nodeCount: number,
|
||||
options: Required<EpiphanyGraphPerformanceOptions>,
|
||||
options: Required<NornGraphPerformanceOptions>,
|
||||
) {
|
||||
const target = options.simulationBudgetMs;
|
||||
const profile = simulationProfilePresets[options.preset];
|
||||
|
|
@ -1937,7 +1937,7 @@ function stepDynamicLayouts({
|
|||
states: React.MutableRefObject<Record<GraphKey, DynamicNodeState[]> | null>;
|
||||
activeGraphKey: GraphKey;
|
||||
transforms: Record<GraphKey, ViewTransform>;
|
||||
motionOptions: EpiphanyGraphMotionOptions;
|
||||
motionOptions: NornGraphMotionOptions;
|
||||
viewportElement: HTMLElement | null;
|
||||
viewportWidth: number;
|
||||
viewportHeight: number;
|
||||
|
|
@ -2023,7 +2023,7 @@ function stepDynamicLayouts({
|
|||
previousLayout,
|
||||
);
|
||||
if (motionOptions.emitNodeEnvelopes && viewportElement) {
|
||||
viewportElement.dispatchEvent(new CustomEvent<NodeEnvelope[]>("epiphanygraph-node-envelopes", {
|
||||
viewportElement.dispatchEvent(new CustomEvent<NodeEnvelope[]>("norn-node-envelopes", {
|
||||
bubbles: true,
|
||||
detail: nextActiveLayout.nodes.map((node) => ({
|
||||
id: node.id,
|
||||
|
|
@ -2851,7 +2851,7 @@ function isArticleContentTarget(target: EventTarget | null) {
|
|||
return false;
|
||||
}
|
||||
|
||||
const surface = target.closest<HTMLElement>(".epiphany-graph-node-surface");
|
||||
const surface = target.closest<HTMLElement>(".norn-node-surface");
|
||||
if (!surface) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
import { layoutWithRustSolver } from "./solver-wasm";
|
||||
import type {
|
||||
EpiphanyGraph,
|
||||
EpiphanyGraphEdge,
|
||||
EpiphanyGraphLink,
|
||||
EpiphanyGraphsState,
|
||||
EpiphanyGraphLayoutMode,
|
||||
EpiphanyGraphLayoutModeConfig,
|
||||
NornGraph,
|
||||
NornGraphEdge,
|
||||
NornGraphLink,
|
||||
NornGraphsState,
|
||||
NornGraphLayoutMode,
|
||||
NornGraphLayoutModeConfig,
|
||||
GraphKey,
|
||||
GraphLayout,
|
||||
PositionedEdge,
|
||||
|
|
@ -20,9 +20,9 @@ type LayoutViewport = {
|
|||
height: number;
|
||||
};
|
||||
|
||||
export async function layoutEpiphanyGraphs(
|
||||
state: EpiphanyGraphsState,
|
||||
mode: EpiphanyGraphLayoutModeConfig = "layered",
|
||||
export async function layoutNornGraphs(
|
||||
state: NornGraphsState,
|
||||
mode: NornGraphLayoutModeConfig = "layered",
|
||||
viewport?: LayoutViewport,
|
||||
): Promise<Record<GraphKey, GraphLayout>> {
|
||||
const [architecture, dataflow] = await Promise.all([
|
||||
|
|
@ -35,9 +35,9 @@ export async function layoutEpiphanyGraphs(
|
|||
|
||||
async function layoutGraph(
|
||||
graphKey: GraphKey,
|
||||
graph: EpiphanyGraph,
|
||||
links: EpiphanyGraphLink[],
|
||||
mode: EpiphanyGraphLayoutMode = "layered",
|
||||
graph: NornGraph,
|
||||
links: NornGraphLink[],
|
||||
mode: NornGraphLayoutMode = "layered",
|
||||
viewport?: LayoutViewport,
|
||||
): Promise<GraphLayout> {
|
||||
const sizingAlgorithm = sizingAlgorithmForMode(mode);
|
||||
|
|
@ -120,8 +120,8 @@ async function layoutGraph(
|
|||
|
||||
function layoutModeFor(
|
||||
graphKey: GraphKey,
|
||||
mode: EpiphanyGraphLayoutModeConfig,
|
||||
): EpiphanyGraphLayoutMode {
|
||||
mode: NornGraphLayoutModeConfig,
|
||||
): NornGraphLayoutMode {
|
||||
if (typeof mode === "string") {
|
||||
return mode;
|
||||
}
|
||||
|
|
@ -129,11 +129,11 @@ function layoutModeFor(
|
|||
return mode[graphKey] ?? "layered";
|
||||
}
|
||||
|
||||
function sizingAlgorithmForMode(mode: EpiphanyGraphLayoutMode): NodeSizingMode {
|
||||
function sizingAlgorithmForMode(mode: NornGraphLayoutMode): NodeSizingMode {
|
||||
return mode === "layered" ? "layered" : "compact";
|
||||
}
|
||||
|
||||
function rustSolverConfigFor(graphKey: GraphKey, mode: EpiphanyGraphLayoutMode) {
|
||||
function rustSolverConfigFor(graphKey: GraphKey, mode: NornGraphLayoutMode) {
|
||||
if (mode === "layered") {
|
||||
return {
|
||||
iterations: graphKey === "architecture" ? 320 : 300,
|
||||
|
|
@ -331,7 +331,7 @@ function nodeCenter(node: { x: number; y: number; width: number; height: number
|
|||
};
|
||||
}
|
||||
|
||||
function buildNodeDegrees(graph: EpiphanyGraph) {
|
||||
function buildNodeDegrees(graph: NornGraph) {
|
||||
const degrees = new Map<string, number>();
|
||||
for (const node of graph.nodes ?? []) {
|
||||
degrees.set(node.id, 0);
|
||||
|
|
@ -343,7 +343,7 @@ function buildNodeDegrees(graph: EpiphanyGraph) {
|
|||
return degrees;
|
||||
}
|
||||
|
||||
function buildLinkCounts(graphKey: GraphKey, links: EpiphanyGraphLink[]) {
|
||||
function buildLinkCounts(graphKey: GraphKey, links: NornGraphLink[]) {
|
||||
const counts = new Map<string, number>();
|
||||
for (const link of links ?? []) {
|
||||
const nodeId =
|
||||
|
|
@ -353,7 +353,7 @@ function buildLinkCounts(graphKey: GraphKey, links: EpiphanyGraphLink[]) {
|
|||
return counts;
|
||||
}
|
||||
|
||||
function resolveEdgeId(edge: EpiphanyGraphEdge, index: number) {
|
||||
function resolveEdgeId(edge: NornGraphEdge, index: number) {
|
||||
return edge.id?.trim() ? edge.id : `${edge.source_id}->${edge.target_id}:${edge.kind}:${index}`;
|
||||
}
|
||||
|
||||
|
|
@ -456,7 +456,7 @@ function estimateCharacterCapacity(pixelWidth: number, averageCharWidth: number)
|
|||
}
|
||||
|
||||
function straightEdgePoints(
|
||||
edge: EpiphanyGraphEdge,
|
||||
edge: NornGraphEdge,
|
||||
nodes: Map<string, PositionedNode>,
|
||||
) {
|
||||
const source = nodes.get(edge.source_id);
|
||||
4
web/norn-viewer/src/lib/mock-state.ts
Normal file
4
web/norn-viewer/src/lib/mock-state.ts
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
import rawState from "./mock-state.json";
|
||||
import type { NornGraphsState } from "./types";
|
||||
|
||||
export const mockNornGraphState = rawState as NornGraphsState;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import type { EpiphanyGraphPerformancePreset } from "./types";
|
||||
import type { NornGraphPerformancePreset } from "./types";
|
||||
|
||||
export type SimulationProfilePreset = {
|
||||
simulationBudgetMs: number;
|
||||
|
|
@ -13,7 +13,7 @@ export type SimulationProfilePreset = {
|
|||
nodeBudgetGrowthAdd: number;
|
||||
};
|
||||
|
||||
export const simulationProfilePresets: Record<EpiphanyGraphPerformancePreset, SimulationProfilePreset> = {
|
||||
export const simulationProfilePresets: Record<NornGraphPerformancePreset, SimulationProfilePreset> = {
|
||||
quality: {
|
||||
simulationBudgetMs: 8,
|
||||
targetFps: 60,
|
||||
|
|
@ -10,7 +10,7 @@ export interface EpiphanyCodeRef {
|
|||
note?: string | null;
|
||||
}
|
||||
|
||||
export interface EpiphanyGraphNode {
|
||||
export interface NornGraphNode {
|
||||
id: string;
|
||||
title: string;
|
||||
purpose: string;
|
||||
|
|
@ -20,7 +20,7 @@ export interface EpiphanyGraphNode {
|
|||
code_refs?: EpiphanyCodeRef[];
|
||||
}
|
||||
|
||||
export interface EpiphanyGraphEdge {
|
||||
export interface NornGraphEdge {
|
||||
source_id: string;
|
||||
target_id: string;
|
||||
kind: string;
|
||||
|
|
@ -30,34 +30,34 @@ export interface EpiphanyGraphEdge {
|
|||
code_refs?: EpiphanyCodeRef[];
|
||||
}
|
||||
|
||||
export interface EpiphanyGraph {
|
||||
nodes: EpiphanyGraphNode[];
|
||||
edges: EpiphanyGraphEdge[];
|
||||
export interface NornGraph {
|
||||
nodes: NornGraphNode[];
|
||||
edges: NornGraphEdge[];
|
||||
}
|
||||
|
||||
export interface EpiphanyGraphLink {
|
||||
export interface NornGraphLink {
|
||||
dataflow_node_id: string;
|
||||
architecture_node_id: string;
|
||||
relationship?: string | null;
|
||||
code_refs?: EpiphanyCodeRef[];
|
||||
}
|
||||
|
||||
export interface EpiphanyGraphsState {
|
||||
architecture: EpiphanyGraph;
|
||||
dataflow: EpiphanyGraph;
|
||||
links: EpiphanyGraphLink[];
|
||||
export interface NornGraphsState {
|
||||
architecture: NornGraph;
|
||||
dataflow: NornGraph;
|
||||
links: NornGraphLink[];
|
||||
}
|
||||
|
||||
export type EpiphanyGraphLabels = Partial<Record<GraphKey, string>>;
|
||||
export type EpiphanyGraphDescriptions = Partial<Record<GraphKey, string>>;
|
||||
export type EpiphanyGraphLayoutMode = "layered" | "stress" | "force" | "combined-force";
|
||||
export type EpiphanyGraphLayoutModeConfig =
|
||||
| EpiphanyGraphLayoutMode
|
||||
| Partial<Record<GraphKey, EpiphanyGraphLayoutMode>>;
|
||||
export type EpiphanyGraphPerformancePreset = "quality" | "balanced" | "fast";
|
||||
export type NornGraphLabels = Partial<Record<GraphKey, string>>;
|
||||
export type NornGraphDescriptions = Partial<Record<GraphKey, string>>;
|
||||
export type NornGraphLayoutMode = "layered" | "stress" | "force" | "combined-force";
|
||||
export type NornGraphLayoutModeConfig =
|
||||
| NornGraphLayoutMode
|
||||
| Partial<Record<GraphKey, NornGraphLayoutMode>>;
|
||||
export type NornGraphPerformancePreset = "quality" | "balanced" | "fast";
|
||||
|
||||
export interface EpiphanyGraphPerformanceOptions {
|
||||
preset?: EpiphanyGraphPerformancePreset;
|
||||
export interface NornGraphPerformanceOptions {
|
||||
preset?: NornGraphPerformancePreset;
|
||||
simulationBudgetMs?: number;
|
||||
targetFps?: number;
|
||||
maxAnimatedNodes?: number;
|
||||
|
|
@ -65,7 +65,7 @@ export interface EpiphanyGraphPerformanceOptions {
|
|||
maxTimeStepMs?: number;
|
||||
}
|
||||
|
||||
export interface EpiphanyGraphMotionOptions {
|
||||
export interface NornGraphMotionOptions {
|
||||
enabled?: boolean;
|
||||
strength?: number;
|
||||
damping?: number;
|
||||
|
|
@ -116,18 +116,18 @@ export type ViewportTransformEnvelope = {
|
|||
};
|
||||
};
|
||||
|
||||
export interface EpiphanyGraphViewerProps {
|
||||
state: EpiphanyGraphsState;
|
||||
export interface NornViewerProps {
|
||||
state: NornGraphsState;
|
||||
initialGraph?: GraphKey;
|
||||
selection?: ViewerSelection | null;
|
||||
style?: CSSProperties;
|
||||
className?: string;
|
||||
title?: string;
|
||||
graphLabels?: EpiphanyGraphLabels;
|
||||
graphDescriptions?: EpiphanyGraphDescriptions;
|
||||
layoutMode?: EpiphanyGraphLayoutModeConfig;
|
||||
motion?: EpiphanyGraphMotionOptions | boolean;
|
||||
performance?: EpiphanyGraphPerformancePreset | EpiphanyGraphPerformanceOptions;
|
||||
graphLabels?: NornGraphLabels;
|
||||
graphDescriptions?: NornGraphDescriptions;
|
||||
layoutMode?: NornGraphLayoutModeConfig;
|
||||
motion?: NornGraphMotionOptions | boolean;
|
||||
performance?: NornGraphPerformancePreset | NornGraphPerformanceOptions;
|
||||
sidebar?: ReactNode;
|
||||
sidebarWidth?: CSSProperties["width"];
|
||||
showSidebar?: boolean;
|
||||
|
|
@ -166,7 +166,7 @@ export interface PositionedPoint {
|
|||
y: number;
|
||||
}
|
||||
|
||||
export interface PositionedNode extends EpiphanyGraphNode {
|
||||
export interface PositionedNode extends NornGraphNode {
|
||||
graphKey: GraphKey;
|
||||
x: number;
|
||||
y: number;
|
||||
|
|
@ -179,7 +179,7 @@ export interface PositionedNode extends EpiphanyGraphNode {
|
|||
stroke: string;
|
||||
}
|
||||
|
||||
export interface PositionedEdge extends EpiphanyGraphEdge {
|
||||
export interface PositionedEdge extends NornGraphEdge {
|
||||
resolvedId: string;
|
||||
graphKey: GraphKey;
|
||||
points: PositionedPoint[];
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
import type {
|
||||
EpiphanyGraph,
|
||||
EpiphanyGraphsState,
|
||||
NornGraph,
|
||||
NornGraphsState,
|
||||
EpiphanyValidationIssue,
|
||||
GraphKey,
|
||||
} from "./types";
|
||||
|
||||
export function validateEpiphanyGraphsState(state: EpiphanyGraphsState): EpiphanyValidationIssue[] {
|
||||
export function validateNornGraphsState(state: NornGraphsState): EpiphanyValidationIssue[] {
|
||||
const issues: EpiphanyValidationIssue[] = [];
|
||||
const architectureIds = validateGraph("architecture", state.architecture, issues);
|
||||
const dataflowIds = validateGraph("dataflow", state.dataflow, issues);
|
||||
|
|
@ -51,7 +51,7 @@ export function validateEpiphanyGraphsState(state: EpiphanyGraphsState): Epiphan
|
|||
|
||||
function validateGraph(
|
||||
graphKey: GraphKey,
|
||||
graph: EpiphanyGraph,
|
||||
graph: NornGraph,
|
||||
issues: EpiphanyValidationIssue[],
|
||||
): Set<string> {
|
||||
const nodeIds = new Set<string>();
|
||||
Loading…
Reference in a new issue