math-tasks/CLAUDE.md

13 KiB
Raw Blame History

Math Tasks Generator

Printable math worksheet generator (A4 PDF) for children aged 79. Claude Code-driven workflow: user describes a task idea → Claude generates JSON config → creates HTML pages with Tailwind CSS → converts to PDF via Puppeteer.

No template engine. Claude Code generates fresh HTML pages directly from JSON task configs each time.

Commands

pnpm build:css          # Build Tailwind CSS (minified)
pnpm build:css:watch    # Watch mode for CSS
pnpm preview            # Serve HTML at localhost:3000 with live-reload
pnpm dev                # CSS watch + preview server (concurrent)
pnpm pdf -- <file>      # Convert HTML file to PDF
pnpm remove-bg -- <file|dir>  # Remove white background from PNG icons

Generate images via /gen-image skill (uses Banatie API, reads BANATIE_KEY from .env).

Directory Structure

src/
  styles/main.css              — Tailwind source with A4/print styles
  templates/space-base.html    — Base template (layout/styling reference)
  examples/space-worksheet2.html — Finished 3-page example (output reference)
  scripts/
    generate-pdf.mjs           — HTML → PDF via Puppeteer
    remove-bg.mjs              — Remove white background from PNGs (flood fill)
tasks/                         — JSON task definition files
assets/
  hero-images/                 — spaceship1-6.jpeg (header hero images)
  footers/                     — planet1-6.jpeg (footer panorama images)
  icons/pack1/                 — minerals1-6 + plants1-6, 16 variants each ({name}-{row}-{col}.png)
  backgrounds/                 — large background images per theme (~1200x1700px)
output/
  html/                        — generated HTML (gitignored)
  pdf/                         — generated PDFs (gitignored)
  css/                         — built Tailwind CSS (gitignored)

JSON Task Format

Each task is a JSON file in tasks/ defining a multi-page document. See tasks/space-exploration-1.json for a real example.

{
  "id": "space-exploration-1",
  "title": "Исследуй Планету",
  "description": "3-page space worksheet: addition ±, multiply by 5 ±, multiplication table ±",
  "labels": {
    "title": "Исследуй Планету",
    "subtitle": "Собери ресурсы, решая примеры!",
    "footerBubble": "Итого собрано на планете:"
  },
  "theme": {
    "style": "space",
    "template": "space-base",
    "icons": "assets/icons/pack1/"
  },
  "layout": {
    "columns": 2,
    "problemsPerPage": 20
  },
  "pages": [
    {
      "task": "A + B ± C, где A от 8 до 16, B от 4 до 8, C от 1 до 3. Знак ± выбирается случайно",
      "problemCount": 20,
      "heroImage": "assets/hero-images/spaceship2.jpeg",
      "footerImage": "assets/footers/planet3.jpeg",
      "heroDirection": "row-reverse"
    }
  ]
}

Fields

  • pages[] — array of pages, each with its own task and images
  • pages[].task — free-text description of problems to generate (Claude reads this and creates concrete expressions)
  • pages[].problemCount — how many problems on this page
  • pages[].heroImage — path to hero image for this page
  • pages[].footerImage — path to footer panorama for this page
  • pages[].heroDirectionrow (hero left) or row-reverse (hero right)
  • layout.columns — 1 or 2 column layout
  • layout.problemsPerPage — max problems per A4 page
  • labels — all visible text (no hardcoded language)
  • theme.style — visual theme name (e.g. "space")
  • theme.template — which base template to use (e.g. "space-base")
  • theme.icons — path to icon directory for problem cards

Space Base Template

Base template: src/templates/space-base.html Finished example: src/examples/space-worksheet2.html (3-page output matching tasks/space-worksheet2.json)

The base template defines the visual design for all space-themed worksheets. The example shows a complete generated document. When generating a new worksheet, read both files first, then produce a new HTML with these variations:

