# Writing the docs

> How these docs are built, where each page lives, and how to keep them in step with the app.

These docs live in the Flozu repo, next to the code, in `apps/docs`. They’re built with [Starlight](https://starlight.astro.build) into a static site, so any static host can serve them.

- apps/docs/

  - public/\_headers Cloudflare’s headers for the Markdown copies

  - scripts/

    - check-twins.ts checks every page’s Markdown copy after the build
    - screens.ts takes the screenshots
    - shots.ts the steps for each screenshot

  - src/

    - assets/screens/ the screenshots, in both themes

      - …

    - components/

      - Diagram.astro a diagram drawn in SVG, in the page’s colours

      - diagrams/ each diagram, such as how a failure travels

        - …

      - DocsSearch.astro search, as a command menu over Pagefind’s index

      - PageActions.astro the Copy page menu beside each title

      - Screen.astro shows a screenshot in the reader’s theme

      - ShotToCome.astro a dashed box where a screenshot still to take will go

      - overrides/ the head, header, sidebar, page title, page outline, page foot, phone menu and theme picker, in place of Starlight’s

        - …

      - reference/ tables read from the code

        - …

    - content/docs/ one Markdown page per file

      - …

    - data/reference.ts

    - pages/ the Markdown copies, llms.txt and llms-full.txt

      - …

    - styles/theme.css the docs’ look

    - brand.ts the product’s name, logo and addresses

    - drill.ts the sections the sidebar, header and search list

    - search.ts turns Pagefind’s results into search’s rows

    - sections.ts a line and an icon for each section, for the Guides menu and the sidebar

    - icons.ts the few Lucide icons the docs draw, through components/Icon.astro

    - markdown.ts turns a page’s HTML into Markdown

    - twins.ts renders every page for its Markdown copy

    - sidebar.ts the sidebar, in reading order

    - pages.test.ts checks every page

    - markdown.test.ts checks the Markdown copies read well

    - theme.test.ts checks the colours stay readable

## Run them

```sh
pnpm docs:dev                      # http://localhost:4321, reloading as you edit
pnpm --filter @flozu/docs build     # the site, in apps/docs/dist
```

Use `pnpm docs:dev`, not `pnpm docs`: that one is pnpm’s own command, which opens a package’s page on npm. The site runs in the foreground until you press `Ctrl`+`C`. Astro starts its dev server in the background when it thinks an AI agent ran it, and the docs’ `dev` script turns that off. If a background one is ever left running, `pnpm --filter @flozu/docs exec astro dev stop` stops it.

## How they look

The docs are a plain reference site, so nothing competes with the words. The colours follow Vercel’s docs and the sizes follow Linear’s: a light grey page in light and a black one in dark, with no rules between the header, the sidebar, the page and its outline; a slim header, a narrow sidebar of small rows, and the words in 15px type in a column of about 75 characters, under calm, lightly tracked headings (`theme.test.ts` holds the sizes). On a wide screen the sidebar, the words and “On this page” sit together as one centred block, the outline as wide as the sidebar, and the words start in the same place on every page, outline or not. The header has **Get started** and a **Guides** menu of every section. Search sits at the top of the sidebar, stays there as the sidebar scrolls, and opens a command menu of pages and headings. Under it the sidebar lists every section (`src/drill.ts` works them out from `src/sidebar.ts`), each a row with its icon in a small square (`sectionIcons` in `src/sections.ts`) that folds its pages away. The section you’re in is always open, folded ones stay folded from page to page in that browser, and the sidebar opens scrolled to the page you’re on, which is a grey pill. **Contact support** and **Get help** stay at its foot. In “On this page”, one bar slides down a grey track to the section you’re reading. The theme picker at the top right is a button that opens a menu of System, Light and Dark. Code, notes, tables and cards are white boxes with a hairline. Text is near black, with grey for everything that isn’t the text you came for, and links are the text’s own colour with a soft underline. Flozu’s orange is only in the logo. Every colour comes from `src/styles/theme.css`, and `theme.test.ts` checks that the orange is the app’s and that text, links and buttons stay readable in both themes. The docs don’t copy the app’s or the homepage’s look.

The name and logo live in `src/brand.ts` and `src/assets/logo-*.svg`, so a new name or logo changes those files and nothing else.

## For assistants

Every page is also plain Markdown at its own address plus `.md`, such as [`/guides/lines.md`](https://docs.flozu.app/guides/lines.md), so an assistant can read it without the page around it. [`/llms.txt`](https://docs.flozu.app/llms.txt) lists every page with a line about it, and [`/llms-full.txt`](https://docs.flozu.app/llms-full.txt) holds them all in one file. Each page’s head links to its copy, and **Copy page**, beside each title, copies it, opens it, or hands the page to Claude or ChatGPT.

The copies are made from each page’s rendered HTML (`src/twins.ts` and `src/markdown.ts`), so a screenshot becomes its picture with its alt text, an aside a quote, tabs a list, and a table read from the code the same table. Nothing is written twice. After every build, `scripts/check-twins.ts` fails if a page has no copy, if a copy still holds a component tag, if it holds fewer words than the page shows, or if `llms.txt` doesn’t list it. A new component that draws something special needs a rule in `markdown.ts` and a test in `markdown.test.ts`.

## When you change the app

A pull request that changes what someone sees or does updates the docs in the same pull request:

1. **Find the page.** Each feature has a guide under `src/content/docs/guides`. A new feature gets a new page, listed in `src/sidebar.ts`.
2. **Update the words.** Say what a person does and sees, in the app’s own words: the same button names, in bold.
3. **Update the screenshots** if the screen looks different. Run `pnpm --filter @flozu/docs screens <name>` for the shots that changed, or with no name for all of them. Add a new shot to `scripts/shots.ts` as the steps that get the app there. If a shot can’t be taken yet, put a `ShotToCome` component where it goes, with the alt text the shot will have: it draws a dashed box that says what the picture will show. Swap it for a `Screen` with the same alt once the shot is taken. `grep -rn ShotToCome src/content` lists the ones left.
4. **Run the checks.** `pnpm check` builds the docs and fails on a broken link, a page missing from the sidebar or a screenshot that doesn’t exist.

## What updates itself

Some pages read straight from the code, so they never need editing by hand:

- [Part kinds](https://docs.flozu.app/reference/part-kinds.md) and the part keys, from the app’s parts catalogue.
- [Presets](https://docs.flozu.app/reference/presets.md) and [drawings](https://docs.flozu.app/reference/drawings.md), from `@flozu/core`.
- [Ready-made scenarios](https://docs.flozu.app/reference/scenario-presets.md), from `@flozu/core`.
- The [Mac app’s menu](https://docs.flozu.app/mac/overview.md#the-menu-bar), from the Mac app’s Rust source.
- Counts in the prose, such as how many presets there are, through `<Count of="presets" />`.

When a list like these appears in a guide, prefer one of these components to typing it out.

## How a guide reads

Every guide follows the same shape, so a reader always knows where to look:

1. **What it’s for,** in a sentence or two, as the question the reader has. “Will your checkout cope on Black Friday?”
2. **Try it,** three to six steps on the **Checkout system** template, ending in something they can see. Every guide uses the same map, so readers learn it once.
3. **What you’re looking at,** with the screenshot, and what each colour or number means.
4. **Doing more,** each task under a heading named for the job, such as “Take a whole region down”.
5. **Good to know,** the exact rules and edge cases, at the foot, for whoever needs them.

Use real numbers from the map, worked out by Flozu, rather than made-up ones: the reader will see the same numbers when they try it. Walkthroughs go further and answer one question from start to finish. Concepts pages are where the docs get technical: the rules, the maths and diagrams. A diagram is an SVG component in `src/components/diagrams`, drawn with the `dg-` classes in the theme, so it follows light and dark and never needs retaking when the app changes.

## How to write

- **Short, plain and in sentence case.** Write for someone who has never seen Flozu.
- **Say what to do, then what happens.** “Select **Save version**. The map is kept as it is now.”
- **Use the app’s words.** A part, a line, a zone, a note. Bold the names of buttons and tabs.
- **Show, don’t list.** One screenshot near the top of a guide beats a long description of it.
- **Write alt text that teaches.** Say what the picture shows, so the Markdown copy makes sense without it.
- **Every page has a description,** used by search and link previews.

## Publish them

`pnpm --filter @flozu/docs build` writes a plain static site to `apps/docs/dist`, with its own search index, so any static host can serve it, such as Cloudflare. Set `DOCS_SITE` to the address it’s served from, such as `https://docs.example.com`, so its sitemap and links point there.
