RelationMap JSON format (data_json v1.2)

A RelationMap chart is one JSON object. The same format is used everywhere a chart goes in or out of the editor:

  • Export → JSON Data downloads it. JSON export is free on every plan.
  • Open, or dragging a .json file onto the canvas, opens it.
  • The paste box at /edit/?paste=1 opens it when you paste JSON instead of a cast list.
  • A #data= link opens it.
  • Charts saved to the cloud are stored in it (the data_json column).

The current version is "1.2".

Minimal example

Only nodes is required. This opens a chart with two people and one relationship:

{
  "nodes": [
    { "id": "kai", "name": "Kai" },
    { "id": "mira", "name": "Mira" }
  ],
  "edges": [
    { "id": "e1", "source": "kai", "target": "mira", "label": "mentor" }
  ]
}

Top level

KeyRequiredWhat it is
nodesyesThe characters. A list with at least one entry.
edgesnoThe relationships between them.
metanoTitle, subtitle, lore, cover and display settings.
groupsnoGroups a character can belong to, drawn as a tinted area around the members.
tagsnoLabels shown as small colored dots under a character.
customColorRulesnoYour own relationship words and their colors.

A file that is not a JSON object, or whose nodes list is missing or empty, does not open. Keys not listed on this page are dropped the next time the editor saves the chart.

nodes

KeyRequiredDefaultWhat it is
idrecommended"n0", "n1", … by positionUnique id. Numbers are turned into strings. If two nodes share an id, only the first one is kept.
nameno"Untitled"The name under the circle.
subtitlenononeA short line under the name, such as a role. It is drawn on one line in small type and is never wrapped or cut, so a long one runs into the characters beside it. Keep it to about 30 characters or fewer (30 characters are about 140 px wide) and put longer text in description.
descriptionnononeLonger notes. Line breaks are kept. Not drawn on the chart: it shows in the editor’s character panel when you click the character.
groupsno[]Ids from groups.
tagsno[]Ids from tags.
colornofrom a 16-color palette, by positionColor of the circle when there is no picture, as "#RRGGBB".
avatarnononePicture: an image URL or a data: URI.
radiusnometa.settings.nodeRadiusSize of this one circle, in pixels, 12 to 60.
positionnonone{ "x": 0, "y": 0 }. Usually leave it out: the editor then lays the chart out itself and zooms to show all of it. Give it when the layout matters, as in a family tree; see Positions.

An older field, bio, is read as subtitle when subtitle is missing.

Positions

Leave positions out unless the layout carries meaning, such as generations in a family tree or ranks in a chain of command. If you give them:

  • Give a position to every node. A node without one is placed by the automatic layout around the fixed ones, ignores your rows, and can end up off screen.
  • Units are pixels at 100% zoom: x grows to the right and y grows downward. Any origin works. When the chart opens and part of it is off screen, the editor centers it, zooming out as far as 20% if it has to, but never in past 100%.
  • At the default size a circle is 60 px across, and with its name and subtitle a character is about 90 px tall. Rows about 200 px apart, and characters at least 150 px apart in a row, leave room for names up to about 25 characters, subtitles up to about 30, and the labels on the lines. Space them wider for longer names.
  • Characters with a position stay where you put them: the automatic layout doesn’t move them. You can still drag them in the editor.

edges

KeyRequiredDefaultWhat it is
idrecommended"e0", "e1", … by positionUnique id.
sourceyesThe id of a node. Not a name.
targetyesThe id of a node. Not a name.
labelno""The relationship, read as “source is target’s label”: kai → mira, "mentor" means Kai is Mira’s mentor. The label also picks the line color, see below.
bidirectionalnofalsetrue draws an arrow at both ends of the line; without it there is one arrow, pointing at the target. Arrows come only from this field, never from the label, so use it with labels that read the same both ways, like “sisters” or “friends”.
colornofrom the label"#RRGGBB". Overrides the color the label would give.

An edge whose source or target doesn’t match any node id is skipped. The editor then says “Opened, but skipped 1 relationship(s) pointing to missing characters.”

Two characters can have more than one relationship. Every edge is kept and drawn; nothing is merged and no warning is shown. But the lines lie on top of each other or nearly so: in the editor, two edges in the same direction are drawn exactly on top of each other, and two in opposite directions about 15 px apart, with their labels almost touching. The shared chart page and embeds also draw them close together. When two characters have two relationships, use one edge whose label says both, like “husband and cousin”.

Family trees

