From c828bf77678e67e53712e1035e51d7201941fb7f Mon Sep 17 00:00:00 2001 From: Oleg Proskurin Date: Wed, 22 Apr 2026 19:16:24 +0700 Subject: [PATCH] add split asteroids --- .claude/settings.local.json | 3 +- CLAUDE.md | 50 +- tasks/asteroid-splitting/CLAUDE.md | 134 +++ .../docs/asteroid-splitting-1.data.json | 244 ++++++ .../docs/asteroid-splitting-1.md | 47 ++ .../docs/asteroid-splitting-1.template.html | 786 ++++++++++++++++++ tasks/asteroid-splitting/editor.html | 275 ++++++ tasks/asteroid-splitting/index.html | 182 ++++ tasks/asteroid-splitting/scripts/generate.mjs | 145 ++++ tasks/index.html | 13 + 10 files changed, 1875 insertions(+), 4 deletions(-) create mode 100644 tasks/asteroid-splitting/CLAUDE.md create mode 100644 tasks/asteroid-splitting/docs/asteroid-splitting-1.data.json create mode 100644 tasks/asteroid-splitting/docs/asteroid-splitting-1.md create mode 100644 tasks/asteroid-splitting/docs/asteroid-splitting-1.template.html create mode 100644 tasks/asteroid-splitting/editor.html create mode 100644 tasks/asteroid-splitting/index.html create mode 100644 tasks/asteroid-splitting/scripts/generate.mjs diff --git a/.claude/settings.local.json b/.claude/settings.local.json index f88392f..11a76df 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -46,7 +46,8 @@ "Bash(mv freighter-mining1.png freighter11.png)", "Bash(mv freighter-science1.png freighter12.png)", "Bash(sort -t'\\(' -k2 -n)", - "Bash(grep -o 'scale\\(3.50\\).\\\\{0,200\\\\}')" + "Bash(grep -o 'scale\\(3.50\\).\\\\{0,200\\\\}')", + "Bash(python3 -c ':*)" ] } } diff --git a/CLAUDE.md b/CLAUDE.md index df11990..2a734b4 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -133,13 +133,26 @@ cat tasks/{type}/temp/{docId}.diff.json # see what changed # Read screenshot PNGs from tasks/{type}/temp/{docId}-page-{N}.png to verify visually ``` -## Index Page +## Preview Pages Structure -`tasks/index.html` — Claude updates manually when creating new documents. Each document has View and Edit links. Different task types can have different card styles. +Three-level navigation hierarchy, maintained manually by Claude: + +``` +tasks/index.html — main index (all categories) + → tasks/{type}/index.html — category page (all documents of this type) + → tasks/{type}/docs/{docId}.* — individual document files +``` + +**Main index** (`tasks/index.html`) — lists all task types as cards. Each card links to the category page (`/tasks/{type}/`). + +**Category page** (`tasks/{type}/index.html`) — lists all documents within this type. Contains View/PDF/Editor links per document. Back link to main index. Has "editor mode" toggle for dev-only features. + +**When creating a new task type:** create both the main index card AND the category `index.html`. +**When creating a new document:** add a doc-card to the category `index.html`. **Preview:** `http://localhost:3300/tasks/index.html` -The `frontend-design` skill is installed but applies **only to `tasks/index.html`** and other UI/navigation pages. Worksheet documents (`*.template.html`) are print/PDF layouts, not web pages — web design principles do not apply to them. +The `frontend-design` skill is installed but applies **only to `tasks/index.html`**, category pages, and other UI/navigation pages. Worksheet documents (`*.template.html`) are print/PDF layouts, not web pages — web design principles do not apply to them. ## Script Principles (Orchestrator Pattern) @@ -187,6 +200,7 @@ Use `chrome-devtools-mcp` tools (`navigate_page`, `take_screenshot`) to check pa - Checking editor functionality (drag, keyboard, save) - Verifying hover/click states - Inspecting specific elements +- **Verifying all links and navigation** after creating new task types or documents ### When to verify @@ -196,6 +210,36 @@ Use `chrome-devtools-mcp` tools (`navigate_page`, `take_screenshot`) to check pa - **After modifying asset paths or server config** — check all types - **Do not ask the user to verify** what you can check yourself via screenshots +### Post-creation link verification (MANDATORY) + +After creating a new task type or new document, use chrome-devtools MCP to verify the full navigation chain: + +1. Navigate to the main index (`/tasks/index.html`) — verify the new card renders and its link works +2. Click through to the category page (`/tasks/{type}/`) — verify it loads and lists all documents +3. Click through to each document link — verify View/Editor links work +4. If any link is broken or page fails to load — fix the issue immediately and re-verify in Chrome that the fix works + +**Do not consider the task complete until all links are verified in the live browser.** + +### Editor end-to-end verification (MANDATORY) + +**After creating or modifying any editor**, verify the FULL save cycle in Chrome DevTools before telling the user it works: + +1. Open the editor in the browser (`editor.html?file=...`) +2. Make a real change (click element, press keyboard shortcut) +3. Click Save (or call save programmatically) +4. **Wait for save to complete** (check server response) +5. **Read the saved `data.json` file** — verify it contains the changed values (NOT defaults) +6. **Run `generate.mjs`** and verify transforms appear in `output.html` +7. **Reload the editor page** — verify saved state is restored from `data.json` + +If ANY step fails, the editor is broken — fix it before presenting to the user. Never tell the user "editor works" based on visual-only checks without verifying the saved data file. + +**Common editor pitfalls:** +- Live-reload can reset editor state after save (fix: load data.json on init to restore) +- ES module imports may not work with `window`-exported globals (fix: use ` + + + + Расщепи Астероид + + + + + +
+
+ +
+
+
+ +
+

