Writing Docs
About 1361 wordsAbout 5 min
How to edit the MaaKEDR docs site (VuePress Theme Plume).
Layout
docs/zh|en/{manual,develop,protocol}/
docs/.vuepress/config/navigation.ts # navbar + sidebarAdd new pages to both locale sidebars when applicable.
Homepage
Both homepages (docs/zh/README.md, docs/en/README.md) use Plume's home frontmatter; the order of the config entries is the order on the page.
- Four custom blocks live in
docs/.vuepress/components/:HomeDownload,HomeStats,HomePointerField(the drifting detection-box layer behind the content) andHomeFX(scroll progress bar + card pointer spotlight + scroll-in reveal). They must be registered inclient.tsbeforeconfigcan reference them bytype: HomeFXis a pure enhancement layer: after mount it only sets markers on the DOM (data-hp-reveal,data-hp-hero-away,is-revealed) and appends a progress bar tobody; every style keyed off those markers lives inhome-hero.css. With JS disabled, reduced motion on, or a coarse pointer, the page merely loses the corresponding effect — content stays visible. Follow that contract when adding homepage motion: never make content visibility depend on JS- All homepage-only CSS sits in the single file
docs/.vuepress/styles/home-hero.css. Every rule selector in it starts with.vp-homeso it cannot leak into doc pages; the only exception is the--vp-home-*custom properties, which have to be declared on the global:root/html[data-theme="dark"]to be inherited at all — the prefix is what keeps them from colliding with the theme's own variables - After mount,
HomeDownloaddetects the current device and shows only the matching build, collapsing the rest behind a small entry. Architecture is only reported when there is hard evidence: Chromium's high-entropy hints, an architecture literally spelled out in the UA (including the emulator'ssdk_gphone64_x86_64), or the macOS WebGL renderer name. Without evidence it reports “unknown” instead of guessing — a wrong guess sends the visitor to a build that will not run. Three endings: an unknown Mac chip gets two buttons (“Apple silicon” / “Intel”); an unknown Android ABI falls back to arm64-v8a (or universal) for widest coverage with an “architecture not detected” note; and when a desktop platform has no build for the local architecture the card explains why rather than falling back across architectures (the full list is one click away). A separate “may not run” warning covers a mismatch between the local architecture and the suggested build (in practice only reachable through the Android coverage fallback — desktop never falls back across architectures). Detection only exists on the client — the SSR output always contains the full list, so there is no hydration mismatch - The homepage version and download links are generated, never hand-written: on every build
tools/gen-docs-downloads.mjscalls the GitHub Release API for the latest stable release (/releases/latestskips prereleases) and takes the tag, publish time and asset list, parsingMaaKEDR-<os>-<arch>-<tag>-<ui>.<ext>into OS / architecture / interface. Freshness on the site is guaranteed by two triggers in.github/workflows/deploy-docs.yml: a change underdocs/**, and an automatic rebuild after the Release workflow succeeds (workflow_run). A manualworkflow_dispatchis available to force a refresh - The download section already reserves a slot for Android APKs: the script recognises
MaaKEDR-android-<universal|arm64-v8a|x86_64>-<tag>.apk(matching the Rename Release APK step inandroid-build.yml), and an APK'suifield is always an empty string (the Android build ships a single shell, with no MFAA/MXU split). Whenever the current stable release carries APKs, the "Android" group shows up automatically and Android browsers get the matching ABI suggested; when the asset list has none (e.g. a release from before Android support), the whole group is skipped instead of rendering an empty one - Automatic updates depend on the API being reachable: the script reads
GH_TOKEN/GITHUB_TOKENto authenticate (CI passes it), because the anonymous quota is only 60 requests/hour and once it is exhausted the script silently keeps the previous data and the site keeps showing the old version. When it does pick up a new version the build log printswrote N assets for vX.Y.Z; check that line when it looks stale docs/.vuepress/data/*.jsonis generated at build time —pnpm docs:build/docs:devruntools/gen-docs-downloads.mjsandtools/gen-docs-stats.mjsfirst. When the data cannot be fetched (a fresh clone with no network, for instance) the scripts write a placeholder (empty assets / zeroed figures) and both blocks degrade to a one-line notice instead of breaking the build; a previously generated file that no longer parses, or is missing a figure the homepage reads, is overwritten by that placeholder rather than kept. Never edit those files by hand- The node-name labels in
HomePointerFieldare a static snapshot taken fromresource/base/pipeline/*.json; renaming or dropping a pipeline node does not update the homepage
Acceptance checklist when changing the homepage
The homepage's custom components (especially HomeDownload) mix SSR fallbacks, device detection and conditional rendering, and some classes of defect slip through every existing gate. After changing them, work through this table:
| Defect class | pnpm check | docs:build | Browser console | Output inspection |
|---|---|---|---|---|
| Template references an undefined binding | ❌ | ❌ | ❌ | ❌ |
| Control condition is always false (button never renders) | ❌ | ❌ | ❌ | ❌ |
| Runtime exception | ❌ | ❌ | ⚠️ dev only | ❌ |
The first two have actually happened in this project: a template referenced a variable that was never defined in script. That is not a compile error and the build succeeds; Vue's production build strips the “accessed but not defined” warning; and the detection card does not render during SSR because detected === null, so the output never shows it either. “Build passes + console is clean” therefore cannot cover these.
So beyond checking which build was recommended, verify that the controls themselves exist and respond:
// Run in the browser console: confirm the expected number of controls,
// not just that the recommendation looks right
document.querySelectorAll(".picked-ui-btn").length; // 2 on desktop (MFAA/MXU); 0 means something is wrong
document.querySelector(".picked-dl")?.href; // should point at a real assetCover every conditional branch: detection succeeded / failed / architecture unknown / no build for this architecture. For each one ask: did the elements that should appear actually appear, and did the ones that should vanish actually vanish?
The long-term fix is adding
vue-tsc --noEmitfor.vuefiles, which detects undefined bindings statically. It is not wired up yet: it needs a shim declaration for virtual modules such as@theme/*and a few pre-existing type errors fixed first. It guards against a low-frequency, low-severity class of bug, so it is not worth the cost today. Revisit if the custom components keep growing or this class of bug shows up a second time.
Frontmatter
---
order: 1
icon: ri:tools-fill
---Containers
Tips
Tip box
Warning
Warning
MarkdownLint
Docs must pass MarkdownLint. The config lives at docs/.markdownlint.yaml (rule overrides and the reasons for disabling rules are annotated there).
- Rule reference: MarkdownLint Rules
- The VSCode extension picks up
.markdownlint.yamlautomatically for live hints - MarkdownLint is not wired into
pnpm checkor CI, and no related package is installed — it only runs in your editor, so do not expect a failing CI job to point at your Markdown - Division of labor with Prettier: Prettier handles formatting (indentation, line breaks, table alignment); MarkdownLint handles conventions (heading levels, list correctness, link validity). They do not conflict: noisy rules unrelated to Prettier (e.g. MD013 line length) are disabled in
.markdownlint.yaml
Preview
pnpm docs:dev
pnpm docs:buildpnpm docs:previewdoes not match the site'sbase: /MaaKEDR/right now, so the root URL 404s — usepnpm docs:devto look at your work- Running
vuepress dev docsdirectly skips the data generators, and the homepage blocks fail to build whendocs/.vuepress/data/is missing pnpm docs:buildpasses--clean-cache --clean-temp, which also kills a dev server that is currently running — do not run both at once
Keep user manuals aligned with tasks/*.json. Keep protocol pages aligned with pipelines. Release notes: update interface.json version / title manually (see AGENTS.md).
