Vancetope — Document Kind mindmap

Specifies the mindmap payload for documents that carry a hierarchical, ordered set of items rendered as a radial mindmap. Reuses the tree schema 1:1 and adds optional per-node visual metadata (color, icon, link, tags) plus document-level rendering options. See also: doc-kind-tree | doc-kind-items | web-ui


1. Purpose

kind: tree (see doc-kind-tree) models hierarchical items with an outliner UX. kind: mindmap is the same hierarchy, but:

  • with optional per-node metadata for visual distinction (color, icon, link, tags),
  • with a Mindmap renderer instead of an outliner editor — radial layout starting from the root item.

Design Principle: The topic text per node and fluid editing are central. The additional fields are all optional — a Mindmap document can consist solely of text + children and remain fully functional. There are intentionally no mandatory fields beyond text.

Separation from tree:

  • tree is a textually-structured outliner. Edit-focused.
  • mindmap is a visually-structured mindmap. View-focused; in v1, read-only render on a second tab, editing still in the Tree View.

What this spec defines:

  • Extended items model (tree fields + optional color, icon, link, tags).
  • Top-level Mindmap options (mindmap: block — theme, direction, initialExpandLevel).
  • Format mapping md/json/yaml — the same codec as tree, with pass-through for the new fields.
  • Web-UI activation (Tab Mindmap in addition to Tree and Raw).

What it does not define:

  • Free-form node positions (x/y). Mindmap layouts are automatically calculated from the Tree topology — both markmap and mind-elixir work this way. Concept-map-like free-positioning would be a separate kind (graph).
  • In-place Mindmap editing (dragging & dropping nodes directly in the radial layout). See §6.
  • Mindmap-specific server indexing — items continue to live in the inlineText body.
  • Embedded images per node. Intentionally excluded to keep the spec simple — images in mindmaps are rarely the value driver, and hosting (document attachment vs. remote URL) would be a separate spec step.

2. Items Model

Per item, same base as tree:

Field Type Required Meaning
text string yes Node topic, single- or multi-line.
children Item[] no Subordinate nodes, recursive. Missing / empty array = leaf.

Mindmap-specific additional fields (all optional — none are required, a node with only text is valid):

