From 6bcc5b8b65223402b8f2d70312d7758a2dd957b6 Mon Sep 17 00:00:00 2001 From: Chris Lates Date: Sat, 11 Jul 2026 15:19:39 -0400 Subject: [PATCH] =?UTF-8?q?feat:=20agentic=20harness=20=E2=80=94=20CLAUDE.?= =?UTF-8?q?md,=20skills=20(feature/generate-week/test),=20settings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - CLAUDE.md: environment bootstrap, verified command table, architecture map, week-output conventions, skills index - .claude/skills/feature: full explore→plan→implement→test→PR pipeline with 'tests within reason' policy - .claude/skills/generate-week: offline Claude-authored themed weeks rendered via worksheet_html_renderer; teacher guide emitted by the same script - .claude/skills/test: pytest + Playwright invocation, triage, troubleshooting - .claude/settings.json: conservative permission allowlist - .gitignore: track .claude/ (except settings.local.json); ignore scripts/reference/ - scripts/generate_weather_week_series.py: canonical example produced by a cold dry-run of the generate-week skill (11 pages + embedded teacher guide) - frontend/.prettierignore: exclude Playwright artifacts so format:check passes after local e2e runs Both skills validated by cold subagent dry-runs: weather week generated clean (11 pages, all spot-checks pass); /health feature PR #90 shipped with 137 pytest + 41 e2e green. Co-Authored-By: Claude Fable 5 --- .claude/settings.json | 31 + .claude/skills/feature/SKILL.md | 75 ++ .claude/skills/generate-week/SKILL.md | 137 ++++ .claude/skills/test/SKILL.md | 49 ++ .gitignore | 5 +- CLAUDE.md | 65 ++ frontend/.prettierignore | 4 + scripts/generate_weather_week_series.py | 909 ++++++++++++++++++++++++ 8 files changed, 1274 insertions(+), 1 deletion(-) create mode 100644 .claude/settings.json create mode 100644 .claude/skills/feature/SKILL.md create mode 100644 .claude/skills/generate-week/SKILL.md create mode 100644 .claude/skills/test/SKILL.md create mode 100644 CLAUDE.md create mode 100644 scripts/generate_weather_week_series.py diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 0000000..1d64e4b --- /dev/null +++ b/.claude/settings.json @@ -0,0 +1,31 @@ +{ + "permissions": { + "allow": [ + "Bash(venv/bin/python -m pytest:*)", + "Bash(venv/bin/python scripts/:*)", + "Bash(venv/bin/python src/ingest_standards.py)", + "Bash(venv/bin/pip install -r requirements.txt)", + "Bash(venv/bin/uvicorn:*)", + "Bash(uv venv:*)", + "Bash(npm run dev:*)", + "Bash(npm run build:*)", + "Bash(npm run type-check:*)", + "Bash(npm run format:*)", + "Bash(npm run test:e2e:*)", + "Bash(npx playwright test:*)", + "Bash(npx playwright install chromium)", + "Bash(git status:*)", + "Bash(git diff:*)", + "Bash(git log:*)", + "Bash(git show:*)", + "Bash(git fetch:*)", + "Bash(git add:*)", + "Bash(git commit:*)", + "Bash(git branch:*)", + "Bash(git checkout -b:*)", + "Bash(gh pr view:*)", + "Bash(gh pr checks:*)", + "Bash(gh pr list:*)" + ] + } +} diff --git a/.claude/skills/feature/SKILL.md b/.claude/skills/feature/SKILL.md new file mode 100644 index 0000000..40cb32a --- /dev/null +++ b/.claude/skills/feature/SKILL.md @@ -0,0 +1,75 @@ +--- +name: feature +description: Take a feature request through the full pipeline — explore, plan, implement on a branch, test, and open a PR. Use when the user requests a new feature or behavior change in the app. +--- + +# Feature pipeline + +Input: a feature request, possibly one line. Output: a reviewed-ready PR with tests. + +## 1. Scope + +Restate the request in one sentence. If it is genuinely ambiguous (not just underspecified in ways +sensible defaults cover), ask **one** clarifying question; otherwise proceed. + +## 2. Explore + +Find the closest existing analog and mirror its structure rather than inventing new patterns: +- New endpoint → nearest endpoint in `src/main.py` + its test in `tests/test_*_api.py` +- New UI behavior → nearest page/component under `frontend/app/` + its spec in `frontend/e2e/` +- New worksheet type → existing type in `src/worksheets/` + `factory.py` registration + AGENTS.md §3 + +## 3. Plan + +Write a short plan before coding: files to touch, tests to add, done-criteria. For non-trivial +features, show the plan to the user before implementing. + +## 4. Branch + +```bash +git fetch origin +git checkout -b feat/ origin/main # or fix/ +``` +Follow AGENTS.md §7 (never commit to `main`; verify the branch isn't already merged before pushing). + +## 5. Implement + +Match surrounding style. Before committing, on every file you touched: +`venv/bin/python -m ruff check --fix && venv/bin/python -m black ` for Python, +`npm run format` for frontend files. Pre-commit hooks enforce these. + +## 6. Test policy — required, within reason + +- Each new backend behavior gets a pytest test (use `tests/factories.py` builders and + `tests/conftest.py` fixtures; temp DBs only). +- Each UI-facing use case gets Playwright coverage of its **happy path** in the relevant + `frontend/e2e/*.spec.ts` (seeding helpers in `e2e/fixtures/api.ts`). Cover the use case's + correctness, **not** exhaustive boundary matrices. +- No new test frameworks. Ad-hoc lesson content (`/generate-week`) is exempt from this policy. + +## 7. Verify + +Use the `/test` skill. While iterating, run single files/specs; before the PR, all of: + +```bash +venv/bin/python -m pytest tests/ -v --tb=short +cd frontend && npm run type-check && npm run format:check && npm run test:e2e +``` + +All green before opening the PR. Report failures verbatim — never weaken an existing test to pass. +If a check fails, confirm it isn't pre-existing (`git stash && && git stash pop`): +report pre-existing failures to the user separately instead of bundling fixes into your PR. + +## 8. PR + +```bash +git push -u origin +gh pr create --head --base main --title "feat: " --body "..." +``` + +(`--head`/`--base` are required when the working tree has unrelated uncommitted files — +without them `gh` may refuse to pick a branch.) + +- Conventional-commit title (`feat:` / `fix:`). +- Body: what & why, test evidence (suite counts), `Closes #N` when an issue exists. +- End the body with the standard Claude Code attribution footer. diff --git a/.claude/skills/generate-week/SKILL.md b/.claude/skills/generate-week/SKILL.md new file mode 100644 index 0000000..6de007b --- /dev/null +++ b/.claude/skills/generate-week/SKILL.md @@ -0,0 +1,137 @@ +--- +name: generate-week +description: Author a themed 5-day printable lesson week offline — Claude writes all content (no OpenAI key), renders via the HTML packet engine, and emits a student packet + teacher guide. Use when asked to generate a lesson week, unit, or worksheet packet ad hoc. +--- + +# Generate a themed lesson week + +You author every passage, question, and worksheet yourself — there is no LLM API call. Quality of +the written content is the whole product; budget most of your effort there, not on plumbing. + +## 0. Required reading + +Read `AGENTS.md` first. You will need: +- §3 — the worksheet-type table: **only HTML-capable kinds** (camelCase, e.g. `readingWorksheet`) + can go in a print packet, and the `feature_matrix` items-format gotcha (HTML wants plain strings). +- §2 — the "Instructional Pair" pattern (reading page + application page). +- §4 — pedagogy: "LET'S DISCUSS" closer with `response_lines: 0`, shuffled word banks/vocabulary, + outdoor activity in `instructions`, and a consistent narrator character introduced on Day 1. + +Then skim `scripts/generate_weather_week_series.py` — the tracked canonical example of this skill's +full output, including the embedded teacher guide. + +**Exact field names per kind are NOT all documented in AGENTS.md.** Before writing data dicts for a +kind you haven't used, read its render function in `src/worksheet_html_renderer.py` (e.g. +`causeEffectWorksheet` takes `pairs` with `cause`/`effect`/`effect_lines`; `treeMapWorksheet` +supports an optional `columns` layout key; `matchingWorksheet` items may be strings or +`{"text": ...}` dicts). + +## 1. Inputs + +- **Theme** (required) — e.g. "weather", "ancient Egypt". +- Optional: age/grade, subject, standards. Default to the established audience (Christopher, + age 6, grade K–1) if unspecified. If asked to align to standards, look them up in + `standards_data/` or `curriculum.db`. + +## 2. Design the week (before writing code) + +- A 5-day **causal arc** — each day's concept builds on the previous (e.g. Sun → tilt → seasons → + climate → biomes). Write the arc as one line; it goes in the script docstring. +- Per day: an **instructional pair** — a `readingWorksheet` plus one application worksheet + (featureMatrix / treeMap / causeEffect / wordSort / matching / oddOneOut / tChart / frayerModel). + Vary the application kinds across the week. Keep feature matrices to ≤6 properties so the + printed table stays readable. +- Friday: a capstone that synthesizes the whole arc. +- Final page: a **Parent Feedback & Teaching Notes** page (a `readingWorksheet` whose questions ask + the parent about comprehension, curiosity, and topics to revisit). +- Annotate each day with standards IDs in the docstring when standards were given. + +## 3. Write the script + +Create `scripts/generate__week_series.py`. Canonical skeleton (ruff already exempts +`scripts/*.py` from E402, so the `os.chdir` preamble is fine): + +```python +""" + — Week Series +Grade | | Causal Arc: + +Standards: + Monday — () + ... +""" + +import os + +os.chdir(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +import sys +from pathlib import Path + +sys.path.insert(0, os.path.abspath("src")) + +from worksheet_html_renderer import build_print_packet_html, render_worksheet_html + + +def generate__week_series(): + output_dir = Path("_week_series") + output_dir.mkdir(exist_ok=True) + pages: list[tuple[str, str]] = [] + + def add(kind: str, data: dict, day_label: str) -> None: + fragment = render_worksheet_html(kind, data, day_label) + if fragment is None: + raise ValueError(f"No HTML renderer for kind={kind!r}") + pages.append((day_label, fragment)) + + # MONDAY ... FRIDAY: add(...) calls, then the parent-feedback page + + html = build_print_packet_html(pages, packet_title=" Week — ") + (output_dir / "_week.html").write_text(html, encoding="utf-8") + + TEACHER_GUIDE = """...""" # see step 4 + (output_dir / "_week_teacher_guide.html").write_text(TEACHER_GUIDE, encoding="utf-8") + + print(f"Generated {len(pages)} pages -> {output_dir}/") + # then print a one-line label per page (the manifest) + + +if __name__ == "__main__": + generate__week_series() +``` + +`scripts/generate_weather_week_series.py` is the tracked, canonical realization of this skeleton. +`scripts/reference/` (gitignored, may not exist on every machine) holds older bespoke one-offs — +skimmable if present, but not canonical. + +## 4. Teacher guide — emitted by the same script + +Output directories are gitignored; the script is the only tracked artifact and must reproduce the +entire week. Embed the guide as an HTML string in the script and write it alongside the packet. +Contents per day: answer key for every question/cell, guidance for the "LET'S DISCUSS" prompt, +misconceptions to watch for, and one extension activity. Model the document structure and CSS on +the teacher guide embedded in `scripts/generate_weather_week_series.py` (self-contained HTML, +day-color headings matching the packet palette). + +## 5. Run and validate + +```bash +venv/bin/python scripts/generate__week_series.py +``` + +- Exit 0 (the `add()` helper raises on any unknown kind — an exception means a bad kind or field). +- Printed page count matches your design (typically 11: 5×2 + feedback page). +- Both HTML files exist and are non-trivially sized (packet is typically 40–60 KB). +- Read back one or two fragments from the packet HTML to spot-check content landed in the right + fields (e.g. vocabulary in the sidebar, `response_lines: 0` rendered without write-in lines). +- Tell the user to open the packet in a browser — the print dialog opens automatically. + +**No tests are required for generated weeks** — the validation above is sufficient. + +## 6. Commit + +Before committing, run `venv/bin/python -m ruff check --fix` and `venv/bin/python -m black` on the +script (pre-commit enforces both; f-strings without placeholders are a common miss), then re-run +the script once to confirm it still generates. + +Commit the script only (outputs are gitignored), on a branch with a PR per AGENTS.md §7: +`feat: week — `. diff --git a/.claude/skills/test/SKILL.md b/.claude/skills/test/SKILL.md new file mode 100644 index 0000000..44defc6 --- /dev/null +++ b/.claude/skills/test/SKILL.md @@ -0,0 +1,49 @@ +--- +name: test +description: Run and interpret the backend pytest suite and the Playwright E2E suite. Use for regression checks, before any PR, or when asked to run tests. +--- + +# Running the test suites + +Both suites must pass before any PR. Run from the repo root unless noted. + +## Backend (pytest) + +```bash +venv/bin/python -m pytest tests/ -v --tb=short # full suite (~135 tests, ~3s) +venv/bin/python -m pytest tests/test_feedback_api.py # one file +venv/bin/python -m pytest tests/ -k "cooldown" # by keyword +``` + +- Fixtures (`tests/conftest.py`) create temp SQLite DBs — tests never touch `curriculum.db`. +- Test-data builders live in `tests/factories.py`; prefer them over hand-rolled dicts. +- On failure: report the failing assertion verbatim, then fix or escalate — do not skip or + loosen an assertion to get green. + +## E2E (Playwright) + +```bash +cd frontend +npm run test:e2e # full suite (~41 tests, <1 min) +npx playwright test e2e/feedback.spec.ts # one spec +npx playwright test --grep "Edit Student" # one test by title +npx playwright test --headed # watch the browser +npm run test:e2e:ui # interactive UI mode +npm run test:e2e:report # open last HTML report +``` + +- Self-contained: `global-setup.ts` spawns `venv/bin/uvicorn` on port 8182 with an isolated DB + at `/tmp/playwright-test.db`; the frontend test server runs on port 3002. Dev servers and + `curriculum.db` are untouched. +- Requires the repo-root `venv/` and `npx playwright install chromium` (see CLAUDE.md bootstrap). +- Seeding helpers for new tests: `frontend/e2e/fixtures/api.ts` (`createStudent`, `createPacket`, + `submitFeedback`, `backdateFeedback`). + +### Troubleshooting + +- **Port 8182 or 3002 in use**: a previous run left processes behind — kill stale `uvicorn` + (`/tmp/playwright-backend.pid`) and `next dev` processes, then re-run. +- **Failure triage**: re-run just the failing spec (optionally `--headed`), read the failing step + in the report (`frontend/playwright-report/`), and include the report path when summarizing. +- A timeout on the first test of a run usually means the backend never became healthy — check + that `venv/bin/uvicorn` exists and imports cleanly (`venv/bin/python -c "import sys; sys.path.insert(0,'src'); import main"`). diff --git a/.gitignore b/.gitignore index c03c218..ea08be0 100644 --- a/.gitignore +++ b/.gitignore @@ -29,7 +29,10 @@ artifacts/ # Local environment and tooling .env -.claude/ +.claude/settings.local.json + +# Ad-hoc bespoke generator scripts kept locally as reference material (not canonical) +scripts/reference/ # Generated worksheet series output (produced by scripts/generate_*.py) *_series/ diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..811de19 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,65 @@ +# CLAUDE.md + +Homeschool curriculum app: FastAPI backend (`src/`) + Next.js frontend (`frontend/`) + offline +worksheet generators (`scripts/`). SQLite DB at `curriculum.db`. + +## Environment bootstrap + +Always use `venv/bin/python` — never system python. The E2E suite hard-codes `venv/bin/uvicorn` +(`frontend/global-setup.ts`), so the venv must live at the repo root. + +```bash +# Python 3.11–3.13 required (CI uses 3.12; Pillow<11 does not build on 3.14+). +# If system python is too new, use uv: +uv venv --python 3.12 --seed venv +venv/bin/pip install -r requirements.txt + +cd frontend && npm install && npx playwright install chromium +venv/bin/python src/ingest_standards.py # creates curriculum.db (one-time) +``` + +## Commands + +| What | Command | Notes | +|------|---------|-------| +| Backend dev server | `cd src && ../venv/bin/uvicorn main:app --reload` | port 8000 | +| Frontend dev server | `cd frontend && npm run dev` | port 3000 | +| Backend tests | `venv/bin/python -m pytest tests/ -v --tb=short` | fast (~3s) | +| E2E tests | `cd frontend && npm run test:e2e` | self-contained, see below | +| Type check | `cd frontend && npm run type-check` | | +| Format check | `cd frontend && npm run format:check` | Prettier | +| Python lint/format | ruff + black, 100-char lines | pre-commit enforces | +| Generate a week packet | `venv/bin/python scripts/generate__week_series.py` | see /generate-week skill | + +The E2E suite spawns its own backend on port 8182 with an isolated DB (`/tmp/playwright-test.db`) +and a frontend test server on port 3002 — it never touches `curriculum.db` or the dev servers. + +## Architecture map + +- `src/main.py` — FastAPI app; students, weekly packets, feedback, artifacts endpoints +- `src/agent.py` — OpenAI-driven weekly plan generation (needs `OPENAI_API_KEY`) +- `src/trio_generator.py` — generates 3 plans per student post-feedback; NTFY notify via `src/ntfy.py` +- `src/worksheet_html_renderer.py` — HTML print-packet engine (preferred for printables) +- `src/worksheet_renderer.py` — PIL engine (PNG/PDF, image-heavy types) +- `src/worksheets/` — 20 worksheet types; `factory.py` is the unified entry point +- `tests/` — pytest; fixtures in `conftest.py`, builders in `factories.py` (temp DBs, never `curriculum.db`) +- `frontend/e2e/` — Playwright specs; seeding helpers in `fixtures/api.ts` (backed by `scripts/e2e_seed.py`) + +## Conventions + +- **Read `AGENTS.md` before any worksheet/lesson work** — worksheet-type table, pedagogy patterns, + renderer selection, and git workflow rules live there. Do not duplicate them here. +- **Never commit to `main`** — branch from `origin/main`, open a PR (AGENTS.md §7). +- Conventional commits: `feat:` / `fix:` / `docs:`. +- **Week output rule**: a generated week's assets go in its own `_week_series/` directory at + the repo root — `_week.html` (student packet) and `_week_teacher_guide.html` + (teacher guide), both emitted by the generator script. Output dirs are gitignored: the script is + the only tracked artifact and must fully reproduce the week. +- `scripts/reference/` (gitignored, may be absent) holds bespoke one-off generator scripts kept as + local reference — not canonical patterns. + +## Skills + +- `/feature ` — full pipeline: explore → plan → implement on a branch → tests → PR +- `/generate-week ` — author a themed 5-day printable week offline (no OpenAI key) +- `/test` — run/interpret the pytest and Playwright suites, including single-test invocations diff --git a/frontend/.prettierignore b/frontend/.prettierignore index 74dcc15..08a6e05 100644 --- a/frontend/.prettierignore +++ b/frontend/.prettierignore @@ -25,3 +25,7 @@ coverage # Cache .cache .eslintcache + +# Playwright artifacts +test-results +playwright-report diff --git a/scripts/generate_weather_week_series.py b/scripts/generate_weather_week_series.py new file mode 100644 index 0000000..91063b6 --- /dev/null +++ b/scripts/generate_weather_week_series.py @@ -0,0 +1,909 @@ +""" +Weather — Week Series +Grade K–1 | Science | Causal Arc: Sun's Energy → Atmosphere & Clouds → Water Cycle → Wind & Pressure → Weather Patterns & Forecasting + +Narrator: Zara the Zebra Finch, introduced on Monday. A small speckled bird who flies through +every kind of weather and notices how the sky changes each day. +Output: single printable HTML document — weather_week_series/weather_week.html + +Standards (Virginia SOL): + Monday — K.9, K.9.a (weather conditions: sun, clouds, temperature) + Tuesday — K.9.a, K.9.b (cloud types, precipitation) + Wednesday — K.9.c, 1.6 (water cycle: evaporation, condensation, precipitation) + Thursday — K.9.b, 1.6.a (wind: direction, speed, pressure) + Friday — K.9, K.9.a–d (capstone: weather patterns, forecasting, weather tools) +""" + +import os + +os.chdir(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +import sys +from pathlib import Path + +sys.path.insert(0, os.path.abspath("src")) + +from worksheet_html_renderer import build_print_packet_html, render_worksheet_html + + +def generate_weather_week_series(): + output_dir = Path("weather_week_series") + output_dir.mkdir(exist_ok=True) + + pages: list[tuple[str, str]] = [] # (day_label, html_fragment) + + def add(kind: str, data: dict, day_label: str) -> None: + fragment = render_worksheet_html(kind, data, day_label) + if fragment is None: + raise ValueError(f"No HTML renderer for kind={kind!r}") + pages.append((day_label, fragment)) + + # ========================================================================= + # MONDAY — The Sun Heats Our World + # Standards: K.9, K.9.a — weather conditions, role of the sun + # ========================================================================= + + add( + "readingWorksheet", + { + "title": "Monday: The Sun Heats Our World", + "passage_title": "Meet Zara — and Why the Sun Matters!", + "instructions": ( + "Before reading: Go outside for two minutes. Stand in the sun, then in the shade. " + "Feel the difference! Come back inside and share what you noticed." + ), + "passage": ( + "Meet Zara the Zebra Finch! Zara is a small speckled bird with an orange beak and " + "a striped tail. Every morning, Zara wakes up on her branch and checks the sky before " + "she flies out to find seeds. 'What will the weather be like today?' she chirps.\n\n" + "Zara knows that everything about weather starts with the Sun. The Sun is a giant ball " + "of burning gas far away in space, and it sends energy all the way to Earth as light " + "and heat. When sunlight reaches Earth, it warms the ground, the water, and the air " + "above it. The more directly the Sun shines on a spot, the warmer it gets.\n\n" + "On a sunny day, Zara feels warm and cozy in the sunlight. The air around her is " + "warmer too, which means the air temperature is high. Temperature tells us how warm " + "or cold the air feels. We measure temperature with a thermometer. When there are " + "no clouds and the Sun shines all day, we call that a clear or sunny day.\n\n" + "But the Sun's energy does more than just warm us up — it also drives everything else " + "about weather. Without the Sun, there would be no wind, no rain, and no clouds. " + "Every storm, every rainbow, and every gentle breeze on Earth starts with the energy " + "our Sun provides. 'It all begins with the Sun,' Zara tweets to herself as she spreads " + "her wings and soars into the bright blue sky." + ), + "vocabulary": [ + { + "term": "weather", + "definition": "What the air outside is like right now — sunny, cloudy, rainy, windy, or snowy.", + }, + { + "term": "temperature", + "definition": "How warm or cold the air is. We measure temperature with a thermometer.", + }, + { + "term": "thermometer", + "definition": "A tool that shows how warm or cold the air is.", + }, + { + "term": "energy", + "definition": "The power the Sun sends to Earth as light and heat.", + }, + { + "term": "sunny", + "definition": "A day with no clouds blocking the Sun, so the sky looks bright blue and clear.", + }, + ], + "questions": [ + { + "prompt": "Where does all of Earth's weather energy come from?", + "response_lines": 2, + }, + { + "prompt": "What is temperature, and what tool do we use to measure it?", + "response_lines": 2, + }, + { + "prompt": "What did you notice when you stood in the sun vs. the shade before the lesson?", + "response_lines": 2, + }, + { + "prompt": "LET'S DISCUSS: If the Sun suddenly turned off, what do you think would happen to the weather on Earth? Explain your thinking!", + "response_lines": 0, + }, + ], + }, + "Monday", + ) + + add( + "wordSortWorksheet", + { + "title": "Monday: Sunny Days and Cloudy Days — Word Sort", + "instructions": ( + "Look at each weather word in the word bank. " + "Write it in the correct box — does it go with Sunny Weather or Cloudy / Rainy Weather?" + ), + "categories": [{"label": "Sunny Weather"}, {"label": "Cloudy / Rainy Weather"}], + "tiles": [ + "Bright sky", + "Rain puddles", + "Warm air", + "Gray clouds", + "Clear sky", + "Thunderstorm", + "Rainbows", + "Cool shade", + "Hot sidewalk", + "Wet grass", + ], + }, + "Monday", + ) + + # ========================================================================= + # TUESDAY — Clouds and Precipitation + # Standards: K.9.a, K.9.b — clouds as water droplets, types of precipitation + # ========================================================================= + + add( + "readingWorksheet", + { + "title": "Tuesday: Clouds and Precipitation", + "passage_title": "What Are Clouds Made Of?", + "instructions": ( + "Read about clouds with Zara. Then answer the questions below.\n\n" + "Outdoor observation: Look up at the sky today. Are there clouds? " + "Are they fluffy and white, thin and wispy, or flat and gray? " + "Remember what you saw for the feature matrix activity." + ), + "passage": ( + "Zara was zooming through the sky when she flew right through a low, " + "soft cloud. 'It feels like flying through a cold, wet fog!' she chirped in surprise. " + "That is exactly what clouds are — millions of tiny water droplets or ice crystals " + "floating together in the air. Clouds form when warm, wet air rises and cools down. " + "As the air cools, the water vapor in it turns into tiny droplets — that is called " + "condensation. Those droplets clump together to make a cloud.\n\n" + "Not all clouds look the same! Cumulus clouds are the big, puffy, white clouds " + "that look like cotton balls piled up in the sky. They usually mean fair, sunny weather. " + "Stratus clouds are flat, gray sheets that spread out low across the sky like a blanket. " + "They often bring light rain or drizzle. Cirrus clouds are thin, wispy streaks high up " + "in the sky, made of ice crystals. They look like feathers or horse tails.\n\n" + "When clouds hold too much water, the water falls back to Earth as precipitation. " + "Precipitation is any form of water that falls from clouds. It can be rain (liquid), " + "snow (frozen flakes), sleet (frozen rain drops), or hail (balls of ice). " + "Zara loves flying after a rain shower — the air smells fresh and clean, " + "and sometimes a beautiful rainbow appears when sunlight shines through the raindrops!" + ), + "vocabulary": [ + { + "term": "cloud", + "definition": "Millions of tiny water droplets or ice crystals floating together in the air.", + }, + { + "term": "condensation", + "definition": "When water vapor in warm air cools down and turns into tiny droplets — how clouds form.", + }, + { + "term": "precipitation", + "definition": "Any water that falls from clouds to the ground — rain, snow, sleet, or hail.", + }, + { + "term": "cumulus", + "definition": "Puffy, white, cotton-ball clouds — usually mean fair weather.", + }, + { + "term": "stratus", + "definition": "Flat, gray, blanket-like clouds that often bring drizzle or light rain.", + }, + { + "term": "cirrus", + "definition": "Thin, wispy, feathery clouds high in the sky, made of ice crystals.", + }, + ], + "questions": [ + {"prompt": "What are clouds made of? How do they form?", "response_lines": 3}, + { + "prompt": "Describe the three cloud types from the passage. Which one usually means good weather?", + "response_lines": 3, + }, + { + "prompt": "Name four types of precipitation. How are rain and snow different?", + "response_lines": 2, + }, + { + "prompt": "LET'S DISCUSS: If you see dark, flat stratus clouds rolling in, what do you think the weather will be like soon? Would you change any plans because of it?", + "response_lines": 0, + }, + ], + }, + "Tuesday", + ) + + add( + "featureMatrixWorksheet", + { + "title": "Tuesday: Cloud Types — What Do You Know?", + "instructions": ( + "Put a check mark in every box that describes each cloud type. " + "Use your reading card to help — look for clues in the passage!" + ), + "items": ["Cumulus", "Stratus", "Cirrus"], + "properties": [ + "Puffy and white", + "Flat and gray", + "Thin and wispy", + "High in the sky", + "Low in the sky", + "Made of ice crystals", + "Brings fair weather", + "Brings rain or drizzle", + ], + }, + "Tuesday", + ) + + # ========================================================================= + # WEDNESDAY — The Water Cycle + # Standards: K.9.c, 1.6 — evaporation, condensation, precipitation + # ========================================================================= + + add( + "readingWorksheet", + { + "title": "Wednesday: The Water Cycle", + "passage_title": "Water's Amazing Journey — Up and Down, Again and Again", + "instructions": ( + "Read about the water cycle with Zara. Then answer the questions below.\n\n" + "Hands-on activity: Pour a small puddle of water on the sidewalk in the sun. " + "Check it every 15 minutes. Where does the water go? " + "What happened — was the water cycle at work?" + ), + "passage": ( + "Zara watched a rain puddle on the sidewalk every morning for a week. " + "'The puddle was big on Monday,' she chirped, 'but by Wednesday it was gone! " + "Where did all that water go?' The answer is the water cycle — " + "one of the most important patterns in all of nature.\n\n" + "The water cycle has three main steps. Step 1 is EVAPORATION. " + "The Sun heats water in puddles, ponds, lakes, rivers, and oceans. " + "That heat turns liquid water into an invisible gas called water vapor, " + "which floats up into the air. This is what happened to Zara's puddle!\n\n" + "Step 2 is CONDENSATION. As the water vapor floats higher into the sky, " + "the air up there is colder. Cold air cannot hold as much water vapor, " + "so the vapor cools down and turns back into tiny liquid droplets. " + "Those droplets clump together — and they form clouds!\n\n" + "Step 3 is PRECIPITATION. When clouds collect enough water droplets, " + "the drops get heavy and fall back to Earth as rain, snow, sleet, or hail. " + "The water soaks into the ground, fills rivers and lakes, " + "and then the whole cycle begins again with evaporation. " + "'So the water in this puddle,' said Zara with wide eyes, " + "'might have once been in the ocean, then in a cloud, and now it is back on the ground! " + "And it will do that journey over and over, forever.'" + ), + "vocabulary": [ + { + "term": "water cycle", + "definition": "The never-ending journey of water from Earth's surface up into the sky and back down again.", + }, + { + "term": "evaporation", + "definition": "When heat turns liquid water into water vapor — an invisible gas that rises into the air.", + }, + { + "term": "water vapor", + "definition": "Water in its gas form — invisible, it rises into the sky when liquid water is heated.", + }, + { + "term": "condensation", + "definition": "When water vapor cools down and turns back into tiny liquid droplets to form clouds.", + }, + { + "term": "precipitation", + "definition": "Water that falls from clouds to the ground — rain, snow, sleet, or hail.", + }, + ], + "questions": [ + { + "prompt": "What are the three steps of the water cycle? List them in order.", + "response_lines": 3, + }, + {"prompt": "What is evaporation? What causes it?", "response_lines": 2}, + { + "prompt": "What causes condensation to happen up in the sky?", + "response_lines": 2, + }, + { + "prompt": "Why do the same water molecules keep going through the cycle over and over?", + "response_lines": 2, + }, + { + "prompt": "LET'S DISCUSS: Zara says the water in a puddle might once have been in the ocean. Do you think that is really true? Could water from a cloud over your town have started in the Pacific Ocean?", + "response_lines": 0, + }, + ], + }, + "Wednesday", + ) + + add( + "causeEffectWorksheet", + { + "title": "Wednesday: Water Cycle — Cause and Effect", + "instructions": ( + "Each cause describes something that happens in the water cycle. " + "Write the effect — what happens next? Use your reading card if you need a clue." + ), + "pairs": [ + { + "cause": "The Sun heats a puddle of water on the sidewalk.", + "effect": "", + "effect_lines": 2, + }, + { + "cause": "Water vapor rises high into the cold upper air.", + "effect": "", + "effect_lines": 2, + }, + { + "cause": "A cloud collects enough water droplets to become heavy.", + "effect": "", + "effect_lines": 2, + }, + { + "cause": "Rain falls on a mountain and flows into a river.", + "effect": "", + "effect_lines": 2, + }, + ], + }, + "Wednesday", + ) + + # ========================================================================= + # THURSDAY — Wind and Air Pressure + # Standards: K.9.b, 1.6.a — wind direction, speed, how pressure differences cause wind + # ========================================================================= + + add( + "readingWorksheet", + { + "title": "Thursday: Wind and Air Pressure", + "passage_title": "Why Does the Wind Blow?", + "instructions": ( + "Read about wind with Zara. Then answer the questions below.\n\n" + "Outdoor activity: Go outside and lick your finger. Hold it up in the air. " + "The side that feels cooler is the direction the wind is coming FROM. " + "Which direction is the wind blowing today?" + ), + "passage": ( + "Zara spread her wings and felt a strong gust of wind. It lifted her higher in the " + "sky without her even flapping! 'Wind is so helpful,' she sang, 'but where does it " + "come from?' The answer starts with temperature.\n\n" + "Remember that the Sun does not heat all parts of Earth equally. " + "Land heats up faster than water, and dark surfaces warm faster than light ones. " + "When a patch of ground gets warm, the air above it gets warm too. " + "Warm air is lighter than cool air, so warm air RISES — like a hot-air balloon. " + "As the warm air rises, it leaves behind an area of lower air pressure. " + "Air pressure is the weight of air pressing down on the ground.\n\n" + "Cool air nearby is heavier and has higher pressure. " + "High-pressure air always moves toward low-pressure areas — " + "it rushes in to fill the space left by the rising warm air. " + "THAT rushing movement of air is the WIND. The bigger the difference in pressure, " + "the stronger the wind blows.\n\n" + "We measure wind with special tools. An anemometer measures wind SPEED " + "— how fast the wind is blowing, in miles per hour. " + "A weather vane shows wind DIRECTION — the direction the wind is coming FROM. " + "If a weather vane points north, the wind is blowing FROM the north (called a north wind). " + "Zara loved riding the warm thermals — rising columns of warm air — " + "that helped her soar across the sky without tiring her wings!" + ), + "vocabulary": [ + { + "term": "wind", + "definition": "Moving air — caused when high-pressure air rushes into a low-pressure area.", + }, + { + "term": "air pressure", + "definition": "The weight of air pressing down on the ground. Warm air has low pressure; cool air has high pressure.", + }, + { + "term": "anemometer", + "definition": "A weather tool that measures wind speed — how fast the wind is blowing.", + }, + { + "term": "weather vane", + "definition": "A weather tool that spins and points to show the direction the wind is coming from.", + }, + { + "term": "thermal", + "definition": "A rising column of warm air — birds like Zara ride thermals to soar without flapping.", + }, + ], + "questions": [ + { + "prompt": "What causes wind? Explain in your own words using 'warm air' and 'pressure'.", + "response_lines": 3, + }, + { + "prompt": "What is the difference between an anemometer and a weather vane?", + "response_lines": 3, + }, + { + "prompt": "If the weather vane points south, which direction is the wind blowing FROM?", + "response_lines": 1, + }, + { + "prompt": "Why can Zara soar without flapping when she finds a thermal?", + "response_lines": 2, + }, + { + "prompt": "LET'S DISCUSS: On a hot summer day at the beach, the sand heats up faster than the ocean. Which way do you think the wind blows — from land to sea, or from sea to land? Why?", + "response_lines": 0, + }, + ], + }, + "Thursday", + ) + + add( + "matchingWorksheet", + { + "title": "Thursday: Weather Tools and Wind Words — Matching", + "instructions": ( + "Draw a line from each weather word or tool on the left to its correct meaning on the right." + ), + "left_items": [ + "Anemometer", + "Weather vane", + "Air pressure", + "Thermal", + "Wind", + "High pressure", + ], + "right_items": [ + "Measures how fast the wind is blowing", + "Points to show where wind comes FROM", + "The weight of air pressing on the ground", + "A rising column of warm air birds ride", + "Moving air caused by pressure differences", + "Found where air is cool and heavy", + ], + }, + "Thursday", + ) + + # ========================================================================= + # FRIDAY — Weather Patterns and Forecasting (Capstone) + # Standards: K.9, K.9.a–d — putting it all together, weather forecasting + # ========================================================================= + + add( + "readingWorksheet", + { + "title": "Friday: Weather Patterns and Forecasting", + "passage_title": "How Do Meteorologists Predict the Weather?", + "instructions": ( + "Read the capstone passage with Zara. Then answer the questions.\n\n" + "Capstone activity: Before starting, write down today's weather without looking at a " + "forecast. After the lesson, look up tomorrow's forecast online or on TV. " + "What weather tools helped the meteorologist make that prediction?" + ), + "passage": ( + "Zara had been watching the sky all week and she felt like she was getting very good " + "at guessing what the weather would do next. 'I think I am becoming a meteorologist!' " + "she chirped proudly. A meteorologist is a scientist who studies weather and makes " + "forecasts — predictions about what the weather will be like in the future.\n\n" + "Meteorologists have learned that weather follows patterns. " + "A weather pattern is when the same kind of weather happens in the same way, over and over. " + "For example, in many parts of the United States, summer afternoons often bring " + "thunderstorms — because the hot ground heats the air, which rises, forms big storm clouds, " + "and then the rain falls. That is the water cycle and wind working together!\n\n" + "Meteorologists use many special tools to collect data about the weather. " + "A thermometer measures temperature. A rain gauge is a small container that collects " + "and measures how much rain has fallen. An anemometer measures wind speed. " + "A barometer measures air pressure — when pressure drops quickly, a storm is often coming! " + "Weather satellites in space take pictures of clouds over huge areas of Earth, " + "and weather stations on the ground send data to computers every hour.\n\n" + "All of these measurements are put together into giant computer models that predict " + "how the atmosphere will change over the next few days. That is how meteorologists " + "can tell you whether to bring an umbrella tomorrow. " + "Zara ruffled her feathers and looked at the clouds building in the west. " + "'I predict rain by evening,' she tweeted — and she was right!" + ), + "vocabulary": [ + { + "term": "meteorologist", + "definition": "A scientist who studies weather and makes forecasts.", + }, + { + "term": "forecast", + "definition": "A prediction about what the weather will be like in the future.", + }, + { + "term": "weather pattern", + "definition": "Weather that repeats in a predictable way — like summer afternoon thunderstorms.", + }, + { + "term": "rain gauge", + "definition": "A tool that collects and measures how much rain has fallen.", + }, + { + "term": "barometer", + "definition": "A tool that measures air pressure — a quick pressure drop often means a storm is coming.", + }, + { + "term": "data", + "definition": "Measurements and facts collected by weather tools — meteorologists use data to make forecasts.", + }, + ], + "questions": [ + { + "prompt": "What is a meteorologist? What is a weather forecast?", + "response_lines": 2, + }, + { + "prompt": "Name four weather tools described in the passage. What does each one measure?", + "response_lines": 4, + }, + { + "prompt": "What does it mean for weather to follow a 'pattern'? Give one example from the passage.", + "response_lines": 3, + }, + { + "prompt": "How do all of this week's topics — Sun, clouds, water cycle, and wind — work together to create a thunderstorm? Explain the chain!", + "response_lines": 4, + }, + { + "prompt": "LET'S DISCUSS: If a barometer reading drops sharply in the morning, what should you predict for the afternoon — and would you change any outdoor plans?", + "response_lines": 0, + }, + ], + }, + "Friday", + ) + + add( + "treeMapWorksheet", + { + "title": "Friday: Weather Tools — Tree Map Capstone", + "instructions": ( + "Sort each weather word or tool from the word bank into the correct branch. " + "Each item belongs in only one branch — think about what it measures or describes!" + ), + "root_label": "Weather Science", + "branches": [ + {"label": "Measuring Tools", "slot_count": 4}, + {"label": "Water Cycle Steps", "slot_count": 3}, + {"label": "Cloud Types", "slot_count": 3}, + ], + "columns": 3, + "word_bank": [ + "Thermometer", + "Evaporation", + "Cumulus", + "Rain gauge", + "Condensation", + "Stratus", + "Anemometer", + "Precipitation", + "Cirrus", + "Barometer", + ], + }, + "Friday", + ) + + # ========================================================================= + # PARENT FEEDBACK & TEACHING NOTES + # ========================================================================= + + add( + "readingWorksheet", + { + "title": "End-of-Week Parent Feedback — Weather Week", + "passage_title": "Week Summary & Teaching Notes for the Parent", + "instructions": ( + "Please complete this feedback sheet after the week wraps up. " + "Your notes help shape next week's lessons." + ), + "passage": ( + "This week followed a causal arc through Earth's weather. " + "Monday established that all weather energy comes from the Sun, and introduced " + "the idea of temperature. Tuesday explored how clouds form through condensation " + "and the different types of precipitation. Wednesday traced the full water cycle " + "— evaporation, condensation, precipitation — as a continuous loop powered by the Sun. " + "Thursday explained wind as the movement of air from high pressure to low pressure, " + "caused by unequal heating. Friday pulled everything together with weather patterns " + "and forecasting — how meteorologists use tools and data to predict the weather.\n\n" + "Zara the Zebra Finch appeared throughout the week as a friendly narrator, " + "experiencing the weather from a bird's-eye view that gave concrete, relatable examples " + "for each concept.\n\n" + "Key concepts to check for genuine understanding — not just recall:\n" + "1) The Sun is the ultimate energy source for all weather.\n" + "2) Clouds form through condensation, not just 'water in the sky'.\n" + "3) The water cycle is continuous — the same water molecules keep cycling.\n" + "4) Wind is caused by pressure differences, not just 'air moving'.\n" + "5) Meteorologists use multiple tools and look for patterns — forecasting is data-driven.\n\n" + "Common misconceptions to watch for:\n" + "• 'Rain comes from the ocean' (partially true, but water vapor can come from any liquid water).\n" + "• 'Clouds are made of steam' (they are made of tiny liquid droplets or ice, not steam).\n" + "• 'Wind blows toward the warmer area' (wind blows FROM high pressure INTO low pressure — " + "toward the warmer, less dense air).\n\n" + "Suggested follow-on activities: keep a five-day weather journal; look up the local " + "barometer reading each morning and see if low pressure really does predict rain; " + "watch a TV weather forecast together and identify all the tools and maps used." + ), + "vocabulary": [ + { + "term": "Key Misconception to Watch", + "definition": "Clouds are NOT made of steam — they are made of tiny liquid water droplets or ice crystals formed through condensation.", + }, + { + "term": "Strongest Concept This Week", + "definition": "(Fill in after the week — which idea did Christopher grasp best?)", + }, + { + "term": "Next Week's Hook", + "definition": "Seasons and climate — why do some places get more sun? How does the Sun's angle change throughout the year?", + }, + ], + "questions": [ + { + "prompt": "Overall comfort with the week's content — how well did Christopher grasp the concepts? (1 = struggled throughout, 5 = strong grasp of all concepts)", + "response_lines": 1, + }, + { + "prompt": "Which day's lesson generated the most curiosity or questions?", + "response_lines": 2, + }, + { + "prompt": "By Friday, could Christopher explain the full chain: Sun → evaporation → cloud → rain → wind?", + "response_lines": 2, + }, + { + "prompt": "Did any weather events happen during the week (a real rain shower, wind, clouds) that you connected to the lessons in real time?", + "response_lines": 2, + }, + {"prompt": "Topics or vocabulary to revisit next week:", "response_lines": 2}, + ], + }, + "Friday", + ) + + # ========================================================================= + # Assemble & write + # ========================================================================= + + html = build_print_packet_html(pages, packet_title="Weather Week — Science for Christopher") + out_path = output_dir / "weather_week.html" + out_path.write_text(html, encoding="utf-8") + + # Teacher guide + TEACHER_GUIDE = """ + + + + Weather Week — Teacher Guide + + + + +
+

