How it works
Every demo is an HTML page containing inline SVG (the SVG is written directly in the page, not loaded as an image — page CSS cannot reach the inside of an <img>). The page links the shared stylesheet:
<link rel="stylesheet" href="agTeachingDemos.css">
SVG elements then carry no colours of their own. A shape is given semantic classes describing what it is, and the stylesheet decides what that looks like:
<rect class="ag-metal ag-outline" x="40" y="40" width="120" height="200"/>
<rect class="ag-water" x="160" y="40" width="200" height="200"/>
<line class="ag-line-thin" x1="40" y1="260" x2="360" y2="260"/>
Because appearance lives in one file, changing a colour or line weight there restyles every demo, slide and document built on the framework. All class names and CSS variables are prefixed ag- to avoid collisions with host-environment CSS.
General lines
Basic drawing lines come in three weights, all sharing one colour (--ag-c-line). Use them for construction lines, dimension leaders, dividers — anything that is a drawing element rather than a physical object.
| Sample | Class | Width variable |
|---|---|---|
.ag-line-thin | --ag-sw-thin |
|
.ag-line-medium | --ag-sw-medium |
|
.ag-line-thick | --ag-sw-thick |
The line classes set fill: none, so they are safe on open paths and polylines as well as straight lines.
Materials
Material classes are pure fills — they say what a region is made of, nothing more.
| Sample | Class | Colour variable | Notes |
|---|---|---|---|
.ag-metal |
--ag-c-metal |
Shiny (gradient) when the defs block below is present; flat grey otherwise. | |
.ag-water |
--ag-c-water |
||
.ag-air |
--ag-c-air |
Lighter than water. | |
.ag-insulation |
--ag-c-insulation |
||
.ag-brick |
--ag-c-brick |
||
.ag-wood |
--ag-c-wood |
||
.ag-plastic |
--ag-c-plastic |
Milky off-white (polyethylene, PVC, ...). | |
.ag-stone |
--ag-c-stone |
Rock: granite, limestone, ... |
Named material tints (flat fills)
Any material whose fill is flat (no active gradient) can be retinted per element by overriding its colour variable — the same rule as flat particles. So that the same material is the same colour in every demo, the framework defines named tints; use these rather than inventing local colours:
<rect class="ag-metal" style="--ag-c-metal: var(--ag-c-metal-copper)"/>
Tints: --ag-c-metal-titanium, --ag-c-metal-iron, --ag-c-metal-aluminium, --ag-c-metal-gold, --ag-c-metal-copper. New tints are added as demos need them. Limitation: a per-element override only works on a flat fill — with the metal-gradient defs block present, every .ag-metal shares the one gradient, so a demo that needs differently coloured metals must omit the defs block (flat metals), exactly as flat vs shiny particles.
Material outline (toggleable)
To outline a material region, add .ag-outline alongside the material class; remove it to drop the outline. The outline (--ag-c-outline, --ag-sw-outline) is the same for every material and belongs to materials only — it is independent of the general line weights above.
<rect class="ag-water ag-outline" .../> <!-- outlined -->
<rect class="ag-water" .../> <!-- no outline -->
Shiny metal: the gradient defs block
CSS alone can only produce flat fills in SVG; a metallic sheen needs an SVG gradient, and gradients must be defined inside the SVG document that uses them. To get shiny metal, paste this standard block just inside the <svg> tag of your demo (once per SVG):
<defs>
<linearGradient id="agMetalGradient" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="#e9edf1"/>
<stop offset="0.45" stop-color="#9daab6"/>
<stop offset="0.6" stop-color="#c6cdd5"/>
<stop offset="1" stop-color="#8b98a5"/>
</linearGradient>
</defs>
The stylesheet declares fill: url(#agMetalGradient) var(--ag-c-metal), so this is safe to omit: without the block, .ag-metal simply falls back to the flat grey. The gradient scales automatically to each shape's bounding box.
Example — the same class with and without the defs block present:
Particles
Small dots representing atoms or molecules in particle views (conduction lattices, gas models). The framework styles the dot — size, body colour, outline colour and outline width — and any motion is the demo's JavaScript.
<circle class="ag-particle" cx="30" cy="20"/> <!-- radius comes from the stylesheet -->
Note the radius is set by the stylesheet: the CSS r property overrides any r="" attribute, so resize particles by overriding --ag-particle-r, not the attribute.
Shiny (3-D ball) particles. Like metal, particles become shiny when this standard defs block is in the SVG; without it they are flat fills. The gradient computes its highlight and shade from --ag-c-particle using color-mix(), so overriding that single variable retints the whole ball:
<defs>
<radialGradient id="agParticleGradient" cx="0.33" cy="0.3" r="0.85">
<stop offset="0" style="stop-color: color-mix(in srgb, var(--ag-c-particle), #ffffff 80%)"/>
<stop offset="0.35" style="stop-color: var(--ag-c-particle)"/>
<stop offset="1" style="stop-color: color-mix(in srgb, var(--ag-c-particle), #000000 45%)"/>
</radialGradient>
</defs>
| Variable | Controls |
|---|---|
--ag-c-particle | Body colour (and, via the gradient, highlight and shade). |
--ag-c-particle-outline | Outline colour. |
--ag-sw-particle | Outline width. |
--ag-particle-r | Radius. |
Limitations: with the gradient active, colour is per-SVG (all shiny particles share one gradient) — recolour on the <svg> or a page-level rule, not per element; flat particles can be recoloured individually. color-mix() needs a 2023-or-newer browser; older browsers show flat particles.
Arrows
An arrow is drawn as a stroked line (or path) plus a separate filled polygon for the head:
<line class="ag-heat-arrow" x1="10" y1="30" x2="340" y2="30"/>
<polygon class="ag-heat-arrow-head" points="340,21 358,30 340,39"/>
| Class | Variables | Notes |
|---|---|---|
.ag-heat-arrow |
--ag-c-heat-arrow, --ag-sw-arrow, --ag-heat-arrow-speed |
Dashes march along the line. Works on lines, paths and polylines (bent arrows). |
.ag-heat-arrow-head |
--ag-c-heat-arrow |
Filled polygon; place at the end of the line. |
The marching speed can be overridden per element — e.g. a demo can make arrows march faster when the heat flux is larger: el.style.setProperty("--ag-heat-arrow-speed", "0.3s") (lower = faster). The animation switches off automatically for users whose system requests reduced motion.
Graphs
Elements for plots drawn inside demo SVGs. Gridlines are the light reference lines that divide or locate regions of a figure — they are equally useful outside graphs (e.g. projecting a layer boundary down onto a temperature profile).
| Class | Variables | Notes |
|---|---|---|
.ag-axis |
--ag-c-axis, --ag-sw-axis |
Use one <polyline> for an L-shaped axis pair. |
.ag-axis-label |
--ag-c-axis, --ag-fs-axis-label |
Text style for axis titles and tick labels. |
.ag-axis-label-vertical |
— | Modifier: add alongside .ag-axis-label to run a y-axis title vertically; position the text at its desired centre point. |
.ag-gridline |
--ag-c-gridline, --ag-sw-gridline |
Light reference lines; draw before (under) the data. |
.ag-default-curve1 |
--ag-c-curve1, --ag-sw-curve |
First data curve — dark red unless a demo states otherwise. |
.ag-default-curve2 |
--ag-c-curve2, --ag-sw-curve |
Second data curve — dark blue. |
.ag-graph-label |
--ag-c-graph-label, --ag-fs-axis-label |
Annotation text that is not an axis label (region names, "q″ in", ...). |
Sliders
Styling for the HTML control panel that accompanies a demo — the one section that styles HTML elements rather than SVG. Wrap the controls in .ag-controls; each slider is a <label for=...> / <input type="range" id=...> pair (the pairing keeps sliders accessible to screen readers), with an .ag-readout span for the live value.
<div class="ag-controls">
<label for="iQ">heat flux q″ <span class="ag-readout" id="oQ">3.5</span></label>
<input type="range" id="iQ" min="1" max="5" step="0.1" value="3.5">
</div>
Rendered example above (readouts here are static; a real demo updates them from JavaScript). Variables: --ag-c-control-accent (slider and readout colour), --ag-c-control-text.
Read-only meter
For displaying a value the user cannot adjust — typically a quantity computed from the other sliders (e.g. h combined from its components). A filled bar with no thumb: the missing thumb is the visual signal that this is a display, not a control. Use role="meter" and update aria-valuenow together with the fill width so screen readers track it too:
<span class="ag-meter-label" id="hLabel">h</span>
<div class="ag-meter" role="meter" aria-labelledby="hLabel"
aria-valuemin="0" aria-valuemax="1" aria-valuenow="0.75">
<div class="ag-meter-fill" style="width: 75%"></div>
</div>
Variables: --ag-c-meter-track, --ag-c-meter-border; the fill uses --ag-c-control-accent.
Scope
The framework currently defines general lines, materials, particles, arrows (heat arrow), graph elements (axis, axis labels, gridlines, data curves, annotation labels) and slider controls. Planned additions as demos need them: boundaries (hot/cold surfaces), further arrow types (flow, force), buttons, and results/readout boxes.