Color mode

ExcaliBrain

Structured relationship maps for notes, modelled on ExcaliBrain by Zsolt Viczián.

日本語

Overview

excaliBrain() renders each note in a planar layout with seven regions:

Region Direction Role
Parents top parent
Children bottom child
Left friends left leftFriend
Right friends right rightFriend
Previous far left previous
Next far right next
Siblings periphery sibling

Relationships come from ExcaliBrain's ontology: YAML frontmatter fields and dataview inline fields in the note body. When a relationship is not stated explicitly, it is inferred from the content graph.

Usage

ts
import { defineConfig } from "@riebeckite/core";
import { excaliBrain } from "@riebeckite/plugin-excalibrain";
 
export default defineConfig({
  // ...
  plugins: [
    excaliBrain({
      render: "build",
    }),
  ],
});

The plugin runs with order: -10.

Declaring relationships

Explicit relations win over inferred ones.

YAML frontmatter

md
---
title: ExcaliBrain Center
parent: "[[excalibrain-parent]]"
children: ["[[excalibrain-child-a]]", "[[excalibrain-child-b]]"]
---

Dataview inline fields

md
children:: [[excalibrain-child]]
 
related:: [[note-a]] and [[note-b]] are similar

An inline field may appear on its own line or inside brackets ([field:: [[target]]]).

Ontology

Field names are matched case-insensitively and spaces are normalized to hyphens. The default ontology is:

Role Field names
parents parent, parents, up, u, north, origin, inception, source, parent domain
children children, child, down, d, south, leads to, contributes to, nurtures
leftFriends friends, friend, jump, jumps, j, similar, supports, alternatives, advantages, pros
rightFriends opposes, disadvantages, missing, cons
previous previous, prev, west, w, before
next next, n, east, e, after
hidden hidden

The ontology option extends the defaults: each role's field names are appended to that role's defaults rather than replacing them. An override can still add an existing field to another role, but earlier roles in the canonical order (parents, children, leftFriends, rightFriends, previous, next, hidden) win when a field is listed twice.

hidden follows ExcaliBrain: it lists the targets to hide from this note's map; it never hides the note itself. showHidden reveals those targets.

Inference

When infer is enabled (the default):

  • a forward link (this note → other) becomes a child;
  • a backlink (other → this note) becomes a parent;
  • a mutual link (this note ↔ other) becomes a leftFriend.

With siblings enabled (the default), the other children of this note's parents become sibling nodes. Sibling inference also requires infer: setting infer: false disables it. Link targets are resolved against the content manifest; unresolved targets become virtual nodes labelled with the raw link text (data-node-virtual="true").

Publication boundary

Nodes are resolved against the content manifest. A target whose publishing.routable flag is false is dropped from the map, so notes excluded from publication never appear as nodes or links and their titles and permalinks are not leaked.

Rendering

The render option selects where the map is produced:

Mode Behavior
"build" (default) The SVG is generated at build time and inlined into the article.
"client" A div.rb-excalibrain__canvas carries the escaped graph/layout payload; initExcaliBrain() builds the SVG in the browser.
"both" Inline SVG plus the client layer for progressive enhancement.

