# Teaching Material Repository.

The aim is to create a reusable, well-organised teaching resource repository that supports both traditional course materials and lightweight interactive web-based teaching tools. The Teaching Demos should be easy to embed, visually consistent, accessible, and reusable across multiple courses or teaching contexts.

The repository will contain two main types of content:

1. Teaching Materials
These are traditional course materials such as notes, worksheets, explanations, worked examples, activities, lab sheets, tutorials, assessments, and supporting resources. 
2. Teaching Demos
These are discrete, interactive, web-based teaching tools. They are intended to be embedded inside teaching materials, web pages, or learning platforms.

The repository should be organised into clear sections for:

* teaching-materials/
For traditional teaching resources.
* teaching-demos/
For standalone interactive web-based teaching demos.
* framework/
For shared styling, guidance, and reusable design assets.

## Framework
This repository will be built by creating content while simultaneously identifying the framework elements that need to be included. The framework will not be built in its entirety at the start. Therefore, it is critical to ensure that structure is maintained within the framework and that elements are not duplicated or unnecessarily added overall.

Any part of this claude.md file, including these header instructions, can be updated as the project progresses. 

When creating or modifying content in this repository:

* Preserve the separation between teaching content and embeddable interactive demos.
* Do not duplicate CSS unnecessarily inside individual demos if a reusable style exists in agTeachingDemos.css.
* If a new reusable style pattern is needed, propose adding it to the shared framework rather than applying inconsistent local styling.
* Use clear file names that describe the teaching topic or demo purpose.
* Keep assets organised in predictable folders.
* Prefer simple, robust implementations over complex ones.

## Teaching Demos

Inside the framework/ folder there is a CSS file called: agTeachingDemos.css
This contains reusable style definitions that should be used by all Teaching Demos to ensure a consistent look and feel.

There is also a guide file: agTeachingDemosGuide.html
This explains how the CSS framework should be used when creating new Teaching Demos.

Teaching Demos should be designed as embeddable components. They should avoid unnecessary surrounding page context, such as full-page titles, headers, navigation bars, footers, or explanatory material that belongs in the surrounding teaching content.

Each Teaching Demo should focus on a single concept, interaction, model, visualisation, or learning activity.

Teaching Demos should:
* Use the shared CSS definitions in framework/agTeachingDemos.css.
* Follow the design guidance in framework/agTeachingDemosGuide.html.
* Have a consistent visual style across the repository.
* Be self-contained enough to function when embedded in other teaching material.
* Avoid hard-coded assumptions about where they will be embedded.
* Be responsive and usable on different screen sizes.
* Be accessible, including keyboard operation where relevant, readable colour contrast, semantic HTML, and useful labels for screen readers.
* Keep explanatory text concise, since fuller explanation may be provided in the surrounding teaching material.
* Use clear, maintainable HTML, CSS, and JavaScript.

## Teaching Material Requirements

Teaching materials may include fuller context, explanations, headings, learning outcomes, instructions, references, and links to embedded Teaching Demos. Teaching materials should be structured clearly and consistently. Where appropriate, they should include:

* A short description of the topic.
* Intended audience or level.
* Learning outcomes.
* Prerequisite knowledge.
* Instructions for students.
* Notes for educators.
* Links to relevant Teaching Demos.
* Any required files, data, or assets.

## Golden Rules
These rules apply to every project. They sit above all project-specific instructions.

