Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions .github/workflows/docs-site.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Documentation site (ADR-0009). Linux-only, Node-only, and deliberately
# INDEPENDENT of the C++/CMake matrix in ci.yml: no CMake target invokes npm and
# no job here needs a C++ toolchain, so a developer build never requires Node.
name: docs site

on:
push:
branches: [main]
paths:
- 'docs/user-guide/**'
- 'docs-site/**'
- 'editor/src/theme/theme.cpp'
- 'editor/src/help/help_registry.cpp'
- '.github/workflows/docs-site.yml'
pull_request:
paths:
- 'docs/user-guide/**'
- 'docs-site/**'
- 'editor/src/theme/theme.cpp'
- 'editor/src/help/help_registry.cpp'
- '.github/workflows/docs-site.yml'

permissions:
contents: read

jobs:
build:
name: build docs site
runs-on: ubuntu-latest
defaults:
run:
working-directory: docs-site
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: docs-site/.nvmrc
cache: npm
cache-dependency-path: docs-site/package-lock.json

# sharp is kept out by package.json's `overrides` (see stubs/sharp):
# its libvips binaries are LGPL-3.0-or-later and Qt is this project's only
# sanctioned LGPL dependency. `--omit=optional` was NOT usable here — it
# would also drop rollup's required native binary.
- name: Install
run: npm ci

- name: Licence gate
run: npm run licenses

- name: Theme tokens (from theme.cpp)
run: npm run theme

- name: Adapt docs/user-guide
run: npm run adapt

# Every F1-reachable page must exist on the site too, so a page can never
# be reachable in-app but missing here.
- name: F1 coverage
run: npm run check

- name: Build
run: npx astro build

- uses: actions/upload-artifact@v4
with:
name: docs-site
path: docs-site/dist
retention-days: 7
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,6 @@ gw2_replay_out/

