Skip to content

Commit a88dbea

Browse files
alexnodelandclaude
andcommitted
docs: Fugue Explorables — interactive data-first docs rehaul
Adds an Explorables section: six interactive pages in the tradition of Bret Victor's explorable explanations and 3Blue1Brown's visual math, built on a shared dependency-free canvas library (docs/fugue-viz.js, ~5k lines total, no CDNs, no build step, theme-aware, reduced-motion safe, seeded/reproducible). Every widget centers on live data: draggable observations with priors and posteriors updating in real time. Metropolis and HMC share one Bayesian linear regression as twin-panel views (data space with posterior spaghetti <-> parameter space with the sampler), with live split-R-hat/ESS implementing the 0.2.0 diagnostics math in JS. The monad page performs a Normal-mean model one effect at a time over a draggable dataset with its exact conjugate posterior. SMC shows the filtering distribution and mean band over its particle cloud. Also a 0.2.0 truth pass over all existing pages: fixed broken prob! snippets (raw for-loops the macro cannot parse), a duplicate-address hierarchical sample that would panic, a fabricated ScoreGivenTrace API, dead example references, wrong repo URLs, and stale memory- subsystem claims; every remaining snippet verified against src/. Fixes a live site bug: default-theme was "dark", which is not an mdbook theme name, so light-OS visitors got the light CSS fallback while the html class claimed dark; now navy, and the viz library detects dark/light from mdbook's --bg token instead of class names. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DEAKcbnLVP8iSXub2Pqor2
1 parent 2595cfa commit a88dbea

38 files changed

Lines changed: 6926 additions & 183 deletions

docs/book.toml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,15 @@ text-direction = "ltr"
1010
create-missing = true
1111

1212
[output.html]
13-
default-theme = "dark"
13+
# "navy" is mdbook's dark theme; the previous value "dark" is not a real
14+
# mdbook theme name, so light-OS visitors silently got the light CSS fallback
15+
# while the html class still claimed dark.
16+
default-theme = "navy"
17+
preferred-dark-theme = "navy"
1418
git-repository-url = "https://github.com/alexnodeland/fugue"
1519
site-url = "/fugue/"
16-
additional-css = ["./mdbook-admonish.css"]
17-
additional-js = ["mermaid.min.js", "mermaid-init.js"]
20+
additional-css = ["./mdbook-admonish.css", "fugue-viz.css"]
21+
additional-js = ["mermaid.min.js", "mermaid-init.js", "fugue-viz.js", "viz/anatomy.js", "viz/monad.js", "viz/metropolis.js", "viz/hmc.js", "viz/smc.js", "viz/distributions.js"]
1822

1923
[output.html.fold]
2024
enable = true

