/CLAUDE.md
CLAUDE.md at /CLAUDE.md
Path: CLAUDE.md
Zudo Design Token Panel
Documentation site built with zudo-doc — a ZFB 4.7.0 documentation host with MDX, Wind CSS, and native zudo-react islands (zudo-doc 7.1.0). This project is intentionally minimal: one config file (zfb.config.ts) plus markdown content — layout, chrome, and islands all ship from @takazudo/zudo-doc in node_modules.
Tech Stack
ZFB 4.7.0 — documentation build framework; import configuration helpers from
@takazudo/zfb/ config MDX — content format, authored under
src/content/Wind — the host utility CSS engine; zudo-doc registers its Wind manifest automatically. Keep
@layer zw-reset, zd-flow;and the public theme-before-feature CSS import order insrc/. Token overrides belong in ordinarystyles/ global. css :root; do not add Tailwind directives or scan packagedist/files.zudo-react — native host JSX and interactive islands; extend
@takazudo/without React/Preact JSX aliases. The panel owns its separate Preact tree; never pass its VNodes into native host JSX or Island JSON props.zudo- doc/ tsconfig. base. json zfb semantic highlighting — native build-time fenced-code rendering plus lazy
@takazudo/zfb-md-wasmfor HtmlPreview; both emithi-*classes resolved through--zd-syntax-*design tokens@takazudo/zudo-doc — the package that owns everything: layout, chrome, islands, default design tokens, and (via
packageOwnedRoutes, on by default) the doc routes themselves
Commands
pnpm dev— runs the zfb dev server (port 4321) and the doc-history API server (port 4322) concurrently viarun-p(pnpm dev:zfb/pnpm dev:historyindividually)pnpm dev:network— same, but zfb binds--host 0.0.0.0for LAN access (pnpm dev:zfb:networkindividually); the doc-history server stays loopback-only and LAN clients reach it through zfb's/dev proxydoc- history/ * Trusted networks only: this also serves your git doc-history — including UNPUBLISHED local commits — to anyone on the LAN via the
/proxydoc- history/ * run-pswallows trailing args, so other zfb flags don't forward throughpnpm dev— pass them directly instead:pnpm run dev:zfb -- <flags>pnpm build— static HTML export todist/pnpm check— TypeScript type checkingpnpm preview— serve the builtdist/
The docs dev scripts use scripts/ to select ZFB's supported eager startup (ZFB_DEV_BOOT_LAZY=0). On 4.3.1, cold-lazy route discovery can produce incompatible native island identities during SPA navigation. Use dev:zfb (or dev:zfb:network) so the real server and current-host CI exercise the same mode; keep transport identity checks enabled. Retain this workaround on 4.7.0: the 4.5.2 ready-banner fix, the 4.5.3 include-parsing fix, the 4.5.4 islands build-identity change (which keys island bytes to the resolved browser graph), the 4.6.0 shadow-staging and Windows path fixes and the 4.7.0 Rolldown bundler switch do not claim cold-lazy transport identity safety. The packed current-host dev probe also passed with ZFB_DEV_BOOT_LAZY=1 on 4.7.0, but that probe was not shown to catch the original 4.3.1 failure, so it is not proof the workaround can go.
Key Directories
zfb.config.ts # THE one config file — zudoDoc({ ...only fields you chose })
pages/
├── index.tsx # package home re-export + local island scanner edge
└── docs/[[...slug]].tsx # retained native doc-route stub (explicit host ownership)
[locale]/docs/[[...slug]].tsx # same, for non-default locales
src/
├── chrome-bindings.tsx # typed native panel bootstrap boundary
├── content/
│ └── docs/ # MDX content (this project's showcase docs)
│ └── docs-ja/ # Japanese MDX content (mirrors docs/)
└── styles/
└── global.css # @import chain + a token-override slot — that's it Everything else — layout, header, sidebar, footer, doc chrome, islands, and the default design tokens — lives in node_modules/@takazudo/zudo-doc. For supported markup replacement, create src/ with defineChromeBindings, set chromeBindingsModule, and use the primary Header / Footer / Sidebar / Toc / Breadcrumb / DocPager slots or the named headerRightComponents registry. The generated default, locale, and doc-history route shapes already consume the same binding object; do not fork a route stub for presentational customization. npx zudo-doc eject <component> only copies source: heed its primary, nested-chrome, or content-layer remediation before expecting the copy to render. Settings you didn't set explicitly in zfb.config.ts use the package's documented defaults — hover zudoDoc's ZudoDocConfig argument in your editor to see every field and its @default.
The local DesignTokenPanelBootstrap boundary preserves early header clicks across native SPA swaps in zudo-doc 7.x. src/ queues toggle parity between zfb:before-swap and incoming scope activation, then calls the public bootstrap controller with the native scope's abort signal and replays at most one intent. zudo-doc 7 limits its loading overlay to the content area, so the header trigger stays clickable while a navigation is still fetching (before zfb:before-swap); such a click toggles the live outgoing host and its state must survive the swap or a superseding navigation. Package code still owns lazy loading, cancellation, configuration and the opaque panel runtime. Keep direct route imports of the binding module: the virtual host-callables channel alone does not guarantee static island discovery. First-load, pending-navigation and incoming-unhydrated clicks are covered by the current-host probe.
zdtp ↔ zudo-doc relationship
The doc/ workspace intentionally consumes the pinned npm release of @takazudo/zdtp; never force-link it to packages/zdtp. The pin governs which panel build the site runs — the embedded panel widget and the three-site demo split below — not what the documentation prose may describe. Doc content is free to document main-branch panel behavior ahead of the pinned release; that split is stated publicly in the note at the top of getting-, which this section cross-references rather than restates: read the two together as one rule, not two that can be read as contradicting each other.
This is a deliberate three-site split, kept separate because of the honesty problem tracked in #593: doc/ answers what can be installed from the pinned npm release, examples/minimal/ runs the workspace build as the smallest wiring that works, and playground/ runs the workspace build at full size, including the real vendored zudo-doc PanelConfig and prose pages. Do not make either workspace demo consume the pinned doc/ dependency, or make doc/ consume the workspace package, to make their versions appear consistent.
Use the root playground/ workspace to exercise unpublished panel changes in a real zfb consumer. Its default manifest covers the panel's control kinds, while ?manifest=zudo-doc uses the real zudo-doc PanelConfig vendored by scripts/ (the S17 vendor script). The generated file records the source @takazudo/zudo-doc version so drift is visible.
Verifying an unpublished panel in the real doc site
The committed doc/ workspace remains pinned to the published panel release. To inspect an unpublished panel build in the real zudo-doc consumer, run this from the repository root:
bash scripts/doc-with-local-panel.shThe script builds and packs packages/zdtp, copies the doc source into a temporary directory, and installs that scratch site with a file override for the packed panel. It prints the local panel version, then runs the scratch site's pnpm dev; open the printed URL and activate the design-token-panel header trigger. The terminal output includes the exact local package version being served (the fixed window.zdtp API itself intentionally exposes only show, hide, and toggle). The temporary directory, workspace override, install lock, and generated build output are removed when the dev command exits. The committed doc/ and root lockfile are never modified.
The override belongs in the temporary pnpm-workspace.yaml rather than a package-level pnpm field because pnpm 11 no longer reads that package.json configuration. The script also verifies that the scratch site resolved the packed panel version and the current ZFB/zudo-doc family. The native host does not render with Preact or require a shared host/panel Preact installation. The panel retains its own runtime dependency and DOM ownership. Treat a version or peer mismatch as a failed consumer check and resolve the boundary before claiming validation.
The informational consumer-smoke job in . runs separately named current-host and legacy checks. Current-host checks repeat the packed-panel override, build the scratch doc, serve its static output, and use Chromium to open one doc page, activate the header trigger, assert the real zudo-doc panel tabs are mounted, and reject console or page errors. Current-host remount coverage also exercises real SPA navigation and panel persistence. The retained legacy remount regression uses the self-contained ZFB 2.20.3 / zudo-doc 5.27.0 fixture in scripts/, not a copy of these migrated docs with only two packages repinned. Its shared Preact assertion applies only to that legacy host. Run scripts/ or --host legacy (the default) to select the host explicitly. Legacy manifests remain templates until materialized outside the checkout; do not add old real package.json files to the dependency resolver's repository scan.
The scheduled . workflow installs the latest zudo-doc for the consumer-manifest contract check, on the Node range that release declares in engines.node, so an upstream engine bump does not masquerade as manifest drift. Its five-example matrix is manual-dispatch-only and informational while those public examples still pin older panel APIs; failures open or update one deduplicated issue per job.
Content Conventions
Frontmatter
Required:
title(string)Optional:
description,sidebar_position(number),categorySidebar order is driven by
sidebar_position
Admonitions
Available in all MDX files without imports, via directive syntax: :::note, :::tip, :::info, :::warning, :::danger, :::caution, :::details. Each accepts an optional bracketed title: :::note[Custom Title].
Docusaurus-style {title="..."} is NOT supported. MDX parses the braces as a JS expression, so it either fails the build with ReferenceError: title is not defined or is silently ignored. Always use the bracketed form.
Headings
Do NOT use h1 (#) in doc content — the page title from frontmatter is rendered as h1. Start content headings from h2 (##).
Built-in MDX components
@takazudo/zudo-doc ships a few globally-available MDX components — usable in any .mdx file with no import. The seeded getting- already uses one:
<CategoryNav category="..." />— a card-grid list of the pages in a docs category (this is the one seeded intogetting-).started/ index. mdx <CategoryTreeNav category="..." />— the same listing as a compact nested tree, better for deeper hierarchies.<SiteTreeNavDemo />— a full-site documentation tree (the MDX-available wrapper of theSiteTreeNavisland).
Admonitions (above), tabbed content (<Tabs> / <TabItem>, <CodeGroup>), and block math (<MathBlock>) work the same way — no import. Full reference: https:
i18n
English (default):
/— content indocs/ . . . src/content/ docs/ Japanese:
/— content inja/ docs/ . . . src/content/ docs- ja/ Japanese docs should mirror the English directory structure
Both
pages/docs/[[...slug]].tsxandpages/[locale]/docs/[[...slug]].tsxretain explicit host route ownership and local history/locale adaptations. Keep their native JSX, untranslated-page fallback, and existing URL/base-path behavior. Don't delete them.Custom document-history bindings use the server
DocHistoryBoundary. Keep server fallback markup outside finite JSON Island props; no host Preact VNodes may cross that boundary.
Enabled Features
search — Package-owned full-text search UI and generated
search-index.json(the v6 browser runtime does not call Pagefind)claudeResources — Auto-generated docs for Claude Code resources
designTokenPanel — Interactive tabbed panel for tweaking spacing, font, size, and color tokens
sidebarResizer — Draggable sidebar width
sidebarToggle — Show/hide desktop sidebar
versioning — Multi-version documentation support
docHistory — Document edit history
llmsTxt — Generates llms.txt for LLM consumption
changelog — Per-version EN/JA pages under
src/are the source of truth; the docs build generatescontent/ docs*/ changelog/ .from the English pages, so do not edit that package file directly. / packages/ zdtp/ CHANGELOG. md