@restless-dreams/orbit 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +168 -2
- package/dist/bin/orbit.js +11666 -0
- package/dist/bin/orbit.js.map +60 -0
- package/dist/chunk-fkdfgtx9.js +17295 -0
- package/dist/chunk-fkdfgtx9.js.map +75 -0
- package/dist/chunk-y748hzcr.js +82 -0
- package/dist/chunk-y748hzcr.js.map +10 -0
- package/dist/chunk-zze4tc9n.js +408 -0
- package/dist/chunk-zze4tc9n.js.map +10 -0
- package/dist/core/auto-render.d.ts +85 -0
- package/dist/core/branch-colors.d.ts +57 -0
- package/dist/core/browser.d.ts +23 -0
- package/dist/core/create.d.ts +23 -0
- package/dist/core/diagnostics.d.ts +40 -0
- package/dist/core/dispatch.d.ts +23 -0
- package/dist/core/document-options.d.ts +18 -0
- package/dist/core/document-source.d.ts +128 -0
- package/dist/core/editing.d.ts +66 -0
- package/dist/core/engine/animation-clock.d.ts +40 -0
- package/dist/core/engine/camera.d.ts +70 -0
- package/dist/core/engine/colors.d.ts +51 -0
- package/dist/core/engine/display.d.ts +125 -0
- package/dist/core/engine/export.d.ts +32 -0
- package/dist/core/engine/glide.d.ts +34 -0
- package/dist/core/engine/labels.d.ts +106 -0
- package/dist/core/engine/node-drag.d.ts +49 -0
- package/dist/core/engine/scene.d.ts +160 -0
- package/dist/core/engine/spin.d.ts +62 -0
- package/dist/core/engine/surface-pattern.d.ts +20 -0
- package/dist/core/engine/text-measure.d.ts +116 -0
- package/dist/core/engine/views.d.ts +361 -0
- package/dist/core/extensions.d.ts +155 -0
- package/dist/core/format-upgrades.d.ts +33 -0
- package/dist/core/index.d.ts +46 -0
- package/dist/core/input-controller.d.ts +116 -0
- package/dist/core/languages.d.ts +201 -0
- package/dist/core/layout.d.ts +61 -0
- package/dist/core/map-tools/definitions.d.ts +71 -0
- package/dist/core/map-tools/input.d.ts +62 -0
- package/dist/core/map-tools/reading.d.ts +40 -0
- package/dist/core/map-tools/tools.d.ts +51 -0
- package/dist/core/markdown-writing.d.ts +87 -0
- package/dist/core/material.d.ts +25 -0
- package/dist/core/media.d.ts +42 -0
- package/dist/core/node-attributes.d.ts +31 -0
- package/dist/core/node-links.d.ts +25 -0
- package/dist/core/other-apps/freemind.d.ts +8 -0
- package/dist/core/other-apps/icons.d.ts +16 -0
- package/dist/core/other-apps/ideas.d.ts +76 -0
- package/dist/core/other-apps/import.d.ts +28 -0
- package/dist/core/other-apps/inflate.d.ts +22 -0
- package/dist/core/other-apps/markup.d.ts +51 -0
- package/dist/core/other-apps/notes.d.ts +80 -0
- package/dist/core/other-apps/opml.d.ts +26 -0
- package/dist/core/other-apps/reading.d.ts +36 -0
- package/dist/core/other-apps/xmind.d.ts +14 -0
- package/dist/core/other-apps/zip.d.ts +37 -0
- package/dist/core/parser-markdown.d.ts +42 -0
- package/dist/core/parser-yaml.d.ts +8 -0
- package/dist/core/print-layout.d.ts +70 -0
- package/dist/core/render-to-svg.d.ts +57 -0
- package/dist/core/renderer/content-painter.d.ts +30 -0
- package/dist/core/renderer/dom.d.ts +15 -0
- package/dist/core/renderer/families.d.ts +35 -0
- package/dist/core/renderer/label-painter.d.ts +93 -0
- package/dist/core/renderer/node-painter.d.ts +113 -0
- package/dist/core/renderer/numbers.d.ts +2 -0
- package/dist/core/renderer/options.d.ts +12 -0
- package/dist/core/renderer/rings-and-links.d.ts +23 -0
- package/dist/core/renderer/scene-helpers.d.ts +33 -0
- package/dist/core/renderer/trees.d.ts +22 -0
- package/dist/core/serializer-markdown.d.ts +18 -0
- package/dist/core/serializer-yaml.d.ts +2 -0
- package/dist/core/source-patch.d.ts +24 -0
- package/dist/core/source.d.ts +27 -0
- package/dist/core/styles.d.ts +6 -0
- package/dist/core/suggest.d.ts +8 -0
- package/dist/core/svg-renderer.d.ts +626 -0
- package/dist/core/text-layout.d.ts +54 -0
- package/dist/core/themes.d.ts +62 -0
- package/dist/core/types.d.ts +471 -0
- package/dist/core/ui/actions.d.ts +75 -0
- package/dist/core/ui/controls.d.ts +61 -0
- package/dist/core/ui/detail-sheet.d.ts +88 -0
- package/dist/core/ui/frames.d.ts +11 -0
- package/dist/core/ui/icons.d.ts +14 -0
- package/dist/core/ui/inline-editor.d.ts +79 -0
- package/dist/core/ui/media-players.d.ts +65 -0
- package/dist/core/ui/media-viewer.d.ts +169 -0
- package/dist/core/ui/media-zoom.d.ts +51 -0
- package/dist/core/ui/note-markdown.d.ts +19 -0
- package/dist/core/ui/outline.d.ts +44 -0
- package/dist/core/url-guard.d.ts +40 -0
- package/dist/core/utils.d.ts +23 -0
- package/dist/core/web-page/page.d.ts +59 -0
- package/dist/core/web-page/runtime.d.ts +13 -0
- package/dist/core/web-page/start.d.ts +1 -0
- package/dist/core/yaml-mini.d.ts +54 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +4357 -0
- package/dist/index.js.map +29 -0
- package/dist/marked/index.d.ts +31 -0
- package/dist/marked/index.js +110 -0
- package/dist/marked/index.js.map +10 -0
- package/dist/react/index.d.ts +55 -0
- package/dist/react/index.js +352 -0
- package/dist/react/index.js.map +1 -0
- package/dist/web-page.d.ts +2 -0
- package/dist/web-page.js +130 -0
- package/llms-full.txt +2785 -0
- package/llms.txt +36 -0
- package/package.json +118 -4
- package/skills/orbit/SKILL.md +140 -0
- package/skills/orbit/references/editing.md +195 -0
- package/skills/orbit/references/extending.md +247 -0
- package/skills/orbit/references/format.md +331 -0
- package/skills/orbit/references/guide.md +546 -0
- package/skills/orbit/references/import-export.md +115 -0
- package/skills/orbit/references/languages.md +160 -0
- package/skills/orbit/references/map-tools.md +188 -0
- package/skills/orbit/references/media.md +160 -0
- package/skills/orbit/references/recipes.md +236 -0
- package/skills/orbit/references/theming.md +199 -0
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
<!-- A copy of docs/extending.md, made by scripts/build-llms.ts, with links to other files pointing at the repository. Edit the original. -->
|
|
2
|
+
|
|
3
|
+
# Extending Orbit
|
|
4
|
+
|
|
5
|
+
Orbit has four ways to make maps your own: **node types**, **actions**, **status words** and **themes**. Each works for one map, through its options, or for every map once registered, which also covers `<orbit-map>` elements and maps in markdown pages, where you don't write code per map. A map's own options win over registered ones.
|
|
6
|
+
|
|
7
|
+
| | For one map | For every map |
|
|
8
|
+
| --- | --- | --- |
|
|
9
|
+
| Node types | `nodeTypes: { milestone: { … } }` | `registerNodeType('milestone', { … })` |
|
|
10
|
+
| Actions | `actions: [{ id, label, run }]` | `registerAction({ id, label, run })` |
|
|
11
|
+
| Status words | `statuses: { review: 'active' }` | `registerStatus('review', 'active')` |
|
|
12
|
+
| Themes | `theme: { preset, tokens }` | `registerTheme('brand', { preset, tokens })` |
|
|
13
|
+
|
|
14
|
+
Each `register…` function returns a function that removes the registration again.
|
|
15
|
+
|
|
16
|
+
## Node types
|
|
17
|
+
|
|
18
|
+
A node picks a type with the `type` attribute, in any case:
|
|
19
|
+
|
|
20
|
+
```markdown
|
|
21
|
+
# Launch
|
|
22
|
+
## v1.0 beta <!-- orbit type: milestone -->
|
|
23
|
+
- Ana Torres <!-- orbit type: person, role: Design -->
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
In YAML it's `type: milestone`. The type decides how those nodes look and behave:
|
|
27
|
+
|
|
28
|
+
```js
|
|
29
|
+
import { createOrbitMap } from '@restless-dreams/orbit';
|
|
30
|
+
|
|
31
|
+
createOrbitMap(element, markdown, {
|
|
32
|
+
nodeTypes: {
|
|
33
|
+
milestone: {
|
|
34
|
+
label: 'Milestone',
|
|
35
|
+
icon: '🏁',
|
|
36
|
+
color: '#F59E0B',
|
|
37
|
+
tokens: { 'node-stroke': '#B45309', 'node-stroke-width': '3' },
|
|
38
|
+
},
|
|
39
|
+
person: {
|
|
40
|
+
label: 'Person',
|
|
41
|
+
render(node, element) {
|
|
42
|
+
element.textContent = node.text.split(' ').map((word) => word[0]).join('');
|
|
43
|
+
},
|
|
44
|
+
details(node, element) {
|
|
45
|
+
element.textContent = `Role: ${node.attrs?.role ?? 'not set'}`;
|
|
46
|
+
},
|
|
47
|
+
actions: [{ id: 'email', label: 'Email', icon: '✉️', run: (node) => window.open(`mailto:${node.attrs?.email}`) }],
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
| Key | What it does |
|
|
54
|
+
| --- | --- |
|
|
55
|
+
| `label` | The type's name for people, shown as a chip in the detail sheet, in the tooltip and to screen readers. |
|
|
56
|
+
| `icon` | The icon these nodes get unless they set their own. |
|
|
57
|
+
| `color` | The color these nodes get unless they set their own. Their children take shades of it. |
|
|
58
|
+
| `tokens` | [Theme tokens](theming.md#custom-properties) for these nodes only, without `--orbit-`: their rim, shadow, glow, label and status colors. |
|
|
59
|
+
| `render(node, element)` | Draws inside the node, the way a picture does. `element` is a 100 × 100 px box, clipped to the node's circle and scaled with it, and the label moves outside, onto a pill that shows the node's icon before its name. Return a function to clean up; it runs when the node leaves the map. |
|
|
60
|
+
| `details(node, element)` | Adds a section to the detail sheet, above the note. These nodes get a "Show details" button. |
|
|
61
|
+
| `actions` | Actions only these nodes offer, after the map's own. |
|
|
62
|
+
| `version` | The version of the fields these nodes keep in their attributes, once the type changes them (1 at first). See [Versions](#versions). |
|
|
63
|
+
| `upgrade(node, from)` | Brings a node written for an older version of the type up to date. |
|
|
64
|
+
|
|
65
|
+
- **Custom attributes** like `<!-- orbit role: Design -->` are on `node.attrs`, which makes them handy in `render` and `details`.
|
|
66
|
+
- **`render` is for showing:** clicks go through to the node, so use actions for anything to press. It runs when the node comes on the map; navigating away and back draws it again.
|
|
67
|
+
- **Errors stay contained:** if a type's `render` or `details`, or an action, throws, the console says which one and the map keeps working.
|
|
68
|
+
|
|
69
|
+
### Types for display only
|
|
70
|
+
|
|
71
|
+
`nodeTypeFor(node)` gives a node that names no type one to be drawn as, as if it said `type: name`: that type's look, what it draws inside and its actions. It's for display only: Orbit never writes it to the map, so saving keeps the node as it was, and never upgrades a node for it.
|
|
72
|
+
|
|
73
|
+
```js
|
|
74
|
+
createOrbitMap(element, markdown, {
|
|
75
|
+
nodeTypes: { progress: { label: 'Progress', render: drawProgressRing } },
|
|
76
|
+
// Ideas with to-dos right under them show a ring, unless they have a type of their own.
|
|
77
|
+
nodeTypeFor: (node) => (node.children.some((child) => child.status) ? 'progress' : undefined),
|
|
78
|
+
});
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
- **A node's own `type` wins:** `nodeTypeFor` is only asked about nodes without one.
|
|
82
|
+
- **It's asked whenever the map draws,** often, so keep it quick, and return `undefined` to draw a node as it is. An answer that changes with the map, after an edit to the node's children say, shows as the map draws the edit; after a change elsewhere that answers depend on, `render()` the map again.
|
|
83
|
+
- **The type shows wherever a type does:** in the detail sheet's chip, the tooltip, what screen readers hear, `data-orbit-type`, the label's font and exports (`renderToSVGString(source, { nodeTypes, nodeTypeFor })`).
|
|
84
|
+
- **If it throws,** the console says so once, and nodes are drawn as they are.
|
|
85
|
+
|
|
86
|
+
### Versions
|
|
87
|
+
|
|
88
|
+
A type's nodes keep their own fields in attributes, so changing those fields changes what older maps say. Give the type a `version` and an `upgrade` that brings older nodes up to date:
|
|
89
|
+
|
|
90
|
+
```js
|
|
91
|
+
registerNodeType('task', {
|
|
92
|
+
label: 'Task',
|
|
93
|
+
version: 2,
|
|
94
|
+
// Version 1 kept the person in `assignee`; version 2 calls it `owner`.
|
|
95
|
+
upgrade(node, from) {
|
|
96
|
+
if (from < 2 && node.attrs?.assignee !== undefined) {
|
|
97
|
+
const { assignee, ...rest } = node.attrs;
|
|
98
|
+
node.attrs = { ...rest, owner: assignee };
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
- **Nodes say which version they were written for:** `type: task@2`; none means 1. A map upgrades older nodes when it draws them, and the next save writes them as `task@2` with their new fields, changing nothing else in the file.
|
|
105
|
+
- **Nodes written for a newer version** than the type knows are left as they are, and saving keeps everything in them.
|
|
106
|
+
- **Without a map** (on a server, in a script), `upgradeNodeTypes(document.root, nodeTypes)` does the same, with the types you pass and the registered ones, and returns how many nodes it upgraded.
|
|
107
|
+
- **If `upgrade` throws,** the console says which type failed and the node stays as it was.
|
|
108
|
+
|
|
109
|
+
## Actions
|
|
110
|
+
|
|
111
|
+
Actions are buttons under the node in focus, after Orbit's own (details, picture, video, note, link), and in the node's detail sheet.
|
|
112
|
+
|
|
113
|
+
```js
|
|
114
|
+
createOrbitMap(element, markdown, {
|
|
115
|
+
actions: [
|
|
116
|
+
{
|
|
117
|
+
id: 'assign',
|
|
118
|
+
label: 'Assign',
|
|
119
|
+
icon: '👤',
|
|
120
|
+
when: (node) => node.children.length === 0,
|
|
121
|
+
run: (node, event) => openAssignDialog(node),
|
|
122
|
+
},
|
|
123
|
+
],
|
|
124
|
+
});
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
| Key | What it does |
|
|
128
|
+
| --- | --- |
|
|
129
|
+
| `id` | The action's name in the `action` event. Use ids other than Orbit's own: `details`, `image`, `video`, `embed`, `note` and `link`. |
|
|
130
|
+
| `label` | The button's name, read by screen readers, shown as its tooltip and in the detail sheet. A function gets the node: ``(node) => `Assign ${node.text}` ``. |
|
|
131
|
+
| `icon` | An emoji or short symbol (`'✏️'`), SVG path data on a 24-unit grid (`'M4 20h4L20 8l-4-4L4 16z'`), or one of Orbit's icons: `note`, `link`, `goto`, `info`, `image`, `video`, `embed`, `list`. Without one, the label's first letter. |
|
|
132
|
+
| `when(node)` | Which nodes offer it. Default: every node. |
|
|
133
|
+
| `run(node, event)` | What it does. |
|
|
134
|
+
|
|
135
|
+
- **The `action` event fires first** (`orbit-action` on the element), with `action` set to the id. `preventDefault()` there, or returning `false` from `onAction`, skips `run`.
|
|
136
|
+
- **In the detail sheet,** pressing an action closes the sheet first, so a dialog your action opens is in front.
|
|
137
|
+
- **One button per id:** a map's own action wins over a registered one with the same id, and a node type's actions come last.
|
|
138
|
+
|
|
139
|
+
## Status words
|
|
140
|
+
|
|
141
|
+
`status` is free text, and [some words](format.md#statuses) get a colored dot. Add your own words, as one of the tones or with a color of their own:
|
|
142
|
+
|
|
143
|
+
```js
|
|
144
|
+
createOrbitMap(element, markdown, {
|
|
145
|
+
statuses: {
|
|
146
|
+
review: 'active',
|
|
147
|
+
shipped: 'done',
|
|
148
|
+
'on hold': '#A855F7',
|
|
149
|
+
},
|
|
150
|
+
});
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
The tones are `active`, `done`, `blocked`, `todo` and `neutral`; their colors come from the theme (`--orbit-status-active`, …). Words match in any case.
|
|
154
|
+
|
|
155
|
+
## Themes
|
|
156
|
+
|
|
157
|
+
Register a theme once to use it by name everywhere: in options, in a document's frontmatter and on `<orbit-map theme="…">`.
|
|
158
|
+
|
|
159
|
+
```js
|
|
160
|
+
import { registerTheme } from '@restless-dreams/orbit';
|
|
161
|
+
|
|
162
|
+
registerTheme('brand', {
|
|
163
|
+
preset: 'night',
|
|
164
|
+
tokens: { 'color-root': '#FFD166', 'color-1': '#06D6A0', surface: '#0B1020' },
|
|
165
|
+
});
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
```markdown
|
|
169
|
+
---
|
|
170
|
+
theme: brand
|
|
171
|
+
---
|
|
172
|
+
# Launch
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
- **What a theme is:** it starts from `preset` (a built-in theme or another registered one) and sets its own [tokens](theming.md#custom-properties).
|
|
176
|
+
- **Building on it:** a theme object can start from a registered theme too. `{ preset: 'brand', tokens: { … } }` adds its tokens to brand's.
|
|
177
|
+
- **Names:** built-in names can't be reused, and `themeNames()` lists every name.
|
|
178
|
+
- **Validation:** `orbit validate` doesn't know the themes your code registers, so it reports `theme: brand` as unknown.
|
|
179
|
+
|
|
180
|
+
## For every map
|
|
181
|
+
|
|
182
|
+
Register at startup, before maps are created. Maps created earlier pick up registered types, actions and words when they next redraw.
|
|
183
|
+
|
|
184
|
+
```js
|
|
185
|
+
import { defineOrbitMapElement, registerAction, registerNodeType, registerStatus, registerTheme } from '@restless-dreams/orbit';
|
|
186
|
+
|
|
187
|
+
registerTheme('brand', { preset: 'night', tokens: { 'color-root': '#FFD166' } });
|
|
188
|
+
registerNodeType('milestone', { label: 'Milestone', icon: '🏁', color: '#F59E0B' });
|
|
189
|
+
registerStatus('review', 'active');
|
|
190
|
+
registerAction({ id: 'copy-link', label: 'Copy link', icon: 'link', run: (node) => navigator.clipboard.writeText(`${location.href}#${node.id}`) });
|
|
191
|
+
defineOrbitMapElement();
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
```html
|
|
195
|
+
<orbit-map theme="brand">
|
|
196
|
+
# Launch
|
|
197
|
+
## v1.0 beta <!-- orbit type: milestone, status: review -->
|
|
198
|
+
</orbit-map>
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
The functions they return remove the registrations again, which helps with hot reloading and tests.
|
|
202
|
+
|
|
203
|
+
## In React
|
|
204
|
+
|
|
205
|
+
`<OrbitMindMap>` takes the same options as props. Inline objects are fine: the map compares what node types and actions declare, and calls their latest functions, `nodeTypeFor`'s too.
|
|
206
|
+
|
|
207
|
+
```tsx
|
|
208
|
+
import { OrbitMindMap } from '@restless-dreams/orbit/react';
|
|
209
|
+
|
|
210
|
+
export const Roadmap = ({ markdown, onAssign }: { markdown: string; onAssign: (id: string) => void }) => {
|
|
211
|
+
return (
|
|
212
|
+
<div style={{ height: 480 }}>
|
|
213
|
+
<OrbitMindMap
|
|
214
|
+
source={markdown}
|
|
215
|
+
nodeTypes={{ milestone: { label: 'Milestone', icon: '🏁', color: '#F59E0B' } }}
|
|
216
|
+
actions={[{ id: 'assign', label: 'Assign', icon: '👤', run: (node) => onAssign(node.id) }]}
|
|
217
|
+
statuses={{ review: 'active' }}
|
|
218
|
+
/>
|
|
219
|
+
</div>
|
|
220
|
+
);
|
|
221
|
+
};
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## Styling nodes with CSS
|
|
225
|
+
|
|
226
|
+
Each node's element and label carry hooks for CSS:
|
|
227
|
+
- `data-orbit-type`: the type, lowercase;
|
|
228
|
+
- `data-orbit-status`: the status word, lowercase;
|
|
229
|
+
- `data-orbit-tags`: the tags, separated by spaces.
|
|
230
|
+
|
|
231
|
+
Page CSS can target these on maps drawn with `createOrbitMap` or React:
|
|
232
|
+
|
|
233
|
+
```css
|
|
234
|
+
.orbit-node[data-orbit-type='milestone'] .orbit-node__shade {
|
|
235
|
+
stroke-dasharray: 4 3;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
.orbit-label[data-orbit-tags~='urgent'] {
|
|
239
|
+
font-weight: 800;
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
A map inside `<orbit-map>` sits in a shadow root that page CSS can't reach, so use a type's `tokens` there.
|
|
244
|
+
|
|
245
|
+
## Exports
|
|
246
|
+
|
|
247
|
+
`toSVGString()`, `renderToSVGString()` and `orbit render` draw node types' icons, colors and tokens, and your status colors. `renderToSVGString(source, { nodeTypes, statuses, nodeTypeFor })` takes them as options too. What `render` draws is HTML, so it isn't part of an exported SVG.
|
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
<!-- A copy of docs/format.md, made by scripts/build-llms.ts, with links to other files pointing at the repository. Edit the original. -->
|
|
2
|
+
|
|
3
|
+
# Map format
|
|
4
|
+
|
|
5
|
+
The complete reference for writing Orbit maps. A map is a tree: one root, and nodes with children. Write it in **orbit-md**, Orbit's markdown (the default, for maps people write), or in **YAML** (for maps programs write). `npx @restless-dreams/orbit example` prints a map with the main features, and `npx @restless-dreams/orbit validate map.md` checks one.
|
|
6
|
+
|
|
7
|
+
- [Markdown](#markdown)
|
|
8
|
+
- [The tree](#the-tree)
|
|
9
|
+
- [Node titles](#node-titles)
|
|
10
|
+
- [Notes](#notes)
|
|
11
|
+
- [Links between nodes](#links-between-nodes)
|
|
12
|
+
- [Media](#media)
|
|
13
|
+
- [Attributes](#attributes)
|
|
14
|
+
- [Statuses](#statuses)
|
|
15
|
+
- [Document options](#document-options)
|
|
16
|
+
- [YAML](#yaml)
|
|
17
|
+
- [Which flavor a document is](#which-flavor-a-document-is)
|
|
18
|
+
- [Node ids](#node-ids)
|
|
19
|
+
- [Checking a map](#checking-a-map)
|
|
20
|
+
|
|
21
|
+
## Markdown
|
|
22
|
+
|
|
23
|
+
```markdown
|
|
24
|
+
---
|
|
25
|
+
title: Product roadmap
|
|
26
|
+
theme: night
|
|
27
|
+
---
|
|
28
|
+
# 🚀 Product roadmap
|
|
29
|
+
What ships this year.
|
|
30
|
+
|
|
31
|
+
## Research <!-- orbit status: done -->
|
|
32
|
+
Six weeks of interviews before we commit to scope.
|
|
33
|
+
- [x] User interviews
|
|
34
|
+
- Competitor teardown #market
|
|
35
|
+
|
|
36
|
+
## Build
|
|
37
|
+
### Frontend
|
|
38
|
+
- [/] App shell
|
|
39
|
+
- Offline sync <!-- orbit status: blocked -->
|
|
40
|
+
Waits on the [backend](#backend) sync API.
|
|
41
|
+
### Backend
|
|
42
|
+
|
|
43
|
+
## [Launch](https://example.com/launch-plan)
|
|
44
|
+

|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### The tree
|
|
48
|
+
|
|
49
|
+
**Every heading and every list item is a node.** Everything else belongs to the node above it.
|
|
50
|
+
|
|
51
|
+
- **Headings** (`#` to `######`) nest by level: a heading's children are the headings below it, up to the next heading at its own level or higher. A line underlined with `===` is a `#` heading, and with `---` a `##` heading. Headings may be indented up to three spaces and end with closing `#`s.
|
|
52
|
+
- **Lists** are children of the heading above them, every list, in the order written next to that heading's subheadings. Bullets (`-`, `*`, `+`) and numbered items (`1.`, `1)`) work the same. Indent an item further than the one above it to nest it under that item; lists go as deep as you like, past the six heading levels. A tab counts as four spaces.
|
|
53
|
+
- **The root** is the single top heading: the only heading at the highest level used, usually `#`. Several top headings share a root, as do the top items of a document that is just a list: it's named after the frontmatter `title`, a one-line paragraph above them, or "Untitled map". A list with a single top item is rooted at that item. Text before the root heading belongs to the root.
|
|
54
|
+
- A ```` ```orbit ```` or `~~~orbit` fence around the whole map is fine: `parseOrbit` unwraps it.
|
|
55
|
+
|
|
56
|
+
### Node titles
|
|
57
|
+
|
|
58
|
+
A heading's text, or a list item's first line, is the node's title, read in this order:
|
|
59
|
+
|
|
60
|
+
| Written | Becomes |
|
|
61
|
+
| --- | --- |
|
|
62
|
+
| `[ ] Draft` / `[x] Ship` / `[/] Build` | status `todo` / `done` / `active` |
|
|
63
|
+
| `🚀 Launch` (emoji first) | icon `🚀`, text `Launch` |
|
|
64
|
+
| `Offline sync #frontend #sprint-3` | tags `frontend` and `sprint-3`, text `Offline sync` |
|
|
65
|
+
| `Launch [plan](https://…)` | text `Launch plan`, link `https://…` |
|
|
66
|
+
| `**Frontend**`, `*Docs*`, `` `api` ``, `~~Old idea~~` | the text without the symbols |
|
|
67
|
+
| `Launch <!-- orbit status: active -->` | an attribute, inline (see [Attributes](#attributes)) |
|
|
68
|
+
|
|
69
|
+
- **Hashtags** count at the end of a title, after a space, and need a letter: `C# rewrite` and `Fix #42` stay as written.
|
|
70
|
+
- **Links:** a title that is all link works the same; with several links, the first is the node's link.
|
|
71
|
+
- **A backslash** keeps a character as written: `\*not bold\*`, `ship \#notatag`, `\[x] not a task`.
|
|
72
|
+
|
|
73
|
+
They combine: `## 📈 [Growth](https://example.com/growth) #q3 <!-- orbit status: active -->`.
|
|
74
|
+
|
|
75
|
+
### Notes
|
|
76
|
+
|
|
77
|
+
A note is longer text shown in the detail sheet, as markdown. Everything under a heading or list item that isn't a heading or list item is its note: paragraphs, `>` quotes, code blocks and tables.
|
|
78
|
+
|
|
79
|
+
- Under a list item, indent the note under it, as you would write anything under a heading. A line right after the item, with no blank line between, continues the item too.
|
|
80
|
+
- To keep a list inside a note, instead of making it children, quote it with `>`: headings and bullets inside a quote stay note text.
|
|
81
|
+
|
|
82
|
+
```markdown
|
|
83
|
+
# Launch
|
|
84
|
+
## Research
|
|
85
|
+
Questions to answer:
|
|
86
|
+
> - Who buys it?
|
|
87
|
+
> - Why now?
|
|
88
|
+
|
|
89
|
+
- Frontend
|
|
90
|
+
Vite and React. Ships behind the beta flag.
|
|
91
|
+
- Backend
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Links between nodes
|
|
95
|
+
|
|
96
|
+
A link to `#id` points at another node of the map, the way `#heading` links point at headings in a page: a note link like `[Research](#research)`, or a node whose link is `#research`. It flies to that node instead of opening a page.
|
|
97
|
+
|
|
98
|
+
```markdown
|
|
99
|
+
# Launch
|
|
100
|
+
## Build
|
|
101
|
+
Starts when [Research](#research) is done.
|
|
102
|
+
## [Read the research](#research)
|
|
103
|
+
## Research
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
The id is the node's text in lowercase with dashes (see [Node ids](#node-ids)); `#Research` and GitHub-style `#-research` find it too. A link to a node the map doesn't have is reported.
|
|
107
|
+
|
|
108
|
+
### Media
|
|
109
|
+
|
|
110
|
+
A node shows its image (or its video's thumbnail) inside it. Its image and video open over the whole window, in the media viewer ([Pictures and videos](media.md)), and its embed in the detail sheet. Put each on a line of its own under the heading, or indented under the list item:
|
|
111
|
+
|
|
112
|
+
| Line | Becomes |
|
|
113
|
+
| --- | --- |
|
|
114
|
+
| `` | the image |
|
|
115
|
+
| `[Trailer](https://www.youtube.com/watch?v=…)` | the video: YouTube, Vimeo, or a `.mp4`, `.webm` or `.mov` file |
|
|
116
|
+
| `[](https://vimeo.com/…)` | the video, with that thumbnail |
|
|
117
|
+
| `[Any other link](https://…)` | note text |
|
|
118
|
+
|
|
119
|
+
A node has at most one image, one video and one embed; extra media lines stay in the note. Embeds (a page shown in a frame) are set with the `embed` attribute. To read a media line differently, follow it with `<!-- orbit contentType: image -->` (or `video`, `embed`, or `none` to keep it as note text), and caption it the same way, with `<!-- orbit caption: The summit at dawn -->` right under it. Relative URLs resolve against `baseUrl`.
|
|
120
|
+
|
|
121
|
+
```markdown
|
|
122
|
+
# Trip
|
|
123
|
+
- Summit
|
|
124
|
+

|
|
125
|
+
- Trail
|
|
126
|
+
[Walkthrough](https://www.youtube.com/watch?v=aqz-KE-bpKQ)
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Attributes set media too: `<!-- orbit image: images/photo.jpg -->`.
|
|
130
|
+
|
|
131
|
+
### Attributes
|
|
132
|
+
|
|
133
|
+
Attributes go in an HTML comment that starts with `orbit` (in any case, with or without a colon after it), written as YAML:
|
|
134
|
+
|
|
135
|
+
```markdown
|
|
136
|
+
## Build
|
|
137
|
+
<!-- orbit
|
|
138
|
+
color: "#F5A3A8"
|
|
139
|
+
status: active
|
|
140
|
+
priority: 1
|
|
141
|
+
tags: [frontend, sprint-3]
|
|
142
|
+
-->
|
|
143
|
+
|
|
144
|
+
- Frontend <!-- orbit status: active -->
|
|
145
|
+
- Backend
|
|
146
|
+
<!-- orbit
|
|
147
|
+
image: diagrams/backend.png
|
|
148
|
+
note: Talks to the billing service.
|
|
149
|
+
-->
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
- **Block form**: on the lines after a heading, or indented under a list item. Any number of keys. A block written right under a list item without its indent still belongs to the heading above the list, and an `attributes-after-list` note says so: indent it to set the list item's.
|
|
153
|
+
- **Inline form**: at the end of a heading or list item's line. Separate several with commas: `<!-- orbit status: active, priority: 1 -->`.
|
|
154
|
+
- **Other HTML comments** are hidden, as markdown hides them: Orbit keeps them in the file, out of titles, ids and notes as they're shown, and a renamed idea keeps the ones at the end of its title. One that reads like attributes but doesn't start with `orbit` (`<!-- status: done -->`) sets nothing, and a `comment-without-orbit` note says how to write it.
|
|
155
|
+
|
|
156
|
+
| Key | Value | Example | Effect |
|
|
157
|
+
| --- | --- | --- | --- |
|
|
158
|
+
| `color` | any CSS color | `"#F5A3A8"`, `tomato` | The node's color, instead of its branch's. Its children take shades of it. |
|
|
159
|
+
| `paletteColor` | number | `3` | Which of the palette's colors the node takes when it has no `color`: `1` is the first after the root's, cycling. Its children take shades of it. Editing on the map writes it to keep an idea's color (see [Colors](#colors)). |
|
|
160
|
+
| `icon` | emoji or short symbol | `🚀`, `"★"` | Shown before the text. Same as an emoji at the start of the title. |
|
|
161
|
+
| `status` | text | `active`, `done`, `blocked` | Shown in the detail sheet; some words get a colored dot (see [Statuses](#statuses)). |
|
|
162
|
+
| `priority` | number | `1` | Shown in the detail sheet. |
|
|
163
|
+
| `tags` | list of text | `[frontend, sprint-3]` | Shown in the detail sheet. A single word works too, and so do words separated by commas: `tags: frontend, sprint-3`. Hashtags at the end of the title add to them. |
|
|
164
|
+
| `collapsed` | `true` / `false` | `true` | Hides the node's children (they show as a "+N" count) until you fly into it. |
|
|
165
|
+
| `link` | URL, or `#id` | `https://example.com` | Offered as a button when the node is in focus. Same as a link in the title. `#id` goes to another node (see [Links between nodes](#links-between-nodes)). |
|
|
166
|
+
| `note` | text | `Ships in May.` | The node's note. Same as a paragraph or blockquote. |
|
|
167
|
+
| `noteFormat` | `markdown` / `plain` | `plain` | How the note is shown. Default `markdown`. |
|
|
168
|
+
| `image` | URL, or `{ src, alt, caption }` | `images/photo.jpg` | The node's image. |
|
|
169
|
+
| `video` | URL, or `{ src, provider, thumbnail, caption }` | `https://youtu.be/…` | The node's video. `provider`: `youtube`, `vimeo` or `native`. |
|
|
170
|
+
| `embed` | URL, or `{ src, caption }` | `https://example.com/demo` | A page shown in a frame in the detail sheet. |
|
|
171
|
+
| `caption` | text | `The summit at dawn.` | Caption for the media line just above it, or for the one image, video or embed set next to it. Anywhere else, for the node's video, embed or image (in that order). |
|
|
172
|
+
| `id` | text | `launch` | The node's id, instead of one made from its text (see [Node ids](#node-ids)). |
|
|
173
|
+
| `type` | text | `milestone` | The node's type. A type your code defines sets its look, content and actions (see [Extending](extending.md#node-types)). Any case. |
|
|
174
|
+
| `contentType` | `image` / `video` / `embed` / `none` | `embed` | Markdown only: how to read the media line just above. |
|
|
175
|
+
|
|
176
|
+
Any other key is kept as a **custom attribute** in `node.attrs`, for your own code (`<!-- orbit owner: Ana -->`). A key that looks like a misspelled attribute (`colour`, `stauts`) is kept too, with a warning that suggests the right one.
|
|
177
|
+
|
|
178
|
+
### Statuses
|
|
179
|
+
|
|
180
|
+
`status` is free text, shown as written. These words (any case) also get a colored dot on the node and in the detail sheet:
|
|
181
|
+
|
|
182
|
+
| Dot | Words |
|
|
183
|
+
| --- | --- |
|
|
184
|
+
| active (blue) | `active`, `doing`, `in progress`, `wip`, `started`, `ongoing` |
|
|
185
|
+
| done (green) | `done`, `complete`, `completed`, `shipped`, `finished`, `closed` |
|
|
186
|
+
| blocked (red) | `blocked`, `stuck`, `at risk`, `failed` |
|
|
187
|
+
| todo (gray) | `todo`, `to do`, `planned`, `backlog`, `next`, `open` |
|
|
188
|
+
|
|
189
|
+
Other words get a neutral dot. Checkboxes set `todo` (`[ ]`), `done` (`[x]`) and `active` (`[/]`).
|
|
190
|
+
|
|
191
|
+
### Colors
|
|
192
|
+
|
|
193
|
+
The root takes the palette's first color: the theme's, or the frontmatter's `palette`. The top-level nodes take the others in turn, cycling, and deeper nodes take shades of their branch's color, so siblings stay apart. A node's own `color` wins, then its type's.
|
|
194
|
+
|
|
195
|
+
`paletteColor` gives a node one of the palette's colors by number, so it still changes with the theme. The top-level nodes without one take turns with the colors no top-level node has by number: give two nodes the same number for them to share a color.
|
|
196
|
+
|
|
197
|
+
Edits keep the colors of the nodes around them, on screen and through the map tools: adding, moving or removing a top-level node writes `paletteColor` where a color would change otherwise, as few times as it can.
|
|
198
|
+
|
|
199
|
+
- A moved node keeps its color, and a new one takes a color no other top-level node has, while there is one.
|
|
200
|
+
- A node moved under another one drops its `paletteColor` and takes its new branch's shade.
|
|
201
|
+
- Where the top level has more nodes than the palette has colors, colors repeat, and an edit that would write more numbers than there are colors writes none.
|
|
202
|
+
|
|
203
|
+
## Document options
|
|
204
|
+
|
|
205
|
+
Set in the frontmatter (markdown) or as top-level keys (YAML). Options passed in code win over these.
|
|
206
|
+
|
|
207
|
+
| Key | Value | Default | |
|
|
208
|
+
| --- | --- | --- | --- |
|
|
209
|
+
| `title` | text | the root's text | The map's accessible name and SVG title. Names the root when a document has no single top heading. |
|
|
210
|
+
| `theme` | `paper`, `night`, `glass`, `glass-night`, `cosmos`, `blueprint`, `ink`, `contrast`, `flat`, `flat-night`, `material`, `material-night`, `liquid`, `liquid-night` or `auto` | `paper` | See [Theming](theming.md). |
|
|
211
|
+
| `view` | `focus` or `all` | `focus` | The first view: one node with its children around it, or the overview of the whole tree. |
|
|
212
|
+
| `palette` | list of colors | the theme's | The root's color, then one per top-level branch, cycling. A comma-separated string works too. |
|
|
213
|
+
| `maxDepth` | number | all levels | Levels below the root to draw: `1` is the root and its children. |
|
|
214
|
+
| `showRings` | `true` / `false` | `true` | Draw the orbit rings. |
|
|
215
|
+
| `interactive` | `true` / `false` | `true` | `false` draws a still picture. |
|
|
216
|
+
| `animation` | `true` / `false` | `false` | Let the orbit drift slowly on its own. |
|
|
217
|
+
| `speed` | seconds | `90` | Seconds per turn of that drift. |
|
|
218
|
+
| `height` | pixels | `420` | Height of `<orbit-map>` elements and marked placeholders. |
|
|
219
|
+
| `baseUrl` | URL | | Resolves relative image, video and link URLs. |
|
|
220
|
+
| `className` | text | | Class names added to the map's element. |
|
|
221
|
+
| `schemaVersion` | number | | The version of the format the document is written for: `1`. See [Versions](#versions). |
|
|
222
|
+
| `flavor` | `markdown` or `yaml` | | Forces the flavor (see [Which flavor a document is](#which-flavor-a-document-is)). |
|
|
223
|
+
|
|
224
|
+
Flags also read `yes`, `no`, `on` and `off`.
|
|
225
|
+
|
|
226
|
+
## YAML
|
|
227
|
+
|
|
228
|
+
For maps that programs generate:
|
|
229
|
+
|
|
230
|
+
```yaml
|
|
231
|
+
title: Product roadmap
|
|
232
|
+
theme: night
|
|
233
|
+
nodes:
|
|
234
|
+
- text: Product roadmap
|
|
235
|
+
icon: 🚀
|
|
236
|
+
note: What ships this year.
|
|
237
|
+
children:
|
|
238
|
+
- text: Research
|
|
239
|
+
status: done
|
|
240
|
+
children: [User interviews, Competitor teardown]
|
|
241
|
+
- text: Build
|
|
242
|
+
status: active
|
|
243
|
+
children:
|
|
244
|
+
- text: Frontend
|
|
245
|
+
children:
|
|
246
|
+
- App shell
|
|
247
|
+
- text: Offline sync
|
|
248
|
+
status: blocked
|
|
249
|
+
- text: Launch
|
|
250
|
+
link: https://example.com/launch-plan
|
|
251
|
+
image: images/poster.png
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
- `nodes` is a list with the root node. Several top-level nodes share a root named after `title`, as in markdown.
|
|
255
|
+
- A node is a map with `text` and optionally `children`, plus any [attribute](#attributes) (`icon`, `color`, `status`, `link`, `note`, `image`, …) as a key. Custom keys are kept in `node.attrs`. A node without `text` but with `title`, `name` or `label`, or without `children` but with `items`, `nodes` or `subnodes`, is read with those as its text and children, and reported (`misnamed-node-key`) until they're renamed.
|
|
256
|
+
- A plain string in `children` is a node with just that text.
|
|
257
|
+
- Document options go at the top level, next to `nodes`.
|
|
258
|
+
|
|
259
|
+
## Which flavor a document is
|
|
260
|
+
|
|
261
|
+
`parseOrbit` reads a document as YAML when its frontmatter says `flavor: yaml`, its first line is `nodes:`, or the whole text reads as a YAML map: one with a `nodes:` list, or one that starts with a document option (`title:`, `theme:`, `view:`, …). Anything else is markdown, so a first line like `Status: draft`, or a note that starts with `nodes:`, stays markdown. `parseOrbitMarkdown` and `parseOrbitYAML` skip the detection.
|
|
262
|
+
|
|
263
|
+
## What saving keeps
|
|
264
|
+
|
|
265
|
+
Orbit never drops what a document says, even what it doesn't read:
|
|
266
|
+
|
|
267
|
+
- **Saving keeps the file as it was written.** `serializeOrbitMarkdown` (and a map's `toMarkdown()`) write a document parsed from markdown back line for line, and only the ideas an edit changed are written again: a renamed idea gets a new title line, a checked-off item a new checkbox, a moved idea takes its lines along. So a note written by hand or by another app keeps its formatting, its frontmatter keys, its HTML comments and rules, and its link definitions at the end. `{ keepSource: false }` writes the whole map in Orbit's own form instead; so does `orbit convert`.
|
|
268
|
+
- **Keys and values Orbit doesn't read are kept.** Frontmatter and top-level YAML keys it doesn't know are on `document.extra`, and both serializers write them back, with any changes an app makes to them: an app can keep a setting of its own there. A document without `extra` changes none of them, so no key another app wrote is lost; an `extra` object, even `{}`, changes or removes them. An attribute Orbit doesn't know is a custom attribute on `node.attrs`; a value it can't read for one of its own (a list for `status`, a word for `priority`) is reported and kept there under its own name. A picture or video keeps fields Orbit doesn't use (`width`, a `provider` it doesn't know).
|
|
269
|
+
- **A file that isn't a map yet** (only paragraphs) is a root with the text as its note: adding the first idea gives it a heading and keeps the text.
|
|
270
|
+
|
|
271
|
+
## Versions
|
|
272
|
+
|
|
273
|
+
A document says which version of the format it's written for with `schemaVersion`; none means `1`, the current one.
|
|
274
|
+
|
|
275
|
+
- **Older documents are upgraded as they're read.** When the format changes, Orbit brings documents written for the version before up to date as it reads them (a `format-upgraded` note says so), and the next save writes them as the new version, changing only what the upgrade changed.
|
|
276
|
+
- **Newer documents are read as well as they can be,** and reported with `unsupported-schema-version`, an error: apps should open them without letting them be edited. Nothing in them is lost by saving, but what this version doesn't know of them isn't understood either.
|
|
277
|
+
- **Node types have versions of their own,** for the fields their nodes keep in attributes: `type: task@2` says a node was written for version 2 of `task`, and none means 1. A type that changes its fields says so with `version` and brings older nodes up to date with `upgrade` (see [Extending Orbit](extending.md#versions)); a node written for a newer version of its type is left as it is.
|
|
278
|
+
|
|
279
|
+
### Changing the format
|
|
280
|
+
|
|
281
|
+
Maps outlive the version of Orbit that wrote them. Older and newer versions read them, and so do apps that bundle a copy of their own. So each change to the format is one of three kinds:
|
|
282
|
+
|
|
283
|
+
- **Something older versions can do without:** a new attribute (like `paletteColor`) or a new document option. An older version keeps the attribute as a custom one, and the option as an unknown frontmatter key, which it reports. It writes both back unchanged and draws the map as it did before. No new version of the format is needed.
|
|
284
|
+
- **Something an older version would misread:**
|
|
285
|
+
- a new kind of value for an attribute it already reads: Orbit 0.1.0 takes `color: 3` for a color and draws it wrong, without a word;
|
|
286
|
+
- new syntax in titles or notes: it shows `==First==` as text;
|
|
287
|
+
- an attribute renamed, removed, or given a new meaning.
|
|
288
|
+
|
|
289
|
+
These raise `schemaVersion`, with a step in `FORMAT_UPGRADES` (`src/core/format-upgrades.ts`) that brings documents written for the version before up to date. Older versions then report `unsupported-schema-version`, and apps open those maps read-only.
|
|
290
|
+
- **A change to a node type's own fields:** the type gets a new `version` and an `upgrade` (see [Extending Orbit](extending.md#versions)), not a new version of the format.
|
|
291
|
+
|
|
292
|
+
`tests/fixtures/releases/` holds maps as each released version wrote them. Every version must read each one without errors, write it back exactly, and understand it the same way, after its upgrades.
|
|
293
|
+
|
|
294
|
+
## Node ids
|
|
295
|
+
|
|
296
|
+
Each node gets an id from its text: lowercase, accents folded, other letters kept (`Investigación` → `investigacion`, `研究` → `研究`, `Q3 plan` → `q3-plan`). Repeated ids get `-2`, `-3`, … in tree order. Set `id` to choose one; ids are what `renderer.flyTo(id)`, the `focus` export option and the React `focusedId` prop take.
|
|
297
|
+
|
|
298
|
+
## Checking a map
|
|
299
|
+
|
|
300
|
+
Parsing is forgiving: when something is wrong but the map can still be drawn, the parser works around it and records a diagnostic with a `code`, a `severity`, a message that says how to fix it and the `line` where it has one. `{ strict: true }` throws an `OrbitParseError` on the first one instead, except for the few that only note something and leave the map valid: `unknown-attribute` (kept as your own attribute), `synthetic-root`, `caption-without-media`, `format-upgraded`, `ignored-node-entry`, `comment-without-orbit` and `attributes-after-list`.
|
|
301
|
+
|
|
302
|
+
```bash
|
|
303
|
+
npx @restless-dreams/orbit validate map.md # every problem as map.md:line: severity: message [code]
|
|
304
|
+
npx @restless-dreams/orbit validate --json map.md # the same as JSON: valid, flavor, root, nodes, depth, diagnostics
|
|
305
|
+
npx @restless-dreams/orbit validate --tree map.md # the map as Orbit reads it, a node a line with its #id
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
`validate` exits with 1 while the map has a problem that makes it invalid, and lists the notes too (add `--loose` to accept the problems the map works around, but never a map it can't read).
|
|
309
|
+
|
|
310
|
+
| Code | Meaning |
|
|
311
|
+
| --- | --- |
|
|
312
|
+
| `empty-document` | Nothing to draw. |
|
|
313
|
+
| `no-structure` | No headings or lists (markdown), or no `nodes:` list (YAML). |
|
|
314
|
+
| `synthetic-root` | Several top headings, items or YAML nodes and no title, so the root is called "Untitled map". |
|
|
315
|
+
| `invalid-frontmatter` | The frontmatter isn't valid YAML `key: value` pairs. |
|
|
316
|
+
| `unknown-frontmatter-key` | A frontmatter key Orbit doesn't know: kept and written back, but not used. The message names the one you probably meant. |
|
|
317
|
+
| `unknown-yaml-key` | The same, for a YAML document's top-level keys. |
|
|
318
|
+
| `invalid-option-value` | A document option with a value Orbit can't use, such as an unknown theme or a `flavor` other than `markdown` or `yaml`. |
|
|
319
|
+
| `unsupported-schema-version` | The document is written for a newer version of the format (an error: open it without editing it). |
|
|
320
|
+
| `format-upgraded` | The document was written for an older version of the format and read as the current one; saving writes it in the current one. |
|
|
321
|
+
| `invalid-attributes` | An attribute block isn't valid YAML, or a value has the wrong type: kept as written, but not used. |
|
|
322
|
+
| `unknown-attribute` | A key that looks like a misspelled attribute, kept as a custom one. |
|
|
323
|
+
| `media-missing-source` | An `image`, `video` or `embed` without a URL. |
|
|
324
|
+
| `unknown-content-type` | `contentType` isn't `image`, `video`, `embed` or `none`. |
|
|
325
|
+
| `caption-without-media` | A `caption` on a node with no image, video or embed. |
|
|
326
|
+
| `unknown-link-target` | A `#id` link points at no node of the map; the message suggests the id you probably meant. |
|
|
327
|
+
| `invalid-yaml` | The YAML document can't be read. |
|
|
328
|
+
| `ignored-node-entry` | A YAML node that is neither a map nor text. |
|
|
329
|
+
| `comment-without-orbit` | An HTML comment that reads like attributes (`<!-- status: done -->`) but doesn't start with `orbit`, so it sets nothing. |
|
|
330
|
+
| `attributes-after-list` | An attribute block right under a list item, without its indent: it sets the heading's attributes, not the item's. |
|
|
331
|
+
| `misnamed-node-key` | A YAML node's text under `title`, `name` or `label`, or its children under `items`, `nodes` or `subnodes`: read as them, but write `text` and `children`. |
|