Weather Week — Teacher / Parent Guide

+

Theme: Weather  |  Audience: Christopher, age 6, K–1  |  + Narrator: Zara the Zebra Finch

+

Causal Arc: Sun's Energy → Atmosphere & Clouds → Water Cycle → Wind & Pressure → Weather Patterns & Forecasting

+ +

Monday — The Sun Heats Our World

+

Answer Key — Reading Questions

+
+

Q1 (Energy source): All of Earth's weather energy comes from the Sun. It sends light and heat energy to Earth.

+

Q2 (Temperature): Temperature is how warm or cold the air is. We measure it with a thermometer.

+

Q3 (Outdoor observation): Personal response — student should note feeling warmer in sunlight and cooler in shade. Guide them to connect this to the passage's explanation of direct sunlight warming surfaces.

+
+

LET'S DISCUSS Guidance

+
+

"If the Sun turned off, what would happen to the weather?"

+

Expected reasoning: No energy = no evaporation, no wind, no rain. Earth would get very cold very quickly. All weather would stop. There is no single right answer here — encourage logical chaining of causes.

+
+

Word Sort Answer Key

+
+

Sunny: Bright sky, Warm air, Clear sky, Rainbows, Hot sidewalk

+

Cloudy/Rainy: Rain puddles, Gray clouds, Thunderstorm, Cool shade, Wet grass

