Skip to content

πŸ“ Visualli SpecificationΒΆ

Visualli uses JSONL (JSON Lines) as its primary interchange format. Each line in a .visualli file is a single JSON object representing exactly one entity: Meta, Extension, or Layer.

Single source of truth. The formal validation rules are defined in visualli.schema.json.

Reading the concepts first? See Concepts for the mental model β€” infinite canvas, layers vs. levels, and the role of each entity.

File StructureΒΆ

A valid .visualli file is a sequence of JSON objects, separated by newlines (\n):

Meta        β†’ required, exactly one, first line
Extension   β†’ optional, zero or more, after Meta, before Layers
Layer       β†’ required, one or more, after Meta/Extensions
{"type": "meta", ...}
{"type": "extension", ...}
{"type": "layer", ...}
{"type": "layer", ...}

Minimal exampleΒΆ

{"type": "meta", "version": "2.0", "title": "Example Map", "created": "2024-05-21T10:00:00Z", "lastModified": "2024-05-22T15:30:00Z"}
{"type": "layer", "id": "layer-1", "level": 0, "nodes": [{"id": "n1", "position": {"x": 0, "y": 0}, "data": {"label": "Root Node", "summary": "The starting point"}}]}

Entity Relationship DiagramΒΆ

How the top-level entities and their embedded components relate:

classDiagram
    %% Meta Information (Line 1)
    class meta {
        +type
        +version
        +title
        +created
    }

    %% Extension Entity (Lines 2..M - Optional)
    class extension {
        +type
        +id
        +data
    }

    %% Layer Entity (Lines M+1..N)
    class layer {
        +type
        +id
        +level
        +parentLayerId [0..1]
        +parentNodeId [0..1]
    }

    %% Node Entity (Embedded in Layer)
    class nodes {
        +id
        +position
        +data
    }

    %% Connection Entity (Embedded in Layer)
    class connections {
        +id
        +from
        +to
        +data
    }

    %% Container Entity (Embedded in Layer)
    class containers {
        +id
        +nodes
        +data
    }

    %% Relationships
    layer "1" *-- "*" nodes : contains
    layer "1" *-- "*" connections : contains
    layer "1" *-- "*" containers : contains

    %% Hierarchical Links
    layer ..> layer : parentLayerId (Child Layer -> Parent Layer)
    layer ..> nodes : parentNodeId (Layer attached to Node)

    %% Connection Links
    connections ..> nodes : from (references Node ID)
    connections ..> nodes : to (references Node ID)

    %% Container Links
    containers ..> nodes : nodes (groups Node IDs)

Schema DefinitionsΒΆ

1. Meta ObjectΒΆ

Must be the first line of the file. Exactly one per file.

interface Meta {
  type: "meta";
  version: string;       // e.g. "2.0"
  title: string;         // Project title
  created: string;       // ISO 8601 date
  lastModified: string;  // ISO 8601 date
}

2. Extension ObjectΒΆ

Optional. Appears after Meta and before any Layer lines. Extensions add metadata or behavior without changes to the core schema (examples: semantic anchors, themes, visual-effects configuration).

interface Extension {
  type: "extension";
  id: string;            // e.g. "semantic-anchors"
  data?: any[];          // Extension-specific payload
}

Example β€” a semantic-anchors extension that links terms to descriptions:

{
  "type": "extension",
  "id": "semantic-anchors",
  "data": [
    { "word": "atmosphere",
      "description": "The envelope of gases surrounding the earth or another planet.",
      "knowMoreUrl": null },
    { "word": "water circulation",
      "description": "The continuous movement of water on, above and below the surface of the Earth.",
      "knowMoreUrl": null }
  ]
}

3. Layer ObjectΒΆ

The core content unit β€” each Layer line is a self-contained slice of the document.

interface Layer {
  type: "layer";
  id: string;                       // Unique layer ID
  level: number;                    // Depth in the hierarchy (0 = root)
  parentLayerId?: string;           // Parent layer ID (absent for root layers)
  parentNodeId?: string;            // Node in the parent layer this layer attaches to
  layout?:
    | "radial"
    | "linear-horizontal"
    | "linear-vertical";
  nodes?: Node[];
  connections?: Connection[];
  containers?: Container[];
}

layout describes how nodes are positioned across the whole layer. It differs from Container.data.formation: layout positions all nodes in the layer relative to the parent node, while formation arranges only the nodes inside a specific container.

Layer.layout When to use
radial Peer categories radiating from a parent node β€” the common default for branches with no inherent order.
linear-horizontal Chronological sequences, timelines, ordered progressions, geographic or alphabetical flows.
linear-vertical Priority ordering, ranked lists, ranked hierarchy, or steps in a process.

3.1 Node Object (embedded in Layer)ΒΆ

A discrete unit of information, positioned at (x, y) on the canvas.

interface Node {
  id: string;
  position: { x: number; y: number };
  data: {
    label: string;
    summary?: string;
    color?: string;    // any valid CSS color
  };
}
Attribute Value When to use
Node.data.color Any valid CSS color (#ff0000, red, hsl(...)) Visually distinguish nodes by category, priority, or state.

3.2 Connection Object (embedded in Layer)ΒΆ

A directed relationship between two nodes in the same layer.

interface Connection {
  id: string;
  from: string;     // source Node ID
  to: string;       // target Node ID
  data: {
    label: string;
    style?: "dashed" | "solid";
  };
}
Connection.data.style When to use How it looks
solid Strong, direct, or causal relationship β€” clear flow or dependency. solid
dashed Indirect or associative link β€” related but no direct causal chain. (placeholder)

3.3 Container Object (embedded in Layer)ΒΆ

A visual grouping of nodes within the same layer. It does not create hierarchy; it communicates that a set of nodes share a role or category.

interface Container {
  id: string;
  nodes: string[];   // Node IDs being grouped
  data: {
    label: string;
    formation?:
      | "radial"
      | "linear-horizontal"
      | "linear-vertical";
    style?: "dashed" | "none";
  };
}

Container.data.formation shares its vocabulary with Layer.layout but has a different scope: a formation arranges nodes inside the container grouping, while a layout arranges all nodes in the layer. A container can legitimately use a different formation than its enclosing layer's layout.

Attribute Value When to use How it looks
Container.data.formation radial Nodes in the group radiate from a shared center; good for peer categories within the grouping. (placeholder)
Container.data.formation linear-horizontal Nodes in the group are arranged along a horizontal axis; good for sequences or timelines. (placeholder)
Container.data.formation linear-vertical Nodes in the group are arranged along a vertical axis; good for ranked lists or hierarchies. (placeholder)
Container.data.style dashed Container boundary is drawn with a dashed stroke. dashed
Container.data.style none Container boundary is hidden; grouping is logical only (used e.g. to target the group via an extension). none