Расщепи Астероид

+

Раздели каждый астероид на две неравные части!

+
+
+
+ + +
+
+ + 10 +
+
+
10
=1+9
+
10
=4+6
+
10
= + 
+
10
= + 
+
10
= + 
+
10
= + 
+
+
+ +
+ + +
+
+ + 7 +
+
+
7
=1+ 
+
7
= +4
+
7
= + 
+
7
= + 
+
7
= + 
+
+
+ +
+ + +
+
+ + 5 +
+
+
5
=1+ 
+
5
= +3
+
5
= + 
+
+
+ +
+
+
+ +
+
+ +
+
+
+ +
+

Расщепи Астероид

+

Раздели каждый астероид на две неравные части!

+
+
+
+ + +
+
+ + 9 +
+
+
9
=1+8
+
9
=4+5
+
9
= + 
+
9
= + 
+
9
= + 
+
9
= + 
+
+
+ +
+ + +
+
+ + 6 +
+
+
6
=1+ 
+
6
= +4
+
6
= + 
+
+
+ +
+ + +
+
+ + 3 +
+
+
3
= + 
+
+
+ +
+
+
+ +
+
+ +
+
+
+ +
+

Расщепи Астероид

+

Раздели каждый астероид на две неравные части!

+
+
+
+ + +
+
+ + 8 +
+
+
8
=1+7
+
8
=3+5
+
8
= + 
+
8
= + 
+
8
= + 
+
+
+ +
+ + +
+
+ + 4 +
+
+
4
= + 
+
4
= + 
+
4
= + 
+
+
+ +
+ + +
+
+ + 2 +
+
+
2
= + 
+
+
+ +
+
+
+ +
+
+ +
+
+
+ +
+

Расщепи Астероид

+

Раздели каждый астероид на две неравные части!

+
+
+
+ + +
+
+ + 10 +
+
+
10
=3+7
+
10
=7+3
+
10
= + 
+
10
= + 
+
10
= + 
+
10
= + 
+
+
+ +
+ + +
+
+ + 7 +
+
+
7
= + 
+
7
= + 
+
7
= + 
+
7
= + 
+
7
= + 
+
+
+ +
+ + +
+
+ + 6 +
+
+
6
= + 
+
6
= + 
+
6
= + 
+
+
+ +
+
+
+ +
+
+ +
+
+
+ +
+

Расщепи Астероид

+

Раздели каждый астероид на две неравные части!