These conventions keep a family tree readable:

  • Parent and child: one edge from each parent to the child, labeled “father” or “mother”. mr-bennet → jane, "father" reads “Mr. Bennet is Jane’s father”. A child with both parents in the chart gets two edges.
  • Marriage: one edge per marriage, from husband to wife, labeled “husband” (or from wife to husband, labeled “wife”). Leave bidirectional off: with an arrow at both ends, “husband” would read both ways. For a two-way line, use a label that reads both ways, like “married”, and give it a color yourself, since it is gray by default.
  • Siblings: shared parents already show them. Add a “sisters” or “brothers” edge with "bidirectional": true only when their parents aren’t in the chart.
  • Layout: give every character a position, one generation per row, spouses side by side.
  • Size: each child brings two edges, so a family tree often has 1.5 to 2 times as many relationships as people. Split a big family into branches.

The colors of family words are under Words for family trees. A complete family tree to copy is in Make a chart with AI.

groups and tags

Both are lists of the same shape:

KeyRequiredWhat it is
idyesReferenced from a node’s groups or tags.
nameyesShown in the legend; a group’s name is also written on the canvas.
colorrecommended"#RRGGBB". Without it the group area and the legend dot have no color.
notenoWhat the group or tag means.

Entries without an id or a name are skipped. A character can be in several groups and have several tags.

meta

KeyDefaultWhat it is
titlenoneChart title. Saved up to 80 characters.
subtitlenoneSaved up to 120 characters.
lorenoneBackground notes, the text under World & lore.
versionWrite "1.2".
covernoneImage URL shown faintly behind the chart.
coverOpacity5Cover opacity in percent, 0 to 15.
settings.nodeRadius30Circle size for every node without its own radius, 16 to 56.
settings.showGroupstrueDraw the group areas.
settings.avatarStyle"initials"Picture for characters without one: initials, notionists, lorelei, open-peeps, pixel-art or thumbs (Initials, Sketch, Illustrated, Hand-drawn, Pixel and Blobs under Project → Default avatar in the editor). Each face is drawn from the node’s id, so the same id always gets the same face. The faces show in the editor and in exported images; the shared chart page and embeds show initials.

The editor writes a few more keys itself (generator, created_at, autosaved_at, visibility, license). Leave them out of JSON you write by hand or with an AI.

Relationship colors

Each line is colored by its label. The editor checks the label against these word lists in this order, and the first match wins. Letter case doesn’t matter.

CategoryColorWords that match
Romance#E91E63love, crush, marry, wife, husband, CP, and 爱 恋 喜欢 暗恋 夫妻 情人 嫁 娶
Hostility#EF5350hate, enemy, betray, kill, jealous, sworn, nemesis, eliminate, and 恨 仇 敌 害 杀 背叛 嫉妒 陷害
Family#66BB6Afamily, father, mother, brother, sister, son, daughter, parent, sibling, and 父 母 兄 弟 姐 妹 子 女 祖 孙 叔 姑 亲
Friendship#42A5F5friend, buddy, comrade, pal, bond, and 友 闺蜜 知己 伙伴 战友 朋友 同窗 同学
Hierarchy#FF9800master, servant, mentor, student, subordinate, follower, admire, and 主 仆 侍 下属 上司 师 徒 臣
Alliance#26C6DAally, partner, alliance, and 盟 党 搭档 合作 同盟 结义
Rivalry#FFA726rival, and 竞争 对手 宿敌
none#78909C (gray)anything else

The check is a plain search for each word inside the label. Letter case doesn’t matter, but there are no word boundaries and no plurals:

  • A word counts inside a longer word: “loves”, “lover” and “in love with” are romance; “grandfather”, “stepmother” and “sister-in-law” are family.
  • A plural counts only if it still contains the word: “friends”, “sisters” and “rivals” are colored, but “enemies”, “allies” and “families” stay gray, because “enemy”, “ally” and “family” lose their “y”. “married” is gray for the same reason: it doesn’t contain “marry”.
  • The first matching list wins: “husband and cousin” is romance, and “sworn brothers” is hostility, because “sworn” comes before family.

Some results that surprise people:

  • Gray, though you might expect a color: married, spouse, fiancé, engaged, dating, uncle, aunt, cousin, nephew, niece, twin, child, teacher, apprentice, boss, employee, king, colleague, classmate, guardian, competitor, enemies, allies.
  • A different color than you might expect: girlfriend and boyfriend are friendship (they contain “friend”); romantic partner is alliance (“partner”); person, reason, prison, poisoned and parson are family (“son”); skills is hostility (“kill”); really and finally are alliance (“ally”); principal is friendship (“pal”).

To fix a color, use a word from the table, set color on the edge, or add a custom color rule.

Custom color rules

