---
name: "interactive_teaching_sites"
description: "Build an interactive teaching site end to end: lesson pages with worked and faded examples, in-page exercises with specific instant feedback, progress tracking in localStorage with no accounts, and a WCAG 2.2 AA pre-launch check. Triggers when building a teaching, tutorial, or self-study site, adding practice exercises to lesson pages, or tracking learner progress without sign-up."
metadata: { "includeInPrompt": true }
---

# Interactive Teaching Sites

## Purpose
One workflow for a whole teaching site, not a pile of separate tricks for lessons, quizzes, progress, and accessibility bolted together after. The site this skill produces is static by default: lesson pages a learner can open and use with no account, no server, and no sign-up wall before the first useful thing happens. Exercises give feedback a learner can act on, progress survives a browser restart on that device, and an accessibility gate runs before launch, not after complaints. A tested exercise component, a progress store, a worked demo lesson, and a site checker ship in `assets/demo-site/` and `bin/check_site.py`. For the evidence behind the choices, see `references/evidence.md`. For the exercise component contract, see `references/component-spec.md`.

## Workflow

1. **Write the final performance first.** State what the learner will do unaided at the end, in plain words. Weak: "understand fractions". Strong: "add two fractions with different denominators and explain why the denominators had to match first". Every lesson, example, and exercise on the site traces back to that sentence. If a page does not serve it, cut the page.

2. **Map the site backwards from that performance.** List the sub-skills the final task needs, order them by dependency, and give each sub-skill one lesson page. A small site is 3 to 7 lessons. One page teaches one sub-skill. Write the map as a table in the plan: lesson id, sub-skill, prerequisite lesson ids, exercise ids, and the check that closes the lesson. Refuse a flat pile of pages with no order: learners cannot tell what to do next, and neither can the progress display.

3. **Pick the simplest stack that runs the exercises.** Default to static HTML, CSS, and vanilla JavaScript served as files. It needs no build, no backend, and no accounts, and progress lives in the browser. Move up only for a named reason:
   - An existing learning platform already hosts the audience: embed exercises there instead of building a second home, and keep this skill's lesson anatomy and feedback rules.
   - Exercises need server grading, for example running learner code against hidden tests: add the smallest grading endpoint that returns the feedback strings this workflow defines, and keep lessons static.
   - Never pick a framework, a database, or an account system because it feels like a real product. Each one adds a failure mode between the learner and the first lesson.

4. **Build each lesson page in this order, every time.** The anatomy is fixed so learners learn the shape once and stop spending attention on navigation:
   - A goal line in learner words: "By the end of this page you will ..."
   - A short hook problem the learner cannot solve yet, shown before any teaching, so the lesson has a reason to exist.
   - Teaching in small sections, each ending where an example starts. No section runs long without an example or a try-it.
   - A fully worked example with each step shown and the reason for the step stated next to it, not after.
   - A faded example: same structure, later steps blank for the learner to complete. Support fades across the site, full examples early, faded examples mid-site, bare problems late.
   - An exercise set of 3 to 6 items (step 5).
   - A closing retrieval check, closed book style: 2 to 4 fresh items on this page's sub-skill only.
   - A summary of one to three lines, a link to the next lesson, and a progress display that reflects stored state, not hope.

5. **Design exercises by the job they do, and write the feedback before the code.** Pick the type by cognitive job, not by novelty:
   - Choice (radio inputs, one correct): discriminating between close ideas, catching a named misconception.
   - Short text or number input: recalling a term, a value, or the next step.
   - Completion (a faded example with blanks): applying a procedure with support.
   - Ordering with buttons, not drag only: sequencing steps. Any ordering control must also work by keyboard and by tap, with move up and move down buttons.
   For every item, write these fields first, in the content file, before any markup: prompt, correct answer, why it is correct, one feedback string per planned wrong answer that names the wrong rule the learner used and the next move to try, a hint ladder of two hints (point at the relevant step, then offer the first move), and the retry rule. Feedback that only says correct or incorrect is a failed item. Specific feedback is the teaching. See `references/component-spec.md` for the item schema.

6. **Build exercises on native controls with the shipped component.** Use radio inputs, text inputs, and real buttons. Native controls bring keyboard operation, focus, and screen reader labels with them; custom widgets have to earn all of that back by hand. Wire the component from `assets/demo-site/`:
   - The live feedback region exists empty in the page from load, as `<div class="exercise-feedback" role="status" aria-live="polite"></div>`, and JavaScript updates its text after a check. A region created at the same moment as its message is often never announced.
   - Checking an answer never moves focus, never reloads the page, and never clears the learner's input on a wrong answer. The learner reads the feedback, changes the answer, and checks again.
   - Retry is unlimited on practice items. Show the hint ladder after the first wrong attempt, and count attempts in the progress record, not as a punishment score on screen.
   - Grade with the pure functions in `exercise.js` (`gradeChoice`, `gradeText`) so the same logic runs in the browser and in a Node test.