Field Type Meaning
color string Line and text color of the node as HTML hex (#rrggbb or #rgb). Inherited by children if they do not have their own color.
background string Background fill of the node bubble as HTML hex.
icon string Glyph before the topic — emoji or short text. A single icon (not an array).
link string Hyperlink of the node (URL) — opened on click.
tags string[] Tag chips on the node. Pure display, no semantic link to document tags.

Color format: Canonical is HTML hex#rrggbb (e.g., #3b82f6) or as a shorthand #rgb (e.g., #39f). Rationale:

  • Unambiguously parseable — no locale, no token resolution, no theme dependency.
  • Round-trip stable without normalization leeway (exactly one string per color).
  • Universal in mindmap/diagram tools (markmap, mind-elixir, draw.io, Mermaid).
  • LLM output is reliable here — hex codes are well represented in training data.

When reading, CSS named colors (red, blue, …) and rgb(…)/hsl(…) are also accepted; when writing, the codec normalizes to #rrggbb (canonical lower-case six-hex form). Alpha/transparency is not planned for v1 — those who want transparent nodes will wait for a later spec point.

Forward compatibility: As with tree, additional, unknown fields are passed through via an extra map. Known Mindmap fields live flat next to text/children — the Tree codec does not know them by name but passes them through (see §3.4).

Markdown limitation: Markdown can only express text + children. All Mindmap additional fields are lost during the md round-trip. Those who maintain a Mindmap document with colors/icons keep it in JSON or YAML — same convention as for tree for multi-field items.

Canonical form (JSON):

{
  "$meta": { "kind": "mindmap" },
  "mindmap": {
    "theme": "default",
    "direction": "right",
    "initialExpandLevel": -1
  },
  "items": [
    {
      "text": "Vancetope",
      "color": "#3b82f6",
      "children": [
        {
          "text": "Brain",
          "icon": "🧠",
          "children": [
            { "text": "Engines", "tags": ["arthur", "ford"], "children": [] }
          ]
        },
        {
          "text": "Foot",
          "icon": "🐾",
          "link": "https://example.com/docs/foot",
          "children": []
        },
        {
          "text": "Face",
          "children": []
        }
      ]
    }
  ]
}

Header convention: as with doc-kind-items §2 — both JSON and YAML carry kind in a $meta mapping at the top level. The mindmap: block remains at the body top level (nested object, filtered out in $meta anyway).

Exactly one top-level item is the canonical Mindmap form (the root item is placed radially in the center). Multiple top-level items are allowed — the renderer treats them as a “Forest” and renders them as parallel trees side-by-side.


3. On-Disk Formats

3.1 Markdown

---
kind: mindmap
mindmap:
  theme: default
  direction: right
---
- Vancetope
  - Brain
    - Engines
  - Foot

Reading rules:

  • Front-Matter like tree (--- fences). mindmap: block (Mindmap options) is optional and placed under kind:.
  • Body: identical to tree — \s*[-*]\s+ bullets with 2-space indent, tabs = 4 spaces, skip-level is clamped to the next shallowest.
  • No per-node fields — Markdown has no syntax for Color/Icon/Link at the bullet level that would be round-trip stable. Documented limitation.

Writing rules:

  • Pre-order DFS, identical to tree.
  • Per-node Mindmap fields are not written (would be lost on read — so not included at all).
  • Top-level mindmap: block is preserved in the Front-Matter (pass-through like all Front-Matter keys).

3.2 JSON

Identical to tree, with:

  • $meta wrapper for kind (see doc-kind-items §2).
  • Top-level key mindmap (Object) before items.
  • Any additional keys from §2 (color/icon/etc.) per item as pass-through.

When writing:

  • 2-space indent.
  • Order of top-level keys: $meta, mindmap, items, then unknown pass-through keys in insertion order.
  • Order of item keys: text, children, then mindmap fields (color, background, icon, link, tags) in exactly this order — followed by unknown pass-through keys. Fields not set for a node are omitted (no null writing).

3.3 YAML

$meta:
  kind: mindmap
mindmap:
  theme: default
  direction: right
  initialExpandLevel: -1
items:
  - text: Vancetope
    color: "#3b82f6"
    children:
      - text: Brain
        icon: "🧠"
        children:
          - text: Engines
            tags: [arthur, ford]
            children: []
      - text: Foot
        icon: "🐾"
        link: https://example.com/docs/foot
        children: []

Single-Document: Top-level mapping with $meta: { kind: mindmap } as the first key, followed by mindmap: block and items at the same level. Block-style sequences, 2-space indent. No string shorthand for items (same rule as tree — separation of item text vs. sub-item would otherwise remain ambiguous).

3.4 Codec Impact

Important: The existing tree codec (treeItemsCodec.ts + Server HeaderStrategy) remains unchanged. Mindmap fields automatically travel through TreeItem.extra: Record<string, unknown>. The Mindmap view reads them from extra, and the Mindmap edit view (when it comes) also writes them to extra. This means kind: mindmap does not require a new codec or a new server mapping — only renderer code in the Web-UI.

Only when the Mindmap-specific fields become first-class in the editor UI (color picker, icon picker) will the codec promote them from extra to typed properties on a MindmapItem subtype. This is an additive extension, not a breaking change.


4. Server Path

Like tree and list: no dedicated endpoint, no server-side Mindmap parser. The HeaderStrategy path automatically mirrors kind: mindmap to DocumentDocument.kind.

The mindmap: top-level block is transparent to the server — like all Front-Matter keys (Markdown) or all top-level JSON/YAML keys, it lands unparsed in the body and is returned unchanged.


5. Web-UI

5.1 Editor Activation

  • kind === 'mindmap' + Format ∈ {md, json, yaml} → three tabs: Mindmap (Default) / Tree / Raw.
  • Otherwise (not a Mindmap document): unchanged.

The Tree tab uses the existing <TreeView> component unchanged — the hierarchy is the same. Per-node Mindmap fields are not displayed or edited in v1 in the Tree View (but they remain round-trip stable via extra).

The Mindmap tab is read-only render based on markmap-lib + markmap-view. Rationale:

  • markmap directly accepts our Markdown bullet form — the adapter is trivial.
  • markmap is ~50 KB minified, MIT, actively maintained.
  • Read-only Mindmap covers the viewing use case (brainstorming template, strategy draft), editing remains convenient in the Tree View.

5.2 Feature Set v1

Feature v1 Note
Mindmap Render (radial layout) markmap
Pan / Zoom markmap built-in
Expand / Collapse per node markmap built-in (click on disclosure)
Edit (via Tree tab) existing <TreeView>
Per-node Color/Icon/Link/Tags (◯) persisted (round-trip), but not editable and only partially rendered in v1
In-Place Edit in Mindmap Layout see §6
Custom Theme / direction options (◯) persisted in the mindmap: block, but UI operation only via Raw in v1
Forest (multiple roots) markmap renders multiple top-level bullets side-by-side

(◯) = Feature is not actively editable in v1, but data passes through round-trip stably.

5.3 Components

  • <MindmapView> — top-level Mindmap tab. Receives :doc: TreeDocument (same type as TreeView), converts it to markmap Markdown, instantiates markmap. Read-only.
  • <TreeView> — existing Tree editor, unchanged. Serves the Tree tab.
  • Tab bar like for tree (content-tab class from DocumentApp.vue), extended to three tabs.

5.4 Markmap Adapter

The adapter is a function treeToMarkmapMarkdown(doc: TreeDocument): string:

  • Pre-order DFS.
  • Per item: Indent (depth × 2 Spaces) + - + first topic line.
  • If link is set: Topic becomes [<text>](<link>).
  • icon is prefixed to the topic text (emoji directly, followed by a space).
  • tags/color/background are not passed to markmap in v1 (no direct markmap equivalent — color is global via colorFreezeLevel, markmap does not have tags rendering). However, they are in the document and will be active in a later edit/render iteration.
  • Top-level: mindmap: block from the document is prepended as markmap Front-Matter (---\nmarkmap:\n ...\n---) — theme, direction, initialExpandLevel map 1:1.

5.5 Visual Conventions

  • Mindmap tab fills the editor content completely (no second vertical scrolling — markmap takes 100% height).
  • Pan/Zoom hint subtly in the bottom right (“Mouse wheel zooms, drag pans”) as a small help tooltip.
  • Default theme aligns with the DaisyUI theme via CSS variables — markmap allows CSS override, so Light/Dark mode follows.

6. Future (not v1)

6.1 In-Place Mindmap Editing

mind-elixir (https://github.com/ssshooter/mind-elixir-core, MIT, ~70 KB minified) replaces markmap in the Mindmap tab. This enables:

  • Double-click on node → inline topic edit.
  • Drag & drop of nodes between parents (true 2D re-parenting).
  • Context menu per node: Color picker, Icon picker, Link editor, Tag editor.
  • Keyboard shortcuts like in the Tree editor (Tab/Shift+Tab/Enter).

mind-elixir has its own data model ({ topic, id, style, tags, icons, hyperLink, expanded, children }, plus optional image which we do not use); the adapter between our TreeItem form and mind-elixir form is 1:1 — all fields defined in §2 map directly.

Migration path: codec remains the same, only <MindmapView> is replaced. Tree tab and Raw tab unchanged.

6.2 Active Mindmap Fields in Tree Editor

Per-node Color/Icon/Link/etc. will also be displayed and editable in the Tree View (inline picker or side panel). This means Mindmap metadata will not only live in the Mindmap tab. This is useful only when actual users need it — until then, the Mindmap view is sufficient.

6.3 Mindmap Linker / Cross-Document Linking

Nodes could refer to other documents in the same Project (link: doc:<documentId> or link: vance:document/<id>). The renderer resolves this to an app-internal tab open. Requires a convention for vance: URLs — a separate spec point.

6.4 Persistent Expand/Collapse

As with tree (§6.3 there): per-user setting or per-item field. Not now.


7. Open Points

  • Single-Root Requirement: Should we restrict kind: mindmap to exactly one top-level item? markmap also renders forests, but UX-wise, a Mindmap user expects a single radial center. Suggestion: allow it, but warn in the editor if more than one top-level item is present.
  • markmap vs. mind-elixir Default: If the first real Mindmap creation shows that viewing without editing is insufficient, the default will switch directly to mind-elixir. Until then, Markmap, because of the leaner adapter.
  • Tags Rendering: markmap has no tag display. Either append as inline code spans (`tag`) to the topic or natively with mind-elixir migration. Decision pending until the first use case.