+

Note: "Rainbows" appear after rain (so rainy could be argued) but rainbows require sunlight — accept either category with good reasoning.

+
+

Misconceptions to Watch

+
+

Students often think the Sun "warms the air directly." Emphasize that the Sun first warms the GROUND and WATER, and the ground/water then warms the air above it. This matters for understanding wind formation on Thursday.

+
+

Extension Activity

+
+

Set up two small cups of water in the same spot — one covered with black paper, one uncovered white. Check the temperature of each after 20 minutes of sunlight. Why is the black cup warmer? (Darker surfaces absorb more solar energy.)

+
+ +

Tuesday — Clouds and Precipitation

+

Answer Key — Reading Questions

+
+

Q1 (Cloud formation): Clouds are made of millions of tiny water droplets or ice crystals. They form when warm, wet air rises, cools, and the water vapor undergoes condensation — turning into droplets that clump together.

+

Q2 (Cloud types): Cumulus = puffy, white, fair weather. Stratus = flat, gray, light rain or drizzle. Cirrus = thin, wispy, high up, made of ice. Cumulus usually means good weather.

+

Q3 (Precipitation): Rain (liquid), snow (frozen flakes), sleet (frozen rain drops), hail (balls of ice). Rain is liquid; snow is solid frozen water crystals — different temperatures cause different forms.