"customColorRules": [
  { "keyword": "girlfriend", "color": "#E91E63" },
  { "keyword": "married", "color": "#E91E63" }
]

Custom rules are checked before the table above. A rule whose keyword is the whole label wins first; after that, the first rule whose keyword appears anywhere in the label. Keywords are stored lowercased and trimmed; a rule without a keyword or a color is skipped. In the editor, the same rules are made under World & lore, where you pick a color for a relationship label. An edge’s own color overrides every rule.

Words for family trees

ColorLabels
Family (green)father, mother, parent, son, daughter, brother, sister, sibling, half-brother, half-sister, stepfather, stepmother, stepson, stepdaughter, foster father, adoptive mother, godfather, godmother, grandfather, grandmother, grandson, granddaughter, great-grandfather, father-in-law, mother-in-law, son-in-law, brother-in-law, sister-in-law, twin brother, twin sister
Romance (pink)husband, wife, ex-husband, ex-wife, first wife, second husband, lover
Gray (no category)married, marriage, spouse, fiancé, fiancée, betrothed, engaged, widow, widower, consort, mistress, uncle, aunt, cousin, nephew, niece, twin, child, children, guardian, ward, heir, ancestor, descendant, relative, in-law

To color the gray ones, add custom rules to the chart:

"customColorRules": [
  { "keyword": "uncle", "color": "#66BB6A" },
  { "keyword": "aunt", "color": "#66BB6A" },
  { "keyword": "cousin", "color": "#66BB6A" },
  { "keyword": "nephew", "color": "#66BB6A" },
  { "keyword": "niece", "color": "#66BB6A" },
  { "keyword": "married", "color": "#E91E63" }
]

Full example

Every field on this page in one chart:

{
  "meta": {
    "title": "Ship of Fools",
    "subtitle": "Crew of the salvage ship Meridian",
    "lore": "A salvage crew far from home.\nThe old captain still haunts the engine room.",
    "version": "1.2",
    "cover": "",
    "coverOpacity": 5,
    "settings": { "nodeRadius": 30, "showGroups": true, "avatarStyle": "initials" }
  },
  "nodes": [
    { "id": "kai", "name": "Kai", "subtitle": "Captain", "description": "Grew up on Mars.", "groups": ["crew"], "tags": ["pov"], "position": { "x": 0, "y": 0 } },
    { "id": "mira", "name": "Mira", "subtitle": "Pilot", "groups": ["crew"], "color": "#0984E3", "position": { "x": 240, "y": -60 } },
    { "id": "elise", "name": "Élise", "subtitle": "Engineer", "groups": ["crew"], "radius": 36, "position": { "x": 160, "y": 200 } },
    { "id": "jun", "name": "Jun", "subtitle": "Stowaway", "position": { "x": -220, "y": 180 } },
    { "id": "rook", "name": "Rook", "subtitle": "The old captain", "groups": ["ghosts"], "tags": ["deceased"], "position": { "x": -240, "y": -140 } }
  ],
  "edges": [
    { "id": "e1", "source": "kai", "target": "mira", "label": "mentor" },
    { "id": "e2", "source": "kai", "target": "rook", "label": "brothers", "bidirectional": true },
    { "id": "e3", "source": "mira", "target": "elise", "label": "girlfriend", "bidirectional": true },
    { "id": "e4", "source": "jun", "target": "kai", "label": "owes a debt to" },
    { "id": "e5", "source": "rook", "target": "jun", "label": "haunts", "color": "#8E24AA" }
  ],
  "groups": [
    { "id": "crew", "name": "Crew", "color": "#26C6DA", "note": "Everyone still aboard." },
    { "id": "ghosts", "name": "Ghosts", "color": "#90A4AE" }
  ],
  "tags": [
    { "id": "pov", "name": "Point of view", "color": "#FDCB6E" },
    { "id": "deceased", "name": "Deceased", "color": "#636E72" }
  ],
  "customColorRules": [
    { "keyword": "girlfriend", "color": "#E91E63" },
    { "keyword": "owes", "color": "#FF9800" }
  ]
}

In this chart “mentor” is orange (hierarchy), “brothers” green (family), “girlfriend” pink through the custom rule instead of blue, “owes a debt to” orange through the second rule, and “haunts” purple from the edge’s own color.

What the editor writes back

When you export a chart (Export → JSON Data), every node gets all its fields: avatar, subtitle, description and radius (null when not set), color, groups, tags and the current position. Every edge gets bidirectional, and color (null when not set). groups, tags and customColorRules are left out when they are empty, and meta.version is always "1.2". Opening the exported file again gives the same chart.

Updated November 15, 2026. Markdown version of this page. Open the editor.