7. **Track progress in localStorage, with no accounts and no personal data.** Use the store in `assets/demo-site/progress.js`. The contract:
   - One versioned key for the whole site, for example `teachsite.progress.v1`. The value is a JSON string, because Web Storage holds strings only: `{ "version": 1, "lessons": { "fractions-add": { "status": "done", "best": 4, "of": 5, "attempts": 7, "updated": "2026-10-19" } } }`.
   - Status is one of `not-started`, `started`, or `done`. Done means the closing check was passed at the bar set in the plan, not that the page was opened.
   - Wrap every `setItem` in try and catch. On a quota or privacy mode error, keep progress in memory for the session and show a plain note that progress will not be saved on this device. Never let a storage error break an exercise.
   - Store no names, no emails, no free text answers. Progress is per device and per browser, and the site must say so in one line near the progress display, with buttons to export the progress JSON, import it back, and clear it. A learner who switches devices and loses progress with no warning was misled, not unlucky.

8. **Run the accessibility gate before launch, WCAG 2.2 AA.** Run the checker, then do the manual passes. Both, not either:
```sh
python3 bin/check_site.py assets/demo-site
```
   The checker covers the mechanical failures: missing `lang`, missing or multiple `h1`, images with no `alt`, inputs with no label, buttons with no accessible name, a missing skip link, a missing live feedback region on exercise pages, and no visible focus style in the CSS.
   Manual passes, in this order:
   - Keyboard only: tab through a whole lesson and its exercises. Every control reachable, focus always visible, focus never hidden behind a sticky header (WCAG 2.2 criterion 2.4.11), logical order, no traps.
   - Contrast: body text at least 4.5 to 1 against its background, large text and interface component parts at least 3 to 1 (criteria 1.4.3 and 1.4.11). Check feedback colors too, and never carry the correct or wrong signal by color alone: pair it with words.
   - Targets and dragging: pointer targets at least 24 by 24 CSS pixels with the spacing exceptions in criterion 2.5.8, and no action that only works by dragging (2.5.7).
   - Zoom and reflow: read a lesson at 200 percent text size and at a narrow phone width. No horizontal scrolling for reading, no clipped exercise controls.
   - Screen reader: do one exercise end to end. The prompt, the options, the check result, and the feedback must all be announced, and an empty answer must produce an error message that names the problem (criterion 3.3.1) inside the polite live region.
   - Reduced motion and timing: no exercise is timed by default. If a timed mode exists, it is optional, off by default, and extendable.

9. **Test the exercises like an opponent, then launch.** Run the logic tests and a hostile pass by hand:
```sh
node assets/demo-site/exercise.test.mjs
python3 -m py_compile bin/check_site.py
```
   By hand, per exercise: submit the correct answer, each planned wrong answer, an empty answer, and the same wrong answer twice. Reload mid-lesson and confirm stored progress returns. Clear site data and confirm the site still works with empty storage. Turn JavaScript off and confirm lessons still read as plain teaching pages, with exercises degrading to questions with a printed answer key at the foot of the page. Fix any failure before launch. A wrong answer key found by a learner costs more trust than a late launch.

## Worked Mini Site Plan
Topic: adding fractions with different denominators, for learners who can already add fractions with the same denominator. Final performance: "add two fractions with different denominators and explain why a common denominator is needed first".
- Lesson 1 `why-common`: why denominators must match, shown by adding lengths. Worked example in pictures and numbers, faded example, 3 choice items aimed at the misconception "just add the tops and the bottoms".
- Lesson 2 `find-common`: finding a common denominator by listing multiples. Worked example, two faded examples, 4 short number items with per-answer feedback for the common wrong picks.
- Lesson 3 `add-and-simplify`: the full procedure plus simplifying the result. Full worked example, faded example, closing check of 3 fresh additions that mixes lessons 1 and 2. Passing 2 of 3 marks the site done in the progress store.
The demo lesson in `assets/demo-site/index.html` is lesson 3's shape, with real exercises, the live feedback region, and the progress store wired in. Copy it per lesson and change the content fields, not the structure.

## Output Contract
- A site plan: final performance, lesson map with ids, prerequisites, exercise ids, and the passing bar for each closing check.
- Lesson pages in the fixed anatomy of step 4, readable with JavaScript off.
- An exercise content file per lesson using the schema in `references/component-spec.md`, with per-answer feedback and a two-step hint ladder written for every item.
- A working progress display backed by the versioned localStorage record, with export, import, and clear controls, and the one-line per-device warning.
- A launch record: checker output, the six manual accessibility passes marked pass or fail with notes, and the hostile exercise test results. No launch with an open fail in the record.

## Operating Rules
1. No account, no sign-up, no email ask before or during learning. Progress on the device is the whole identity system.
2. One sub-skill per lesson page, one fixed page anatomy across the site. Consistency is a teaching tool.
3. Worked example first, faded example second, bare problems last, in that order on every page. Novices who start by searching for a solution spend their effort on the search, not on the pattern.
4. Feedback names the wrong rule and the next move. Correct, incorrect, and a score with no words are all failures of the item, not of the learner.
5. Native controls first. A custom widget needs a written reason plus keyboard, focus, and announcement behavior equal to the native control it replaces.
6. Never grade by color alone, never announce by color alone, never store by hope alone. Every state change has words, and every storage write has an error path.
7. Done means passed the closing check, not visited the page. Progress displays that lie teach learners to distrust the site.
8. Store the minimum: lesson status, best score, attempts, date. No personal data, no free text, no answer history in localStorage, which any script on the same origin can read.
9. Keep the site static until a named need forces a server. Each added moving part is a new way for a learner to hit an error page instead of a lesson.
10. Cut unverifiable teaching claims the same way as unverifiable facts. If the plan says a method works, it points at the evidence in `references/evidence.md` or it reads as a plain design choice, not a result.