docs/fugue-viz.css

Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
/*
2+
* fugue-viz.css — styling for the Fugue Explorables shared infrastructure.
3+
*
4+
* Defines the semantic color algebra (blue x yellow = green) as CSS custom
5+
* properties, theme-switched via mdbook's <html> theme class:
6+
* light family -> html.light, html.rust
7+
* dark family -> html.coal, html.navy, html.ayu, html.dark, and ALSO the
8+
* default (no theme class), since the book default is dark.
9+
* The dark palette is the :root default so the absent-class case is dark.
10+
*/
11+
12+
:root {
13+
--fv-prior: #58a6ff;
14+
--fv-data: #f2cc60;
15+
--fv-post: #56d364;
16+
--fv-hot: #ff7b72;
17+
--fv-flow: #bc8cff;
18+
--fv-ink: rgba(230, 237, 243, 0.9);
19+
--fv-grid: rgba(230, 237, 243, 0.08);
20+
--fv-panel: rgba(110, 118, 129, 0.08);
21+
}
22+
23+
/* Light theme families */
24+
html.light,
25+
html.rust {
26+
--fv-prior: #0969da;
27+
--fv-data: #9a6700;
28+
--fv-post: #1a7f37;
29+
--fv-hot: #cf222e;
30+
--fv-flow: #8250df;
31+
--fv-ink: rgba(31, 35, 40, 0.9);
32+
--fv-grid: rgba(31, 35, 40, 0.08);
33+
--fv-panel: rgba(175, 184, 193, 0.12);
34+
}
35+
36+
/* Explicit dark families (redundant with :root default, but future-proof) */
37+
html.coal,
38+
html.navy,
39+
html.ayu,
40+
html.dark {
41+
--fv-prior: #58a6ff;
42+
--fv-data: #f2cc60;
43+
--fv-post: #56d364;
44+
--fv-hot: #ff7b72;
45+
--fv-flow: #bc8cff;
46+
--fv-ink: rgba(230, 237, 243, 0.9);
47+
--fv-grid: rgba(230, 237, 243, 0.08);
48+
--fv-panel: rgba(110, 118, 129, 0.08);
49+
}
50+
51+
/* ---- The widget panel (full-width) ---------------------------------------- */
52+
53+
.fugue-explorable {
54+
border: 1px solid var(--fv-grid);
55+
border-radius: 8px;
56+
background: var(--fv-panel);
57+
padding: 12px 14px;
58+
margin: 1.4rem 0;
59+
font-size: 0.8rem;
60+
}
61+
62+
.fv-canvas {
63+
display: block;
64+
width: 100%;
65+
border-radius: 6px;
66+
touch-action: none; /* let pointer drags on canvas work on touch */
67+
}
68+
69+
/* ---- Controls row --------------------------------------------------------- */
70+
71+
.fv-controls {
72+
display: flex;
73+
flex-flow: row wrap;
74+
gap: 10px;
75+
align-items: flex-end;
76+
margin-bottom: 10px;
77+
}
78+
79+
.fv-control {
80+
display: inline-flex;
81+
flex-direction: column;
82+
gap: 3px;
83+
font-size: 0.8rem;
84+
}
85+
86+
.fv-control-label {
87+
text-transform: uppercase;
88+
letter-spacing: 0.08em;
89+
opacity: 0.65;
90+
font-size: 0.68rem;
91+
}
92+
93+
.fv-control-value {
94+
font-family: var(--mono-font, "Source Code Pro", monospace);
95+
font-variant-numeric: tabular-nums;
96+
opacity: 0.9;
97+
}
98+
99+
.fv-range {
100+
width: 140px;
101+
accent-color: var(--fv-prior);
102+
cursor: pointer;
103+
}
104+
105+
.fv-range:focus-visible {
106+
outline: 2px solid var(--fv-prior);
107+
outline-offset: 2px;
108+
}
109+
110+
/* Toggle */
111+
.fv-toggle {
112+
flex-direction: row;
113+
align-items: center;
114+
gap: 6px;
115+
cursor: pointer;
116+
}
117+
118+
.fv-checkbox {
119+
accent-color: var(--fv-post);
120+
cursor: pointer;
121+
}
122+
123+
/* Buttons */
124+
.fv-buttons {
125+
display: inline-flex;
126+
gap: 6px;
127+
align-items: center;
128+
}
129+
130+
.fv-btn {
131+
font-size: 0.75rem;
132+
padding: 4px 10px;
133+
border-radius: 6px;
134+
border: 1px solid var(--fv-grid);
135+
background: transparent;
136+
color: var(--fv-ink);
137+
cursor: pointer;
138+
font-family: inherit;
139+
line-height: 1.4;
140+
}
141+
142+
.fv-btn:hover {
143+
border-color: var(--fv-prior);
144+
}
145+
146+
.fv-btn:focus-visible {
147+
outline: 2px solid var(--fv-prior);
148+
outline-offset: 2px;
149+
}
150+
151+
.fv-btn.fv-primary {
152+
background: var(--fv-prior);
153+
border-color: var(--fv-prior);
154+
color: #0d1117;
155+
font-weight: 600;
156+
}
157+
158+
html.light .fv-btn.fv-primary,
159+
html.rust .fv-btn.fv-primary {
160+
color: #ffffff;
161+
}
162+
163+
/* ---- Readouts row --------------------------------------------------------- */
164+
165+
.fv-readouts {
166+
display: flex;
167+
flex-flow: row wrap;
168+
gap: 16px;
169+
margin-top: 10px;
170+
align-items: baseline;
171+
}
172+
173+
.fv-readout {
174+
display: inline-flex;
175+
flex-direction: column;
176+
gap: 1px;
177+
}
178+
179+
.fv-readout-label {
180+
text-transform: uppercase;
181+
letter-spacing: 0.08em;
182+
opacity: 0.65;
183+
font-size: 0.66rem;
184+
}
185+
186+
.fv-readout-value {
187+
font-family: var(--mono-font, "Source Code Pro", monospace);
188+
font-variant-numeric: tabular-nums;
189+
font-size: 0.95rem;
190+
}
191+
192+
/* ---- The Victor scrub number (in prose) ----------------------------------- */
193+
194+
.fv-scrub {
195+
border-bottom: 1px dashed var(--fv-prior);
196+
cursor: ew-resize;
197+
font-family: var(--mono-font, "Source Code Pro", monospace);
198+
font-variant-numeric: tabular-nums;
199+
color: var(--fv-prior);
200+
user-select: none;
201+
padding: 0 1px;
202+
white-space: nowrap;
203+
}
204+
205+
.fv-scrub:focus-visible {
206+
outline: 2px solid var(--fv-prior);
207+
outline-offset: 2px;
208+
}
209+
210+
.fv-scrub-active {
211+
color: var(--fv-hot);
212+
border-bottom-color: var(--fv-hot);
213+
}
214+
215+
/* ---- Inline prose color classes (the color algebra in text) --------------- */
216+
217+
.fv-c-prior { color: var(--fv-prior); }
218+
.fv-c-data { color: var(--fv-data); }
219+
.fv-c-post { color: var(--fv-post); }
220+
.fv-c-hot { color: var(--fv-hot); }
221+
.fv-c-flow { color: var(--fv-flow); }
222+
223+
/* ---- The "try this" hint -------------------------------------------------- */
224+
225+
.fv-hint {
226+
font-style: italic;
227+
opacity: 0.7;
228+
font-size: 0.78rem;
229+
margin-top: 8px;
230+
}
231+
232+
.fv-hint::before {
233+
content: "try: ";
234+
font-style: normal;
235+
text-transform: uppercase;
236+
letter-spacing: 0.08em;
237+
opacity: 0.7;
238+
font-size: 0.66rem;
239+
}
240+
241+
/* Canvas instruction line (drag/paint affordances) */
242+
.fv-instruction {
243+
font-size: 0.72rem;
244+
opacity: 0.6;
245+
margin-top: 4px;
246+
text-align: center;
247+
}
248+
249+
/* ---- Reduced motion ------------------------------------------------------- */
250+
251+
@media (prefers-reduced-motion: reduce) {
252+
.fugue-explorable * {
253+
transition: none !important;
254+
animation: none !important;
255+
}
256+
}

0 commit comments

Comments
 (0)