# The scale bench writes its measurements beside the binary it runs from.
scale-metrics.json
docs-site/dist/
docs-site/node_modules/
docs-site/.astro/
12 changes: 6 additions & 6 deletions ASSETS_LICENSES.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,10 +213,10 @@ models, fonts, images). Policy — see [`docs/standards/assets.md`](docs/standar
| `assets/signs/us/W11-2.svg` | original work (this repository), drawn after the public-domain US federal sign specifications (MUTCD); no third-party artwork file was copied. Embedded as SVG text by `scripts/gen_sign_symbols.py` | RoadMaker contributors | Apache-2.0 | 2026-07-25 |
| `assets/signs/us/W3-1.svg` | original work (this repository), drawn after the public-domain US federal sign specifications (MUTCD); no third-party artwork file was copied. Embedded as SVG text by `scripts/gen_sign_symbols.py` | RoadMaker contributors | Apache-2.0 | 2026-07-25 |
| `docs/standards/golden-look.png` | original work (this repository), editor screenshot | RoadMaker contributors | Apache-2.0 | 2026-07-13 |
| `docs/user-guide/img/create-road.png` | original work (this repository), editor screenshot | RoadMaker contributors | Apache-2.0 | 2026-07-13 |
| `docs/user-guide/img/junction.png` | original work (this repository), editor screenshot | RoadMaker contributors | Apache-2.0 | 2026-07-13 |
| `docs/user-guide/img/elevation.png` | original work (this repository), editor screenshot | RoadMaker contributors | Apache-2.0 | 2026-07-13 |
| `docs/user-guide/img/library.png` | original work (this repository), editor screenshot | RoadMaker contributors | Apache-2.0 | 2026-07-13 |
| `docs/user-guide/img/workflow.gif` | original work (this repository), scripted frame sequence via `scripts/editor_screenshot.py` (`--drag-ghost`/`--drop-library`) | RoadMaker contributors | Apache-2.0 | 2026-07-21 |
| `docs/user-guide/img/gs1_hero.png` | original work (this repository), editor screenshot via `scripts/editor_screenshot.py` (same command as CI `visual-artifacts`) | RoadMaker contributors | Apache-2.0 | 2026-07-21 |
| `docs/user-guide/reference/img/create-road.png` | original work (this repository), editor screenshot | RoadMaker contributors | Apache-2.0 | 2026-07-13 |
| `docs/user-guide/reference/img/junction.png` | original work (this repository), editor screenshot | RoadMaker contributors | Apache-2.0 | 2026-07-13 |
| `docs/user-guide/reference/img/elevation.png` | original work (this repository), editor screenshot | RoadMaker contributors | Apache-2.0 | 2026-07-13 |
| `docs/user-guide/reference/img/library.png` | original work (this repository), editor screenshot | RoadMaker contributors | Apache-2.0 | 2026-07-13 |
| `docs/user-guide/reference/img/workflow.gif` | original work (this repository), scripted frame sequence via `scripts/editor_screenshot.py` (`--drag-ghost`/`--drop-library`) | RoadMaker contributors | Apache-2.0 | 2026-07-21 |
| `docs/user-guide/reference/img/gs1_hero.png` | original work (this repository), editor screenshot via `scripts/editor_screenshot.py` (same command as CI `visual-artifacts`) | RoadMaker contributors | Apache-2.0 | 2026-07-21 |
| `docs/roadmap/archive/2026-07-pre-reset/golden_scenes/img/gs1_baseline_v0.6.0.png` | original work (this repository), viewport render from the GS-1 fixed camera, rendered by CI (`visual-artifacts`) | RoadMaker contributors | Apache-2.0 | 2026-07-15 |
35 changes: 30 additions & 5 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,31 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
Current version on `main`: **0.0.1**.

### Added
- **The user guide is split into tiers, and a documentation site is scaffolded**
([#345](https://github.com/Robomous/RoadMaker/issues/345), docs-s1 —
[ADR-0009](docs/decisions/0009-documentation-site-tiered-docs.md)). The
per-tool and per-panel pages moved to `docs/user-guide/reference/` (dual
source: shipped in the in-app Qt Help book **and** on the site); tutorials and
guides are site-only. `docs/user-guide/index.md` stays the ordering manifest
for **both** pipelines, which is what stops the two outputs drifting.

The Qt Help generator is narrowed to the reference tier, and what became dead
is deleted rather than left inert: the `TocEntry::tutorial` flag, the synthetic
"Tutorials" TOC node, and the `tutorials/` `<files>` patterns.

New `docs-site/`: pinned Astro Starlight on Node LTS with a committed
lockfile, a Node adapter that synthesizes Starlight frontmatter from each
page's first H1 and **fails the build on a broken link**, and a Linux-only CI
workflow that builds the site as an artifact. No CMake target invokes npm and
nothing in the site build needs a C++ toolchain — the graphite-amber palette
reaches the site by *parsing* `theme.cpp`, so `theme::graphite_amber()` stays
the single source of truth without coupling the two builds. The committed
in-app `help.css` is untouched.

A licence gate over the npm tree runs in CI. It caught Astro's optional
`sharp` dependency, whose prebuilt libvips binaries are **LGPL-3.0-or-later** —
Qt is this project's only sanctioned LGPL dependency, so `sharp` is overridden
to a local no-op stub and Astro uses its passthrough image service instead.
- **An authored road now says what kind of road it is**
([#454](https://github.com/Robomous/RoadMaker/issues/454)). The model, reader
and writer for OpenDRIVE `<type>`/`<speed>` landed earlier, and
Expand Down Expand Up @@ -1717,7 +1742,7 @@ Grouped with the two sub-sections below, which were also never released.
Baselines are captured from the branch's own CI artifact — macOS has no
offscreen GL context, so a dev machine cannot produce one.
- **Textured-rendering user guide** ([#52](https://github.com/Robomous/RoadMaker/issues/52)):
`docs/user-guide/textured-rendering.md` documents the
`docs/user-guide/reference/textured-rendering.md` documents the
`View ▸ Textured Rendering` toggle — what Sober and Textured are each for,
why Sober is the default, and what "textured" deliberately does not include
(no shadows, no IBL). The mode shipped in 0.5.0 and CI renders with it, but
Expand Down Expand Up @@ -1980,7 +2005,7 @@ is headless-testable.
Road's tangent-continuation snap now produces a genuinely *linked* road, not
merely an adjacent one. Named fixture `CloseGapNoCurvatureKinkWhenArcStartsAtJoint`
proves the connector's curvature meets each neighbour within `tol::kWeldCurvature`.
Python `edit.create_linked_road`. Docs: `docs/user-guide/context-menus.md`.
Python `edit.create_linked_road`. Docs: `docs/user-guide/reference/context-menus.md`.
- **Drop a T/X intersection ONTO a road** (gate finding 1): dragging a T or X
assembly from the Library onto an existing road now tees/crosses INTO it,
aligned to the road tangent, instead of dropping a superimposed floating
Expand Down Expand Up @@ -2025,7 +2050,7 @@ is headless-testable.
still reachable. Removal is one undoable `edit::remove_lane` command that
restores the exact lane on undo; a success toast surfaces via the panel's new
`status_message` signal. Behaviour and tests:
`docs/user-guide/lane-profile.md`, `docs/user-guide/context-menus.md`.
`docs/user-guide/reference/lane-profile.md`, `docs/user-guide/reference/context-menus.md`.
- **First-run guided tour** (UI revamp Phase 4): a 5-step, skippable coach-mark
tour runs once on a first launch — draw a road → drag in an intersection →
plant a tree → shape the elevation → export — dimming the app and ringing the
Expand Down Expand Up @@ -2314,7 +2339,7 @@ is headless-testable.
README hero + drag-and-drop workflow GIF, the committed **golden-look**
baseline (`docs/standards/golden-look.png`, from the new
`assets/samples/golden_scene.xodr` T-junction-with-props scene) wired into the
UI-design standard, a new [Library](docs/user-guide/library.md) user-guide
UI-design standard, a new [Library](docs/user-guide/reference/library.md) user-guide
page, themed screenshots on the Create Road / Junction / Elevation / Objects
pages, and a refreshed in-editor props story on the Objects page. The M3a UI
revamp epic is complete; remaining standards-track work (junction boundary,
Expand Down Expand Up @@ -2397,7 +2422,7 @@ GW-1 + GW-2 executed by the maintainer.
the projected station, dashed ghost line from the selected end, and the
highlighted `[s−gap, s+gap]` span the junction will replace; the status
text also appears as a viewport-corner hint for every tool; new
[T-junction user-guide page](docs/user-guide/t-junction.md); kernel
[T-junction user-guide page](docs/user-guide/reference/t-junction.md); kernel
`edit::t_attach_gap` (bound in Python) exposes the auto-gap the preview
and the command share; committed tee sample `assets/samples/t_attach.xodr`.

Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ package sit on top ([architecture](docs/architecture/overview.md)).
![The RoadMaker editor: an urban intersection — a signalized four-arm
junction with crosswalks, stop lines, lane arrows, traffic lights, and street
trees — in the graphite-amber theme with the Library catalogue
open](docs/user-guide/img/gs1_hero.png)
open](docs/user-guide/reference/img/gs1_hero.png)

Drag a road assembly, an intersection, or a prop straight from the **Library**
onto the scene — every drop is one undoable edit:

![Placing trees along a junction by dragging them from the Library](docs/user-guide/img/workflow.gif)
![Placing trees along a junction by dragging them from the Library](docs/user-guide/reference/img/workflow.gif)

Prebuilt editor packages (DMG / NSIS installer / AppImage) and Python wheels
will ship with the first release, **v0.1.0** — published when the
Expand Down
7 changes: 7 additions & 0 deletions docs-site/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Adapted content is generated by scripts/adapt.mjs — never committed, never
# hand-edited. Same for the theme CSS, which is derived from theme.cpp.
src/content/docs/
src/styles/theme.css
node_modules/
dist/
.astro/
1 change: 1 addition & 0 deletions docs-site/.nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
24
70 changes: 70 additions & 0 deletions docs-site/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# RoadMaker documentation site

Astro Starlight project that publishes `docs/user-guide/` as a static site
([ADR-0009](../docs/decisions/0009-documentation-site-tiered-docs.md)).

## The content here is GENERATED — never hand-edit it

`src/content/docs/` and `src/styles/theme.css` are build outputs and are
gitignored. The sources are:

| Output | Source | Generator |
|---|---|---|
| `src/content/docs/**` | `docs/user-guide/**` | `scripts/adapt.mjs` |
| `src/styles/theme.css` | `editor/src/theme/theme.cpp` | `scripts/theme-css.mjs` |

Editing a generated file silently loses the edit on the next build. Change the
source instead.

## The two pipelines share one manifest

`docs/user-guide/index.md` is the ordering manifest for **both** the in-app Qt
Help book and this site: `helpc::build_toc()` reads its links in document order,
and `scripts/adapt.mjs` derives the reference-tier sidebar order from the same
list. That is deliberate — it is what stops the two outputs drifting. A page not
linked from `index.md` is invisible to both.

Tiers ([ADR-0009](../docs/decisions/0009-documentation-site-tiered-docs.md)):

- `reference/` — dual-source: shipped in the `.qhp` **and** on the site.
- `tutorials/`, `guides/` — site only.

## Commands

```sh
npm ci
npm run build # theme -> adapt -> F1 coverage -> astro build
npm run dev # same, then a dev server
npm run licenses # licence gate over the installed tree
```

The adapter **fails the build** on a broken link, naming the source page and the
target.

## Licences

Every npm dependency must be MIT/BSD/Apache-2.0-compatible under
[the dependency policy](../docs/standards/dependencies.md). `npm run licenses`
enforces that over the installed tree and runs in CI, so a transitive dependency
cannot introduce a copyleft licence between audits.

Astro's default image service is `sharp`, whose prebuilt libvips binaries are
**LGPL-3.0-or-later** — and Qt is this project's only sanctioned LGPL
dependency. So `astro.config.mjs` uses Astro's passthrough image service, and
`package.json`'s `overrides` points `sharp` at [`stubs/sharp`](stubs/sharp),
a no-op that throws if anything ever imports it. Guide images are editor
screenshots that need no build-time processing.

`--omit=optional` would have been the obvious mechanism and does **not** work:
it also drops rollup's required native binary. Overriding the single package is
the narrowest option npm offers.

## Node

Node LTS is pinned by `.nvmrc` and `engines`. CI uses `npm ci` against the
committed `package-lock.json`.

**No CMake target invokes npm**, and nothing here needs a C++ toolchain: the
theme generator parses `theme.cpp` as text rather than depending on a build
artifact, so a developer build never requires Node and this workflow never
requires a compiler.
27 changes: 27 additions & 0 deletions docs-site/astro.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// @ts-check
import { defineConfig, passthroughImageService } from 'astro/config';
import starlight from '@astrojs/starlight';

// The site is built from adapted content (see scripts/adapt.mjs); nothing under
// src/content/docs/ is hand-written.
export default defineConfig({
// Astro's default image service is `sharp`, whose prebuilt libvips binaries
// are LGPL-3.0-or-later. Qt is this project's ONLY sanctioned LGPL dependency
// (docs/standards/dependencies.md), so the passthrough service is used and
// `npm ci --omit=optional` keeps sharp out of the tree entirely. Guide images
// are editor screenshots that need no build-time processing.
image: { service: passthroughImageService() },
integrations: [
starlight({
title: 'RoadMaker',
description:
'Open-source ASAM OpenDRIVE road authoring — user guide, tutorials and tool reference.',
customCss: ['./src/styles/theme.css'],
sidebar: [
{ label: 'Guide', link: '/' },
{ label: 'Reference', autogenerate: { directory: 'reference' } },
{ label: 'Tutorials', autogenerate: { directory: 'tutorials' } },
],
}),
],
});
Loading
Loading