+
+

Feature Matrix Answer Key

+
+

Cumulus: Puffy and white ✓, Brings fair weather ✓, Low in the sky ✓

+

Stratus: Flat and gray ✓, Low in the sky ✓, Brings rain or drizzle ✓

+

Cirrus: Thin and wispy ✓, High in the sky ✓, Made of ice crystals ✓

+
+

LET'S DISCUSS Guidance

+
+

"If you see dark stratus clouds rolling in, what will the weather be like?"

+

Expected: Rain or drizzle is likely soon. Students may want to bring an umbrella, move activities indoors, or cover outdoor plants. The goal is to practice applying cloud-type knowledge to real-world decisions.

+
+

Misconceptions to Watch

+
+

"Clouds are made of steam." Correct this clearly: clouds are tiny LIQUID droplets (or ice crystals), not steam. Steam is invisible hot water vapor. When you see a visible cloud, condensation has already happened.

+
+

Extension Activity

+
+

Cloud journaling: Print or draw the three cloud types. For three consecutive days, go outside and draw which cloud type you see. Did the clouds correctly predict the weather that followed?

+
+
+ +
+

Wednesday — The Water Cycle

+

Answer Key — Reading Questions

+
+

Q1 (Three steps): 1) Evaporation — Sun heats water, turns it to vapor. 2) Condensation — vapor rises, cools, forms clouds. 3) Precipitation — water falls as rain/snow/sleet/hail.

