Skip to content

Living product docs — Playwright tour → docs site + screen specs

This recipe walks the full living-product-docs flow against a tiny example app. The result: one MDX file produces both an Astro docs page and an Excel screen-specifications spreadsheet, with drift between MDX + live UI caught at lint time.

Terminal window
pnpm add @ingcreators/annot-product-docs
pnpm add @ingcreators/annot-product-docs-astro
pnpm add @ingcreators/annot-product-docs-xlsx
pnpm add -D @playwright/test
pnpm exec playwright install chromium

Scaffold:

Terminal window
pnpm annot-docs init

Three files land in the repo:

annot-docs.config.ts
tests/docs/example.spec.ts
docs/books/example/SC-001-login.mdx

Edit docs/books/example/SC-001-login.mdx:

---
annot:
id: SC-001
title: Login screen
xlsx:
book: Screen specifications
sheet: SC-001 Login
role: screen
---
import Screen from "@ingcreators/annot-product-docs-astro/components/Screen.astro";
import Overlay from "@ingcreators/annot-product-docs-astro/components/Overlay.astro";
# Login screen
The screen where users sign in with email and password.
<Screen id="login" src="./shots/login.png">
<Overlay match={{ role: "textbox", name: "Email" }} intent="required" number={1}>
**Email** — Enter your registered email address.
</Overlay>
<Overlay match={{ role: "textbox", name: "Password" }} intent="required" number={2}>
**Password** — 8+ characters with upper, lower, and a digit.
</Overlay>
<Overlay match={{ role: "button", name: "Sign in" }} intent="action" number={3}>
After client-side validation, sends the auth request to the server.
</Overlay>
</Screen>

tests/docs/auth.spec.ts:

import { test } from "@ingcreators/annot-product-docs";
test("login flow", async ({ page, productDocs }) => {
await page.goto("/login");
await productDocs.sync({
id: "login",
mdxPath: "docs/books/example/SC-001-login.mdx",
});
});

Run it against the dev server:

Terminal window
pnpm dev &
pnpm exec playwright test tests/docs/auth.spec.ts

The tour:

  • Captures docs/books/example/shots/login.png
  • Rewrites the annot:snapshot block in the MDX with the current aria-snapshot YAML + [box=...] markers
  • Rewrites the annot:attributes block with the per-ref HTML attribute extraction

The diff on second run (no UI change) is empty.

Wire productDocsIntegration() into your astro.config.mjs and build:

astro.config.mjs
import { defineConfig } from "astro/config";
import mdx from "@astrojs/mdx";
import { productDocsIntegration } from "@ingcreators/annot-product-docs-astro";
export default defineConfig({
integrations: [mdx(), productDocsIntegration()],
});
Terminal window
pnpm build

The output includes a page that renders the screenshot with three numbered overlay callouts composited at the exact bbox coordinates the tour captured.

4. Render the screen-specifications spreadsheet

Section titled “4. Render the screen-specifications spreadsheet”
annot-docs.config.ts
import { defineConfig } from "@ingcreators/annot-product-docs";
export default defineConfig({
meta: {
projectName: "Customer management system",
customerName: "Acme Corp.",
},
xlsx: {
defaultBook: "Screen specifications",
books: {
"Screen specifications": {
// No `template` — use the OSS default layout.
},
},
},
});
Terminal window
pnpm annot-docs-xlsx render --book "Screen specifications"

Output: dist/xlsx/Screen specifications.xlsx with cover / history / screen-list / per-screen sheets, the annotated PNG embedded on the per-screen sheet, the overlay table populated from the three <Overlay> entries.

For a customer-supplied template, swap the defineConfig above with the template + templateSheets form shown on the xlsx-templates page.

Add the bundled GitHub Actions workflow to .github/workflows/docs.yml:

on:
pull_request:
paths:
- "packages/web/**"
- "docs/books/**"
- "tests/docs/**"
jobs:
drift:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v6
- uses: actions/setup-node@v6
with:
node-version-file: .nvmrc
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm dev &
- run: npx wait-on http://localhost:5173
- run: pnpm exec playwright install chromium
- run: pnpm exec playwright test tests/docs/
- run: pnpm annot-docs lint --ci --json --url http://localhost:5173 > drift.json || true
- run: node node_modules/@ingcreators/annot-product-docs/dist/cli/annotate-pr.js < drift.json

A PR that adds a new button — without updating the MDX — gets a yellow warning annotation on the PR diff:

⚠ added — button "Cancel" appears under <form name="sign in"> but is not
documented in docs/books/example/SC-001-login.mdx

The author either:

  • Adds an <Overlay match> for the new button, runs the tour, the warning clears.
  • Runs annot-docs lint --fix if the new button is intentionally undocumented (it gets recorded but produces no warning).