diff --git a/src/components/GuideBlocks.svelte b/src/components/GuideBlocks.svelte
index 10fa1a3..41d3984 100644
--- a/src/components/GuideBlocks.svelte
+++ b/src/components/GuideBlocks.svelte
@@ -71,7 +71,7 @@
{:else if b.kind === 'recipe'}
{@html richToHtml(b.text, dark)}
{:else if b.kind === 'list'}
-
+
{#each b.items as item}
{@html richToHtml(item, dark)}
{/each}
{:else if b.kind === 'conceptOverlay'}
diff --git a/src/components/HelpModal.svelte b/src/components/HelpModal.svelte
index 22549a9..be2dd78 100644
--- a/src/components/HelpModal.svelte
+++ b/src/components/HelpModal.svelte
@@ -1329,7 +1329,49 @@
{/if}
{/snippet}
{#snippet chWidget(id: string)}
- {#if id === 'ravine-race'}
+ {#if id === 'problem-grid'}
+ {#each Object.entries(problemCards) as [groupName, list]}
+
{groupName}
+
+ {#each list as p}
+
+
+ {#if p.customIcon}{p.customIcon}
+ {:else if p.icon}{/if}
+
+
+
{p.name}
+
{p.formula}
+
{p.tag}
+
+
+ {/each}
+
+ {/each}
+ {:else if id === 'experiments-list'}
+ {#each experiments as exp (exp.id)}
+
+
+
{exp.title}
+
{exp.blurb}
+
+
+
+ {/each}
+ {:else if id === 'keyboard'}
+
+ Space Train / Pause
+ S Step
+ R Reset
+ ←→↑↓ Nudge marker (⇧ = bigger)
+ D 2D / 3D
+ A Arrows
+ F Flow
+ C Contours
+
+ {:else if id === 'ravine-race'}
@@ -2654,8 +2648,8 @@
.experiment p { margin-bottom: 0; font-size: 0.875rem; }
/* ---------- Viz list ---------- */
- .viz-list { padding-left: 1.2rem; }
- .viz-list li { margin-bottom: 0.6rem; }
+ .reading-column :global(.viz-list) { padding-left: 1.2rem; }
+ .reading-column :global(.viz-list li) { margin-bottom: 0.6rem; }
/* ---------- Keyboard ---------- */
.kbd-row { display: flex; flex-wrap: wrap; gap: 0.625rem 1.25rem; align-items: center; }
diff --git a/src/content/blocks.ts b/src/content/blocks.ts
index f31d767..7ab1eb7 100644
--- a/src/content/blocks.ts
+++ b/src/content/blocks.ts
@@ -28,8 +28,8 @@ export type Block =
| { kind: 'display'; formula: FormulaKey; center?: boolean }
/** The imperative recipe blockquote — "Nudge. Measure. Divide." */
| { kind: 'recipe'; text: Rich }
- /** A bulleted list (the ▸-marker knob-bullets style). */
- | { kind: 'list'; items: Rich[] }
+ /** A bulleted list: ▸-marker knob style (default), or the plain viz-list. */
+ | { kind: 'list'; items: Rich[]; variant?: 'viz' }
/** A titled concept box, optionally with a small illustration beside it. */
| { kind: 'concept'; title: string; text: Rich; fig?: string }
/**
diff --git a/src/content/chapters/index.ts b/src/content/chapters/index.ts
index 5c824f3..dd9921d 100644
--- a/src/content/chapters/index.ts
+++ b/src/content/chapters/index.ts
@@ -16,6 +16,7 @@ import { chCurvature } from './ch-curvature';
import { chSchedule } from './ch-schedule';
import { chNoise } from './ch-noise';
import { chGeneralize } from './ch-generalize';
+import { chProblems, chExperiments, chPanels, chKeys } from './reference';
import {
chRavine,
chMomentum,
@@ -42,5 +43,9 @@ export const chapterBlocks: Record = {
'ch-adaptive': chAdaptive,
'ch-adam': chAdam,
'ch-second-order': chSecondOrder,
- 'ch-self-tuning': chSelfTuning
+ 'ch-self-tuning': chSelfTuning,
+ 'ch-problems': chProblems,
+ 'ch-experiments': chExperiments,
+ 'ch-panels': chPanels,
+ 'ch-keys': chKeys
};
diff --git a/src/content/chapters/reference.ts b/src/content/chapters/reference.ts
new file mode 100644
index 0000000..ca43136
--- /dev/null
+++ b/src/content/chapters/reference.ts
@@ -0,0 +1,42 @@
+import type { Block } from '../blocks';
+
+/**
+ * Part V · The zoo, and the reference pages. These chapters are thin by
+ * design: the problem bestiary and the experiment cards are data
+ * (problemCards.ts, experiments.ts) rendered by the chapter shell; the
+ * keyboard map is app-only and drops from print.
+ */
+
+/** Chapter 18 · The landscape zoo. */
+export const chProblems: Block[] = [
+ {
+ kind: 'p',
+ text: 'Every problem here has at most two parameters — the three 1D warm-ups use just $\\alpha$ — and a loss surface you can see live. Each surface tells a different story, from a single clean bowl to four-way ties and exploding cliffs, and each ships with a curated default learning rate and view (and, where it helps, momentum).'
+ },
+ { kind: 'widget', id: 'problem-grid' }
+];
+
+/** Chapter 19 · Things to try. */
+export const chExperiments: Block[] = [
+ {
+ kind: 'p',
+ text: 'Each card is a ready-made scenario — one click sets everything up, starts training, and tells you what to watch for.'
+ },
+ { kind: 'widget', id: 'experiments-list' }
+];
+
+/** Reference · Reading the panels. */
+export const chPanels: Block[] = [
+ {
+ kind: 'list',
+ variant: 'viz',
+ items: [
+ '**Data plot** — the data points and the current model. For curve fits, blue solid is the current fit and green dashed is the truth. For 2D problems, the orange marker shows your parameters directly on the plot.',
+ '**Loss & Gradient** — the loss landscape seen from above: the vivid end of the colour scale marks low loss (bright in night mode, deep in day mode — the colour bar shows which), thin contours join equal-loss points, and the field arrows are $-\\nabla\\mathcal{L}$. On the marker, the {blue:blue arrow} is steepest descent and the {red:red arrow} is the step actually taken. Drag the marker to teleport.',
+ '**Loss History** — train and test loss versus step. A clean decline is healthy; spikes mean you’re overshooting (too much $\\gamma$ or $\\mu$); a persistent train/test gap hints at overfitting.'
+ ]
+ }
+];
+
+/** Reference · Keyboard — app-only; print drops it. */
+export const chKeys: Block[] = [{ kind: 'widget', id: 'keyboard' }];