+

Q2 (Evaporation): Evaporation is when heat turns liquid water into invisible water vapor gas. Heat from the Sun causes it.

+

Q3 (Condensation cause): Higher in the sky, the air is colder. Cold air cannot hold as much water vapor, so the vapor cools and turns back into liquid droplets — condensation.

+

Q4 (Continuous cycle): The same water keeps cycling because it is never destroyed — it just changes form (liquid → gas → liquid again) and location, driven by the Sun's energy.

+
+

Cause-and-Effect Answer Key

+
+

Cause 1 → Effect: The water evaporates — turns into invisible water vapor and rises into the air.

+

Cause 2 → Effect: The vapor cools down and condenses into tiny water droplets, forming a cloud.

+

Cause 3 → Effect: The droplets become too heavy and fall as precipitation — rain, snow, sleet, or hail.

+

Cause 4 → Effect: The water soaks into the ground, refills lakes and rivers, and the water cycle begins again with evaporation.

+
+

LET'S DISCUSS Guidance

+
+

"Could water from a cloud over your town have started in the Pacific Ocean?"

+

Yes! Winds carry water vapor thousands of miles. Ocean water evaporates, vapor travels inland, condenses into clouds, and falls as rain far from the original source. This is a wonderful real-world demonstration that the water cycle operates at a global scale.