+
+
+
+ + +
+
+ + 9 +
+
+
9
=3+6
+
9
=6+3
+
9
= + 
+
9
= + 
+
9
= + 
+
9
= + 
+
+
+ +
+ + +
+
+ + 4 +
+
+
4
= + 
+
4
= + 
+
4
= + 
+
+
+ +
+ + +
+
+ + 3 +
+
+
3
= + 
+
+
+ +
+
+
+ +
+
+ +
+
+
+ +
+

Расщепи Астероид

+

Раздели каждый астероид на две неравные части!

+
+
+
+ + +
+
+ + 8 +
+
+
8
=2+6
+
8
=6+2
+
8
= + 
+
8
= + 
+
8
= + 
+
+
+ +
+ + +
+
+ + 5 +
+
+
5
= + 
+
5
= + 
+
5
= + 
+
+
+ +
+ + +
+
+ + 2 +
+
+
2
= + 
+
+
+ +
+
+
+ +
+
+ +
+
+
+ +
+

Расщепи Астероид

+

Раздели каждый астероид на две неравные части!

+
+
+
+ + +
+
+ + 10 +
+
+
10
=1+ 
+
10
= +6
+
10
= + 
+
10
= + 
+
10
= + 
+
10
= + 
+
+
+ +
+ + +
+
+ + 6 +
+
+
6
= + 
+
6
= + 
+
6
= + 
+
+
+ +
+ + +
+
+ + 3 +
+
+
3
= + 
+
+
+ +
+
+
+ +
+
+ +
+
+
+ +
+

Расщепи Астероид

+

Раздели каждый астероид на две неравные части!

+
+
+
+ + +
+
+ + 9 +
+
+
9
=1+ 
+
9
= +5
+
9
= + 
+
9
= + 
+
9
= + 
+
9
= + 
+
+
+ +
+ + +
+
+ + 7 +
+
+
7
= + 
+
7
= + 
+
7
= + 
+
7
= + 
+
7
= + 
+
+
+ +
+ + +
+
+ + 2 +
+
+
2
= + 
+
+
+ +
+
+
+ +
+
+ +
+
+
+ +
+

Расщепи Астероид

+

Раздели каждый астероид на две неравные части!

+
+
+
+ + +
+
+ + 8 +
+
+
8
=1+ 
+
8
= +5
+
8
= + 
+
8
= + 
+
8
= + 
+
+
+ +
+ + +
+
+ + 5 +
+
+
5
= + 
+
5
= + 
+
5
= + 
+
+
+ +
+ + +
+
+ + 4 +
+
+
4
= + 
+
4
= + 
+
4
= + 
+
+
+ +
+
+
+ +
+
+ +
+
+
+ +
+

Расщепи Астероид

+

Раздели каждый астероид на две неравные части!

+
+
+
+ + +
+
+ + 10 +
+
+
10
= + 
+
10
= + 
+
10
= + 
+
10
= + 
+
10
= + 
+
10
= + 
+
+
+ +
+ + +
+
+ + 8 +
+
+
8
= + 
+
8
= + 
+
8
= + 
+
8
= + 
+
8
= + 
+
+
+ +
+ + +
+
+ + 4 +
+
+
4
= + 
+
4
= + 
+
4
= + 
+
+
+ +
+
+
+ +
+
+ +
+
+
+ +
+

Расщепи Астероид

+

Раздели каждый астероид на две неравные части!

+
+
+
+ + +
+
+ + 9 +
+
+
9
= + 
+
9
= + 
+
9
= + 
+
9
= + 
+
9
= + 
+
9
= + 
+
+
+ +
+ + +
+
+ + 7 +
+
+
7
= + 
+
7
= + 
+
7
= + 
+
7
= + 
+
7
= + 
+
+
+ +
+ + +
+
+ + 5 +
+
+
5
= + 
+
5
= + 
+
5
= + 
+
+
+ +
+
+
+ +
+
+ +
+
+
+ +
+

Расщепи Астероид

+

Раздели каждый астероид на две неравные части!