Injection

  • A ```excalibrain fence is replaced by the map.
  • Otherwise, when auto is enabled and the note has at least one relationship, the map section is appended to the article HTML (both the manifest entry and the cached post content).

heading / headingText control the optional <h2>.

Options

Option Type Default Description
render "build" | "client" | "both" "build" Where the map is rendered
auto boolean true Append the map when a note has no fence
heading boolean true Show the heading
headingText string "ExcaliBrain" Heading text
className string "rb-excalibrain" Root CSS class
maxPerRegion number 8 Maximum nodes per region
infer boolean true Infer relations from links
siblings boolean true Infer siblings from parents (requires infer)
ontology object — Ontology field names appended per role
showHidden boolean false Include targets named by hidden fields
width number 720 SVG viewBox width
height number 480 SVG viewBox height
language string "excalibrain" Fence language

Output

html
<section class="rb-excalibrain" data-excalibrain
         data-excalibrain-render="build"
         data-excalibrain-center="notes/center">
  <h2 class="rb-excalibrain__heading">ExcaliBrain</h2>
  <div class="rb-excalibrain__canvas">
    <svg class="rb-excalibrain__svg" viewBox="0 0 720 480" role="img">…</svg>
  </div>
</section>

Each region is a g.rb-excalibrain__region[data-region]; each node is a g.rb-excalibrain__node[data-node-role][data-node-slug][data-relation-type] wrapping an <a href> around its <rect> and <text>. Links are path.rb-excalibrain__link[data-link-role][data-relation-type].

Limitations

  • The map is read-only. The client layer only builds the SVG; there is no drag, zoom, or expand/collapse interaction.
  • maxPerRegion truncates each region, so a note with more relations than the limit shows only the first nodes.
  • Rendering is limited to the ontology roles above; there is no per-node styling or per-region configuration beyond the options listed below.

Exports

  • excaliBrain(options?) / excaliBrainPlugin — plugin factory
  • resolveExcaliBrainOptions(options?) — resolved defaults
  • buildExcaliBrainGraph(input) — pure graph builder
  • layoutExcaliBrain(graph, options?) — pure deterministic layout
  • renderExcaliBrainSvg(graph, layout, options?) — pure SVG renderer
  • Types: ExcaliBrainOptions, ExcaliBrainGraph, ExcaliBrainNode, ExcaliBrainLink, ExcaliBrainLayout, ExcaliBrainRole, ExcaliBrainRenderMode, …

See also

History

1 changesCollapseExpand
1 + <!-- Generated from packages/plugins/excalibrain/README.md. Do not edit this page directly; edit the package README and run `pnpm docs:sync`. -->
2 +
3 + # ExcaliBrain
4 +
5 + Structured relationship maps for notes, modelled on
6 + [ExcaliBrain](https://github.com/zsviczian/excalibrain) by Zsolt Viczián.
7 +
8 + [日本語](./excalibrain.md)
9 +
10 + ## Overview
11 +
12 + `excaliBrain()` renders each note in a planar layout with seven regions:
13 +
14 + | Region | Direction | Role |
15 + | ------ | --------- | ---- |
16 + | Parents | top | `parent` |
17 + | Children | bottom | `child` |
18 + | Left friends | left | `leftFriend` |
19 + | Right friends | right | `rightFriend` |
20 + | Previous | far left | `previous` |
21 + | Next | far right | `next` |
22 + | Siblings | periphery | `sibling` |
23 +
24 + Relationships come from ExcaliBrain's ontology: YAML frontmatter fields and
25 + dataview inline fields in the note body. When a relationship is not stated
26 + explicitly, it is inferred from the content graph.
27 +
28 + ## Usage
29 +
30 + ```ts
31 + import { defineConfig } from "@riebeckite/core";
32 + import { excaliBrain } from "@riebeckite/plugin-excalibrain";
33 +
34 + export default defineConfig({
35 + // ...
36 + plugins: [
37 + excaliBrain({
38 + render: "build",
39 + }),
40 + ],
41 + });
42 + ```
43 +
44 + The plugin runs with `order: -10`.
45 +
46 + ## Declaring relationships
47 +
48 + Explicit relations win over inferred ones.
49 +
50 + ### YAML frontmatter
51 +
52 + ```md
53 + ---
54 + title: ExcaliBrain Center
55 + parent: "[[excalibrain-parent]]"
56 + children: ["[[excalibrain-child-a]]", "[[excalibrain-child-b]]"]
57 + ---
58 + ```
59 +
60 + ### Dataview inline fields
61 +
62 + ```md
63 + children:: [[excalibrain-child]]
64 +
65 + related:: [[note-a]] and [[note-b]] are similar
66 + ```
67 +
68 + An inline field may appear on its own line or inside brackets
69 + (`[field:: [[target]]]`).
70 +
71 + ### Ontology
72 +
73 + Field names are matched case-insensitively and spaces are normalized to
74 + hyphens. The default ontology is:
75 +
76 + | Role | Field names |
77 + | ---- | ----------- |
78 + | `parents` | `parent`, `parents`, `up`, `u`, `north`, `origin`, `inception`, `source`, `parent domain` |
79 + | `children` | `children`, `child`, `down`, `d`, `south`, `leads to`, `contributes to`, `nurtures` |
80 + | `leftFriends` | `friends`, `friend`, `jump`, `jumps`, `j`, `similar`, `supports`, `alternatives`, `advantages`, `pros` |
81 + | `rightFriends` | `opposes`, `disadvantages`, `missing`, `cons` |
82 + | `previous` | `previous`, `prev`, `west`, `w`, `before` |
83 + | `next` | `next`, `n`, `east`, `e`, `after` |
84 + | `hidden` | `hidden` |
85 +
86 + The `ontology` option extends the defaults: each role's field names are
87 + appended to that role's defaults rather than replacing them. An override can
88 + still add an existing field to another role, but earlier roles in the
89 + canonical order (`parents`, `children`, `leftFriends`, `rightFriends`,
90 + `previous`, `next`, `hidden`) win when a field is listed twice.
91 +
92 + `hidden` follows ExcaliBrain: it lists the targets to hide from this note's
93 + map; it never hides the note itself. `showHidden` reveals those targets.
94 +
95 + ## Inference
96 +
97 + When `infer` is enabled (the default):
98 +
99 + - a forward link (this note → other) becomes a `child`;
100 + - a backlink (other → this note) becomes a `parent`;
101 + - a mutual link (this note ↔ other) becomes a `leftFriend`.
102 +
103 + With `siblings` enabled (the default), the other children of this note's
104 + parents become `sibling` nodes. Sibling inference also requires `infer`:
105 + setting `infer: false` disables it. Link targets are resolved against the
106 + content manifest; unresolved targets become virtual nodes labelled with the
107 + raw link text (`data-node-virtual="true"`).
108 +
109 + ## Publication boundary
110 +
111 + Nodes are resolved against the content manifest. A target whose
112 + `publishing.routable` flag is false is dropped from the map, so notes excluded
113 + from publication never appear as nodes or links and their titles and permalinks
114 + are not leaked.
115 +
116 + ## Rendering
117 +
118 + The `render` option selects where the map is produced:
119 +
120 + | Mode | Behavior |
121 + | ---- | -------- |
122 + | `"build"` (default) | The SVG is generated at build time and inlined into the article. |
123 + | `"client"` | A `div.rb-excalibrain__canvas` carries the escaped graph/layout payload; `initExcaliBrain()` builds the SVG in the browser. |
124 + | `"both"` | Inline SVG plus the client layer for progressive enhancement. |
125 +
126 + ### Injection
127 +
128 + - A ` ```excalibrain ` fence is replaced by the map.
129 + - Otherwise, when `auto` is enabled and the note has at least one
130 + relationship, the map section is appended to the article HTML (both the
131 + manifest entry and the cached post content).
132 +
133 + `heading` / `headingText` control the optional `<h2>`.
134 +
135 + ## Options
136 +
137 + | Option | Type | Default | Description |
138 + | ------ | ---- | ------- | ----------- |
139 + | `render` | `"build" \| "client" \| "both"` | `"build"` | Where the map is rendered |
140 + | `auto` | `boolean` | `true` | Append the map when a note has no fence |
141 + | `heading` | `boolean` | `true` | Show the heading |
142 + | `headingText` | `string` | `"ExcaliBrain"` | Heading text |
143 + | `className` | `string` | `"rb-excalibrain"` | Root CSS class |
144 + | `maxPerRegion` | `number` | `8` | Maximum nodes per region |
145 + | `infer` | `boolean` | `true` | Infer relations from links |
146 + | `siblings` | `boolean` | `true` | Infer siblings from parents (requires `infer`) |
147 + | `ontology` | object | — | Ontology field names appended per role |
148 + | `showHidden` | `boolean` | `false` | Include targets named by `hidden` fields |
149 + | `width` | `number` | `720` | SVG viewBox width |
150 + | `height` | `number` | `480` | SVG viewBox height |
151 + | `language` | `string` | `"excalibrain"` | Fence language |
152 +
153 + ## Output
154 +
155 + ```html
156 + <section class="rb-excalibrain" data-excalibrain
157 + data-excalibrain-render="build"
158 + data-excalibrain-center="notes/center">
159 + <h2 class="rb-excalibrain__heading">ExcaliBrain</h2>
160 + <div class="rb-excalibrain__canvas">
161 + <svg class="rb-excalibrain__svg" viewBox="0 0 720 480" role="img">…</svg>
162 + </div>
163 + </section>
164 + ```
165 +
166 + Each region is a `g.rb-excalibrain__region[data-region]`; each node is a
167 + `g.rb-excalibrain__node[data-node-role][data-node-slug][data-relation-type]`
168 + wrapping an `<a href>` around its `<rect>` and `<text>`. Links are
169 + `path.rb-excalibrain__link[data-link-role][data-relation-type]`.
170 +
171 + ## Limitations
172 +
173 + - The map is read-only. The client layer only builds the SVG; there is no drag,
174 + zoom, or expand/collapse interaction.
175 + - `maxPerRegion` truncates each region, so a note with more relations than the
176 + limit shows only the first nodes.
177 + - Rendering is limited to the ontology roles above; there is no per-node
178 + styling or per-region configuration beyond the options listed below.
179 +
180 + ## Exports
181 +
182 + - `excaliBrain(options?)` / `excaliBrainPlugin` — plugin factory
183 + - `resolveExcaliBrainOptions(options?)` — resolved defaults
184 + - `buildExcaliBrainGraph(input)` — pure graph builder
185 + - `layoutExcaliBrain(graph, options?)` — pure deterministic layout
186 + - `renderExcaliBrainSvg(graph, layout, options?)` — pure SVG renderer
187 + - Types: `ExcaliBrainOptions`, `ExcaliBrainGraph`, `ExcaliBrainNode`,
188 + `ExcaliBrainLink`, `ExcaliBrainLayout`, `ExcaliBrainRole`,
189 + `ExcaliBrainRenderMode`, …
190 +
191 + ## See also
192 +
193 + - [Plugin guide](../reference/plugin-api.en.md)
194 +