+
+

Misconceptions to Watch

+
+

Students may think rain "comes from clouds" as though clouds are containers that get filled with new water. Clarify that clouds ARE condensed water vapor — the water was already in the atmosphere before the cloud formed.

+
+

Extension Activity

+
+

Mini water cycle in a bag: Put a small amount of water in a sealed clear plastic bag and tape it to a sunny window. Over several hours, watch evaporation (water disappearing from the bottom), condensation (drops on the top of the bag), and "precipitation" (drops running back down). Narrate each step as Zara would!

+
+ +

Thursday — Wind and Air Pressure

+

Answer Key — Reading Questions

+
+

Q1 (Cause of wind): The Sun heats the ground unevenly. Warm ground heats the air above it. Warm air is lighter and rises, creating a low-pressure area. Nearby cool, heavy high-pressure air rushes in to fill that space — that rushing air is wind.

+

Q2 (Anemometer vs. weather vane): Anemometer measures wind SPEED (how fast). Weather vane shows wind DIRECTION (which way the wind is coming from).

+

Q3 (Wind direction): If the weather vane points south, the wind is blowing FROM the south — a south wind.

+

Q4 (Thermal): A thermal is a column of rising warm air. Zara can spread her wings and let the rising air carry her upward without having to flap — the air does the lifting work.

