Examples
The package ships two templates: a small starter and a complete Physics map. This documentation also uses a map of the onboarding-map project. Each example is live beside the file that produces it. Open the map full screen to explore it; the download link gives you its TypeScript source.
Starter
Section titled “Starter”The smallest useful starting point: two regions, a few items and two stages. This is what init
copies into a new project. Replace it with your subject, or ask your agent to expand it.
import { defineMap, docLink } from 'onboarding-map';
/*
* A starting point: two regions, a handful of items and two stages. Replace it
* with your own subject, or ask your coding agent to (see AGENTS.md).
*
* The map has two layers:
* - the TERRITORY: regions (domains) → groups (categories) → items.
* Every item is on the route ('path'), a choice not taken ('alternative'),
* or worth knowing it exists ('context').
* - the JOURNEY: stages, each Do → Observe → Read, that pass through the
* route's items and together build the goal.
*/
const docs = docLink('vendor');
export default defineMap({
id: 'starter',
version: '0.1.0',
title: 'Your first week',
motto: 'Do, observe, read, repeat.',
labels: {
intro:
'Everything you will meet in your first week. Follow the route; the rest is territory to recognise.',
period: 'Day',
},
kinds: [
{ id: 'tool', label: 'Tool', plural: 'Tools', description: 'Something you install and use.' },
{ id: 'concept', label: 'Concept', plural: 'Concepts', description: 'An idea you need to understand.' },
],
periods: [{ period: 1, title: 'Getting set up', summary: 'From an empty laptop to your first change.' }],
goal: {
title: 'Your first change',
statement: 'A small change of yours, reviewed and merged.',
doneWhen: 'Your change is merged and you can explain every step it went through.',
modules: [
{
id: 'workstation',
title: 'Workstation',
purpose: 'Everything else happens on it.',
dependsOn: [],
builtFrom: ['editor', 'git'],
produces: ['An editor and git, set up and working'],
},
{
id: 'change',
title: 'Merged change',
purpose: 'Proof that the whole loop works for you.',
dependsOn: ['workstation'],
relations: [{ to: 'workstation', verb: 'is made on' }],
builtFrom: ['pull-request'],
produces: ['A merged pull request'],
},
],
},
domains: [
{ id: 'tools', label: 'Tools', tagline: 'What you work with', order: 0, color: '#3b82f6' },
{ id: 'process', label: 'Process', tagline: 'How work gets in', order: 1, color: '#10b981' },
],
nodes: [
{
id: 'editors',
label: 'Editor',
domain: 'tools',
kind: 'category',
status: 'path',
summary: 'Where you write code.',
},
{
id: 'editor',
label: 'VS Code',
domain: 'tools',
kind: 'tool',
status: 'path',
parent: 'editors',
stage: 'setup',
summary: 'The editor the team uses, with the extensions in the repository recommendations.',
docs: [docs('VS Code docs', 'https://code.visualstudio.com/docs')],
},
{
id: 'other-editor',
label: 'JetBrains IDEs',
domain: 'tools',
kind: 'tool',
status: 'alternative',
alternativeTo: 'editor',
parent: 'editors',
summary: 'Works too; the team settings are only maintained for VS Code.',
},
{
id: 'vcs',
label: 'Version control',
domain: 'tools',
kind: 'category',
status: 'path',
summary: 'Keeping history.',
},
{
id: 'git',
label: 'Git',
domain: 'tools',
kind: 'tool',
status: 'path',
parent: 'vcs',
stage: 'setup',
summary: 'Records every change, so work can be shared, reviewed and undone.',
docs: [docs('Pro Git', 'https://git-scm.com/book')],
},
{
id: 'review',
label: 'Review',
domain: 'process',
kind: 'category',
status: 'path',
summary: 'Getting work in.',
},
{
id: 'pull-request',
label: 'Pull request',
domain: 'process',
kind: 'concept',
status: 'path',
parent: 'review',
stage: 'first-change',
summary: 'A proposed change that others read and approve before it is merged.',
docs: [docs('About pull requests', 'https://docs.github.com/en/pull-requests')],
},
{
id: 'ci',
label: 'CI checks',
domain: 'process',
kind: 'concept',
status: 'context',
parent: 'review',
summary: 'Tests that run on every pull request. You will see them; you do not need to change them yet.',
},
],
edges: [{ from: 'pull-request', to: 'git', kind: 'builds-on' }],
stages: [
{
id: 'setup',
period: 1,
order: 1,
title: 'Set up',
feeling: 'My laptop is ready and I know where the code lives.',
task: 'Install the editor and git, and clone the repository.',
delivers: ['workstation'],
waypoints: ['editor', 'git'],
do: [
'Install VS Code and the recommended extensions.',
{ text: 'Clone the repository.', tip: 'git clone <url>' },
],
observe: [{ text: 'What does `git log` show you?', note: true }],
read: ['editor', 'git'],
checkpoint: 'The project opens in your editor and `git status` is clean.',
},
{
id: 'first-change',
period: 1,
order: 2,
title: 'First change',
feeling: 'I got a change reviewed and merged.',
task: 'Make a small change and take it through review.',
delivers: ['change'],
waypoints: ['pull-request'],
do: ['Fix a typo in the README on a new branch.', 'Open a pull request.'],
observe: [{ text: 'Which checks ran on your pull request?', nodes: ['pull-request'], note: true }],
read: ['pull-request', 'ci'],
checkpoint: 'Your pull request is merged.',
},
],
});import { defineMap, docLink } from 'onboarding-map';
/*
* A starting point: two regions, a handful of items and two stages. Replace it
* with your own subject, or ask your coding agent to (see AGENTS.md).
*
* The map has two layers:
* - the TERRITORY: regions (domains) → groups (categories) → items.
* Every item is on the route ('path'), a choice not taken ('alternative'),
* or worth knowing it exists ('context').
* - the JOURNEY: stages, each Do → Observe → Read, that pass through the
* route's items and together build the goal.
*/
const docs = docLink('vendor');
export default defineMap({
id: 'starter',
version: '0.1.0',
title: 'Your first week',
motto: 'Do, observe, read, repeat.',
labels: {
intro:
'Everything you will meet in your first week. Follow the route; the rest is territory to recognise.',
period: 'Day',
},
kinds: [
{ id: 'tool', label: 'Tool', plural: 'Tools', description: 'Something you install and use.' },
{ id: 'concept', label: 'Concept', plural: 'Concepts', description: 'An idea you need to understand.' },
],
periods: [{ period: 1, title: 'Getting set up', summary: 'From an empty laptop to your first change.' }],
goal: {
title: 'Your first change',
statement: 'A small change of yours, reviewed and merged.',
doneWhen: 'Your change is merged and you can explain every step it went through.',
modules: [
{
id: 'workstation',
title: 'Workstation',
purpose: 'Everything else happens on it.',
dependsOn: [],
builtFrom: ['editor', 'git'],
produces: ['An editor and git, set up and working'],
},
{
id: 'change',
title: 'Merged change',
purpose: 'Proof that the whole loop works for you.',
dependsOn: ['workstation'],
relations: [{ to: 'workstation', verb: 'is made on' }],
builtFrom: ['pull-request'],
produces: ['A merged pull request'],
},
],
},
domains: [
{ id: 'tools', label: 'Tools', tagline: 'What you work with', order: 0, color: '#3b82f6' },
{ id: 'process', label: 'Process', tagline: 'How work gets in', order: 1, color: '#10b981' },
],
nodes: [
{
id: 'editors',
label: 'Editor',
domain: 'tools',
kind: 'category',
status: 'path',
summary: 'Where you write code.',
},
{
id: 'editor',
label: 'VS Code',
domain: 'tools',
kind: 'tool',
status: 'path',
parent: 'editors',
stage: 'setup',
summary: 'The editor the team uses, with the extensions in the repository recommendations.',
docs: [docs('VS Code docs', 'https://code.visualstudio.com/docs')],
},
{
id: 'other-editor',
label: 'JetBrains IDEs',
domain: 'tools',
kind: 'tool',
status: 'alternative',
alternativeTo: 'editor',
parent: 'editors',
summary: 'Works too; the team settings are only maintained for VS Code.',
},
{
id: 'vcs',
label: 'Version control',
domain: 'tools',
kind: 'category',
status: 'path',
summary: 'Keeping history.',
},
{
id: 'git',
label: 'Git',
domain: 'tools',
kind: 'tool',
status: 'path',
parent: 'vcs',
stage: 'setup',
summary: 'Records every change, so work can be shared, reviewed and undone.',
docs: [docs('Pro Git', 'https://git-scm.com/book')],
},
{
id: 'review',
label: 'Review',
domain: 'process',
kind: 'category',
status: 'path',
summary: 'Getting work in.',
},
{
id: 'pull-request',
label: 'Pull request',
domain: 'process',
kind: 'concept',
status: 'path',
parent: 'review',
stage: 'first-change',
summary: 'A proposed change that others read and approve before it is merged.',
docs: [docs('About pull requests', 'https://docs.github.com/en/pull-requests')],
},
{
id: 'ci',
label: 'CI checks',
domain: 'process',
kind: 'concept',
status: 'context',
parent: 'review',
summary: 'Tests that run on every pull request. You will see them; you do not need to change them yet.',
},
],
edges: [{ from: 'pull-request', to: 'git', kind: 'builds-on' }],
stages: [
{
id: 'setup',
period: 1,
order: 1,
title: 'Set up',
feeling: 'My laptop is ready and I know where the code lives.',
task: 'Install the editor and git, and clone the repository.',
delivers: ['workstation'],
waypoints: ['editor', 'git'],
do: [
'Install VS Code and the recommended extensions.',
{ text: 'Clone the repository.', tip: 'git clone <url>' },
],
observe: [{ text: 'What does `git log` show you?', note: true }],
read: ['editor', 'git'],
checkpoint: 'The project opens in your editor and `git status` is clean.',
},
{
id: 'first-change',
period: 1,
order: 2,
title: 'First change',
feeling: 'I got a change reviewed and merged.',
task: 'Make a small change and take it through review.',
delivers: ['change'],
waypoints: ['pull-request'],
do: ['Fix a typo in the README on a new branch.', 'Open a pull request.'],
observe: [{ text: 'Which checks ran on your pull request?', nodes: ['pull-request'], note: true }],
read: ['pull-request', 'ci'],
checkpoint: 'Your pull request is merged.',
},
],
});Physics
Section titled “Physics”A complete example outside software. It shows how regions, route items, stages and a goal fit together for introductory mechanics.
import { defineMap, docLink, ref } from 'onboarding-map';
/*
* Introductory mechanics for a first-year student: from describing motion to
* predicting it with forces and with energy. A small, complete example of a
* map outside software.
*/
const wiki = docLink('wikipedia', 'https://en.wikipedia.org/wiki/');
export default defineMap({
id: 'intro-mechanics',
version: '0.1.0',
title: 'Introductory mechanics',
motto: 'Predict first, then check.',
labels: {
intro:
'Four weeks from describing motion to predicting it. Follow the route; the rest of the map is physics you will meet later.',
period: 'Week',
tip: { label: 'Worked example', hint: 'Hint' },
aria: { map: 'Map of classical mechanics' },
refs: { heading: 'In the textbook' },
sources: { wikipedia: 'Wikipedia', textbook: 'Textbook' },
},
kinds: [
{ id: 'concept', label: 'Concept', plural: 'Concepts', description: 'A quantity or idea used to describe motion.' },
{ id: 'law', label: 'Law', plural: 'Laws', description: 'A statement about nature that experiments keep confirming.' },
{ id: 'method', label: 'Method', plural: 'Methods', description: 'A way of working out an answer.' },
],
periods: [
{ period: 1, title: 'Describing motion', summary: 'Where things are, how fast, and how that changes.' },
{ period: 2, title: 'Causes of motion', summary: 'Forces, and what energy lets you skip.' },
],
documents: [
{
id: 'openstax',
title: 'OpenStax University Physics, Volume 1',
date: '2016-09-19',
audience: 'First-year university students',
url: 'https://openstax.org/details/books/university-physics-volume-1',
},
],
goal: {
title: 'Predicting motion',
statement: 'You can predict how an object moves from the forces on it, and check the answer with energy.',
doneWhen: 'Given a ball thrown off a cliff or a block sliding down a ramp, you can predict where and how fast, two ways.',
story:
'Motion is described with vectors that change in time. Forces change that motion, by Newton’s second law. Energy is a shortcut: when it is conserved, it gives speeds without following the motion step by step.',
modules: [
{
id: 'kinematics',
title: 'Describing motion',
purpose: 'You can only predict what you can describe.',
dependsOn: [],
builtFrom: ['vectors', 'derivatives', 'velocity', 'acceleration'],
produces: ['Position, velocity and acceleration of anything, as vectors'],
refs: [ref('openstax')],
},
{
id: 'projectiles',
title: 'Projectiles',
purpose: 'The first motion you can predict completely.',
dependsOn: ['kinematics'],
relations: [{ to: 'kinematics', verb: 'applies' }],
builtFrom: ['constant-acceleration', 'free-fall', 'projectile-motion'],
produces: ['Where a thrown object lands, and when'],
},
{
id: 'dynamics',
title: 'Forces',
purpose: 'Explains why the acceleration is what it is.',
dependsOn: ['kinematics'],
relations: [{ to: 'kinematics', verb: 'explains' }],
builtFrom: ['newtons-first', 'newtons-second', 'free-body-diagram', 'friction'],
produces: ['The acceleration of an object from the forces on it'],
},
{
id: 'energy',
title: 'Energy',
purpose: 'Answers “how fast?” without following the motion.',
dependsOn: ['dynamics'],
relations: [{ to: 'dynamics', verb: 'shortcuts' }],
builtFrom: ['work', 'kinetic-energy', 'potential-energy', 'energy-conservation'],
produces: ['Speeds from heights, and a second check on every answer'],
},
],
},
domains: [
{ id: 'math', order: 0, label: 'Mathematical tools', shortLabel: 'Math', color: '#6B7280', tagline: 'The language mechanics is written in.' },
{ id: 'kinematics', order: 1, label: 'Kinematics', color: '#2563EB', tagline: 'Describing motion without asking why.' },
{ id: 'dynamics', order: 2, label: 'Dynamics', color: '#DC2626', tagline: 'Forces and how they change motion.' },
{ id: 'conservation', order: 3, label: 'Conservation laws', shortLabel: 'Conservation', color: '#059669', tagline: 'Quantities that stay the same, and what they let you skip.' },
{ id: 'beyond', order: 4, label: 'Beyond mechanics', shortLabel: 'Beyond', color: '#7C3AED', tagline: 'Where classical mechanics stops working.' },
],
nodes: [
// Mathematical tools
{ id: 'math-basics', label: 'Calculus and vectors', domain: 'math', kind: 'category', status: 'path', summary: 'The two tools every later idea uses.' },
{
id: 'vectors', label: 'Vectors', domain: 'math', kind: 'concept', status: 'path', parent: 'math-basics', stage: 'describe',
summary: 'Quantities with a size and a direction, like a displacement of 3 m north-east. Added tip to tail, and split into x and y components.',
docs: [wiki('Vectors', 'Euclidean_vector')], refs: [ref('openstax')],
},
{
id: 'derivatives', label: 'Derivatives', domain: 'math', kind: 'method', status: 'path', parent: 'math-basics', stage: 'describe',
summary: 'How fast one quantity changes as another does. Velocity is the derivative of position with respect to time.',
docs: [wiki('Derivative', 'Derivative')], refs: [ref('openstax')],
},
{
id: 'integrals', label: 'Integrals', domain: 'math', kind: 'method', status: 'context', parent: 'math-basics',
summary: 'The reverse of a derivative: from a velocity over time back to the distance covered.',
},
{
id: 'units', label: 'Dimensional analysis', domain: 'math', kind: 'method', status: 'context', parent: 'math-basics',
summary: 'Checking that the units on both sides of an equation match. Catches most algebra mistakes.',
},
// Kinematics
{ id: 'describing', label: 'Describing motion', domain: 'kinematics', kind: 'category', status: 'path', summary: 'The quantities.' },
{
id: 'velocity', label: 'Velocity', domain: 'kinematics', kind: 'concept', status: 'path', parent: 'describing', stage: 'describe',
summary: 'How fast position changes, and in which direction. Speed is its size.',
docs: [wiki('Velocity', 'Velocity')], refs: [ref('openstax')],
},
{
id: 'acceleration', label: 'Acceleration', domain: 'kinematics', kind: 'concept', status: 'path', parent: 'describing', stage: 'describe',
summary: 'How fast velocity changes. Braking, speeding up and turning are all acceleration.',
docs: [wiki('Acceleration', 'Acceleration')], refs: [ref('openstax')],
},
{
id: 'reference-frames', label: 'Reference frames', domain: 'kinematics', kind: 'concept', status: 'context', parent: 'describing',
summary: 'Motion is always measured relative to something. A ball dropped in a moving train falls straight down for the passenger.',
},
{ id: 'solving', label: 'Solving motion', domain: 'kinematics', kind: 'category', status: 'path', summary: 'Getting positions and times.' },
{
id: 'constant-acceleration', label: 'Constant-acceleration equations', domain: 'kinematics', kind: 'method', status: 'path', parent: 'solving', stage: 'projectile',
summary: 'Four equations linking position, velocity, acceleration and time when the acceleration does not change.',
docs: [wiki('Equations of motion', 'Equations_of_motion')], refs: [ref('openstax')],
},
{
id: 'numerical', label: 'Step-by-step simulation', domain: 'kinematics', kind: 'method', status: 'alternative', parent: 'solving', alternativeTo: 'constant-acceleration',
summary: 'Advancing the motion in small time steps on a computer. Works for any force, but hides the pattern; we solve by hand first.',
docs: [wiki('Numerical methods for ODEs', 'Numerical_methods_for_ordinary_differential_equations')],
},
{
id: 'free-fall', label: 'Free fall', domain: 'kinematics', kind: 'concept', status: 'path', parent: 'solving', stage: 'projectile',
summary: 'Near the ground everything falls with the same acceleration, g ≈ 9.8 m/s², if air resistance is small.',
docs: [wiki('Free fall', 'Free_fall')], refs: [ref('openstax')],
},
{
id: 'projectile-motion', label: 'Projectile motion', domain: 'kinematics', kind: 'concept', status: 'path', parent: 'solving', stage: 'projectile',
summary: 'A thrown object moves steadily sideways while falling freely. Treating the two directions separately is the whole trick.',
docs: [wiki('Projectile motion', 'Projectile_motion')], refs: [ref('openstax')],
},
{
id: 'circular-motion', label: 'Circular motion', domain: 'kinematics', kind: 'concept', status: 'context', parent: 'solving',
summary: 'Moving in a circle at constant speed is still acceleration, pointing to the centre.',
},
// Dynamics
{ id: 'newton', label: 'Newton’s laws', domain: 'dynamics', kind: 'category', status: 'path', summary: 'Why motion changes.' },
{
id: 'newtons-first', label: 'First law', domain: 'dynamics', kind: 'law', status: 'path', parent: 'newton', stage: 'forces',
summary: 'Without a net force, an object keeps its velocity. Motion does not need a cause; changes in motion do.',
docs: [wiki('Newton’s laws of motion', 'Newton%27s_laws_of_motion')], refs: [ref('openstax')],
},
{
id: 'newtons-second', label: 'Second law', domain: 'dynamics', kind: 'law', status: 'path', parent: 'newton', stage: 'forces',
summary: 'Net force equals mass times acceleration, F = ma. The bridge from forces to the kinematics you already know.',
docs: [wiki('Newton’s laws of motion', 'Newton%27s_laws_of_motion')], refs: [ref('openstax')],
},
{
id: 'newtons-third', label: 'Third law', domain: 'dynamics', kind: 'law', status: 'context', parent: 'newton',
summary: 'Forces come in pairs: if A pushes B, B pushes A equally hard the other way.',
},
{
id: 'lagrangian', label: 'Lagrangian mechanics', domain: 'dynamics', kind: 'method', status: 'alternative', parent: 'newton', alternativeTo: 'newtons-second',
summary: 'The same physics derived from energies instead of forces. More powerful for complicated systems; forces are easier to picture first.',
docs: [wiki('Lagrangian mechanics', 'Lagrangian_mechanics')],
},
{ id: 'forces', label: 'Kinds of force', domain: 'dynamics', kind: 'category', status: 'path', summary: 'What pushes and pulls.' },
{
id: 'free-body-diagram', label: 'Free-body diagram', domain: 'dynamics', kind: 'method', status: 'path', parent: 'forces', stage: 'forces',
summary: 'A sketch of one object with every force on it as an arrow. Almost every dynamics problem starts here.',
docs: [wiki('Free body diagram', 'Free_body_diagram')], refs: [ref('openstax')],
},
{
id: 'friction', label: 'Friction', domain: 'dynamics', kind: 'concept', status: 'path', parent: 'forces', stage: 'forces',
summary: 'The force that resists sliding, roughly proportional to how hard the surfaces are pressed together.',
docs: [wiki('Friction', 'Friction')], refs: [ref('openstax')],
},
{ id: 'springs', label: 'Spring force', domain: 'dynamics', kind: 'law', status: 'context', parent: 'forces', summary: 'A spring pulls back in proportion to how far it is stretched (Hooke’s law).' },
{ id: 'drag', label: 'Air resistance', domain: 'dynamics', kind: 'concept', status: 'context', parent: 'forces', summary: 'Grows with speed; the reason a feather and a hammer fall differently on Earth.' },
// Conservation laws
{ id: 'energy-group', label: 'Energy', domain: 'conservation', kind: 'category', status: 'path', summary: 'The quantity that is never lost.' },
{
id: 'work', label: 'Work', domain: 'conservation', kind: 'concept', status: 'path', parent: 'energy-group', stage: 'energy',
summary: 'Force times distance moved along it. The way forces put energy into or take it out of an object.',
docs: [wiki('Work', 'Work_(physics)')], refs: [ref('openstax')],
},
{
id: 'kinetic-energy', label: 'Kinetic energy', domain: 'conservation', kind: 'concept', status: 'path', parent: 'energy-group', stage: 'energy',
summary: 'Energy of motion, ½mv². Doubling the speed quadruples it.',
docs: [wiki('Kinetic energy', 'Kinetic_energy')], refs: [ref('openstax')],
},
{
id: 'potential-energy', label: 'Potential energy', domain: 'conservation', kind: 'concept', status: 'path', parent: 'energy-group', stage: 'energy',
summary: 'Energy stored by position, like mgh for height above the ground.',
docs: [wiki('Potential energy', 'Potential_energy')], refs: [ref('openstax')],
},
{
id: 'energy-conservation', label: 'Conservation of energy', domain: 'conservation', kind: 'law', status: 'path', parent: 'energy-group', stage: 'energy',
summary: 'Without friction, kinetic plus potential energy stays the same. With it, the missing energy has become heat.',
docs: [wiki('Conservation of energy', 'Conservation_of_energy')], refs: [ref('openstax')],
},
{ id: 'momentum-group', label: 'Momentum', domain: 'conservation', kind: 'category', status: 'context', summary: 'The other conserved quantity.' },
{ id: 'momentum', label: 'Momentum', domain: 'conservation', kind: 'concept', status: 'context', parent: 'momentum-group', summary: 'Mass times velocity. Conserved when no outside force acts, which makes collisions solvable.' },
{ id: 'collisions', label: 'Collisions', domain: 'conservation', kind: 'concept', status: 'context', parent: 'momentum-group', summary: 'Momentum is always conserved in a collision; kinetic energy only in elastic ones.' },
{ id: 'angular-momentum', label: 'Angular momentum', domain: 'conservation', kind: 'concept', status: 'context', parent: 'momentum-group', summary: 'Why a spinning skater speeds up when pulling in their arms.' },
// Beyond mechanics
{ id: 'limits', label: 'Where it breaks down', domain: 'beyond', kind: 'category', status: 'context', summary: 'Newton is an approximation.' },
{ id: 'relativity', label: 'Special relativity', domain: 'beyond', kind: 'concept', status: 'context', parent: 'limits', summary: 'Near the speed of light, time and length depend on who measures them.' },
{ id: 'quantum', label: 'Quantum mechanics', domain: 'beyond', kind: 'concept', status: 'context', parent: 'limits', summary: 'At atomic sizes, position and velocity cannot both be known exactly.' },
{ id: 'chaos', label: 'Chaos', domain: 'beyond', kind: 'concept', status: 'context', parent: 'limits', summary: 'Some systems follow Newton exactly yet cannot be predicted far ahead, like a double pendulum.' },
],
edges: [
{ from: 'velocity', to: 'derivatives', kind: 'is-defined-by' },
{ from: 'newtons-second', to: 'acceleration', kind: 'determines' },
{ from: 'free-fall', to: 'newtons-second', kind: 'follows-from', label: 'follows from' },
{ from: 'work', to: 'kinetic-energy', kind: 'changes' },
{ from: 'friction', to: 'energy-conservation', kind: 'turns-energy-into-heat', label: 'turns energy into heat in' },
{ from: 'integrals', to: 'constant-acceleration', kind: 'derives' },
{ from: 'momentum', to: 'newtons-third', kind: 'follows-from' },
],
stages: [
{
id: 'describe', period: 1, order: 1,
title: 'Describe a motion',
feeling: 'I can describe how something moves with numbers, not words.',
task: 'Film something moving, measure its position over time and turn that into velocity and acceleration.',
delivers: ['kinematics'],
waypoints: ['vectors', 'derivatives', 'velocity', 'acceleration'],
do: [
'Film a ball rolling across a table next to a ruler, with your phone.',
{ text: 'Step through the video and write down the position every 0.1 s.', tip: 'Most phones can play video frame by frame; at 30 fps, 0.1 s is every third frame.', tipKind: 'reveal' },
{ text: 'Work out the velocity between each pair of measurements.', nodes: ['velocity', 'derivatives'] },
],
observe: [
{ text: 'Is the velocity the same everywhere? Where does it change?', note: true, nodes: ['acceleration'] },
{ text: 'What would the numbers look like for a ball rolling downhill?', note: true },
],
read: ['vectors', 'derivatives', 'velocity', 'acceleration', 'reference-frames'],
checkpoint: 'From your own table of positions you can give the ball’s velocity and say whether it accelerated.',
refs: [ref('openstax')],
},
{
id: 'projectile', period: 1, order: 2,
title: 'Predict a throw',
feeling: 'I predicted where something would land before it did.',
task: 'Predict where a ball rolled off a table lands, then check.',
delivers: ['projectiles'],
waypoints: ['constant-acceleration', 'free-fall', 'projectile-motion'],
do: [
'Measure the table height and the speed of a ball rolling across it (as in stage 1).',
{ text: 'Predict how far from the table the ball lands.', tip: 'Fall time from the height: h = ½gt². Distance = speed × that time.', tipKind: 'reveal', nodes: ['projectile-motion'] },
'Mark the spot, roll the ball, and see.',
],
observe: [
{ text: 'How far off was your prediction? What could explain the difference?', note: true },
{ text: 'Did the sideways speed change during the fall?', nodes: ['projectile-motion'] },
],
read: ['constant-acceleration', 'free-fall', 'projectile-motion', 'numerical', 'drag'],
checkpoint: 'Your prediction lands within a few centimetres, and you can explain why sideways and downwards are separate.',
refs: [ref('openstax')],
},
{
id: 'forces', period: 2, order: 3,
title: 'Find the forces',
feeling: 'I can explain an acceleration from the forces that cause it.',
task: 'Pull a block along a table with a spring scale and explain its motion with Newton’s second law.',
delivers: ['dynamics'],
waypoints: ['newtons-first', 'newtons-second', 'free-body-diagram', 'friction'],
do: [
'Pull a block steadily with a spring scale and note the force needed to keep it moving at constant speed.',
{ text: 'Draw the free-body diagram for the block.', nodes: ['free-body-diagram'] },
{ text: 'Pull harder and work out the acceleration you expect.', tip: 'Net force = pull − friction; a = net force / mass.', tipKind: 'reveal', nodes: ['newtons-second'] },
],
observe: [
{ text: 'At constant speed, what is the net force? Why?', note: true, nodes: ['newtons-first'] },
{ text: 'Does friction change when you pull harder?', note: true, nodes: ['friction'] },
],
read: ['newtons-first', 'newtons-second', 'free-body-diagram', 'friction', 'newtons-third', 'lagrangian'],
checkpoint: 'You can draw the free-body diagram and predict the block’s acceleration from the pull, its mass and friction.',
refs: [ref('openstax')],
},
{
id: 'energy', period: 2, order: 4,
title: 'Take the shortcut',
feeling: 'I can get a speed from a height without following the motion.',
task: 'Predict a ball’s speed at the bottom of a ramp using energy, and compare with a force-based answer.',
delivers: ['energy'],
waypoints: ['work', 'kinetic-energy', 'potential-energy', 'energy-conservation'],
do: [
{ text: 'Predict the speed at the bottom of a ramp from its height alone.', tip: 'mgh = ½mv², so v = √(2gh). The mass cancels.', tipKind: 'reveal', nodes: ['energy-conservation'] },
'Measure the actual speed with the filming method from stage 1.',
],
observe: [
{ text: 'Why did you not need the ramp’s angle?', note: true, nodes: ['potential-energy'] },
{ text: 'Where did the missing energy go, if the measured speed is lower?', note: true, nodes: ['friction', 'work'] },
],
read: ['work', 'kinetic-energy', 'potential-energy', 'energy-conservation', 'momentum'],
checkpoint: 'You can predict the speed two ways — with forces and with energy — and explain why they differ.',
refs: [ref('openstax')],
},
],
});import { defineMap, docLink, ref } from 'onboarding-map';
/*
* Introductory mechanics for a first-year student: from describing motion to
* predicting it with forces and with energy. A small, complete example of a
* map outside software.
*/
const wiki = docLink('wikipedia', 'https://en.wikipedia.org/wiki/');
export default defineMap({
id: 'intro-mechanics',
version: '0.1.0',
title: 'Introductory mechanics',
motto: 'Predict first, then check.',
labels: {
intro:
'Four weeks from describing motion to predicting it. Follow the route; the rest of the map is physics you will meet later.',
period: 'Week',
tip: { label: 'Worked example', hint: 'Hint' },
aria: { map: 'Map of classical mechanics' },
refs: { heading: 'In the textbook' },
sources: { wikipedia: 'Wikipedia', textbook: 'Textbook' },
},
kinds: [
{ id: 'concept', label: 'Concept', plural: 'Concepts', description: 'A quantity or idea used to describe motion.' },
{ id: 'law', label: 'Law', plural: 'Laws', description: 'A statement about nature that experiments keep confirming.' },
{ id: 'method', label: 'Method', plural: 'Methods', description: 'A way of working out an answer.' },
],
periods: [
{ period: 1, title: 'Describing motion', summary: 'Where things are, how fast, and how that changes.' },
{ period: 2, title: 'Causes of motion', summary: 'Forces, and what energy lets you skip.' },
],
documents: [
{
id: 'openstax',
title: 'OpenStax University Physics, Volume 1',
date: '2016-09-19',
audience: 'First-year university students',
url: 'https://openstax.org/details/books/university-physics-volume-1',
},
],
goal: {
title: 'Predicting motion',
statement: 'You can predict how an object moves from the forces on it, and check the answer with energy.',
doneWhen: 'Given a ball thrown off a cliff or a block sliding down a ramp, you can predict where and how fast, two ways.',
story:
'Motion is described with vectors that change in time. Forces change that motion, by Newton’s second law. Energy is a shortcut: when it is conserved, it gives speeds without following the motion step by step.',
modules: [
{
id: 'kinematics',
title: 'Describing motion',
purpose: 'You can only predict what you can describe.',
dependsOn: [],
builtFrom: ['vectors', 'derivatives', 'velocity', 'acceleration'],
produces: ['Position, velocity and acceleration of anything, as vectors'],
refs: [ref('openstax')],
},
{
id: 'projectiles',
title: 'Projectiles',
purpose: 'The first motion you can predict completely.',
dependsOn: ['kinematics'],
relations: [{ to: 'kinematics', verb: 'applies' }],
builtFrom: ['constant-acceleration', 'free-fall', 'projectile-motion'],
produces: ['Where a thrown object lands, and when'],
},
{
id: 'dynamics',
title: 'Forces',
purpose: 'Explains why the acceleration is what it is.',
dependsOn: ['kinematics'],
relations: [{ to: 'kinematics', verb: 'explains' }],
builtFrom: ['newtons-first', 'newtons-second', 'free-body-diagram', 'friction'],
produces: ['The acceleration of an object from the forces on it'],
},
{
id: 'energy',
title: 'Energy',
purpose: 'Answers “how fast?” without following the motion.',
dependsOn: ['dynamics'],
relations: [{ to: 'dynamics', verb: 'shortcuts' }],
builtFrom: ['work', 'kinetic-energy', 'potential-energy', 'energy-conservation'],
produces: ['Speeds from heights, and a second check on every answer'],
},
],
},
domains: [
{ id: 'math', order: 0, label: 'Mathematical tools', shortLabel: 'Math', color: '#6B7280', tagline: 'The language mechanics is written in.' },
{ id: 'kinematics', order: 1, label: 'Kinematics', color: '#2563EB', tagline: 'Describing motion without asking why.' },
{ id: 'dynamics', order: 2, label: 'Dynamics', color: '#DC2626', tagline: 'Forces and how they change motion.' },
{ id: 'conservation', order: 3, label: 'Conservation laws', shortLabel: 'Conservation', color: '#059669', tagline: 'Quantities that stay the same, and what they let you skip.' },
{ id: 'beyond', order: 4, label: 'Beyond mechanics', shortLabel: 'Beyond', color: '#7C3AED', tagline: 'Where classical mechanics stops working.' },
],
nodes: [
// Mathematical tools
{ id: 'math-basics', label: 'Calculus and vectors', domain: 'math', kind: 'category', status: 'path', summary: 'The two tools every later idea uses.' },
{
id: 'vectors', label: 'Vectors', domain: 'math', kind: 'concept', status: 'path', parent: 'math-basics', stage: 'describe',
summary: 'Quantities with a size and a direction, like a displacement of 3 m north-east. Added tip to tail, and split into x and y components.',
docs: [wiki('Vectors', 'Euclidean_vector')], refs: [ref('openstax')],
},
{
id: 'derivatives', label: 'Derivatives', domain: 'math', kind: 'method', status: 'path', parent: 'math-basics', stage: 'describe',
summary: 'How fast one quantity changes as another does. Velocity is the derivative of position with respect to time.',
docs: [wiki('Derivative', 'Derivative')], refs: [ref('openstax')],
},
{
id: 'integrals', label: 'Integrals', domain: 'math', kind: 'method', status: 'context', parent: 'math-basics',
summary: 'The reverse of a derivative: from a velocity over time back to the distance covered.',
},
{
id: 'units', label: 'Dimensional analysis', domain: 'math', kind: 'method', status: 'context', parent: 'math-basics',
summary: 'Checking that the units on both sides of an equation match. Catches most algebra mistakes.',
},
// Kinematics
{ id: 'describing', label: 'Describing motion', domain: 'kinematics', kind: 'category', status: 'path', summary: 'The quantities.' },
{
id: 'velocity', label: 'Velocity', domain: 'kinematics', kind: 'concept', status: 'path', parent: 'describing', stage: 'describe',
summary: 'How fast position changes, and in which direction. Speed is its size.',
docs: [wiki('Velocity', 'Velocity')], refs: [ref('openstax')],
},
{
id: 'acceleration', label: 'Acceleration', domain: 'kinematics', kind: 'concept', status: 'path', parent: 'describing', stage: 'describe',
summary: 'How fast velocity changes. Braking, speeding up and turning are all acceleration.',
docs: [wiki('Acceleration', 'Acceleration')], refs: [ref('openstax')],
},
{
id: 'reference-frames', label: 'Reference frames', domain: 'kinematics', kind: 'concept', status: 'context', parent: 'describing',
summary: 'Motion is always measured relative to something. A ball dropped in a moving train falls straight down for the passenger.',
},
{ id: 'solving', label: 'Solving motion', domain: 'kinematics', kind: 'category', status: 'path', summary: 'Getting positions and times.' },
{
id: 'constant-acceleration', label: 'Constant-acceleration equations', domain: 'kinematics', kind: 'method', status: 'path', parent: 'solving', stage: 'projectile',
summary: 'Four equations linking position, velocity, acceleration and time when the acceleration does not change.',
docs: [wiki('Equations of motion', 'Equations_of_motion')], refs: [ref('openstax')],
},
{
id: 'numerical', label: 'Step-by-step simulation', domain: 'kinematics', kind: 'method', status: 'alternative', parent: 'solving', alternativeTo: 'constant-acceleration',
summary: 'Advancing the motion in small time steps on a computer. Works for any force, but hides the pattern; we solve by hand first.',
docs: [wiki('Numerical methods for ODEs', 'Numerical_methods_for_ordinary_differential_equations')],
},
{
id: 'free-fall', label: 'Free fall', domain: 'kinematics', kind: 'concept', status: 'path', parent: 'solving', stage: 'projectile',
summary: 'Near the ground everything falls with the same acceleration, g ≈ 9.8 m/s², if air resistance is small.',
docs: [wiki('Free fall', 'Free_fall')], refs: [ref('openstax')],
},
{
id: 'projectile-motion', label: 'Projectile motion', domain: 'kinematics', kind: 'concept', status: 'path', parent: 'solving', stage: 'projectile',
summary: 'A thrown object moves steadily sideways while falling freely. Treating the two directions separately is the whole trick.',
docs: [wiki('Projectile motion', 'Projectile_motion')], refs: [ref('openstax')],
},
{
id: 'circular-motion', label: 'Circular motion', domain: 'kinematics', kind: 'concept', status: 'context', parent: 'solving',
summary: 'Moving in a circle at constant speed is still acceleration, pointing to the centre.',
},
// Dynamics
{ id: 'newton', label: 'Newton’s laws', domain: 'dynamics', kind: 'category', status: 'path', summary: 'Why motion changes.' },
{
id: 'newtons-first', label: 'First law', domain: 'dynamics', kind: 'law', status: 'path', parent: 'newton', stage: 'forces',
summary: 'Without a net force, an object keeps its velocity. Motion does not need a cause; changes in motion do.',
docs: [wiki('Newton’s laws of motion', 'Newton%27s_laws_of_motion')], refs: [ref('openstax')],
},
{
id: 'newtons-second', label: 'Second law', domain: 'dynamics', kind: 'law', status: 'path', parent: 'newton', stage: 'forces',
summary: 'Net force equals mass times acceleration, F = ma. The bridge from forces to the kinematics you already know.',
docs: [wiki('Newton’s laws of motion', 'Newton%27s_laws_of_motion')], refs: [ref('openstax')],
},
{
id: 'newtons-third', label: 'Third law', domain: 'dynamics', kind: 'law', status: 'context', parent: 'newton',
summary: 'Forces come in pairs: if A pushes B, B pushes A equally hard the other way.',
},
{
id: 'lagrangian', label: 'Lagrangian mechanics', domain: 'dynamics', kind: 'method', status: 'alternative', parent: 'newton', alternativeTo: 'newtons-second',
summary: 'The same physics derived from energies instead of forces. More powerful for complicated systems; forces are easier to picture first.',
docs: [wiki('Lagrangian mechanics', 'Lagrangian_mechanics')],
},
{ id: 'forces', label: 'Kinds of force', domain: 'dynamics', kind: 'category', status: 'path', summary: 'What pushes and pulls.' },
{
id: 'free-body-diagram', label: 'Free-body diagram', domain: 'dynamics', kind: 'method', status: 'path', parent: 'forces', stage: 'forces',
summary: 'A sketch of one object with every force on it as an arrow. Almost every dynamics problem starts here.',
docs: [wiki('Free body diagram', 'Free_body_diagram')], refs: [ref('openstax')],
},
{
id: 'friction', label: 'Friction', domain: 'dynamics', kind: 'concept', status: 'path', parent: 'forces', stage: 'forces',
summary: 'The force that resists sliding, roughly proportional to how hard the surfaces are pressed together.',
docs: [wiki('Friction', 'Friction')], refs: [ref('openstax')],
},
{ id: 'springs', label: 'Spring force', domain: 'dynamics', kind: 'law', status: 'context', parent: 'forces', summary: 'A spring pulls back in proportion to how far it is stretched (Hooke’s law).' },
{ id: 'drag', label: 'Air resistance', domain: 'dynamics', kind: 'concept', status: 'context', parent: 'forces', summary: 'Grows with speed; the reason a feather and a hammer fall differently on Earth.' },
// Conservation laws
{ id: 'energy-group', label: 'Energy', domain: 'conservation', kind: 'category', status: 'path', summary: 'The quantity that is never lost.' },
{
id: 'work', label: 'Work', domain: 'conservation', kind: 'concept', status: 'path', parent: 'energy-group', stage: 'energy',
summary: 'Force times distance moved along it. The way forces put energy into or take it out of an object.',
docs: [wiki('Work', 'Work_(physics)')], refs: [ref('openstax')],
},
{
id: 'kinetic-energy', label: 'Kinetic energy', domain: 'conservation', kind: 'concept', status: 'path', parent: 'energy-group', stage: 'energy',
summary: 'Energy of motion, ½mv². Doubling the speed quadruples it.',
docs: [wiki('Kinetic energy', 'Kinetic_energy')], refs: [ref('openstax')],
},
{
id: 'potential-energy', label: 'Potential energy', domain: 'conservation', kind: 'concept', status: 'path', parent: 'energy-group', stage: 'energy',
summary: 'Energy stored by position, like mgh for height above the ground.',
docs: [wiki('Potential energy', 'Potential_energy')], refs: [ref('openstax')],
},
{
id: 'energy-conservation', label: 'Conservation of energy', domain: 'conservation', kind: 'law', status: 'path', parent: 'energy-group', stage: 'energy',
summary: 'Without friction, kinetic plus potential energy stays the same. With it, the missing energy has become heat.',
docs: [wiki('Conservation of energy', 'Conservation_of_energy')], refs: [ref('openstax')],
},
{ id: 'momentum-group', label: 'Momentum', domain: 'conservation', kind: 'category', status: 'context', summary: 'The other conserved quantity.' },
{ id: 'momentum', label: 'Momentum', domain: 'conservation', kind: 'concept', status: 'context', parent: 'momentum-group', summary: 'Mass times velocity. Conserved when no outside force acts, which makes collisions solvable.' },
{ id: 'collisions', label: 'Collisions', domain: 'conservation', kind: 'concept', status: 'context', parent: 'momentum-group', summary: 'Momentum is always conserved in a collision; kinetic energy only in elastic ones.' },
{ id: 'angular-momentum', label: 'Angular momentum', domain: 'conservation', kind: 'concept', status: 'context', parent: 'momentum-group', summary: 'Why a spinning skater speeds up when pulling in their arms.' },
// Beyond mechanics
{ id: 'limits', label: 'Where it breaks down', domain: 'beyond', kind: 'category', status: 'context', summary: 'Newton is an approximation.' },
{ id: 'relativity', label: 'Special relativity', domain: 'beyond', kind: 'concept', status: 'context', parent: 'limits', summary: 'Near the speed of light, time and length depend on who measures them.' },
{ id: 'quantum', label: 'Quantum mechanics', domain: 'beyond', kind: 'concept', status: 'context', parent: 'limits', summary: 'At atomic sizes, position and velocity cannot both be known exactly.' },
{ id: 'chaos', label: 'Chaos', domain: 'beyond', kind: 'concept', status: 'context', parent: 'limits', summary: 'Some systems follow Newton exactly yet cannot be predicted far ahead, like a double pendulum.' },
],
edges: [
{ from: 'velocity', to: 'derivatives', kind: 'is-defined-by' },
{ from: 'newtons-second', to: 'acceleration', kind: 'determines' },
{ from: 'free-fall', to: 'newtons-second', kind: 'follows-from', label: 'follows from' },
{ from: 'work', to: 'kinetic-energy', kind: 'changes' },
{ from: 'friction', to: 'energy-conservation', kind: 'turns-energy-into-heat', label: 'turns energy into heat in' },
{ from: 'integrals', to: 'constant-acceleration', kind: 'derives' },
{ from: 'momentum', to: 'newtons-third', kind: 'follows-from' },
],
stages: [
{
id: 'describe', period: 1, order: 1,
title: 'Describe a motion',
feeling: 'I can describe how something moves with numbers, not words.',
task: 'Film something moving, measure its position over time and turn that into velocity and acceleration.',
delivers: ['kinematics'],
waypoints: ['vectors', 'derivatives', 'velocity', 'acceleration'],
do: [
'Film a ball rolling across a table next to a ruler, with your phone.',
{ text: 'Step through the video and write down the position every 0.1 s.', tip: 'Most phones can play video frame by frame; at 30 fps, 0.1 s is every third frame.', tipKind: 'reveal' },
{ text: 'Work out the velocity between each pair of measurements.', nodes: ['velocity', 'derivatives'] },
],
observe: [
{ text: 'Is the velocity the same everywhere? Where does it change?', note: true, nodes: ['acceleration'] },
{ text: 'What would the numbers look like for a ball rolling downhill?', note: true },
],
read: ['vectors', 'derivatives', 'velocity', 'acceleration', 'reference-frames'],
checkpoint: 'From your own table of positions you can give the ball’s velocity and say whether it accelerated.',
refs: [ref('openstax')],
},
{
id: 'projectile', period: 1, order: 2,
title: 'Predict a throw',
feeling: 'I predicted where something would land before it did.',
task: 'Predict where a ball rolled off a table lands, then check.',
delivers: ['projectiles'],
waypoints: ['constant-acceleration', 'free-fall', 'projectile-motion'],
do: [
'Measure the table height and the speed of a ball rolling across it (as in stage 1).',
{ text: 'Predict how far from the table the ball lands.', tip: 'Fall time from the height: h = ½gt². Distance = speed × that time.', tipKind: 'reveal', nodes: ['projectile-motion'] },
'Mark the spot, roll the ball, and see.',
],
observe: [
{ text: 'How far off was your prediction? What could explain the difference?', note: true },
{ text: 'Did the sideways speed change during the fall?', nodes: ['projectile-motion'] },
],
read: ['constant-acceleration', 'free-fall', 'projectile-motion', 'numerical', 'drag'],
checkpoint: 'Your prediction lands within a few centimetres, and you can explain why sideways and downwards are separate.',
refs: [ref('openstax')],
},
{
id: 'forces', period: 2, order: 3,
title: 'Find the forces',
feeling: 'I can explain an acceleration from the forces that cause it.',
task: 'Pull a block along a table with a spring scale and explain its motion with Newton’s second law.',
delivers: ['dynamics'],
waypoints: ['newtons-first', 'newtons-second', 'free-body-diagram', 'friction'],
do: [
'Pull a block steadily with a spring scale and note the force needed to keep it moving at constant speed.',
{ text: 'Draw the free-body diagram for the block.', nodes: ['free-body-diagram'] },
{ text: 'Pull harder and work out the acceleration you expect.', tip: 'Net force = pull − friction; a = net force / mass.', tipKind: 'reveal', nodes: ['newtons-second'] },
],
observe: [
{ text: 'At constant speed, what is the net force? Why?', note: true, nodes: ['newtons-first'] },
{ text: 'Does friction change when you pull harder?', note: true, nodes: ['friction'] },
],
read: ['newtons-first', 'newtons-second', 'free-body-diagram', 'friction', 'newtons-third', 'lagrangian'],
checkpoint: 'You can draw the free-body diagram and predict the block’s acceleration from the pull, its mass and friction.',
refs: [ref('openstax')],
},
{
id: 'energy', period: 2, order: 4,
title: 'Take the shortcut',
feeling: 'I can get a speed from a height without following the motion.',
task: 'Predict a ball’s speed at the bottom of a ramp using energy, and compare with a force-based answer.',
delivers: ['energy'],
waypoints: ['work', 'kinetic-energy', 'potential-energy', 'energy-conservation'],
do: [
{ text: 'Predict the speed at the bottom of a ramp from its height alone.', tip: 'mgh = ½mv², so v = √(2gh). The mass cancels.', tipKind: 'reveal', nodes: ['energy-conservation'] },
'Measure the actual speed with the filming method from stage 1.',
],
observe: [
{ text: 'Why did you not need the ramp’s angle?', note: true, nodes: ['potential-energy'] },
{ text: 'Where did the missing energy go, if the measured speed is lower?', note: true, nodes: ['friction', 'work'] },
],
read: ['work', 'kinetic-energy', 'potential-energy', 'energy-conservation', 'momentum'],
checkpoint: 'You can predict the speed two ways — with forces and with energy — and explain why they differ.',
refs: [ref('openstax')],
},
],
});This documentation
Section titled “This documentation”The map of this project. It describes the package and route through its contributor work; the docs site you are reading is built from the same one-file format.
import { defineMap, docLink } from 'onboarding-map';
/*
* A map of onboarding-map itself: how someone goes from "I have a subject to
* onboard people into" to "a map I can send". It is the example the docs show,
* and it is written by hand in one file, like any other map.
*/
const docs = docLink('docs', 'https://chidirnweke.github.io/onboarding-map/');
const github = docLink('github', 'https://github.com/ChidiRnweke/onboarding-map');
export default defineMap({
id: 'onboarding-map',
version: '0.1.0',
title: 'Make your own onboarding map',
motto: 'Bring your subject. Get a map.',
labels: {
intro: 'One file describes your subject. The package draws it as a map you can send.',
period: 'Part',
},
kinds: [
{ id: 'concept', label: 'Idea', plural: 'Ideas', description: 'Something to understand.' },
{ id: 'tool', label: 'Step', plural: 'Steps', description: 'Something you do.' },
],
periods: [
{
period: 1,
title: 'See and describe',
summary: 'Look at an example, then say what you are onboarding someone into.',
},
{ period: 2, title: 'Shape and share', summary: 'Draw one path, check the map, and publish it.' },
],
documents: [
{
id: 'docs',
title: 'The documentation',
date: '2026-09-27',
url: 'https://chidirnweke.github.io/onboarding-map/',
},
{
id: 'github',
title: 'The repository',
date: '2026-09-27',
url: 'https://github.com/ChidiRnweke/onboarding-map',
},
],
goal: {
title: 'A map you can send',
statement: 'Your subject written as one file, drawn as a map a newcomer can follow.',
doneWhen: 'Someone follows your map from the first stage to the last and ends up with something real.',
story:
'A map is two things at once. It is everything a newcomer will run into, so nothing feels hidden. And it is one path through that, so they are never deciding what to learn next.',
modules: [
{
id: 'example',
title: 'A walked example',
purpose: 'You cannot judge a map until you have followed one.',
dependsOn: [],
builtFrom: ['starter-example', 'physics-example', 'example-data'],
produces: ['An example you have read and clicked through'],
},
{
id: 'brief',
title: 'A brief',
purpose: 'The map is only as good as what you decide it is about.',
dependsOn: ['example'],
relations: [{ to: 'example', verb: 'is clearer after' }],
builtFrom: ['audience', 'outcome', 'sources'],
produces: ['Who is onboarding, what they should be able to do, and where the material is'],
},
{
id: 'mapfile',
title: 'A first draft',
purpose: 'The subject becomes a file, by hand or with an agent.',
dependsOn: ['brief'],
relations: [{ to: 'brief', verb: 'is written from' }],
builtFrom: ['map-file', 'agent-skills', 'draft-prompt'],
produces: ['A map.ts with regions and items'],
},
{
id: 'route',
title: 'One path',
purpose: 'Choosing a single route is what keeps the map from overwhelming the reader.',
dependsOn: ['mapfile'],
relations: [{ to: 'mapfile', verb: 'is drawn on' }],
builtFrom: ['route', 'stages', 'checkpoint', 'goal'],
produces: ['A journey with a beginning, stages, and a way to know it is done'],
},
{
id: 'checked',
title: 'A checked map',
purpose: 'Links break and content ages; the tool finds both.',
dependsOn: ['route'],
relations: [{ to: 'route', verb: 'checks' }],
builtFrom: ['validate', 'audit', 'changelog'],
produces: ['A map whose references resolve and whose content is current'],
},
{
id: 'published',
title: 'A published map',
purpose: 'A map nobody can open is not a map.',
dependsOn: ['checked'],
relations: [{ to: 'checked', verb: 'is built from' }],
builtFrom: ['build', 'host'],
produces: ['A static site you can send to the newcomer'],
},
],
},
domains: [
{ id: 'start', label: 'Start', tagline: 'See one first', order: 0, color: '#22c55e' },
{ id: 'subject', label: 'Your subject', tagline: 'What you bring', order: 1, color: '#14b8a6' },
{ id: 'agent', label: 'Your agent', tagline: 'The heavy lifting', order: 2, color: '#a855f7' },
{ id: 'map', label: 'The map', tagline: 'The file and its path', order: 3, color: '#3b82f6' },
{ id: 'tool', label: 'Checking and sharing', tagline: 'The tool', order: 4, color: '#f59e0b' },
{ id: 'project', label: 'This project', tagline: 'Where it comes from', order: 5, color: '#64748b' },
],
nodes: [
{
id: 'the-idea',
label: 'Why a map',
domain: 'start',
kind: 'category',
status: 'path',
summary: 'The problem the map solves.',
},
{
id: 'newcomer-problem',
label: 'The reading pile',
domain: 'start',
kind: 'concept',
status: 'context',
parent: 'the-idea',
summary:
'Everything a newcomer needs is written down somewhere, but as separate documents for people who already know the system.',
refs: [{ doc: 'docs' }],
},
{
id: 'one-route',
label: 'One path',
domain: 'start',
kind: 'concept',
status: 'context',
parent: 'the-idea',
summary:
'The map shows everything, but asks the newcomer to follow only one route. The rest is there to recognise, not to learn first.',
},
{
id: 'examples',
label: 'Examples',
domain: 'start',
kind: 'category',
status: 'path',
summary: 'Two maps to look at before you make your own.',
},
{
id: 'starter-example',
refs: [{ doc: 'docs' }],
label: 'Starter example',
domain: 'start',
kind: 'concept',
status: 'path',
parent: 'examples',
stage: 'see',
summary: 'The smallest useful map: two regions, a handful of items, two stages.',
docs: [docs('The starter template', 'user-guide/examples/')],
},
{
id: 'physics-example',
refs: [{ doc: 'docs' }],
label: 'Physics example',
domain: 'start',
kind: 'concept',
status: 'path',
parent: 'examples',
stage: 'see',
summary: 'A complete map outside software: motion, forces and energy, with a full route.',
docs: [docs('The physics template', 'user-guide/examples/')],
},
{
id: 'example-data',
refs: [{ doc: 'docs' }],
label: 'The data behind it',
domain: 'start',
kind: 'concept',
status: 'path',
parent: 'examples',
stage: 'see',
summary: 'Every map is one file. The examples page shows the map and the file next to each other.',
docs: [docs('Examples, map and data', 'user-guide/examples/')],
},
{
id: 'your-subject',
label: 'Your subject',
domain: 'subject',
kind: 'category',
status: 'path',
summary: 'What you decide the map is about.',
},
{
id: 'audience',
refs: [{ doc: 'docs' }],
docs: [docs('How it works', 'user-guide/how-it-works/')],
label: 'Who is arriving',
domain: 'subject',
kind: 'concept',
status: 'path',
parent: 'your-subject',
stage: 'brief',
summary: 'Who is being onboarded, and what they already know. It sets the level of every summary.',
},
{
id: 'outcome',
refs: [{ doc: 'docs' }],
docs: [docs('How it works', 'user-guide/how-it-works/')],
label: 'What they can do',
domain: 'subject',
kind: 'concept',
status: 'path',
parent: 'your-subject',
stage: 'brief',
summary: 'The thing that exists when the onboarding is done. The stages exist to build it.',
},
{
id: 'sources',
label: 'Your material',
docs: [docs('Working with your agent', 'user-guide/working-with-your-agent/')],
domain: 'subject',
kind: 'concept',
status: 'path',
parent: 'your-subject',
stage: 'brief',
summary:
'Notes, slides, a syllabus, a codebase. The map is based on these, and cites them, so it can be refreshed later.',
refs: [{ doc: 'docs' }],
},
{
id: 'existing-docs',
label: 'Docs you already have',
domain: 'subject',
kind: 'concept',
status: 'context',
parent: 'your-subject',
summary:
'Existing documentation stays where it is. The map links to it at the right moment instead of copying it.',
},
{
id: 'the-file',
label: 'The file',
domain: 'map',
kind: 'category',
status: 'path',
summary: 'One file holds the whole map.',
},
{
id: 'map-file',
refs: [{ doc: 'docs' }],
label: 'map.ts',
domain: 'map',
kind: 'tool',
status: 'path',
parent: 'the-file',
stage: 'draft',
summary:
'Your subject as one TypeScript file. Types come from the package, so mistakes show up in your editor.',
docs: [github('The templates', '/tree/main/templates')],
},
{
id: 'hand-write',
docs: [docs('Writing a map', 'user-guide/writing-a-map/')],
label: 'Write it yourself',
domain: 'map',
kind: 'tool',
status: 'alternative',
alternativeTo: 'map-file',
parent: 'the-file',
summary:
'You can write the file by hand. Nothing here needs an agent; the format is the whole interface.',
},
{
id: 'json-map',
docs: [docs('Writing a map', 'user-guide/writing-a-map/')],
label: 'map.json',
domain: 'map',
kind: 'tool',
status: 'alternative',
alternativeTo: 'map-file',
parent: 'the-file',
summary: 'Use JSON instead of TypeScript when another tool needs to write the map.',
},
{
id: 'the-journey',
label: 'The journey',
domain: 'map',
kind: 'category',
status: 'path',
summary: 'The one path through everything.',
},
{
id: 'route',
label: 'The route',
refs: [{ doc: 'docs' }],
docs: [docs('How it works', 'user-guide/how-it-works/')],
domain: 'map',
kind: 'concept',
status: 'path',
parent: 'the-journey',
stage: 'route',
summary:
'The items the newcomer actually uses, in order. Everything else is context or a choice you did not take.',
},
{
id: 'stages',
refs: [{ doc: 'docs' }],
docs: [docs('How it works', 'user-guide/how-it-works/')],
label: 'Stages',
domain: 'map',
kind: 'concept',
status: 'path',
parent: 'the-journey',
stage: 'route',
summary:
'The route cut into stages. Each one is small, and follows the same shape: do something, watch what happens, then read about it.',
},
{
id: 'checkpoint',
refs: [{ doc: 'docs' }],
docs: [docs('How it works', 'user-guide/how-it-works/')],
label: 'Checkpoint',
domain: 'map',
kind: 'concept',
status: 'path',
parent: 'the-journey',
stage: 'route',
summary: 'How the newcomer knows a stage is finished: something they can see, not a feeling.',
},
{
id: 'goal',
refs: [{ doc: 'docs' }],
docs: [docs('How it works', 'user-guide/how-it-works/')],
label: 'The goal',
domain: 'map',
kind: 'concept',
status: 'path',
parent: 'the-journey',
stage: 'route',
summary: 'What the whole journey builds, shown as parts that fill in as the stages go.',
},
{
id: 'context-items',
label: 'Good to know it exists',
domain: 'map',
kind: 'concept',
status: 'context',
parent: 'the-journey',
summary: 'Items off the route. Cheap to add, and they make the map honest about what is out there.',
},
{
id: 'with-an-agent',
label: 'With an agent',
domain: 'agent',
kind: 'category',
status: 'path',
summary: 'Let a coding agent do the first draft.',
},
{
id: 'agent-skills',
refs: [{ doc: 'docs' }],
label: 'The skills',
domain: 'agent',
kind: 'concept',
status: 'path',
parent: 'with-an-agent',
stage: 'draft',
summary:
'The package installs instructions for Claude Code, Codex and other tools: how to write, edit and refresh a map.',
docs: [github('The skills', '/tree/main/skills')],
},
{
id: 'draft-prompt',
refs: [{ doc: 'docs' }],
docs: [docs('Working with your agent', 'user-guide/working-with-your-agent/')],
label: 'Ask for a draft',
domain: 'agent',
kind: 'tool',
status: 'path',
parent: 'with-an-agent',
stage: 'draft',
summary:
'Point the agent at your material and ask it to turn it into a map. Read the result; you decide the route.',
},
{
id: 'the-checks',
label: 'The checks',
domain: 'tool',
kind: 'category',
status: 'path',
summary: 'The command line keeps the map true.',
},
{
id: 'validate',
refs: [{ doc: 'docs' }],
label: 'validate',
domain: 'tool',
kind: 'tool',
status: 'path',
parent: 'the-checks',
stage: 'check',
summary: 'Checks that every reference in the file resolves, and names the ones that do not.',
docs: [docs('Command line', 'reference/cli/')],
},
{
id: 'audit',
refs: [{ doc: 'docs' }],
docs: [docs('Command line', 'reference/cli/')],
label: 'audit',
domain: 'tool',
kind: 'tool',
status: 'path',
parent: 'the-checks',
stage: 'check',
summary:
'Finds the content that has gone stale: dead links, missing sources, route items nobody is sent to.',
},
{
id: 'changelog',
refs: [{ doc: 'docs' }],
docs: [docs('Command line', 'reference/cli/')],
label: 'changelog',
domain: 'tool',
kind: 'tool',
status: 'path',
parent: 'the-checks',
stage: 'check',
summary: 'Shows what changed since the last commit, as a short summary for review.',
},
{
id: 'dev-server',
label: 'See it as you write',
domain: 'tool',
kind: 'tool',
status: 'context',
parent: 'the-checks',
summary: 'The dev command serves the map and reloads it on every save.',
},
{
id: 'publish',
label: 'Publish',
domain: 'tool',
kind: 'category',
status: 'path',
summary: 'Turn the file into a site.',
},
{
id: 'build',
refs: [{ doc: 'docs' }],
docs: [docs('Command line', 'reference/cli/')],
label: 'build',
domain: 'tool',
kind: 'tool',
status: 'path',
parent: 'publish',
stage: 'share',
summary: 'Writes a static site: your map plus the app that draws it.',
},
{
id: 'host',
refs: [{ doc: 'docs' }],
docs: [docs('Command line', 'reference/cli/')],
label: 'Any static host',
domain: 'tool',
kind: 'concept',
status: 'path',
parent: 'publish',
stage: 'share',
summary:
'The output is plain files. There is no server and no account; progress is kept in the reader’s browser.',
},
{
id: 'static-shell',
label: 'The app shell',
domain: 'tool',
kind: 'concept',
status: 'context',
parent: 'publish',
summary: 'One prebuilt app renders any map. Your map file is all that changes.',
},
{
id: 'codebase',
label: 'The codebase',
domain: 'project',
kind: 'category',
status: 'context',
summary: 'What the package is made of.',
},
{
id: 'core',
label: 'The model',
domain: 'project',
kind: 'concept',
status: 'context',
parent: 'codebase',
summary: 'Types, validation and derivation. It runs in Node and the browser, and has no UI.',
docs: [github('src/core', '/tree/main/src/core')],
},
{
id: 'cli',
label: 'The command line',
domain: 'project',
kind: 'concept',
status: 'context',
parent: 'codebase',
summary: 'init, dev, build, validate, changelog, audit, schema and skills install.',
},
{
id: 'app-shell-code',
label: 'The app',
domain: 'project',
kind: 'concept',
status: 'context',
parent: 'codebase',
summary: 'The SvelteKit shell that draws the map and walks the stages.',
},
{
id: 'templates-code',
label: 'The templates',
domain: 'project',
kind: 'concept',
status: 'context',
parent: 'codebase',
summary: 'starter and physics; the two examples this map points at.',
},
{
id: 'docs-site',
label: 'This documentation',
domain: 'project',
kind: 'concept',
status: 'context',
parent: 'codebase',
summary:
'Astro and Starlight, wearing the map’s own palette. The page you are reading is part of the repository.',
docs: [github('docs', '/tree/main/docs')],
},
],
edges: [
{ from: 'agent-skills', to: 'sources', kind: 'drafts-from' },
{ from: 'validate', to: 'map-file', kind: 'checks' },
{ from: 'audit', to: 'map-file', kind: 'checks' },
{ from: 'build', to: 'map-file', kind: 'renders' },
{ from: 'route', to: 'outcome', kind: 'builds-toward' },
],
stages: [
{
id: 'see',
period: 1,
order: 1,
title: 'See one',
feeling: 'I know what a finished map looks like.',
task: 'Open the two examples and follow a stage or two.',
delivers: ['example'],
waypoints: ['starter-example', 'physics-example', 'example-data'],
do: [
'Open the examples page and click around the physics map.',
{
text: 'Switch to the data view and find one item in the file.',
tip: 'The map and the file are shown side by side.',
tipKind: 'reveal',
},
],
observe: [{ text: 'Which items are on the route, and which are just context?', note: true }],
read: ['starter-example', 'example-data', 'one-route'],
checkpoint: 'You can point at one item and say why it is on the route.',
refs: [{ doc: 'docs' }],
},
{
id: 'brief',
period: 1,
refs: [{ doc: 'docs' }],
order: 2,
title: 'Say what it is about',
feeling: 'I can describe who this is for and what they should be able to do.',
task: 'Write down who is arriving, what they can do at the end, and where the material lives.',
delivers: ['brief'],
waypoints: ['audience', 'outcome', 'sources'],
do: [
'Write one sentence for each: who, and what they can do at the end.',
{ text: 'List the documents, slides or repositories the map is based on.', note: true },
],
observe: [{ text: 'Does the outcome describe something you could check, not a feeling?', note: true }],
read: ['outcome', 'sources', 'existing-docs'],
checkpoint: 'You have a short brief you could hand to another person.',
},
{
id: 'draft',
period: 2,
refs: [{ doc: 'docs' }],
order: 3,
title: 'Draft the map',
feeling: 'The subject exists as a file I can run.',
task: 'Start a project and get a first version of the file, by hand or with an agent.',
delivers: ['mapfile'],
waypoints: ['agent-skills', 'draft-prompt', 'map-file'],
do: [
{ text: 'Start a project from a template.', tip: 'npx onboarding-map init my-map' },
{
text: 'Ask your coding agent to turn your brief and sources into a map.',
tip: 'Turn these notes into an onboarding map.',
tipKind: 'copy',
},
],
observe: [{ text: 'What did the agent put on the route that you would not?', note: true }],
read: ['map-file', 'agent-skills', 'hand-write'],
checkpoint: 'The map opens in the dev server without errors.',
},
{
id: 'route',
period: 2,
order: 4,
title: 'Choose one path',
feeling: 'I know exactly what the newcomer does, in order.',
task: 'Mark the items the newcomer will use, and cut them into stages.',
delivers: ['route'],
waypoints: ['route', 'stages', 'checkpoint', 'goal'],
do: [
'Move anything the newcomer will not touch off the route.',
'Cut the route into stages, each with one idea.',
],
observe: [{ text: 'Does every stage end with something you can see?', note: true }],
read: ['stages', 'checkpoint', 'goal', 'context-items'],
checkpoint: 'Every stage has a checkpoint a newcomer could demonstrate.',
refs: [{ doc: 'docs' }],
},
{
id: 'check',
period: 2,
refs: [{ doc: 'docs' }],
order: 5,
title: 'Check it',
feeling: 'I trust the map: it resolves, and I know what is unfinished.',
task: 'Run the checks and fix what they report.',
delivers: ['checked'],
waypoints: ['validate', 'audit', 'changelog'],
do: [
{ text: 'Validate and fix every error.', tip: 'npx onboarding-map validate --json' },
{ text: 'Audit for stale or unfinished content.', tip: 'npx onboarding-map audit' },
],
observe: [{ text: 'What did the audit find that you had forgotten?', note: true }],
read: ['validate', 'audit', 'changelog', 'dev-server'],
checkpoint: 'validate reports no errors and you have read the audit findings.',
},
{
id: 'share',
period: 2,
refs: [{ doc: 'docs' }],
order: 6,
title: 'Share it',
feeling: 'I can send this to the next person who joins.',
task: 'Build the static site and put it somewhere people can open it.',
delivers: ['published'],
waypoints: ['build', 'host'],
do: [
{ text: 'Build the site.', tip: 'npx onboarding-map build' },
'Upload the output folder to any static host.',
],
observe: [{ text: 'Open the map on a phone. Is the route still easy to follow?', note: true }],
read: ['build', 'host', 'static-shell'],
checkpoint: 'Someone else opens your map and starts the first stage.',
},
],
});import { defineMap, docLink } from 'onboarding-map';
/*
* A map of onboarding-map itself: how someone goes from "I have a subject to
* onboard people into" to "a map I can send". It is the example the docs show,
* and it is written by hand in one file, like any other map.
*/
const docs = docLink('docs', 'https://chidirnweke.github.io/onboarding-map/');
const github = docLink('github', 'https://github.com/ChidiRnweke/onboarding-map');
export default defineMap({
id: 'onboarding-map',
version: '0.1.0',
title: 'Make your own onboarding map',
motto: 'Bring your subject. Get a map.',
labels: {
intro: 'One file describes your subject. The package draws it as a map you can send.',
period: 'Part',
},
kinds: [
{ id: 'concept', label: 'Idea', plural: 'Ideas', description: 'Something to understand.' },
{ id: 'tool', label: 'Step', plural: 'Steps', description: 'Something you do.' },
],
periods: [
{
period: 1,
title: 'See and describe',
summary: 'Look at an example, then say what you are onboarding someone into.',
},
{ period: 2, title: 'Shape and share', summary: 'Draw one path, check the map, and publish it.' },
],
documents: [
{
id: 'docs',
title: 'The documentation',
date: '2026-09-27',
url: 'https://chidirnweke.github.io/onboarding-map/',
},
{
id: 'github',
title: 'The repository',
date: '2026-09-27',
url: 'https://github.com/ChidiRnweke/onboarding-map',
},
],
goal: {
title: 'A map you can send',
statement: 'Your subject written as one file, drawn as a map a newcomer can follow.',
doneWhen: 'Someone follows your map from the first stage to the last and ends up with something real.',
story:
'A map is two things at once. It is everything a newcomer will run into, so nothing feels hidden. And it is one path through that, so they are never deciding what to learn next.',
modules: [
{
id: 'example',
title: 'A walked example',
purpose: 'You cannot judge a map until you have followed one.',
dependsOn: [],
builtFrom: ['starter-example', 'physics-example', 'example-data'],
produces: ['An example you have read and clicked through'],
},
{
id: 'brief',
title: 'A brief',
purpose: 'The map is only as good as what you decide it is about.',
dependsOn: ['example'],
relations: [{ to: 'example', verb: 'is clearer after' }],
builtFrom: ['audience', 'outcome', 'sources'],
produces: ['Who is onboarding, what they should be able to do, and where the material is'],
},
{
id: 'mapfile',
title: 'A first draft',
purpose: 'The subject becomes a file, by hand or with an agent.',
dependsOn: ['brief'],
relations: [{ to: 'brief', verb: 'is written from' }],
builtFrom: ['map-file', 'agent-skills', 'draft-prompt'],
produces: ['A map.ts with regions and items'],
},
{
id: 'route',
title: 'One path',
purpose: 'Choosing a single route is what keeps the map from overwhelming the reader.',
dependsOn: ['mapfile'],
relations: [{ to: 'mapfile', verb: 'is drawn on' }],
builtFrom: ['route', 'stages', 'checkpoint', 'goal'],
produces: ['A journey with a beginning, stages, and a way to know it is done'],
},
{
id: 'checked',
title: 'A checked map',
purpose: 'Links break and content ages; the tool finds both.',
dependsOn: ['route'],
relations: [{ to: 'route', verb: 'checks' }],
builtFrom: ['validate', 'audit', 'changelog'],
produces: ['A map whose references resolve and whose content is current'],
},
{
id: 'published',
title: 'A published map',
purpose: 'A map nobody can open is not a map.',
dependsOn: ['checked'],
relations: [{ to: 'checked', verb: 'is built from' }],
builtFrom: ['build', 'host'],
produces: ['A static site you can send to the newcomer'],
},
],
},
domains: [
{ id: 'start', label: 'Start', tagline: 'See one first', order: 0, color: '#22c55e' },
{ id: 'subject', label: 'Your subject', tagline: 'What you bring', order: 1, color: '#14b8a6' },
{ id: 'agent', label: 'Your agent', tagline: 'The heavy lifting', order: 2, color: '#a855f7' },
{ id: 'map', label: 'The map', tagline: 'The file and its path', order: 3, color: '#3b82f6' },
{ id: 'tool', label: 'Checking and sharing', tagline: 'The tool', order: 4, color: '#f59e0b' },
{ id: 'project', label: 'This project', tagline: 'Where it comes from', order: 5, color: '#64748b' },
],
nodes: [
{
id: 'the-idea',
label: 'Why a map',
domain: 'start',
kind: 'category',
status: 'path',
summary: 'The problem the map solves.',
},
{
id: 'newcomer-problem',
label: 'The reading pile',
domain: 'start',
kind: 'concept',
status: 'context',
parent: 'the-idea',
summary:
'Everything a newcomer needs is written down somewhere, but as separate documents for people who already know the system.',
refs: [{ doc: 'docs' }],
},
{
id: 'one-route',
label: 'One path',
domain: 'start',
kind: 'concept',
status: 'context',
parent: 'the-idea',
summary:
'The map shows everything, but asks the newcomer to follow only one route. The rest is there to recognise, not to learn first.',
},
{
id: 'examples',
label: 'Examples',
domain: 'start',
kind: 'category',
status: 'path',
summary: 'Two maps to look at before you make your own.',
},
{
id: 'starter-example',
refs: [{ doc: 'docs' }],
label: 'Starter example',
domain: 'start',
kind: 'concept',
status: 'path',
parent: 'examples',
stage: 'see',
summary: 'The smallest useful map: two regions, a handful of items, two stages.',
docs: [docs('The starter template', 'user-guide/examples/')],
},
{
id: 'physics-example',
refs: [{ doc: 'docs' }],
label: 'Physics example',
domain: 'start',
kind: 'concept',
status: 'path',
parent: 'examples',
stage: 'see',
summary: 'A complete map outside software: motion, forces and energy, with a full route.',
docs: [docs('The physics template', 'user-guide/examples/')],
},
{
id: 'example-data',
refs: [{ doc: 'docs' }],
label: 'The data behind it',
domain: 'start',
kind: 'concept',
status: 'path',
parent: 'examples',
stage: 'see',
summary: 'Every map is one file. The examples page shows the map and the file next to each other.',
docs: [docs('Examples, map and data', 'user-guide/examples/')],
},
{
id: 'your-subject',
label: 'Your subject',
domain: 'subject',
kind: 'category',
status: 'path',
summary: 'What you decide the map is about.',
},
{
id: 'audience',
refs: [{ doc: 'docs' }],
docs: [docs('How it works', 'user-guide/how-it-works/')],
label: 'Who is arriving',
domain: 'subject',
kind: 'concept',
status: 'path',
parent: 'your-subject',
stage: 'brief',
summary: 'Who is being onboarded, and what they already know. It sets the level of every summary.',
},
{
id: 'outcome',
refs: [{ doc: 'docs' }],
docs: [docs('How it works', 'user-guide/how-it-works/')],
label: 'What they can do',
domain: 'subject',
kind: 'concept',
status: 'path',
parent: 'your-subject',
stage: 'brief',
summary: 'The thing that exists when the onboarding is done. The stages exist to build it.',
},
{
id: 'sources',
label: 'Your material',
docs: [docs('Working with your agent', 'user-guide/working-with-your-agent/')],
domain: 'subject',
kind: 'concept',
status: 'path',
parent: 'your-subject',
stage: 'brief',
summary:
'Notes, slides, a syllabus, a codebase. The map is based on these, and cites them, so it can be refreshed later.',
refs: [{ doc: 'docs' }],
},
{
id: 'existing-docs',
label: 'Docs you already have',
domain: 'subject',
kind: 'concept',
status: 'context',
parent: 'your-subject',
summary:
'Existing documentation stays where it is. The map links to it at the right moment instead of copying it.',
},
{
id: 'the-file',
label: 'The file',
domain: 'map',
kind: 'category',
status: 'path',
summary: 'One file holds the whole map.',
},
{
id: 'map-file',
refs: [{ doc: 'docs' }],
label: 'map.ts',
domain: 'map',
kind: 'tool',
status: 'path',
parent: 'the-file',
stage: 'draft',
summary:
'Your subject as one TypeScript file. Types come from the package, so mistakes show up in your editor.',
docs: [github('The templates', '/tree/main/templates')],
},
{
id: 'hand-write',
docs: [docs('Writing a map', 'user-guide/writing-a-map/')],
label: 'Write it yourself',
domain: 'map',
kind: 'tool',
status: 'alternative',
alternativeTo: 'map-file',
parent: 'the-file',
summary:
'You can write the file by hand. Nothing here needs an agent; the format is the whole interface.',
},
{
id: 'json-map',
docs: [docs('Writing a map', 'user-guide/writing-a-map/')],
label: 'map.json',
domain: 'map',
kind: 'tool',
status: 'alternative',
alternativeTo: 'map-file',
parent: 'the-file',
summary: 'Use JSON instead of TypeScript when another tool needs to write the map.',
},
{
id: 'the-journey',
label: 'The journey',
domain: 'map',
kind: 'category',
status: 'path',
summary: 'The one path through everything.',
},
{
id: 'route',
label: 'The route',
refs: [{ doc: 'docs' }],
docs: [docs('How it works', 'user-guide/how-it-works/')],
domain: 'map',
kind: 'concept',
status: 'path',
parent: 'the-journey',
stage: 'route',
summary:
'The items the newcomer actually uses, in order. Everything else is context or a choice you did not take.',
},
{
id: 'stages',
refs: [{ doc: 'docs' }],
docs: [docs('How it works', 'user-guide/how-it-works/')],
label: 'Stages',
domain: 'map',
kind: 'concept',
status: 'path',
parent: 'the-journey',
stage: 'route',
summary:
'The route cut into stages. Each one is small, and follows the same shape: do something, watch what happens, then read about it.',
},
{
id: 'checkpoint',
refs: [{ doc: 'docs' }],
docs: [docs('How it works', 'user-guide/how-it-works/')],
label: 'Checkpoint',
domain: 'map',
kind: 'concept',
status: 'path',
parent: 'the-journey',
stage: 'route',
summary: 'How the newcomer knows a stage is finished: something they can see, not a feeling.',
},
{
id: 'goal',
refs: [{ doc: 'docs' }],
docs: [docs('How it works', 'user-guide/how-it-works/')],
label: 'The goal',
domain: 'map',
kind: 'concept',
status: 'path',
parent: 'the-journey',
stage: 'route',
summary: 'What the whole journey builds, shown as parts that fill in as the stages go.',
},
{
id: 'context-items',
label: 'Good to know it exists',
domain: 'map',
kind: 'concept',
status: 'context',
parent: 'the-journey',
summary: 'Items off the route. Cheap to add, and they make the map honest about what is out there.',
},
{
id: 'with-an-agent',
label: 'With an agent',
domain: 'agent',
kind: 'category',
status: 'path',
summary: 'Let a coding agent do the first draft.',
},
{
id: 'agent-skills',
refs: [{ doc: 'docs' }],
label: 'The skills',
domain: 'agent',
kind: 'concept',
status: 'path',
parent: 'with-an-agent',
stage: 'draft',
summary:
'The package installs instructions for Claude Code, Codex and other tools: how to write, edit and refresh a map.',
docs: [github('The skills', '/tree/main/skills')],
},
{
id: 'draft-prompt',
refs: [{ doc: 'docs' }],
docs: [docs('Working with your agent', 'user-guide/working-with-your-agent/')],
label: 'Ask for a draft',
domain: 'agent',
kind: 'tool',
status: 'path',
parent: 'with-an-agent',
stage: 'draft',
summary:
'Point the agent at your material and ask it to turn it into a map. Read the result; you decide the route.',
},
{
id: 'the-checks',
label: 'The checks',
domain: 'tool',
kind: 'category',
status: 'path',
summary: 'The command line keeps the map true.',
},
{
id: 'validate',
refs: [{ doc: 'docs' }],
label: 'validate',
domain: 'tool',
kind: 'tool',
status: 'path',
parent: 'the-checks',
stage: 'check',
summary: 'Checks that every reference in the file resolves, and names the ones that do not.',
docs: [docs('Command line', 'reference/cli/')],
},
{
id: 'audit',
refs: [{ doc: 'docs' }],
docs: [docs('Command line', 'reference/cli/')],
label: 'audit',
domain: 'tool',
kind: 'tool',
status: 'path',
parent: 'the-checks',
stage: 'check',
summary:
'Finds the content that has gone stale: dead links, missing sources, route items nobody is sent to.',
},
{
id: 'changelog',
refs: [{ doc: 'docs' }],
docs: [docs('Command line', 'reference/cli/')],
label: 'changelog',
domain: 'tool',
kind: 'tool',
status: 'path',
parent: 'the-checks',
stage: 'check',
summary: 'Shows what changed since the last commit, as a short summary for review.',
},
{
id: 'dev-server',
label: 'See it as you write',
domain: 'tool',
kind: 'tool',
status: 'context',
parent: 'the-checks',
summary: 'The dev command serves the map and reloads it on every save.',
},
{
id: 'publish',
label: 'Publish',
domain: 'tool',
kind: 'category',
status: 'path',
summary: 'Turn the file into a site.',
},
{
id: 'build',
refs: [{ doc: 'docs' }],
docs: [docs('Command line', 'reference/cli/')],
label: 'build',
domain: 'tool',
kind: 'tool',
status: 'path',
parent: 'publish',
stage: 'share',
summary: 'Writes a static site: your map plus the app that draws it.',
},
{
id: 'host',
refs: [{ doc: 'docs' }],
docs: [docs('Command line', 'reference/cli/')],
label: 'Any static host',
domain: 'tool',
kind: 'concept',
status: 'path',
parent: 'publish',
stage: 'share',
summary:
'The output is plain files. There is no server and no account; progress is kept in the reader’s browser.',
},
{
id: 'static-shell',
label: 'The app shell',
domain: 'tool',
kind: 'concept',
status: 'context',
parent: 'publish',
summary: 'One prebuilt app renders any map. Your map file is all that changes.',
},
{
id: 'codebase',
label: 'The codebase',
domain: 'project',
kind: 'category',
status: 'context',
summary: 'What the package is made of.',
},
{
id: 'core',
label: 'The model',
domain: 'project',
kind: 'concept',
status: 'context',
parent: 'codebase',
summary: 'Types, validation and derivation. It runs in Node and the browser, and has no UI.',
docs: [github('src/core', '/tree/main/src/core')],
},
{
id: 'cli',
label: 'The command line',
domain: 'project',
kind: 'concept',
status: 'context',
parent: 'codebase',
summary: 'init, dev, build, validate, changelog, audit, schema and skills install.',
},
{
id: 'app-shell-code',
label: 'The app',
domain: 'project',
kind: 'concept',
status: 'context',
parent: 'codebase',
summary: 'The SvelteKit shell that draws the map and walks the stages.',
},
{
id: 'templates-code',
label: 'The templates',
domain: 'project',
kind: 'concept',
status: 'context',
parent: 'codebase',
summary: 'starter and physics; the two examples this map points at.',
},
{
id: 'docs-site',
label: 'This documentation',
domain: 'project',
kind: 'concept',
status: 'context',
parent: 'codebase',
summary:
'Astro and Starlight, wearing the map’s own palette. The page you are reading is part of the repository.',
docs: [github('docs', '/tree/main/docs')],
},
],
edges: [
{ from: 'agent-skills', to: 'sources', kind: 'drafts-from' },
{ from: 'validate', to: 'map-file', kind: 'checks' },
{ from: 'audit', to: 'map-file', kind: 'checks' },
{ from: 'build', to: 'map-file', kind: 'renders' },
{ from: 'route', to: 'outcome', kind: 'builds-toward' },
],
stages: [
{
id: 'see',
period: 1,
order: 1,
title: 'See one',
feeling: 'I know what a finished map looks like.',
task: 'Open the two examples and follow a stage or two.',
delivers: ['example'],
waypoints: ['starter-example', 'physics-example', 'example-data'],
do: [
'Open the examples page and click around the physics map.',
{
text: 'Switch to the data view and find one item in the file.',
tip: 'The map and the file are shown side by side.',
tipKind: 'reveal',
},
],
observe: [{ text: 'Which items are on the route, and which are just context?', note: true }],
read: ['starter-example', 'example-data', 'one-route'],
checkpoint: 'You can point at one item and say why it is on the route.',
refs: [{ doc: 'docs' }],
},
{
id: 'brief',
period: 1,
refs: [{ doc: 'docs' }],
order: 2,
title: 'Say what it is about',
feeling: 'I can describe who this is for and what they should be able to do.',
task: 'Write down who is arriving, what they can do at the end, and where the material lives.',
delivers: ['brief'],
waypoints: ['audience', 'outcome', 'sources'],
do: [
'Write one sentence for each: who, and what they can do at the end.',
{ text: 'List the documents, slides or repositories the map is based on.', note: true },
],
observe: [{ text: 'Does the outcome describe something you could check, not a feeling?', note: true }],
read: ['outcome', 'sources', 'existing-docs'],
checkpoint: 'You have a short brief you could hand to another person.',
},
{
id: 'draft',
period: 2,
refs: [{ doc: 'docs' }],
order: 3,
title: 'Draft the map',
feeling: 'The subject exists as a file I can run.',
task: 'Start a project and get a first version of the file, by hand or with an agent.',
delivers: ['mapfile'],
waypoints: ['agent-skills', 'draft-prompt', 'map-file'],
do: [
{ text: 'Start a project from a template.', tip: 'npx onboarding-map init my-map' },
{
text: 'Ask your coding agent to turn your brief and sources into a map.',
tip: 'Turn these notes into an onboarding map.',
tipKind: 'copy',
},
],
observe: [{ text: 'What did the agent put on the route that you would not?', note: true }],
read: ['map-file', 'agent-skills', 'hand-write'],
checkpoint: 'The map opens in the dev server without errors.',
},
{
id: 'route',
period: 2,
order: 4,
title: 'Choose one path',
feeling: 'I know exactly what the newcomer does, in order.',
task: 'Mark the items the newcomer will use, and cut them into stages.',
delivers: ['route'],
waypoints: ['route', 'stages', 'checkpoint', 'goal'],
do: [
'Move anything the newcomer will not touch off the route.',
'Cut the route into stages, each with one idea.',
],
observe: [{ text: 'Does every stage end with something you can see?', note: true }],
read: ['stages', 'checkpoint', 'goal', 'context-items'],
checkpoint: 'Every stage has a checkpoint a newcomer could demonstrate.',
refs: [{ doc: 'docs' }],
},
{
id: 'check',
period: 2,
refs: [{ doc: 'docs' }],
order: 5,
title: 'Check it',
feeling: 'I trust the map: it resolves, and I know what is unfinished.',
task: 'Run the checks and fix what they report.',
delivers: ['checked'],
waypoints: ['validate', 'audit', 'changelog'],
do: [
{ text: 'Validate and fix every error.', tip: 'npx onboarding-map validate --json' },
{ text: 'Audit for stale or unfinished content.', tip: 'npx onboarding-map audit' },
],
observe: [{ text: 'What did the audit find that you had forgotten?', note: true }],
read: ['validate', 'audit', 'changelog', 'dev-server'],
checkpoint: 'validate reports no errors and you have read the audit findings.',
},
{
id: 'share',
period: 2,
refs: [{ doc: 'docs' }],
order: 6,
title: 'Share it',
feeling: 'I can send this to the next person who joins.',
task: 'Build the static site and put it somewhere people can open it.',
delivers: ['published'],
waypoints: ['build', 'host'],
do: [
{ text: 'Build the site.', tip: 'npx onboarding-map build' },
'Upload the output folder to any static host.',
],
observe: [{ text: 'Open the map on a phone. Is the route still easy to follow?', note: true }],
read: ['build', 'host', 'static-shell'],
checkpoint: 'Someone else opens your map and starts the first stage.',
},
],
});