What to vary per worksheet

  1. Hero image — pick one from assets/hero-images/spaceship{1-6}.jpeg
  2. Footer image — pick one from assets/footers/planet{1-6}.jpeg
  3. Hero position — use flex-row-reverse class (hero right) or default flex direction (hero left) on the header div
  4. Problem icons — pick from assets/icons/pack1/ (minerals and plants, any variant {name}-{row}-{col}.png). Every icon must be unique across the entire document (no repeats across pages). Shuffle minerals and plants together randomly — do not sort by type
  5. Problem alignment — for each problem card, randomly assign justify-start, justify-center, or justify-end within its grid column. No repeating patterns — should look chaotic/scattered
  6. Title, subtitle, footer text — set from the task description
  7. Problems — generate directly from the task text in JSON config. Claude reads the free-text description and creates concrete math expressions

Layout structure (do not change)

  • Page: w-[210mm] h-[297mm] white container
  • Footer: absolute bottom, h-[80mm], with white-to-transparent fade on top. No overflow-hidden on footer container (causes 1px hairline artifact in PDF)
  • Footer bubble: absolute bottom-[12mm], pill-shaped with semi-transparent white bg
  • Content area: px-[12mm] pt-[4mm] pb-[65mm] flex column
  • Header: hero image w-[48%] + title block centered, use flex-row-reverse for hero-right
  • Footer gradient: linear-gradient(to bottom, white 0%, rgba(255,255,255,0.6) 25%, transparent 50%) with h-full
  • Problems: grid grid-cols-2 gap-x-3 gap-y-[3px] — 20 problems total
  • Each problem: 58px icon outside pill + text-[1.2rem] expression + w-16 answer underline inside pill
  • Font: Nunito via Google Fonts
  • Uses Tailwind CDN (<script src="https://cdn.tailwindcss.com">)

Color palette (do not change)

