Concepts
The MDX bundle
Section titled “The MDX bundle”A living-product-docs source unit is one MDX file per screen. The file has three layers:
annot:frontmatter — machine-readable identity + metadata (id, title, optionalxlsx.book/xlsx.sheet/xlsx.role).- MDX body — human prose, the
<Screen>block, and one<Overlay>per annotated element. - Comment blocks —
annot:snapshot(aria YAML with bbox markers) +annot:attributes(extracted HTML attribute set), rewritten on every tour run.
---annot: id: SC-001 title: Login screen xlsx: book: Screen spec 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
<Screen id="login" src="./shots/login.png">
<Overlay match={{ role: "textbox", name: "Email" }} intent="required" number={1}>**Email** — Enter your registered email.</Overlay>
<Overlay match={{ role: "button", name: "Sign in" }} intent="action" number={2}>Click to sign in.</Overlay>
</Screen>
{/* annot:snapshot- textbox [name="Email"] [ref=e1] [box=42,180,420,40]- button "Sign in" [ref=e2] [box=42,260,420,44]*/}
{/* annot:attributese1: id="email" type="email" autocomplete="email"e2: id="signin" type="submit"*/}The two {/* annot:* */} comment blocks are the byte-stable
output of the Playwright tour’s productDocs.sync(...) call.
Storing them in the MDX (rather than in a sidecar JSON) keeps
the source-of-truth in one file the author edits.
<Screen> + <Overlay> semantics
Section titled “<Screen> + <Overlay> semantics”<Screen id="login" src="./shots/login.png"> carries:
id— the identifier the tour passes toproductDocs.sync({ id })to know which screen this is. Multiple screens in one MDX are fine; each<Screen>block has a uniqueid.src— the base screenshot. Relative paths resolve from the MDX file.
<Overlay> children are the annotations:
match={{ role, name }}— accessibility-tree match key. Persistent — the resolver re-finds the element by role + name on every tour run, so a Playwrightref=eNchanging between runs doesn’t break the link.intent—required/action/info/warning/note. Maps to a colour from the Annot design system.number— the callout number. Drives the badge index in the rendered docs site + the row order in the screen-specifications Excel output.- The body content is MDX — text / markdown / further components.
match disambiguation
Section titled “match disambiguation”When role + name resolve to multiple elements, add match.under
or match.nth:
<Overlay match={{ role: "button", name: "Save", under: { role: "dialog", name: "Edit profile" } }}>Saves the profile edits.</Overlay>under constrains the search to descendants of an ancestor that
itself matches the under-clause; nth picks the Nth match if
the role+name pair genuinely repeats.
The snapshot block
Section titled “The snapshot block”annot:snapshot is a verbatim copy of Playwright’s AI-mode aria
snapshot, with [box=x,y,w,h] markers appended to each line by
the screen fixture’s ariaSnapshot({ boxes: true }) call. The
markers feed the Astro Image Service (Phase 5 of the plan) so
overlays render at the correct on-screen coordinates without
the MDX author providing pixel positions by hand.
If a tour hasn’t run yet (the file ships without the snapshot
block), the docs site still builds — <Screen> falls back to
the base PNG verbatim and <Overlay> callouts render as a
numbered list under the screen.
The attributes block
Section titled “The attributes block”annot:attributes extracts a per-ref set of HTML attribute
strings — id, type, autocomplete, aria-*,
data-testid, and a small allowlist of common form-related
attributes. Drives the Excel adapter’s attributes table and
the drift detector’s attribute-drift finding kind.