Skip to content

Writing the docs

These docs live in the Flozu repo, next to the code, in apps/docs. They’re built with Starlight into a static site, so any static host can serve them.

  • Directoryapps/docs/
    • public/_headers Cloudflare’s headers for the Markdown copies
    • Directoryscripts/
      • check-twins.ts checks every page’s Markdown copy after the build
      • screens.ts takes the screenshots
      • shots.ts the steps for each screenshot
    • Directorysrc/
      • Directoryassets/screens/ the screenshots, in both themes
        • …
      • Directorycomponents/
        • Diagram.astro a diagram drawn in SVG, in the page’s colours
        • Directorydiagrams/ 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
        • Directoryoverrides/ the head, header, sidebar, page title, page outline, page foot, phone menu and theme picker, in place of Starlight’s
          • …
        • Directoryreference/ tables read from the code
          • …
      • Directorycontent/docs/ one Markdown page per file
        • …
      • data/reference.ts
      • Directorypages/ 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
Terminal window
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.

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.

Every page is also plain Markdown at its own address plus .md, such as /guides/lines.md, so an assistant can read it without the page around it. /llms.txt lists every page with a line about it, and /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.

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.

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

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

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.

  • 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.

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.