Element Hex
Title text text-indigo-950 (#1e1b4b)
Subtitle text-indigo-400 (#6366f1)
Card border border-indigo-100 (#e0e7ff)
Answer underline border-indigo-300 (#a5b4fc)
Card bg gradient from-white to-indigo-50/40
Footer bubble border border-indigo-200

HTML Generation Guidelines

When generating HTML worksheets:

  • OUTPUT MUST BE STATIC HTML. Generated HTML files in output/html/ must contain only static markup — no embedded <script> that computes, generates, or modifies content at runtime. If you need algorithms or calculations (graph generation, random placement, etc.), run them in a separate Node.js script in src/scripts/, then write the computed results as static HTML to output/html/. The user works with the final HTML directly and expects it to be stable across page reloads.
  • Always read src/templates/space-base.html (structure) and src/examples/space-worksheet.html (finished output) before generating
  • Page size: A4 = 210mm × 297mm
  • CSS: Uses Tailwind CDN in the HTML <script> tag (not the compiled CSS file) — this is the only allowed script
  • Page breaks: Use break-after: page between pages
  • Icons: 58×58px inline images from assets/icons/ next to each problem (outside the pill card)
  • Fonts: Nunito from Google Fonts via <link>
  • Images in PDF: Use local file paths (not URLs). Puppeteer resolves file:// protocol
  • Embed images as base64 data URIs when possible for reliable PDF rendering

Image Generation

Use the /gen-image skill to generate images via the Banatie API. The skill has its own script and full API documentation in .claude/skills/gen-image/. Auth via BANATIE_KEY in .env. Rate limit: 100 requests/hour.

Reference Policy for This Project

When generating new assets for assets/items/, use existing images from the same subfolder as --ref to maintain visual consistency across the set. For example, when creating asteroid2.png, reference asteroid1.png from the same folder. The gen-image skill's default policy is to ask before using refs — this project overrides that: use refs automatically for items in the same asset group.

Style reference chain for themed assets:

  • assets/items/asteroids/ — use any existing asteroid as ref for new ones
  • assets/items/crystals/ — use any existing crystal as ref for new ones
  • assets/icons/ — generate independently (icons have their own pipeline via icon packs)
  • assets/hero-images/, assets/footers/, assets/backgrounds/ — generate independently, no refs needed

Background Removal

Script src/scripts/remove-bg.mjs removes white backgrounds from PNG icons using flood-fill from edges (like magic wand in Photoshop). Uses sharp. White areas inside objects are preserved.

node src/scripts/remove-bg.mjs <file|dir> [--threshold N] [--fuzz N]
  • --threshold — whiteness threshold for R,G,B (default: 230, lower = more aggressive)
  • --fuzz — anti-alias radius in pixels at the boundary (default: 0)
  • Default input: assets/icons/pack2/

This is optional — not all icons need it. After generating/splitting new icons, ask the user if they want background removal on specific files.

PDF Generation

Puppeteer settings for A4 worksheets:

  • Format: A4
  • printBackground: true (required for background images)
  • Margins: zero (CSS handles margins)
  • preferCSSPageSize: true

Space Route Task Type

Generator script: src/scripts/generate-space-route.mjs Output: output/html/space-route-{N}.html

Generation rules

  • Grid: 7×9 hex grid with jitter, nodes evenly distributed across map area
  • Start nodes: Enemy = top-left corner, Player = bottom-left corner. Start nodes trimmed to exactly 2 edges
  • No asteroids on route nodes — decorative objects must not be placed on any node belonging to enemy or player routes, nor on neighbors of start nodes
  • Routes use waypoints — route goes toward an offset waypoint for ~40% of steps, then changes direction toward the final target. This prevents obvious straight-line paths
  • Route length: 7-9 steps for enemy, player gets 10 empty cells
  • Ship orientation: check each ship image and set flipEnemy/flipPlayer flags so all ships face right
  • Difficulty via diffRange: [minNodeValue, maxSpread] — first number = minimum node value, second = max |difference| between connected neighbors

Visual Position Editor

output/html/editor.html — a standalone drag-and-drop editor for repositioning elements (asteroids, icons, etc.) in generated worksheets.

Usage

http://localhost:3300/html/editor.html?file=collecting-asteroids-1.html
  • Mouse drag — move elements freely
  • Arrow keys — nudge 1mm (Shift+Arrow = 5mm)
  • Copy All JSON — export all positions to clipboard
  • Copy Changes — export only moved elements
  • window.getConfig() — same via console

How it works

The editor fetch()es the worksheet HTML and injects it into its own DOM, adding drag-and-drop behavior. The worksheet HTML stays clean — no editor code touches it. The editor identifies draggable elements via CSS selector (e.g., img[src*="pack3-asteroids"] for asteroids).

Applying positions from editor

User copies JSON from editor, gives it to Claude. Claude applies positions via a Node.js one-liner:

// Pattern: regex-replace positions in order per page
html.replace(
  /(<div class="absolute" style="left: )-?\d+mm; top: -?\d+mm(;"><div class="relative w-\[88px\]...pack3-asteroids)/g,
  (match, prefix, suffix) => { /* replace with new left/top from JSON */ }
);

When to use this pattern

Use the visual editor approach whenever a worksheet requires manual fine-tuning of element positions — any time automated placement can't fully replace human judgment (e.g., avoiding overlaps with irregular ship shapes, achieving visual balance). The workflow is:

  1. Claude generates initial positions algorithmically
  2. User opens editor, adjusts positions visually
  3. User exports JSON → Claude applies to HTML
  4. Generate PDF

This pattern can be extended to other element types by adding new CSS selectors to the editor's identification logic.

Workflow

  1. User describes the math task idea (or runs /new-doc)
  2. Claude creates/updates a JSON config in tasks/ with pages[].task descriptions
  3. Claude reads src/templates/space-base.html + src/examples/space-worksheet.html as references
  4. Claude generates HTML file in output/html/ — creates concrete problems from task text, assigns unique shuffled icons, builds all pages
  5. (Optional) User fine-tunes element positions via visual editor at editor.html?file=<name>.html, exports JSON, Claude applies
  6. Add a link to the new document in output/index.html (card with title and path)
  7. Run node src/scripts/generate-pdf.mjs output/html/<file>.html to create PDF
  8. Preview with pnpm preview at localhost:3300