+
+
+
+ + +
+
+ + 6 +
+
+
6
= + 
+
6
= + 
+
6
= + 
+
+
+ +
+ + +
+
+ + 3 +
+
+
3
= + 
+
+
+ +
+ + +
+
+ + 2 +
+
+
2
= + 
+
+
+ +
+
+
+ + \ No newline at end of file diff --git a/tasks/asteroid-splitting/editor.html b/tasks/asteroid-splitting/editor.html new file mode 100644 index 0000000..a0da146 --- /dev/null +++ b/tasks/asteroid-splitting/editor.html @@ -0,0 +1,275 @@ + + + + + + Asteroid Splitting Editor + + + +
+ + Page 1 / ? + +
+ Loading... +
+ + +
+
+
+ Keys: +/- scale • [/] rotate • 0 reset +
+
+
+ + + + + diff --git a/tasks/asteroid-splitting/index.html b/tasks/asteroid-splitting/index.html new file mode 100644 index 0000000..d2077f3 --- /dev/null +++ b/tasks/asteroid-splitting/index.html @@ -0,0 +1,182 @@ + + + + + + Split the Asteroid — Space Math Adventures + + + + + + +
+
+ ← All Categories + + +

Break apart asteroids into two unequal pieces! Each section shows an asteroid with a number, and the child must find different ways to split it into two addends. Great for practicing number decomposition.

+ +
+ +
+
Preview
+
+

Asteroid Splitting 1

+
+ 12 pages + Numbers 2–10
+ Split each number into two unequal parts • 3 sections per page • progressive hints +
+
+ Preview + PDF + Editor +
+
+
+ +
+
+
+ + + + + diff --git a/tasks/asteroid-splitting/scripts/generate.mjs b/tasks/asteroid-splitting/scripts/generate.mjs new file mode 100644 index 0000000..1492d30 --- /dev/null +++ b/tasks/asteroid-splitting/scripts/generate.mjs @@ -0,0 +1,145 @@ +#!/usr/bin/env node + +/** + * Generate output HTML from template + data for asteroid-splitting documents. + * + * Usage: node generate.mjs + * Example: node generate.mjs asteroid-splitting-1 + * + * Reads: docs/.template.html + * Reads: docs/.data.json (optional) + * Writes: docs/.output.html + * + * data.json format: + * { + * pages: [{ + * page: 1, + * sections: [{ index: 0, scale: 1.2, rotate: 15 }] + * }] + * } + * + * Applies transform to big asteroid img (w-[26mm] container) + * and proportionally to small asteroid imgs (w-[12mm] containers) in formula rows. + */ + +import { readFileSync, writeFileSync, existsSync } from 'fs'; +import { join, dirname } from 'path'; +import { fileURLToPath } from 'url'; +import { postGenerate } from '../../../src/scripts/post-generate.mjs'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const docsDir = join(__dirname, '..', 'docs'); + +const docId = process.argv[2]; +if (!docId) { + console.error('Usage: node generate.mjs '); + process.exit(1); +} + +const templatePath = join(docsDir, `${docId}.template.html`); +const dataPath = join(docsDir, `${docId}.data.json`); +const outputPath = join(docsDir, `${docId}.output.html`); + +if (!existsSync(templatePath)) { + console.error(`Template not found: ${templatePath}`); + process.exit(1); +} + +let html = readFileSync(templatePath, 'utf-8'); + +if (existsSync(dataPath)) { + const data = JSON.parse(readFileSync(dataPath, 'utf-8')); + html = applyData(html, data); + console.log(`Applied data from ${data.pages?.length || 0} pages`); +} + +writeFileSync(outputPath, html); +console.log(`Generated: ${outputPath}`); +await postGenerate(outputPath); + +function applyData(html, data) { + if (!data.pages) return html; + + // Split HTML into pages by w-[210mm] divs + const pageRegex = /
)(\s*/g, + `$1 style="${transform}">` + ); + } + + pageHtml = pageHtml.slice(0, secStart) + secHtml + pageHtml.slice(secEnd); + } + + return pageHtml; +} diff --git a/tasks/index.html b/tasks/index.html index 87e53f5..6e75737 100644 --- a/tasks/index.html +++ b/tasks/index.html @@ -204,6 +204,19 @@
+ +
+ Asteroid Splitting +
+
+

Split the Asteroid

+

Break apart asteroids into two unequal pieces! Practice number decomposition by splitting each asteroid's weight into different pairs of addends.

+
+ 1 worksheet + Number Splitting +
+
+