Diagram data reference
A Blueprint Deck is one HTML file. The diagram itself is the JSON in the block at the top of that file:
<script type="application/json" id="bd-data">
{ "meta": { … }, "zones": [ … ], "nodes": [ … ], … }
</script>
<!-- ===== BD-ENGINE … do not edit below this line ===== -->
Everything after that block is the engine (the same in every diagram). The engine fills in defaults, lays out the
boxes, validates the data and renders it when the file opens; there is no build step. Problems are shown on screen,
in the console ([diagram-errors], [diagram-warnings]), in window.__diagramIssues, in the editor’s Check tab,
and by node tools/check.mjs <file> if Node is available.
Text fields may contain inline HTML (<b>, <i>, <br>). Escape a literal < as <; write </ as <\/
(the editor and the tools do this when they save). Coordinates are world pixels; the camera scales the world to the screen.
Top level
{
"meta": { ... }, // required
"hero": { ... }, // start screen; omit or set settings.hero=false to skip it
"settings": { ... }, // behaviour; everything has a default
"theme": { ... }, // look: preset, colours, shape
"status": { ... }, // optional status tags on boxes (MVP/Next/Later, Running/Planned, …)
"frame": { ... }, // optional labelled frame around all zones that are ours
"zones": [ ... ], // required: the areas
"nodes": [ ... ], // required: the boxes
"edges": [ ... ], // connections
"groups": { ... }, // named node sets, referenced as "@name"
"lenses": [ ... ], // tabs; the first one is the overview
"personas": [ ... ], // optional: who uses it, each with a path through the map (becomes a tab + list)
"lists": { ... }, // clickable lists shown in a panel (usage patterns, options …)
"tour": [ ... ], // guided tour steps
"roadmap": { ... }, // optional phases → tour steps + a roadmap sheet
"overlays": [ ... ], // optional full-screen sheets (options, sizing, pricing …)
"icons": { ... } // optional extra icons: { "name": "<path d=…/>" } (24×24, stroke)
}
meta
{ "title": "Private AI Platform", "subtitle": "Product blueprint · Phase 0", "type": "architecture",
"viewpoint": "product", "language": "en", "logo": "icon:shield", "url": "https://example.com" }
type:architecture|data-flow|process|journey|ecosystem|org|custom. Sets the UI wording (legend, panel kicker, tour hint), e.g. “Step” / “External party” for a process. Layout rules per type: style guide.viewpoint:product|mixed(default) |technical. Decides how much technology the side panels show (settings.panel.tech) and how the content is written (style guide). Product = what it does for whom; technical = components, protocols, technology choices and exit paths.logo:icon:<name>, an inline<svg …>, adata:URI (PNG/SVG/JPG, stored in the file), or 1–3 letters.url: clicking the logo opens it (company or product website).
hero
{
"eyebrow": "Product blueprint",
"title": "Private AI Platform",
"lead": "One or two sentences: what it is and for whom.",
"pillars": [ { "icon": "route", "color": "#a78bfa", "title": "Control", "text": "One line of value" } ],
"footnote": "An intended product, not yet built · based on docs/ · use ← → in the tour"
}
Up to 4 pillars look best.
settings (all optional)
{
"hero": true, // show the start screen
"legend": "collapsed", // collapsed (small pill, opens on click) | open | false
"editor": true, // E opens the editor; false locks the file (the ⋯ menu then only exports)
"keyboard": true, // ← → Space Esc F + - P (PDF) E (edit) 1–9 (switch diagram)
"tour": { "position": "auto" }, // auto (right sidebar on landscape screens, else bottom) | right | bottom
"camera": { "zoomToFocus": true, "maxZoom": 1.25, "nodeZoom": 1.15, "zoneZoom": 1.3, "padding": 24 },
"edges": { "filterByContext": true, // inside a tab/step, clicks and hovers show only that tab's edge groups
"raiseOnHover": true, // a hovered box's connections are drawn above the boxes
"labels": "focus", // focus = labels on highlighted edges | never
"particles": "main", // main = dots on the main flow and highlighted edges | focus = only highlighted | off
"mainFlow": "req", // edge group drawn brighter (with dots) in the overview
"overview": "all" }, // edges in the overview: all (faint) | main (only mainFlow) | none
"motion": { "intro": true }, // boxes pop in on load
"panel": { "sections": ["what", "why", "pick", "alt", "links", "sources"], "showSources": true,
"tech": "pick" }, // full = pick + alternatives & exit path | pick = pick only | off; default from meta.viewpoint
"personas": { "tab": true }, // personas get their own tab
"layout": { "grid": { "columns": [280, 280, 640, 380, 300], "rows": [660, 290, 220], "gap": 40, "origin": [60, 230] } },
"labels": { "inside": "Platform component", "outside": "Outside the platform", "what": "What it is", ... }
}
labels overrides any UI string, so the whole UI can be translated: inside, outside, area, boundary
({ours, customer, partner, external}), hint, what, why, pick, alt, links, partOf, sources, overview,
points, components, clickOne, showAll, tour, startTour, explore, back, next, finish, fullRoadmap,
tourHint, legend, personas, personasSub.
theme
{ "preset": "light", "primary": "#0d9488", "secondary": "#7c3aed", "shape": "rounded", "font": "Inter, sans-serif" }
preset: darkmidnight(default: navy, blue and violet),blueprint(navy, blueprint blue and cyan),graphite(neutral),forest(green),ember(dark red); lightlight,paper(warm).primary/secondary: the brand colours (buttons, highlights, the logo tile, progress). Lighter and darker shades are derived automatically and adjusted for light or dark presets.accent/accentAltare accepted as older names.shape:rounded|square|pill.vars: overrides any CSS variable (bg,ink,glass,node-a,node-b,muted,body,font,r-node…).
status
{
"toggleLabel": "MVP scope", "toggleTitle": "Show what is in the MVP and what comes later", "default": true,
"values": [
{ "id": "mvp", "label": "MVP", "long": "In the MVP", "color": "#6ee7b7" },
{ "id": "next", "label": "Next", "long": "Next horizon", "color": "#fcd34d", "dashed": true },
{ "id": "later", "label": "Later", "long": "Later", "color": "#cbd5e1", "dashed": true }
]
}
A node gets a tag with "status": "mvp". dashed also draws the box border dashed while tags are shown.
frame
{ "label": "<b>Private AI platform</b> · Kubernetes · open source only", "margin": 25 }
Without x/y/w/h it wraps all zones that are ours (not external or partner).
zones
{ "id": "gateway", "title": "LLM gateway", "sub": "C2 · C3", "color": "#a78bfa",
"grid": [2, 0], // or explicit "x", "y", "w", "h"; grid = [col, row, colSpan?, rowSpan?]
"boundary": "ours", // ours (default) | customer | partner | external
"base": false, // neutral grey: a foundation layer spanning several columns
"frame": true, // false: keep this zone out of the automatic frame
"tag": "U1", // small pill on the right of the header (replaces the boundary badge)
"icon": "layers",
"layout": { "columns": 2, "gap": 16, "padding": 20, "top": 55 },
"desc": "Panel overview: 2–4 sentences.",
"points": ["Key point", "Key point"],
"sources": ["docs/02-product-scope-mvp.md#C2"] }
boundary makes clear what is not yours: external (third-party services, users’ own apps; dashed border, “External”
badge, legend entry), partner (dashed, “Partner”), customer (dotted, “Customer-owned”, e.g. the customer’s data
centre or VPC). "outside": true is the older name for external. "boundaryTag": false hides the badge.
Each zone needs a 6-digit hex color; its nodes inherit it. Keep headers short: title + sub + badge must fit the zone width.
nodes
{ "id": "llm-gw", "zone": "gateway", "title": "Unified model API", "sub": "LiteLLM · one OpenAI-compatible endpoint",
"icon": "route", "size": "big", "badge": "C2", "status": "mvp",
"what": "1–3 plain sentences: what it is and does here.",
"why": ["2–4 bullets: why it matters to the audience"],
"pick": "Technology pick and why (optional)",
"alt": "Alternatives and exit path (optional)",
"extra": [ { "title": "Sizing", "text": "Paragraph or [\"bullets\"]" } ],
"sources": ["docs/02-product-scope-mvp.md#C2", "docs/06-product-decision-log.md#DL7"],
"kind": "Platform component" }
Placement: omit x/y to let the zone place it (in array order, filling layout.columns; "span": 2 for a wider box),
or give x, y, w, h explicitly. Defaults: w = column width (240 if explicit), h = 64 (normal) or 110 (size: "big").
compact: true uses a smaller title in big boxes. A normal box shows one line of subtitle (cut with …); a big box wraps to two.
icon: a name from reference/icons.md, a name from the diagram’s icons, or an image (data: URI).
edges
Object or array form:
{ "from": "llm-gw", "to": "kserve", "groups": ["req", "serve"], "label": "U2 / U3 · local model", "dashed": false }
["llm-gw", "kserve", ["req", "serve"], "U2 / U3 · local model"]
from/to may be "zone:<id>" to connect to a whole zone. groups are free-form ids: tabs and tour steps select
which groups are shown. dashed = optional/planned connection. The edge takes the colour of its from side’s zone;
set "color": "#hex" to override. Shape: a connection leaves sideways when the boxes are apart horizontally and the
horizontal offset is more than ~0.45× the vertical offset; otherwise it leaves from the top or bottom. That decides
which boxes it passes. A connection that would run through other boxes is better attached to a whole zone
("zone:<id>") or avoided by reordering; the checks warn when it runs through a box that is highlighted with it.
groups
{ "req-core": ["c-apps", "ingress", "llm-gw"], "oss": ["@req-core", "kserve"] }
Use "@req-core" in any nodes or path list.
lenses (tabs)
{ "id": "gov", "title": "Governance & audit", "color": "#f43f5e",
"nodes": ["@gov-core"], "zones": ["guard", "audit"], // what lights up (zones = all their nodes)
"edges": ["gov", "audit"], // which edge groups light up; ["none"] = no edges
"list": "patterns", // optional: open this list in the side panel
"fit": "all", "camZones": ["edge"] } // optional camera: whole map / these zones
The first lens is the overview and normally has no nodes.
personas
[ { "id": "owner", "tag": "A1", "title": "Platform owner", "sub": "Make AI available to every team, governed", "icon": "user-cog",
"text": "Pains and how the product serves them, 1–3 sentences.", "color": "#60a5fa",
"path": ["c-ops", "console", "llm-gw", "keys", "metrics"], // ordered: their way through the map
"nodes": ["dashboards"], // optional: also highlighted, not numbered
"edges": ["ops"], // optional: also light these edge groups
"zone": "users" } ] // optional: also a box on the map, in this zone
Personas become a Personas tab (unless settings.personas.tab is false) that opens the list personas in the
side panel; a tour step can show it too with "list": "personas". icon replaces the tag in the list.
Picking one highlights its path: the boxes are numbered 1, 2, 3 … in order, the connections between consecutive
steps light up, and the panel lists the steps.
With zone, the persona is also a box on the map in that zone (before the zone’s other boxes), with a connection
to the first step of its path; that connection only shows when the persona is picked or hovered. Clicking the box opens
the Personas panel with that persona picked. The box uses the persona’s id (default persona-<n>), title, sub,
icon (default user) and color. The box shows boxSub if given (a short subtitle that fits a box), else sub; set badge for a badge on the box. Use path when the order means something (how they use it), nodes
for what they rely on without an order.
lists
"patterns": { "title": "Usage patterns", "eyebrow": "How inference is served", "sub": "…", "icon": "route", "color": "#f59e0b",
"intro": "Shown above the items.", "edges": ["req", "serve"],
"items": [ { "tag": "U1", "title": "Gateway to cloud LLMs", "sub": "…", "text": "…", "color": "#22d3ee",
"nodes": ["@req-core", "cloudapi"], "path": ["c-apps", "llm-gw", "cloudapi"], "withInside": false } ] }
Clicking an item highlights its nodes and path (plus every inside node if withInside) and the edges of
item.edges, else the list’s edges; with neither, every edge between highlighted nodes lights up. With a path,
the path’s connections light up and the boxes are numbered. Open a list from a lens or tour step with "list": "<id>".
tour
{ "title": "One API for every model", "text": "60–110 words.", "nodes": [...], "zones": [...], "edges": ["req"],
"summary": [["Bold", "one line"], ["Bold", "one line"]], // optional 2–6 tiles
"list": "patterns", // optional clickable list in the card
"overlay": "pilot", // optional: render an overlay's blocks as a wide sheet
"blocks": [0, 1], // optional: only these blocks of the overlay (by index)
"fit": "all", "camZones": ["edge"] }
{ "roadmap": true } // expands to one step per roadmap phase
roadmap
{ "title": "Roadmap", "lead": "How phases are paced.", "buttonLabel": "Roadmap", "buttonOpens": "tour",
"phases": [ { "when": "NOW", "title": "Build the governed core", "main": true, "text": "Tour text for this phase.",
"items": [ { "title": "E1 · Governed gateway core", "text": "Outcome …", "note": "depends on Q2", "nodes": ["llm-gw"] } ] } ],
"notes": [ { "title": "Runtime decision", "text": "…" } ] }
The roadmap button starts a tour through the phases (buttonOpens: "overlay" opens the full roadmap sheet instead).
overlays
{ "id": "pilot", "title": "Pilot options", "eyebrow": "Private AI Platform", "lead": "…", "icon": "rocket",
"buttonLabel": "Pilot options", "button": true,
"blocks": [
{ "type": "cards", "columns": 3, "cards": [ { "tag": "Option A", "title": "…", "text": "…", "main": false, "rows": [["Effort", "~26–52 MD"]] } ] },
{ "type": "note", "title": "Recommendation", "text": "…" },
{ "type": "grid", "title": "Success criteria", "columns": 3, "items": [["In active use", "…"]] },
{ "type": "text", "title": "Assumptions", "text": "…" },
{ "type": "roadmap" } ] }
"button": false hides the overlay’s top-bar button. "tour": false on a block leaves it out when a tour step shows the overlay.
Several diagrams in one file
{
"meta": { "title": "Acme Commerce", "logo": "icon:shopping-cart", "url": "https://acme.example" }, // shared: title of the collection, logo, link
"theme": { "preset": "midnight" }, // shared by all diagrams
"settings": { "legend": "collapsed" }, // shared defaults; a diagram's own settings win
"hero": "first", // first | all | none: which diagrams show their start screen
"diagrams": [
{ "id": "platform", "title": "Platform architecture", "sub": "Components and connections", "meta": { "type": "architecture" }, "zones": […], "nodes": […], … },
{ "id": "checkout", "title": "Checkout process", "sub": "From cart to delivery", "meta": { "type": "process" }, … }
]
}
Each entry in diagrams is a complete diagram plus id, title and sub for the switcher. theme, settings,
icons, status and meta (except title/subtitle) at the top level are shared. The logo box becomes a switcher
(click it, or press 1–9). Deep links: #d=checkout&tour=2.
Deep links
index.html#lens=gov, #tour=5, #overlay=pilot, #node=llm-gw, #zone=audit, #list=personas&item=2,
#status=off, #d=<diagram id>, combinable with &.
#check runs the screen check and stores the result in window.__diagramCheck (re-run with window.__diagramCheckRun()):
text that doesn’t fit, edge labels on boxes or zone headers, highlighted boxes covered by the HUD or off screen,
tour cards/sheets that scroll, steps zoomed out too far. window.__diagramReady turns true when the camera has settled.
window.__diagramIssues holds the data checks (errors, warnings, stats) of the diagram on screen.