1. Assume I'm a generalist, not an expert
I tend to know a little about a lot of things. If I suggest a particular approach, don't just follow it — tell me how an expert in that field would tackle the same problem. Flag best practices, common pitfalls, and established patterns I might not be aware of. Help me learn as we go, not just ship.
2. Everything is meta
Treat every specific problem as a representative of a broader class of problems. If we're solving X, help me understand the general shape of "problems like X" — so the solution is durable, transferable, and not just a one-off fix.
3. Record important stuff as we go
In code: Comment generously. Assume the next reader (probably me, six months from now) will need granular explanation of what the code does and why it does it that way. Don't assume intent is obvious.
In this file: Keep this CLAUDE.md updated with key design decisions, architectural choices, and the reasoning behind them as the project evolves. This file is the project's memory — treat it that way.
4. Validate everything — function and fit
Before calling something done, check it on two dimensions:
Does it work? Does the system behave correctly and robustly?
Does it work for people? Consider the full range of users. Is it inclusive, accessible, and appropriate for its context? If the audience includes students, is it pedagogically sound and clear? If it's public-facing, is it welcoming and respectful of different backgrounds and abilities?
Good enough technically is not good enough if it fails the people using it.
5. Don't be a dick
Assume everyone involved — me, users, stakeholders, future maintainers — is doing their best. Lead with generosity, not judgment. People come first in everything we build together. Write code, make decisions, and give feedback as if the person on the other end of it matters. They do.
6. Build secure stuff
Assume everything you build is going to be attacked by students looking to disrupt my processes. Consider where exploits could exist. Run checks on outputs to validate that there are no places where security could be compromised. 

 <!-- Project-specific context begins below this line --> 

## Design decisions log

