feat: playable SpellGrid page on the site (the highest TS reference, unmodified, in the browser)

The sync step copies the reference's engine, harness and content into
site/src/game/generated/ and replaces only content/index.ts (node:fs) with a
re-export of a browser content module (static imports of cards, words, seams,
levels). /play/ has a level picker, text-tile grid, keyboard and buttons, cards
then tiles, the chooser as buttons, rules, minions, the log tree, Undo by
replay and Restart. test:site plays l3 to the win under plain Node. Lessons
5, 10-13 and the home page link the page; lesson links to site pages go
through their source file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Lucas WintherandClaude Opus 5.5 committed 2026-11-11 14:22:50 +01:00
1 parent e5cde8a556
commit fb3d280be7
16 files changed
+1120 -8

No files matched your search

+12
View File
@@ -93,3 +93,15 @@ test("sync_writes_harness_and_ignores_missing_dirs", () => {
assert.match(page("harness.mdx"), /title: "Harness contract"/);
assert.deepEqual(readdirSync(join(root, "out")).sort(), ["01-a.mdx", "harness.mdx"]);
});
test("sync_links_site_pages_to_their_urls", () => {
const root = fixture(
{ "01-a": "# A\n\n[play](../../site/src/pages/play.astro) and [home](../../site/src/pages/index.astro)\n" },
{ "site/src/pages/play.astro": "---\n---\n", "site/src/pages/index.astro": "---\n---\n" },
);
const page = run(root)("01-a.mdx");
assert.match(page, /\[play\]\(\/play\/\)/);
assert.match(page, /\[home\]\(\/\)/);
const dead = fixture({ "01-a": "# A\n\n[play](../../site/src/pages/nope.astro)\n" });
assert.throws(() => run(dead), /dead link/);
});