## Prerequisites

- **Node.js 22+** — required by zfb and the toolchain
- **pnpm** — recommended package manager

[Dynamic content unavailable in text export]

You can also use npm, yarn, or bun, but this guide uses pnpm for all examples.



## Create a New Project

The fastest way to get started is with the `create-zudo-doc` CLI. It scaffolds a new project with an interactive setup wizard.

```bash
pnpm create zudo-doc
```

Or with other package managers:

```bash
npm create zudo-doc
yarn create zudo-doc
bunx create-zudo-doc
```

For non-interactive usage (CI, automation, AI agents), use `--yes` to accept defaults or pass flags directly:

```bash
pnpm create zudo-doc my-docs --yes
pnpm create zudo-doc my-docs --lang ja --scheme "Default Dark" --no-i18n --pm pnpm --install
```

See the [CLI reference](https://zudo-doc.takazudomodular.com/docs/reference/create-zudo-doc) for all available flags.

The CLI walks you through the following options:

### Project Name

Enter a name for your project directory (default: `my-docs`).

### Default Language

Choose the default language for your documentation site. Supported languages include English, Japanese, Chinese (Simplified/Traditional), Korean, Spanish, French, German, and Portuguese.

The selected language is the primary locale: its content lives in `src/content/docs/` and its routes are unprefixed (`/docs/...`). To add more locales, enter an ordered comma-separated list in the **Additional language codes** field of the Preset Generator, or pass the list directly to the CLI:

```ts title="zfb.config.ts"
export default defineConfig(
  zudoDoc({
    defaultLocale: "en",
    locales: {
      ja: { label: "JA", dir: "src/content/docs-ja" },
      de: { label: "DE", dir: "src/content/docs-de" },
    },
  }),
);
```

```bash
pnpm create zudo-doc my-docs --lang en --additional-langs ja,de --yes
```

An omitted or blank list leaves the scaffold single-language. A non-empty explicit list is normalized, validated for safe locale path segments, and implies i18n; it is the complete list rather than a request for one fixed locale. The scaffold seeds English placeholder prose for arbitrary non-Japanese locales, which you can translate after installation.

### Color Scheme Mode

Choose how your site handles color schemes:

- **Light & Dark (toggle)** — users can switch between light and dark themes. Uses the bundled `Default Light` / `Default Dark` pair.
- **Single scheme** — one fixed color scheme for the entire site, either `Default Light` or `Default Dark`.

When using light/dark mode, you can also set the default mode (light or dark) and whether to respect the user's system color scheme preference.

zudo-doc ships exactly these two schemes, sharing one set of OKLCH ramps — there is no catalog of community or terminal presets to browse. The defaults are package-owned; a fresh scaffold has no color-scheme module. To customize the palette, create your own scheme module and pass it through the `colorSchemes` field of `zudoDoc({ ... })` in `zfb.config.ts` (see the [Color guide](https://zudo-doc.takazudomodular.com/docs/reference/color#adding-a-custom-color-scheme)), then preview changes live with the [Design Token Panel](https://zudo-doc.takazudomodular.com/docs/reference/design-token-panel)'s Palette tab (see [Color Scheme Preview](https://zudo-doc.takazudomodular.com/docs/guides/color-scheme-preview)).

### Features

Use the interactive picker to choose optional modules for search and sidebar tools, Claude and Codex resources and skills, design and navigation controls, versioning and document history, tags and changelogs, desktop wrappers, and indexing. Internationalization is configured by the primary language plus the **Additional language codes** field; a non-empty additional list enables it automatically. Built-in full-text/word-match search, sidebar filtering, image enlarge, dynamic page transitions, and footer copyright are selected by default.

For the complete feature list, defaults, and non-interactive flags, see the [CLI reference](https://zudo-doc.takazudomodular.com/docs/reference/create-zudo-doc#options-features).

### Package Manager

Choose your preferred package manager: pnpm (recommended), npm, yarn, or bun. After scaffolding, the CLI will ask whether to install dependencies for you.

[Dynamic content unavailable in text export]

The installer writes your choices into a single `zfb.config.ts` — a `zudoDoc({ … })` call holding only the fields that differ from the defaults. You can change these settings at any time after project creation. See [Configuration](https://zudo-doc.takazudomodular.com/docs/guides/configuration) for the full field reference.



## Alternative: Clone the Repository

You can also start by cloning the full repository directly:

```bash
git clone https://github.com/zudolab/zudo-doc.git my-docs
cd my-docs
pnpm install
```

[Dynamic content unavailable in text export]

Cloning the repository gives you the complete project including the documentation source and all features enabled. Use this approach if you want to explore the full codebase or contribute to zudo-doc itself.



## Development

```bash
pnpm dev
```

The zfb dev server starts on port 4321 with instant hot module replacement.

[Dynamic content unavailable in text export]

Make sure port 4321 is available. If another process is already using it, `pnpm dev` will fail with `EADDRINUSE` — kill the conflicting process and retry.



## Build

```bash
pnpm build
```

This generates static HTML in the `dist/` directory. You can deploy it to any static hosting service.

## Type Checking

```bash
pnpm check
```

Runs the project's TypeScript type checker in strict mode.

[Dynamic content unavailable in text export]

Never commit the `dist/` directory to source control. It is already excluded via `.gitignore`.



## Project Structure

A freshly scaffolded project is deliberately small — around a dozen files:

```
my-docs/
├── .gitignore              # node_modules, dist, .zfb
├── .npmrc                  # trust-policy-exclude[]=undici-types@6.21.0
├── pnpm-workspace.yaml     # minimumReleaseAge: 0 (disables pnpm 11's release-age gate)
├── CLAUDE.md               # project notes for Claude Code
├── package.json            # deps + dev/build/preview/check scripts
├── tsconfig.json           # 5-line extends of the package base config
├── zfb.config.ts           # the ONE config file — a zudoDoc({ … }) call
├── pages/
│   ├── index.tsx           # home route (1-line re-export)
│   └── docs/
│       └── [[...slug]].tsx # doc-route stub (see the callout below)
└── src/
    ├── content/
    │   └── docs/
    │       └── getting-started/
    │           ├── index.mdx
    │           ├── installation.mdx
    │           └── introduction.mdx
    └── styles/
        └── global.css      # ~20-line @import chain + your token overrides
```

When additional locales are configured, the same `src/content/` tree also contains one exact `docs-<code>/` directory per entry, such as `docs-ja/` and `docs-de/`. Keep filenames and code blocks aligned across these trees while translating prose. See [Internationalization](https://zudo-doc.takazudomodular.com/docs/guides/i18n) for fallback, validation, and default-locale-only rules.

| File | Purpose |
| --- | --- |
| `zfb.config.ts` | Your entire configuration. Imports `zudoDoc` from `@takazudo/zudo-doc/config` and passes the fields you chose; everything else falls back to a documented default. |
| `tsconfig.json` | Extends `@takazudo/zudo-doc/tsconfig.base.json`, with JSX source `@takazudo/zfb/zudo-react` and no React/Preact compatibility aliases. |
| `src/styles/global.css` | `@import`s the package's `theme.css` / `content.css` / `features.css` and leaves you a `:root { … }` block for token overrides. |
| `src/content/docs/` | Your documentation, authored as MDX. The scaffold seeds a few `getting-started/` pages to replace. |
| `pages/index.tsx`, `pages/docs/[[...slug]].tsx` | Thin route stubs — see below. |

### Why so little?

Everything a project used to copy into itself — the layout, header, sidebar, TOC, nav builders, URL helpers, color-scheme utilities, and the frontmatter schema — now ships from `@takazudo/zudo-doc` and is consumed straight from `node_modules`. Doc routes are injected by the package (`packageOwnedRoutes` defaults to `true`), so your `pages/` directory carries only the two stubs below rather than a full set of layout files. A fresh project holds just what is genuinely its own: config, content, and a couple of route seams.

[Dynamic content unavailable in text export]

The home route is a one-line re-export of the package-owned static index route:

```tsx title="pages/index.tsx"
export { default } from "@takazudo/zudo-doc/routes/index";
```

A re-export works here because the static `/` route needs no build-time `paths()` extraction.



[Dynamic content unavailable in text export]

Package route injection renders your doc pages in both **build** and **dev** with zfb 2.13.1. The small self-contained stub remains as an explicit host-owned route seam: it reconstructs the doc route from the package's sanctioned entrypoints (`@takazudo/zudo-doc/route-context` + `/chrome` + the `virtual:zudo-doc-route-context` module) and lets the generated project customize that route while it shadows the package injection. It makes `/docs/…` return 200 in both `zfb dev` and `zfb build`.



See the [Writing Docs](https://zudo-doc.takazudomodular.com/docs/getting-started/writing-docs) guide for how to create and organize your documentation pages, and [Customizing zudo-doc](https://zudo-doc.takazudomodular.com/docs/reference/customizing) for the ladder from a config tweak to full source control.