+
+

Matching Answer Key

+
+

Anemometer → Measures how fast the wind is blowing

+

Weather vane → Points to show where wind comes FROM

+

Air pressure → The weight of air pressing on the ground

+

Thermal → A rising column of warm air birds ride

+

Wind → Moving air caused by pressure differences

+

High pressure → Found where air is cool and heavy

+
+

LET'S DISCUSS Guidance

+
+

"At the beach, which way does the wind blow — land to sea or sea to land?"

+

During a hot day, the sand heats faster than the water (land is hotter, lower pressure). The sea air is cooler (higher pressure) and blows toward the lower-pressure land — this is called a sea breeze. Wind blows FROM the sea TO the land. At night, it reverses (land cools faster than sea).

+
+

Misconceptions to Watch

+
+

Students often say "wind blows toward the hot area" — technically true, but the mechanism is: hot air rises (creating LOW pressure), and wind blows FROM high pressure INTO low pressure. The wind is moving INTO the hot area, but it is the pressure difference that causes the movement, not the heat directly.

+
+

Extension Activity

+
+

Make a simple weather vane: tape a paper arrow to a straw and push the straw into a lump of clay or an eraser. Take it outside and observe which direction the arrow points (it points INTO the wind, showing the wind's source direction). Compare to a weather app to check accuracy.

+
+
+ +
+

Friday — Weather Patterns and Forecasting (Capstone)

+

Answer Key — Reading Questions

+
+

Q1 (Meteorologist / Forecast): A meteorologist is a scientist who studies weather and makes forecasts. A forecast is a prediction about what the weather will be like in the future.

+

Q2 (Four tools): Thermometer = temperature; Rain gauge = how much rain fell; Anemometer = wind speed; Barometer = air pressure. (Also: weather vane = wind direction; weather satellite = cloud images from space.)

+

Q3 (Weather pattern): A pattern is weather that repeats predictably. Example from passage: summer afternoons often bring thunderstorms because hot ground heats air → warm air rises → storm clouds form → rain falls.

+

Q4 (Chain: Sun → thunderstorm): Sun heats the ground → ground heats the air → warm air evaporates water from surfaces → moist warm air rises (wind) → air cools at altitude → condensation forms clouds → water accumulates in cloud → precipitation falls as rain → back to ground. Accept any reasonable causal chain connecting all four topics.

+
+

Tree Map Answer Key

+
+

Measuring Tools (4): Thermometer, Rain gauge, Anemometer, Barometer

+

Water Cycle Steps (3): Evaporation, Condensation, Precipitation

+

Cloud Types (3): Cumulus, Stratus, Cirrus

+
+

LET'S DISCUSS Guidance

+
+

"If the barometer drops sharply, what do you predict for the afternoon?"

+

A rapid drop in air pressure means a low-pressure system is approaching — which typically brings cloudy skies, wind, and rain or storms. Practical decisions: bring an umbrella, move outdoor activities earlier, close windows. This is a great opportunity to check a real barometer app and make a real prediction together.

+
+

Misconceptions to Watch

+
+

"Weather forecasts are just guesses." Clarify that forecasts are data-driven predictions based on measurements and computer models — they are much more accurate than guessing, especially for 1–3 days out. The more data tools we have, the better the forecast.

+
+

Extension Activity

+
+

Five-day weather journal: Each morning for one week, record temperature, cloud type, wind direction, and precipitation. At the end of the week, look back — can you identify a pattern? Compare your observations to the official forecast each day and score accuracy.

+
+ +
+

Week Summary — Causal Chain

+

The week followed this chain of causes:

+
    +
  1. Monday: The Sun provides all weather energy; heats the ground, air, and water.
  2. +
  3. Tuesday: Heat causes evaporation; rising moist air cools and condenses into clouds; clouds produce precipitation.
  4. +
  5. Wednesday: The full water cycle — evaporation → condensation → precipitation → repeat.
  6. +
  7. Thursday: Uneven heating creates pressure differences; air moves from high to low pressure = wind.
  8. +
  9. Friday: All these forces together create weather patterns; meteorologists measure and predict them.
  10. +
+

By Friday, Christopher should be able to trace the path from sunlight on the ground to a rainstorm without prompting — and name at least four weather tools.

+
+ + +""" + + guide_path = output_dir / "weather_week_teacher_guide.html" + guide_path.write_text(TEACHER_GUIDE, encoding="utf-8") + + print("\nSuccessfully generated Weather Week.") + print(f"Student packet: {out_path}") + print(f"Teacher guide: {guide_path}") + print( + f" {len(pages)} pages — open the packet in a browser and print (dialog opens automatically)\n" + ) + print(" Pages:") + labels = [ + "Mon p1 — Reading: The Sun Heats Our World", + "Mon p2 — Word Sort: Sunny vs. Cloudy/Rainy Weather", + "Tue p1 — Reading: Clouds and Precipitation", + "Tue p2 — Feature Matrix: Cloud Types", + "Wed p1 — Reading: The Water Cycle", + "Wed p2 — Cause and Effect: Water Cycle Stages", + "Thu p1 — Reading: Wind and Air Pressure", + "Thu p2 — Matching: Weather Tools and Wind Words", + "Fri p1 — Reading: Weather Patterns and Forecasting (Capstone)", + "Fri p2 — Tree Map: Weather Science Capstone", + " — Parent Feedback & Teaching Notes", + ] + for label in labels: + print(f" {label}") + + +if __name__ == "__main__": + generate_weather_week_series()