* **2026-07-07 — agTeachingDemos.css organisation.** The file is split into topic sections (GENERAL, MATERIALS, more as needed). Each section is self-contained: its own `:root` block holding its variables, followed by its classes. No global variables block at the top of the file. All class and variable names carry the `ag-` prefix to avoid collisions with host-environment CSS when demos are embedded.
* **2026-07-07 — SVG styling approach.** Demos use inline SVG (not `<img src="*.svg">`, which page CSS cannot style). SVG elements carry no colours of their own — semantic classes only; all appearance lives in the framework CSS.
* **2026-07-07 — materials are pure fills; outline is a toggle.** Material classes (`.ag-metal`, `.ag-water`, `.ag-air`, `.ag-insulation`) set fill only. Outlining a region is a separate semantic choice made per element by adding `.ag-outline` (colour/weight from `--ag-c-outline`/`--ag-sw-outline`, material-specific, independent of GENERAL line weights). There is no solid/fluid distinction.
* **2026-07-07 — shiny metal via optional gradient defs.** `.ag-metal` uses `fill: url(#agMetalGradient) var(--ag-c-metal)`. A standard `<defs>` gradient block (documented in agTeachingDemosGuide.html) is pasted into an SVG to get the sheen; without it the fill falls back to flat grey automatically.
* **2026-07-07 — ARROWS and GRAPHS sections added.** Arrows are a stroked line/path plus a separate filled polygon head (`.ag-heat-arrow` + `.ag-heat-arrow-head`) rather than SVG `<marker>`s, because browsers cannot reliably re-colour marker content from CSS and that would break single-file theming. The heat arrow's marching-dash speed is per-element overridable via the `--ag-heat-arrow-speed` custom property (demos can tie it to physical magnitude), and all arrow animation stops under `prefers-reduced-motion` for accessibility. GRAPHS defines `.ag-axis`, `.ag-axis-label`, `.ag-gridline` ("gridline" is the standard charting term for light reference lines, even irregularly spaced ones). MATERIALS gained `.ag-brick`.
* **2026-07-07 — PARTICLES, SLIDERS sections; GRAPHS gains curves and labels.** Promotions from the conduction-physics demo: `.ag-particle` (own PARTICLES section — particles will recur in gas/convection demos, so not graph- or material-specific; framework styles the dot, motion is the demo's JavaScript); GRAPHS gains `.ag-default-curve1` (dark red) / `.ag-default-curve2` (dark blue) — the default curve colours unless a demo states otherwise — and `.ag-graph-label` for annotation text that is not an axis label; new SLIDERS section (`.ag-controls`, `.ag-readout`) styles the HTML control panel — the one section styling HTML rather than SVG; markup contract is `<label for>` / `<input id>` pairs for accessibility. Shared font stacks `--ag-font-ui` / `--ag-font-mono` live in GENERAL because multiple sections set text (avoids duplicated font stacks).
* **2026-07-07 — particles fully parameterised.** `.ag-particle` now defines size, body colour, outline colour and outline width, all as variables demos can override. The radius is set from CSS (the `r` property overrides any `r=""` attribute — resize via `--ag-particle-r`, never the attribute). Optional shiny 3-D ball look via a standard `agParticleGradient` radial-gradient defs block (same opt-in pattern as shiny metal); its highlight and shade are derived from the single `--ag-c-particle` variable using `color-mix()`, so one override retints the whole ball. Limitations, by design: with the gradient active, colour is per-SVG (shared gradient), while flat particles can be recoloured per element; `color-mix()` needs 2023+ browsers, older ones get flat particles.
* **2026-07-07 — conduction demo: slider is total heat rate Q, not flux q&Prime;.** Having both q&Prime; and A as inputs made A physically inert (and silently changed Q behind the scenes). Resolved by imposing Q and computing q&Prime; = Q/A, shown live in the relation box. This makes the area slider a demonstration of the heat-rate vs heat-flux distinction — the most common student misconception here: growing A at fixed Q visibly drops the flux, flattens the gradient and calms the particle jiggle. Arrow marching speed encodes q&Prime; (not Q), identical at both ends because steady state. Slider extremes chosen so max Q, max L, min A, min k puts the hot end exactly at the graph top. The alternative (removing A for a leaner three-slider demo) was considered; if the demo ever feels overloaded, clone a stripped version rather than un-teaching Q/A.
* **2026-07-07 — conduction demo stripped to pure visuals.** Slider numeric readouts, the "insulation" and "ambient" labels, and the q&Prime;/dT-dx relation box were all removed: the demo is qualitative and that explanation belongs in the surrounding teaching material, not the embedded component. Pattern for future demos: sliders carry a word label only; equations and terminology live in the teaching material that embeds the demo.
* **2026-07-07 — conduction demo: Q and &Delta;T are linked two-way sliders.** Both sliders are handles on the single relation Q = k·A·&Delta;T/L: moving either drives the other's position plus the figure. "Last-touched wins": whichever of Q/&Delta;T the user moved last is the imposed boundary condition and holds fixed when k, L or A change — letting students discover fixed-flux vs fixed-temperature boundary behaviour. Implementation notes: a slider's `input` event does not fire on programmatic `.value` assignment, so two-way linking cannot loop; when &Delta;T leads, Q can hit its range limits and both values clamp to the last consistent pair (a linked mechanism with a hard stop); when Q leads no clamp is needed because the ranges were sized so worst-case &Delta;T is exactly 10.
* **2026-07-07 — conduction demo: jiggle strictly proportional to absolute temperature.** Particle vibration amplitude was baseline + scale (affine); now it is exactly proportional to the absolute local temperature, interpolated linearly along the bar like the T(x) line. This makes the two visualisations one consistent statement: the graph's x-axis is absolute zero (zero jiggle), and the dashed ambient line's height above the axis corresponds to the cold-end baseline jiggle. Constants: `JIG` px of amplitude per temperature unit; ambient derived from the graph geometry, not set independently.
* **2026-07-07 — motion policy: essential vs decorative animation.** Discovered when particles appeared frozen: the user's own Windows machine has "Animation effects" off (Settings &gt; Accessibility &gt; Visual effects), which browsers surface as `prefers-reduced-motion: reduce`. Key fact: that media query is an honour system — it stops nothing by itself; pages must opt in (most, like typical matter.js sites, never do). Decision after weighing three options: **physics-carrying motion is essential content and always animates** (WCAG 2.3.3 exempts essential animation — the particle jiggle IS the lesson), while **decorative motion respects the preference** (the arrows' marching dashes stop via the framework CSS `@media` rule). An interim "frozen disorder snapshot" fallback (static displacement &prop; local temperature) was built and then removed in favour of this policy; worth resurrecting if a future demo's essential motion is large/sweeping enough to be a genuine vestibular concern. Apply this essential/decorative split to all future animated demos.
* **2026-07-08 — 1D_conduction_sim.html: the quantitative sibling.** Same figure as the qualitative demo minus the particles, real SI units on everything, A fixed at 1 m&sup2; (labelled on the slab, so Q and q&Prime; are numerically equal — deliberately showing both). Design choices: conductivity is a **dropdown of real materials** (copper 400 &rarr; silica aerogel 0.02 W/m&middot;K, Incropera ~300 K values) because 4.5 decades is unusable on a linear slider; Q gets a **logarithmic slider** (1 W&ndash;1 kW) for the same reason; an "impose &Delta;T / impose Q" radio toggle shows one slider and displays the other quantity; the graph x-axis is fixed 0&ndash;1 m with the slab drawn to scale, and the **y-axis autoscales** to a nice 1/2/5&times;10&#8319; ceiling above the hot-face temperature — insulators under imposed Q legitimately reach thousands of kelvin and the axis follows, because that IS the lesson. Cold face pinned at 20 &deg;C ambient.
* **2026-07-08 — demo sizing for iframe embedding.** Both conduction demos were unbounded and overflowed short windows (the graph fell below the fold). Pattern for all demos: the component gets an overall `max-width` (~860px); the SVG gets a smaller flex-basis (340px), a `max-width` (~600px), **and `max-height: 85vh`** — inside an iframe `vh` is the iframe's own height, so the figure shrinks to fit whatever box the host page provides instead of clipping. ViewBoxes trimmed of dead bottom space. Suggested host embed size ~840&times;460 for these two demos.
* **2026-07-08 — `.ag-axis-label-vertical` modifier added to GRAPHS.** Y-axis titles were colliding with tick labels (seen on the 1D sim). The fix is a framework *modifier* class stacked on `.ag-axis-label`: it only rotates (90&deg; anticlockwise about the text's own centre via `transform-box: fill-box`), so font/colour stay defined once on the base class. Usage: position the text at its desired centre point. The guide's example graph now demonstrates it; prefer this over per-element `transform="rotate(...)"` attributes.
* **2026-07-09 — convection_physics.html: qualitative convection explainer.** Air particles enter cold (blue) on the left, advect over a heated plate, and are coloured individually blue&rarr;red by their temperature — which is exactly why this demo deliberately OMITS the `agParticleGradient` defs block: the shiny gradient is shared per-SVG and cannot tint individual particles, so flat particles with per-element `--ag-c-particle` overrides are required. The motion encodes real boundary-layer physics qualitatively: no-slip (speed grows with height above the plate), a thermal boundary layer (only particles within ~45px of the surface heat up, at a rate fading with distance), and buoyancy (hot particles rise, forming a plume that exits right). The A slider (0.1&ndash;1 m&sup2;, maths kept internal — no numbers shown, per the qualitative-demo pattern) sets the plate length; a longer heating run makes the exit plume hotter and taller. T&#8734; is fixed (inlet always cold). An h control is planned (user has a specific idea); the natural hook is `HEAT_RATE` (and possibly `VX_FREE`), noted in the code. Solid plate keeps the conduction demo's vocabulary: metal slab with two rows of hot red strongly-jiggling lattice particles.
* **2026-07-09 — convection demo: full circulation + surface-temperature slider.** The one-way "heat up and rise" picture became a circulation: vertical velocity is temperature-set in BOTH directions — hot particles rise &prop; how hot they are, cold particles sink &prop; how cold they are (displaced by the rising warm air) — so fresh cold air keeps reaching the surface and convection covers the whole plate. A "surface temperature" slider (20&ndash;100 &deg;C internal, no numbers shown) maps to sHot &isin; [0,1]: boundary-layer particles relax toward the SURFACE temperature (not blindly to max, so a cooler surface heats less and can even cool overheated particles), and the entire circulation strength scales with sHot — at 20 &deg;C (= fixed T&#8734;) heating, buoyancy and sinking all vanish naturally rather than as a special case. The solid lattice's colour and jiggle amplitude also track the surface temperature (blue and calm at ambient). Air block resized to match the plate length, with the active particle count scaled to keep density constant. h control still pending (user's "novel idea"); hook remains HEAT_RATE / VX_FREE.
* **2026-07-09 — convection demo: heat-rate arrows off the surface.** Vertical `.ag-heat-arrow`s march from the plate's top surface up into the air, encoding Q = h&middot;A&middot;&Delta;T across three visual channels: arrow COUNT scales with plate length (one per ~95px, so more area = more arrows), marching SPEED scales with &Delta;T via `--ag-heat-arrow-speed` set on the group (h fixed until the planned h control), and at T&#8347; = T&#8734; the arrows are hidden entirely (visibility, not speed-zero — a stopped dashed arrow would still assert a heat-flow direction when there is none). Drawn before the particle groups so air particles pass in front. No framework CSS changes needed.
* **2026-07-09 — convection demo: h built from two sliders.** The user's design: h has two deliberately jargon-free components — "fluid mechanics" and "material properties" (internally Reynolds- and Prandtl-flavoured) — each a slider spanning 0.25&ndash;0.5, summed to give h &isin; [0.5, 1]. Additive combination is a knowing simplification (real correlations are multiplicative, Nu &prop; Re&#775;&#7511;&middot;Pr&#8319;; flagged to the user, their call). h multiplies the heat flux: particle heating rate and arrow marching speed. Each component has a visible physical tell: fluid mechanics scales the whole flow speed &plusmn;25%; material properties scales the air-particle radius &plusmn;25% via the framework's `--ag-particle-r` group override (no CSS changes). The combined h shows on a **read-only meter** — a filled bar with no thumb (the missing thumb signals "display, not control"), `role="meter"` for screen readers. Meter styling was demo-local at first; promoted to the framework the same day (see next entry).
* **2026-07-09 — read-only meter promoted to the framework.** SLIDERS section gains `.ag-meter` / `.ag-meter-fill` / `.ag-meter-label` (label shares the `.ag-controls label` rule via a combined selector — no duplicated styling). It is the standard for "a value the user cannot adjust", e.g. a quantity computed from other sliders: a filled bar with NO thumb (the missing thumb is the display-not-control signal). Markup contract: `role="meter"` + `aria-valuemin/max/now`, with aria-valuenow updated from JS together with the fill width. Variables: `--ag-c-meter-track`, `--ag-c-meter-border`; fill uses `--ag-c-control-accent`. Documented in the guide with a rendered example; convection demo migrated onto it. Remaining framework candidates: results box, dropdown styling, radio-row styling (all local to 1D_conduction_sim.html).
* **2026-07-09 — convection demo: Q shown on a speedometer-style dial.** The output quantity Q = h&middot;A&middot;&Delta;T gets an instrument of its own (user's idea; dial chosen over a second linear bar so the OUTPUT reads differently from the input controls): a small inline SVG gauge in the control panel — semicircular arc with five ticks (framework `.ag-axis`/`.ag-axis-label` classes), swinging needle (demo-local `.demo-needle`, coloured via `--ag-c-curve1`), labelled "0" to "max". Full deflection is well-defined because every factor is normalised to its slider maximum: qFrac = h &times; A &times; sHot &isin; [0,1]. The needle updates from all three input paths (updateH, updateTemp, rebuildPlate) and the gauge carries `role="meter"` + aria values like the h bar. Needle/hub styling is a declared framework candidate ("gauge" pattern) if it recurs in other demos.
* **Legacy:** `teaching-demos/heat-transfer/composite-wall.html` predates the framework and uses its own local `theme.css`; it does not yet follow the embeddable-component guidance (it has a full-page header). Migration to agTeachingDemos.css is pending.




