- name
- d3-f-pages
- description
- Pages, apps and embeds — a page is a topic: home cards, tables, built-in blocks, embedhtml widgets and the d2 bridge, App: topics, layouts, show=. Get skills only from /api/v2/skills/d3.
- feature
- pages
- concepts
- [page, card, table, block, embed, app, show]
- tags
- #skill #feature #d3skill #wip
d3-f-pages¶✎ edit
Intro¶✎ edit
Pages are topics: tables, blocks, embeds and apps.
In d2 a page is a topic: markdown first, with small fenced blocks for data (table), built-in widgets, live HTML (embedhtml) and, when a page needs a free hand, a whole App: page. show= decides on the server who sees which part. d2's own screens are built the same way. Saving is d3-f-topics and d3-f-drafts; the look d3-f-styles; model and objects d3-f-domain, d3-f-data. Spec: Spec › pages.
Essentials¶✎ edit
- R-pages-1 MUST reach for the simplest thing that works, in order: markdown → a
table→ a built-in block → anembedhtmlwidget → anApp:page. - R-pages-2 Data on a page is a
table, never code; numbers are computed in the model (computed fields), never in the page. - R-pages-3 Keep data in objects and logic in rules; a page only shows and triggers.
- R-pages-4 Who sees what is
show=, applied on the server; NEVER put a secret in a topic, hidden or not. - R-pages-5 NEVER let a secret reach an embed or app (no token, vault or starter route) — an embed can fetch other sites, so whatever reaches it can leave.
- R-pages-6 MUST open the page after saving and read it; a bad table or block shows as a red note in its place.
- R-pages-7 Signed pages run as built-in: base d2's
Page:topics are served inside d2's own page: no frame, same origin, their own script renders on the client with the viewer's session, and the server's role checks decide each call (Razie, 2026-10-10, P-1242). A page d2 itself needs is a signedPage:, never anApp:copied into projects. A project's own Pages, Apps and widgets are user code and run sandboxed in a frame; a sandboxed frame has nolocalStorage: used2.store(P-1239).
Concepts¶✎ edit
page¶✎ edit
A topic rendered as a page at /topics/<name>. Also called: screen, view.
Fields (frontmatter): layout (page | full | none), edit (architect makes it the Architect's alone).
page_check¶✎ edit
- Summary: after saving, open the page and read it.
- When: after every save of a page, table, block or app.
- Needs: the saved topic.
- Call: open
/topics/<name>(or the app's address). - Rules: R-pages-6. A red note → fix what it says and save again.
- Errors: red note → a class or field that doesn't exist, or a bad line.
- Gotchas: —
page_layout¶✎ edit
- Summary:
layout: pagefor a chrome-free page;fullfor a full-page app. - When: a page that shouldn't look like an ordinary topic.
- Needs: —
- Call: frontmatter
layout: page(navbar and body only — no title bar, contents, frontmatter box, history or button row; editors get a floating ✎ Edit) Also:layout: full(whole window, no d2 chrome, a small Home button) · none: an ordinary topic page. - Rules: Use
fullonly when needed (a console, an app for a phone's home screen) and handle your own navigation (hash links). The user menu's Edit is the fail-safe for pages whose own buttons don't show. - Errors: —
- Gotchas: —
card¶✎ edit
A home page's app launcher line in the first ```cards block right after the # title. **Also called:** app card, home card.
**Fields:** icon | title | link | text (link: /path, a URL or [[Topic]]; soon for one not live yet), optional | show=<cond>.
card_add¶✎ edit
- Summary: one card per app, in Home's first
cardsblock. - When: a new app should show on Home.
- Needs:
Homeread first. - Call: save
Homewith the line added to its firstcardsblock (start one right after the#title if none). - Rules: Change only the card block; keep the lines already there; never two cards for one app.
- Errors: —
- Gotchas: —
table¶✎ edit
A ```table fence that draws a class's objects with the page (reload for new data). **Also called:** data table, list.
**Fields (one key: value per line):** class (required), columns (fields or paths through one reference, each optionally as a label; none: every plain field), totals, sort (<col> asc|desc), filter (an expression, account is "TFSA"), color (greens/reds numbers), add: no, title, limit.
table_show¶✎ edit
- Summary: show objects with a
tablefence, not code. - When: any data on a page; for an app, its table(s) at the top of its page, then a line on what it is.
- Needs: the class and field names (d3-f-domain).
- Call:
```tablewithclass: Holding,columns: company, shares, company.price as Price, value, pl as P/L,totals: value, pl,sort: value desc,color: pl. - Rules: R-pages-2. The first cell opens the object's edit form, + Add the new-object form; both return to the page. On a phone each row becomes a card.
- Errors: red note → unknown class or field ·
E_WAIT→ a web fetch in a table, query or computed field: fetch in a rule. - Gotchas: —
block¶✎ edit
A built-in fence d2 renders per viewer (code, not page content). Also called: widget.
Kinds: next-step (Sign up / Log in; make your first project; back to the last-used project), my-projects (the viewer's projects, newest first, then + New project), new-project (the create form alone), connect-ai (the Connect your AI steps).
block_use¶✎ edit
- Summary: drop in a built-in fence; it renders for the viewer.
- When: landing, home or onboarding pages.
- Needs: —
- Call:
```next-step·```my-projects·```new-project·```connect-ai. - Rules:
connect-aiis the only place a starter token shows (sealed, never in page text). A visitor-only renderer shows nothing for an unknown block. - Errors: —
- Gotchas: —
embed¶✎ edit
An ```embedhtml fence: HTML, CSS and a <script> run in a sandboxed frame (no cookies, no same-origin), sized to its content; links open in a new tab. **Also called:** widget, live HTML.
**Bridge:** d2.api(method, path, body), d2.go(url), d2.params (the page address's query, read-only).
embed_write¶✎ edit
- Summary: prefer an embed in a plain topic over an
App:. - When: a page needs live HTML a table or block can't give.
- Needs: —
- Call: an
```embedhtmlfence in the topic. - Rules: Embeds keep the navbar and need no special routing. Use the page's look: the CSS variables (
var(--ink),var(--card),var(--line),var(--soft),var(--leaf),var(--rose),var(--display),var(--body)) or link/styles/current.css(d3-f-styles › style_link). - Errors: —
- Gotchas: —
embed_callD2¶✎ edit
- Summary: talk to d2 only through the bridge, as the viewer, allowlisted routes only.
- When: an embed reads objects or topics, or creates a project.
- Needs: a route on the allowlist.
- Call:
await d2.api(method, path, body)→ the parsed answer (throws with the error) Also:d2.go(url)navigates the page to a URL on this d2. - Rules: R-pages-5. Allowlist:
GET /api/v2/me, reads of/api/v2/dom/…and/api/v2/topics/…on the page's project,GET /api/v2/search,GET /api/v2/projects/available,POST /api/v2/projects. - Errors:
E_SCOPE→ route not on the allowlist (ord2.goto another site): use atable, anApp:, or ask for a platform change. - Gotchas: —
embed_fetchOutside¶✎ edit
- Summary: outside sources only if open CORS and keyless; never a blank on failure.
- When: an embed shows data from another site.
- Needs: a source that allows any origin and needs no key.
- Call:
fetch(<url>)from the embed's script. - Rules: Show a clear state when the source doesn't answer (source unreachable), never a blank. A source that refuses CORS or needs a key → fetch it in a rule (
http.json, d3-f-engine). - Errors: embed shows nothing → its source refused CORS or needs a key.
- Gotchas: —
app¶✎ edit
A model (a Spec: topic with $class lines), its data (objects, often seeded from a Story:), a page (a table, or an App:<name> topic) and a card on Home. An App:<name> topic is a whole HTML page at /app/<name> under the project's top bar. Also called: tool, dashboard.
app_build¶✎ edit
- Summary: model, sample data, a page, a Home card — from your person's words.
- When: your person wants something to track or do.
- Needs: what they said, in their words.
- Call: a
Spec:topic (d3-f-domain) → aStory:with$objectsamples (d3-f-data › object_declare) → a page with atable→card_add. - Rules: Add a few sample objects so they see it working, then show them: with Mind Meld on, take their tab there (d3-f-esp); otherwise give the link.
- Errors: —
- Gotchas: —
app_import¶✎ edit
- Summary: copy an example project's topics under the same names.
- When: your person wants an app like an existing example.
- Needs: the example project's topic names.
- Call:
GET https://<example>/api/v2/topics/<T>(e.g.Spec:portfolio) for each → write it under the same name. - Rules: Offer to replace the samples with their own data.
- Errors: —
- Gotchas: —
app_page¶✎ edit
- Summary: an
App:topic only when a page needs a free hand. - When: a dashboard or a custom editor; an embed won't do.
- Needs: the routes it calls.
- Call: an
App:<name>topic →/app/<name>; it callsawait d2.api(method, path, body)as the viewer, e.g.d2.api("GET", "/api/v2/dom/MarketStatus")or a rule rund2.api("POST", "/api/v2/diesel/run", {story: "$send market.refresh", scratch: false}). - Rules: R-pages-3. Only the project's
/api/v2routes (not accounts, tokens or admin).data-show="<cond>"on any element removes it on the server for viewers who don't match.layout: fullper #page_layout. A project'slandingorhomemay name a full-page app. - Errors:
E_SCOPE→ a route outside the project's/api/v2. - Gotchas: —
app_fast¶✎ edit
- Summary: make an
App:orPage:show at once and stay quick — what a frame costs and how to avoid each cost. - When: writing or reviewing any
App:orPage:topic, d2's own or a project's; a page that feels slow. - Needs: the reads the page makes before it can draw, and after each write.
- Call: what a page costs, and the fix for each:
- The frame starts late. The page loads, then its sandboxed frame (
/embed), then the script is parsed, then the first read. → Keep the script small (load only what the first screen needs, then the rest), and put the first read in frontmatter asboot: /api/v2/<one GET path>: the server runs it as the viewer while serving and the page reads it fromd2.bootbefore any call (falls back to its own read whend2.bootis null).boot:ships with P-1180. - Every
d2.apicall is a hop through the outer page. → One read that answers what the first screen needs (an…/app-style route), never a loop of small reads; at most four reads at once. - Large inputs built in the browser. → Never read whole big topics (Testing, Spec) to compute a view; ask for the computed answer from a server route, cached with
ETag/If-None-Match(the brain map:GET /api/v2/brain, P-1181). Keep what is read insessionStoragefor the session, keyed by project and build. - A full reload after each write. → Patch in place: every write answers with what it changed; put that one row or card into the list and redraw only it. Notice others' changes with a cheap stamp (
GET …/stamp, or the list'sstamp) and reload only when it moved. - Waiting on the slowest part. → Paint the main content first (cards, rows), then the heavy extras (maps, charts) after it; show a one-line placeholder, never a blank frame.
- The frame starts late. The page loads, then its sandboxed frame (
- Rules: R-pages-9. Never ask for server rendering of a page's own script: designer code doesn't run in the server. A route the page needs that the bridge refuses is a coder ticket naming the route, not a workaround.
- Errors:
E_SCOPEfromd2.apion a route the page needs → see #app_page (a basePage:reaches more than a project's page). - Gotchas: Before saving, check the page against points 1–5. Then open it and look at the network: count the reads before the first paint, and after one save (aim: one before, none after).
show¶✎ edit
A condition that removes part of a page on the server before it leaves. Also called: visibility, hidden section.
Where: a heading (## Admin tools {show=admin} hides it to the next heading of the same or higher level), any fence (```cards show=mod), a cards line ending | show=member, a ```show <cond> fence around markdown, data-show in apps.
Conditions: the ladder visitor < guest (signed in, not a member) < member < mod < admin < architect, each at least; person, ai, an agent role (designer, maker…); level:hero|creator|pro|master (at least); projects:none|some. , any of, + and, ! not: show=guest+!member, show=member+level:pro.
show_hide¶✎ edit
- Summary: hide a section, block or line with
show=; server-side everywhere. - When: a part only some viewers should see.
- Needs: the condition.
- Call:
{show=<cond>}on a heading,show=<cond>on a fence,| show=<cond>on a cards line,data-showin an app. - Rules: R-pages-4. Applied on the rendered page,
GET /api/v2/topics/<t>, search, the system view and exports. A token is judged by its role capped by its person's role. A section left empty after filtering is dropped. Inherited pages show with the viewer's role in the project they're on. - Errors: —
- Gotchas:
window.d2user(planned) only decorates on the client; anything that must stay hidden usesshow=.
show_edit¶✎ edit
- Summary: editing needs seeing everything.
- When: editing, drafting, publishing or reading the full text/history of a topic with
show=parts. - Needs: a role that sees every part.
- Call: the ordinary topic write (d3-f-topics).
- Rules: Whoever can't see every part may not edit, draft, publish or read its full text or history.
edit: architectmakes a topic the Architect's alone. Inherited pages are edited only at home, with the role there. - Errors:
E_SCOPEnaming the hidden part's condition → someone who sees all of it edits it. - Gotchas: —
Rules¶✎ edit
- R-pages-7 d2's own screens (the landing
App:Landing, the new-project pages named by basenewProject, admin tiles, the Toolbox) are topics on base d2, changed as pages; code only for what a page can't do itself (a new API or core behaviour). - R-pages-8 Every new user-facing page gets a Toolbox tile and a Help section in the same change (d3-f-help › toolbox_addTile).
- R-pages-9 Every
App:andPage:MUST be fast: its first screen from one read (boot:once it ships), writes patched in place, big inputs computed on the server, the main content painted first (app_fast). Razie, 2026-10-10: "save all this info on how to make a page somewhere where makers and designers can reference, so custom Pages are also fast".
Errors¶✎ edit
- red note where a table or block should be — a class or field that doesn't exist, or a bad line → fix what it says, save again. see #page_check
E_SCOPEfromd2.api/d2.go— route not on the bridge's allowlist, or another site → atable, anApp:, or a platform change. see #embed_callD2E_SCOPEnaming ashow=condition on edit or save — part of the topic is hidden from you → someone who sees all of it edits it. see #show_edit- embed shows nothing — its outside source refused CORS or needs a key → source unreachable, fetch in a rule. see #embed_fetchOutside
- a page slow to show or after a save — too many reads before the first paint, or a full reload after a write → see #app_fast
E_WAIT— a web fetch in a computed field, table or query → fetch in a rule. see #table_show