feat: course website (Astro Starlight)

Pages (index, disclaimer, about), lockfile, root test:site script, fix for
Starlight 0.42 sidebar config and <details> rendering in generated MDX.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
Lucas Winther
2026-10-29 18:35:29 +01:00
co-authored by Claude Opus 5.5
parent d41496655e
commit 699d038d1c
8 changed files with 5230 additions and 3 deletions
+2 -1
View File
@@ -5,6 +5,7 @@
"license": "MIT",
"scripts": {
"test:tools": "node --test tools/test/*.test.mjs",
"check": "node tools/sync-check.mjs"
"check": "node tools/sync-check.mjs",
"test:site": "node --test site/scripts/*.test.mjs"
}
}
+1 -1
View File
@@ -21,7 +21,7 @@ export default defineConfig({
],
sidebar: [
{ label: "Start here", items: ["disclaimer", "about"] },
{ label: "Modules", autogenerate: { directory: "course" } },
{ label: "Modules", items: [{ autogenerate: { directory: "course" } }] },
],
}),
],
+5139
View File
File diff suppressed because it is too large Load Diff
+4
View File
@@ -131,6 +131,10 @@ export function mdxSafeProse(prose) {
let s = p.s.replace(/<!--[\s\S]*?-->/g, "");
s = s.replace(/[{}]/g, (c) => `\\${c}`);
s = s.replace(/<(?!\/?(?:details|summary)\s*>)/g, "&lt;");
// Put each details/summary tag on its own line with blank lines around it, so the
// markdown inside <details> is parsed as markdown rather than as JSX text.
s = s.replace(/[ \t]*(<details>|<\/details>|<summary>[^\n]*?<\/summary>)[ \t]*/g, "\n\n$1\n\n");
s = s.replace(/\n{3,}/g, "\n\n");
return s;
})
.join("");
+1 -1
View File
@@ -79,7 +79,7 @@ test("sync_pairs_code_tabs", () => {
test("sync_strips_comments_and_escapes_mdx", () => {
const out = mdxSafeProse("a <!-- Task 17: re-verify --> b {x} and `{kept}` <details><summary>S</summary> 1 < 2");
assert.doesNotMatch(out, /<!--/);
assert.match(out, /a b \\\{x\\\} and `\{kept\}` <details><summary>S<\/summary> 1 &lt; 2/);
assert.match(out, /a b \\\{x\\\} and `\{kept\}`\n\n<details>\n\n<summary>S<\/summary>\n\n1 &lt; 2/);
const root = fixture({ "01-a": `# A\n\n<!-- hidden -->\n\n${FENCE}rust\nif a < b { <!-- keep --> }\n${FENCE}\n` });
const page = run(root)("01-a.mdx");
assert.doesNotMatch(page, /hidden/);
+12
View File
@@ -0,0 +1,12 @@
---
title: About
description: Licence, source repository and how to report errors.
sidebar:
order: 2
---
A free course on extensible systemic game design, in Rust and TypeScript.
- **Licence**: MIT. Copy, adapt and teach from it. See the [LICENSE](https://gitea.lucaswinther.info/lucasw89/systemic-game-design-course/src/branch/main/LICENSE).
- **Source**: [gitea.lucaswinther.info/lucasw89/systemic-game-design-course](https://gitea.lucaswinther.info/lucasw89/systemic-game-design-course). The lessons on this site are generated from the `course/` directory of that repository.
- **Found an error?** Open an issue in the [Gitea issue tracker](https://gitea.lucaswinther.info/lucasw89/systemic-game-design-course/issues) with the page and what is wrong (a wrong prediction, a test that fails against a correct solution, a dead link).
+13
View File
@@ -0,0 +1,13 @@
---
title: Disclaimer
description: Trademarks, quoted card text and licensing.
sidebar:
order: 1
---
This course is an independent, non-commercial educational project.
- It is **not affiliated with or endorsed by Blizzard Entertainment or Hempuli**. Hearthstone is a trademark of Blizzard Entertainment. Baba Is You is a creation of Hempuli. All trademarks and game names belong to their respective owners.
- Short card and rule texts are quoted for **educational commentary** on game design. No game assets, code or data from those games are included.
- SpellGrid and all other course content are original.
- The course is **free**, and released under the MIT license.
+58
View File
@@ -0,0 +1,58 @@
---
title: Systemic Design Course
description: A free, hands-on course on extensible systemic game design, in Rust and TypeScript.
template: splash
hero:
tagline: Rebuild the rules machinery of Hearthstone and Baba Is You, then prove your design by adding content without touching the engine.
actions:
- text: Start with Module 0
link: /course/00-rewrite-trap/
icon: right-arrow
- text: Source on Gitea
link: https://gitea.lucaswinther.info/lucasw89/systemic-game-design-course
variant: minimal
---
import { Card, CardGrid } from "@astrojs/starlight/components";
## What this is
A free course on **systemic game design**. You learn by rebuilding the rules machinery of two games, then extending it:
- **Part I: Hearthstone**: cards, zones, triggers, death phases, auras, text assembly.
- **Part II: Baba Is You**: rules as pushable text, parsing, movement, win and lose.
- **Part III: SpellGrid**: a small original game that combines both systems.
Every module follows the same beats: Observe, Predict, Spec, Build, Name it, Expansion Drop, Further reading. The Expansion Drop is the test of your design: you add new content without touching the engine.
## Pick your path
<CardGrid>
<Card title="Solo" icon="open-book">
Read the lessons and scenarios, predict outcomes, and reason about the design (designer path), or also make the tests pass in your own engine (builder path).
</Card>
<Card title="With an AI mentor" icon="rocket">
Install the [mentor skill](https://gitea.lucaswinther.info/lucasw89/systemic-game-design-course/src/branch/main/mentor/README.md). Your agent asks, you build: it never writes your engine or content and releases hints one tier at a time.
</Card>
</CardGrid>
## Two tracks
Every code sample and exercise exists in **Rust** and **TypeScript**. Pick one and stay with it; the language tabs in the lessons remember your choice.
## Modules
- [Module 0: The Rewrite Trap](/course/00-rewrite-trap/)
- [Module 1: Handles and order of play](/course/01-handles/)
- [Module 2: The action queue, depth-first](/course/02-action-queue/)
- [Module 3: Deferred death](/course/03-death-step/)
- [Module 4: Interceptors and "trigger twice"](/course/04-interceptors/)
- [Module 5: Behavior as data and Assemble](/course/05-assemble/)
- [Module 6: Grid, lexer and parser](/course/06-parser/)
- [Module 7: Resolving rules: NOT, identity, meta-nouns](/course/07-rule-resolution/)
- [Module 8: Push chains: validate, then commit](/course/08-push-chains/)
- [Module 9: The turn pipeline](/course/09-turn-pipeline/)
- [Module 10: SpellGrid](/course/10-spellgrid/)
- [Harness contract](/course/harness/) (reference)
See also the [disclaimer](/disclaimer/) and [about](/about/) pages.