Skip to content

Migrate the docs to Fumadocs 16 and split the sidebar into tabs - #223

Closed
endel wants to merge 12 commits into
masterfrom
fumadocs
Closed

endel wants to merge 12 commits into
masterfrom
fumadocs

Conversation

@endel

@endel endel commented Sep 26, 2026 •

Copy link
Copy Markdown
Member

Moves docs.colyseus.io from Nextra 3 / Next 13 to Fumadocs 16 / Next 16 (still a static export on Netlify), and splits the one ~26-entry sidebar into four navbar tabs: Docs · Client SDKs · Learn · Deploy & Cloud.

Every URL and anchor is unchanged. The tabs are route-group folders, which don't take part in the URL. A build-to-build comparison against master: same 141 routes, every heading id and every code block identical.

Readers

  • Old URLs get real HTTP 301s from public/_redirects, instead of a 404 page plus a JS redirect. This also ends the /tutorial → /learn/tutorial redirect loop.
  • One persisted SDK language switcher: picking Lua on /sdk carries to /state/callbacks and the netcode pages.
  • Copy Markdown / Open in ChatGPT, Claude… on every page. .md twins and llms-full.txt are kept.
  • On 63 pages the visible heading is now the frontmatter title, e.g. "Colyseus SDK for Unity" instead of "Unity SDK". <title> is unchanged.

Authors

  • Pages live in content/docs/, sidebar order in meta.json, written in Fumadocs' own conventions: built-in Tabs (items + groupId), Steps/Step, Cards, Accordion, Callout type="warn", lucide icons, and // [!code highlight] notation. The Nextra-era custom components are gone; only Mermaid and the engine logos remain beside Fumadocs.
  • Inactive tab panels stay in the static HTML, so every SDK language's code is crawlable (Nextra did this too; Base UI unmounts them by default).
  • pnpm check-links now takes heading ids from Fumadocs itself. It also lints _redirects (dead, shadowed and looping rules) and movedAnchors frontmatter, which replaces <MovedAnchors>.
  • pnpm build: 1m45s → 1m07s.
  • README, move-page and docs-review skills updated.

Merging

Use a merge commit, not a squash. Two commits are pure renames so git log --follow and blame survive; .git-blame-ignore-revs lists them.

Also carries two content commits made on master before branching: the Cloud Read API page and a StateView example fix.

Before marking ready

  • Deploy preview: every legacy URL and _redirects rule answers 301 → 200
  • /room/built-in keeps its #built-in-rooms fragment through the 301
  • Served as plain static files: no Next.js runtime headers; .md twins as text/markdown, unknown paths a real 404 (checked via response headers, not the build log)

🤖 Generated with Claude Code

Assisted-by: Claude Opus 5.5
Pure renames, no content changes, so rename detection keeps blame and
`git log --follow` intact across the migration. Nextra's sibling-file
folder indexes (room.mdx next to room/) become room/index.mdx.

The build stays broken until the Fumadocs scaffold lands.

Assisted-by: Claude Opus 5.5
Mechanical rewrite by a one-off codemod: _meta files become meta.json,
tabs get explicit values instead of positions, filename= becomes title=,
MovedAnchors moves to frontmatter, and body H1s go because Fumadocs
renders the frontmatter title. Heading slugs were checked unchanged
per page.

Every language switcher now joins one persisted group, so a reader's
pick on /sdk carries to /state/callbacks and the netcode pages.

The pages/404.mdx map becomes public/_redirects: prefix rules replace
includes() matching, which also ends the /tutorial -> /learn/tutorial
redirect loop.

Three headings lose their inline link: Fumadocs wraps heading text in
an anchor, and a nested <a> breaks hydration.

Assisted-by: Claude Opus 5.5
Next 16 app router, fumadocs-mdx, Notebook layout, static export as
before. Pages import nothing: every component, octicons included, is
registered in components/mdx.tsx.

Images keep their public URLs rather than becoming bundler imports:
Turbopack rejects the uppercase .PNG files in public/tutorial, and
renaming them would break their URLs.

The search index skips Orama's sort indexes: results rank by relevance
only, and the sort data was a third of the 6.7 MB file.

Assisted-by: Claude Opus 5.5
The scripts now run Fumadocs' own loader() over content/docs, so routes,
sidebar order and labels come from the code that builds the site rather
than a regex evaluation of _meta.tsx JSX.

check-links takes heading ids from Fumadocs' remarkHeading. That fixes
underscores being stripped from four slugs, and folder routes with no
page no longer pass as link targets. It also lints public/_redirects for
dead, shadowed and looping rules, which the includes() map could not
express.

Markdown twins are rendered by the /md route through lib/llms-markdown.ts
instead of a hand-written MDX parser. Unknown components still fail the
build.

Sitemap lastmod follows renames and skips the migration commits, so
moving every page doesn't reset every date.

Assisted-by: Claude Opus 5.5
Nextra's "Edit this page" link in the sidebar is gone; Fumadocs puts
"Edit on GitHub" under the table of contents.

Assisted-by: Claude Opus 5.5
Pure renames: route-group folders are not part of the URL, so every page
keeps its route. Sidebar tabs follow in the next commit.

Assisted-by: Claude Opus 5.5
One sidebar of ~26 top-level entries becomes four navbar tabs, each with
its own sidebar. Every URL is unchanged: the tabs are route-group root
folders, and route groups don't take part in the URL.

/sdk stays in Docs to keep the server → room → state → sdk build loop in
one place; the Client SDKs tab links to it and opens on its first engine
page instead.

llms.txt sections follow the tabs.

Assisted-by: Claude Opus 5.5
Mechanical rewrite by a one-off codemod, verified per file: heading
slugs unchanged, and every highlighted code block rendered through
Fumadocs' own Shiki transformers to confirm the same lines highlight
and the code text is identical.

- Tabs declare `items`; the SDK language tabs are
  `<Tabs groupId="lang" persist>` instead of a LangTabs wrapper
- Steps wrap each step in `<Step>`
- Callouts use `warn`, details become Accordions
- `{1,3-5}` fence meta becomes `// [!code highlight:N]` lines
- sidebar and Card icons are lucide; decorative inline icons are gone
- the scenario cards are Cards, the example tables are GFM tables

Assisted-by: Claude Opus 5.5
The custom ScenarioCard, ClientList, DemoCard and PremiumDemos
components give way to Cards, markdown tables and a shared partial
pulled in with <include>. The Tabs, Steps, image and hero wrappers are
gone too. What's left is Fumadocs, plus Mermaid (Fumadocs' documented
recipe) and the engine logos, which lucide doesn't carry.

Tab keeps inactive panels mounted: without it only the default
language's code reached the static HTML, so crawlers never saw the C#,
Lua, Haxe, GDScript or Dart examples.

Remote image sizes are fetched at build, as Fumadocs does by default,
which retires the plain-<img> fallback.

Assisted-by: Claude Opus 5.5
@endel

endel commented Sep 27, 2026

Copy link
Copy Markdown
Member Author

Closing without merging: keeping the Nextra site.

@endel endel closed this Sep 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant