# Documentation style guide (living) This is the **living** home for documentation authoring conventions for the RDBMS Playground website. It grows as we write. - **Binding rules** come from [ADR-website-001 §7](../docs/website/adr/20260604-adr-website-001.md); this guide must not contradict them. If a convention is significant, durable, or contested, it is decided in an **ADR** (new or amended), and this guide references it. Finer, settled conventions live here directly. - **Open decisions** (not yet settled) are tracked at the bottom so we decide them deliberately rather than re-deciding per page. When one settles, move it up into the body (and to an ADR if it's significant). Status tags used below: **[DECIDED]** (binding or settled) · **[OPEN]** (to be decided — see the log). --- ## Terminology & wording [DECIDED — ADR-website-001 §7] - **No "DSL".** It is internal jargon. Use **simple mode** (the playground's keyword command language) and **advanced mode** (SQL). - **No engine name.** Never name SQLite / STRICT / rusqlite / PRAGMA in user-facing copy. Say **"the database"** or **"the engine"**. (Continues the user-facing posture of ADR-0002.) - Preferred terms (extend as we go): "command", "project", "table", "column", "relationship" (the user-facing word for a declared foreign-key link), "constraint", "index". - Add new banned/preferred terms here as they come up, with a one-line reason. ## Voice & tone [DECIDED, refine as needed] - **Teaching-first.** Pedagogy wins ties (CLAUDE.md). Explain the *why*, not just the *how*; the audience spans beginners through learners ready for raw SQL. - Second person ("you"), present tense. Imperative mood for step instructions ("Create a table…"). - Prefer short sentences and concrete examples over abstract prose. ## Structure [DECIDED] Pragmatic, Diátaxis-influenced split (five top-level sidebar sections, autogenerated per directory under `src/content/docs/`): - **Getting started** — install, first project, simple vs. advanced, the example database. - **Using the playground** — *the application you drive*, kept distinct from the database-language Reference: command-line options, the assistive editor (completion / highlighting / `[ERR]`/`[WRN]` indicator / hints / in-line editing), the output pane (scrolling), projects (save/load/new/rebuild), undo & history, export & import, clipboard, getting help. (ADR-0003's "app-level commands" + ADR-0022/0027 typing assistance + the CLI.) - **Guides** — task-oriented how-tos. *These are the most important didactic content and will be iterated for teaching quality before publication.* - **Reference** — the exhaustive command/SQL/type surface. **Page granularity: one page per topic / command-family** (Tables, Columns, Relationships, Indexes, Constraints, Inserting & editing data, Querying, Types, …), each covering the simple-mode and advanced-mode forms where both apply. Hand-written now (the command surface is settled bar H1a output); small post-release adjustments are expected and fine. - **Concepts** — the "why": projects & storage, undo & history, etc. Ground every reference page in source — `parse.usage.*` and `help.*` in `src/friendly/strings/en-US.yaml`, `src/dsl/command.rs`, `src/dsl/types.rs` — never paraphrase grammar from memory. ## "Planned / not yet available" callouts [DECIDED — ADR-website-001 §7] Any capability that is not yet fully implemented is **omitted** or carries a clear callout — never presented as shipped. Standard form: a Starlight aside ```md :::caution[Planned] This is planned and not yet available. ::: ``` ## Examples & code [DECIDED] - **Shared example database: a small library** — `authors`, `books`, `members`, `loans` (see the canonical schema below). Reuse it across all pages so readers build familiarity; it models 1:n (an author has many books) and m:n (books ↔ members, through loans). - Where both modes apply, show the **simple-mode** form and its **advanced-mode (SQL)** equivalent — the in-app teaching echo already pairs these, so docs mirror it. - Prefer **worked examples** (a real command on the library schema) over abstract prose, and **always cross-link** the related reference/guide pages (use stubs so links resolve before a page is written). - Code blocks for exact input/output; reserve casts for motion/flow. ### Code-block fences - **Simple-mode commands → ` ```rdbms `** — custom highlight grammar in `src/grammars/rdbms.mjs`, registered with Expressive Code in `astro.config.mjs` (keywords + types coloured). - **Advanced-mode SQL → ` ```sql `**; shell / install → ` ```sh `. - A decorative `> ` prompt is prepended to `rdbms` lines via CSS (`src/styles/global.css`) — **do not type `>` in the fence**. It is copy-safe (Expressive Code's copy button uses `data-code`) and `user-select:none`. - **One command per line** in an `rdbms` block; a multi-line single statement (e.g. advanced `CREATE TABLE`) belongs in a ` ```sql ` block, where no prompt is added. - **Command output → a plain unlabelled ` ``` ` fence** placed immediately after the command block (no language, so no `> ` prompt and no highlighting). Output must be **captured from the real app**, never hand-drawn — box-drawing diagrams, query-plan trees, and data tables are copied verbatim (trailing padding spaces trimmed). The capture method: a throwaway in-crate test that builds the canonical library schema and prints the rendered output (`render_structure_with_diagrams`, `render_relationship_diagram`, `render_data_table`, `render_explain_plan`, `show_list`), removed once the output is pasted. Colour is lost in a static block (the structure still reads); the coloured/animated rendering is earmarked for casts. ### Canonical library schema (source of truth for examples) Use these exact names/types in every example: | Table | Columns (playground types) | |-----------|---------------------------------------------------------------------------------------------| | `authors` | `author_id` serial (pk) · `name` text (not null) · `birth_year` int | | `books` | `book_id` serial (pk) · `title` text (not null) · `author_id` int (→ authors) · `published` int · `isbn` text (unique) | | `members` | `member_id` serial (pk) · `name` text (not null) · `joined` date | | `loans` | `loan_id` serial (pk) · `book_id` int (→ books) · `member_id` int (→ members) · `loaned_on` date · `returned_on` date | Relationships: `books.author_id → authors.author_id` (1:n); `loans` joins `books` and `members` (the m:n bridge). Show `shortid` on the Types page via a small standalone example, not by complicating this schema. ## asciinema casts [DECIDED] - Casts show *flow/motion*; static code blocks show *exact input/output*. Prefer a code block when a still example suffices. - Pair a hero/landing cast with a text transcript or the equivalent docs snippet (accessibility + SEO). ### Where to use a cast [DECIDED 2026-06-10] **Rule: a cast wherever the app *does something*.** A cast at the top of a page gives the reader the *shape* of what the page describes — quickly and visually — with the detailed text below for when they need it. (This helps visual learners, but is valuable more broadly.) Concretely: - **Broadly** on the pages about *doing / interacting*: the landing, **Getting started** (first project, modes), **Using the playground** (the assistive editor, output-pane scrolling, undo/redo, projects, copy, export/import), and **Guides**. - **Selectively** on **Reference** — only where motion beats the still (e.g. the relationship diagram being drawn; a query plan appearing). Reference pages keep their **captured static output** regardless; a cast complements, never replaces it. - **Skip** pure-lookup / conceptual pages with nothing to animate (e.g. the Types table, prose Concepts pages). - A cast is **selective**: it shows a chosen, representative slice of what the page documents — it need not exercise every command on the page. - **Autoplay only the landing hero**; elsewhere casts are click-to-play (a poster frame) so they don't all clamor at once. All casts re-record in one `pnpm casts` run, so breadth stays maintainable. ### Cast pacing & clarity [DECIDED 2026-06-11] - **Give the viewer a beat before a command is submitted.** A command that is typed and `Enter`-ed in the same instant vanishes before the viewer can read it. Type, **pause**, then submit — especially for **modal confirmations** (e.g. the `save as` name prompt) and short commands (`new`): script the text and the `Enter` as *separate* steps with a pause between (`{ type: 'x', enter: false, after: … }` then `{ key: 'Enter', after: … }`). - **Surface state where the schema sidebar would.** At the cast width (90 cols) the schema sidebar is hidden (ADR-0046 hides it at ≤90 cols), so the viewer can't see tables/relationships appear and disappear. Insert `show tables` / `show table ` / `show data ` at the points where state **changes**, so a sequence reads clearly (e.g. the projects cast shows `show tables` before saving, after `new`, and after loading — table present → none → present). - **Driver: `autocast`** (ADR-website-001 §2; chosen by the 2026-06-10 spike). `autocast`'s `!Interactive` feeds keys to the running TUI and captures the redraw — the correct model for a full-screen crossterm app. `asciinema-automation` was rejected: it assumes *shell* semantics (Enter as `\n`, and an `expect()` echo-check per keystroke), which a redrawing TUI breaks — it produced a garbled cast. - **Authoring workflow.** Source command-lists live in `casts-src/casts.mjs` (human-readable steps: `type` / `wait` / `key`). `pnpm casts` runs `casts-src/generate.mjs`, which expands them to autocast YAML (one key per character; Enter = `^M`) and records to `public/casts/.cast`. The command-lists are the durable source; **`.cast` files are regenerable** — re-run `pnpm casts` to re-record as the app evolves (a final sweep is due once the app is locked). Needs a `cargo build` binary at `../target/debug`. - **Embedding.** `Demo.astro` (the WASM-swap seam, ADR-website-001 §3) wraps `Cast.astro` (asciinema-player island). Call sites use `Demo`. - **Conventions.** Terminal geometry per cast (default 90×26); file name = cast `name`; player theme `asciinema`. **Cast theme — fixed dark for launch (DECIDED 2026-06-11).** Casts bake the app's dark theme into the recording as RGB SGR codes, so the player theme can't recolour them; true light/dark would require recording light-theme cast variants and swapping via the `Demo` seam. Deferred as not worth the doubled asset/recording cost for launch; revisit with the eventual full re-record. ## Formatting [DECIDED, refine] - Starlight asides for notes/tips/cautions; tables for reference matrices (types, constraints, referential actions). - Keyboard keys rendered consistently (e.g. Ctrl+Z). - Cross-link related pages; never expose ADR numbers or internal jargon to the reader (ADRs are for us, not the docs audience). --- ## Open decisions log Decide these as we write; record the outcome (and escalate to an ADR if significant). **Resolved (2026-06-10):** 9. ~~Cast scripting toolchain~~ → **`autocast`**, proven by spike over `asciinema-automation` (which can't drive a full-screen TUI). Source command-lists in `casts-src/`, `pnpm casts` to record. See the *asciinema casts* section above. (Remaining sub-item: light/dark player theme sync — folded into #8 / Phase B.) **Resolved (2026-06-05):** 1. ~~Depth / organising spine~~ → **Pragmatic** four-section split (see Structure above). 2. ~~Page granularity~~ → **one page per topic / command-family**, both modes per page (see Structure). 3. ~~Standard example dataset~~ → **the library** (schema above). 4. ~~Simple-vs-advanced pairing~~ → **show both where both apply** (see Examples). 5. ~~"Planned" callout~~ → standard `:::caution[Planned]` aside (see above). 6. ~~Reference generation vs hand-writing~~ → **hand-write now** (command surface is settled bar H1a output; small later adjustments expected). **Resolved (2026-06-11):** 7. ~~Versioning~~ → **single-version for launch.** No version selector; one can be added at/after v1 if the docs ever need to diverge by version. Cast light/dark → **fixed dark for launch** (see *asciinema casts* above). `site` set to **`https://relplay.org`** (apex) — enables sitemap, canonical, and Open Graph URL resolution; a `www` host, if used, 301-redirects to apex. **Still open:** 8. **SEO/meta — remaining.** Per-page titles/descriptions are set; canonical + basic Open Graph (`og:title`/`og:url`) now auto-generate from `site`. What remains: **Open Graph social-card images** (`og:image`) — needs a card design, so it travels with the branding work (logo + palette, TBD with the user; the existing favicon is *not* a brand guideline).