Docs System
These docs are plain Markdown files under docs/, rendered by the same
Next.js app that runs the studio. There is no static-site generator — the
/docs route reads from disk on every request.
Layout
veyra/
docs/
index.md
user/
index.md
timeline.md
video-plan/
…
system/
index.md
architecture.md
…
src/
app/
docs/
layout.tsx # docs shell (sidebar + content)
page.tsx # /docs landing
[...slug]/page.tsx # /docs/<section>/<file>
lib/
docs.ts # fs reader, frontmatter parser, tree builder
components/
DocsSidebar.tsx # client component for the nav tree
MarkdownView.tsx # react-markdown wrapper
Authoring
Every .md file starts with YAML frontmatter:
---
title: Page Title
description: One-sentence summary used in the sidebar tooltip.
order: 1 # optional, controls sidebar sort
draft: false # optional, hide from the sidebar when true
---
The body is GitHub-flavoured Markdown — tables, task lists, fenced
code blocks all work. Headings get auto-ids via rehype-slug so you can
deep-link with #heading.
Code highlighting
Fenced code blocks are highlighted by rehype-highlight using
highlight.js. The studio ships the GitHub-dark theme; tag the block
with the right language for best results:
```ts
const beats = await fetch("/api/beat-grid", { method: "POST" });
```
Linking between docs
Use absolute paths that match the URL — /docs/user/timeline, not a
relative .md link. The viewer treats internal links as Next links
(client-side navigation) and external links as new tabs.
User guide vs system. The sidebar shows one top-level documentation tree at a
time: only user pages when the URL is under /docs/user, only system pages
under /docs/system (and likewise for version history). The user-guide
sidebar does not link to system or version docs — readers use the docs
home (/docs) to pick another section. System/version sidebars still link to
other sections. Keep user-facing Markdown free of /docs/system/… links and
keep system docs from linking to the user guide when a topic is split.
Nested manuals (subfolders)
A folder under a section — for example docs/user/video-plan/ with index.md
plus other .md files — renders as one parent row in the sidebar (href =
/docs/user/video-plan) and nested links for each page besides index.
Step URLs look like /docs/user/video-plan/inputs. Implemented by
readNestedDocFolder in src/lib/docs.ts.
How a request is served
- Next routes the request to
src/app/(studio)/docs/[...slug]/page.tsx. - The page calls
loadDoc(slug)fromsrc/lib/docs.ts, which:- Resolves the slug to an
.mdfile underdocs/. - Reads the file, parses frontmatter with
gray-matter. - Returns
{ frontmatter, content }.
- Resolves the slug to an
- The page renders
<MarkdownView>with the body, plus the sidebar tree fromloadDocsTree(). react-markdownruns the body throughremark-gfm,rehype-slug, andrehype-highlight.
The route is force-dynamic; edits to docs/*.md show up on the next
refresh without restarting the dev server.
Screenshots for docs or marketing
Regenerate PNGs under public/screenshots/ with npm run screenshots:update
(Playwright). Use absolute URLs in Markdown, e.g.
, if the viewer allows
it — see public/screenshots/README.md.
User guide in-app screenshots (/docs-user-screenshots/)
The User section can show studio UI captures under /docs-user-screenshots/*.png.
Regenerate from the repo with npm run docs:screenshots (dev server running), then
npm run docs:screenshots:publish to copy from .tmp/docs-user-screenshots/ into
public/docs-user-screenshots/. On the marketing site, run npm run sync:user-guide from
veyra-website/ after publishing PNGs so docs/ and screenshots stay aligned with the app.
Auth and Playwright details live in
e2e/user-guide-screenshots.spec.ts and package.json scripts (docs:auth:capture,
docs:screenshots:ci, etc.). End-user copy should stay in docs/user/; keep maintainer
commands here, not in the User guide body.
Adding a new section
- Create a folder under
docs/, e.g.docs/recipes/. - Add an
index.mdwith frontmatter (title,description,order). - Drop additional
.mdfiles alongside it. - The sidebar will pick them up automatically.
No code changes required for new pages — only when you want to change the rendering pipeline or sidebar behaviour.
