An interactive, scroll-driven web app that teaches emergent dynamics — how simple local rules produce complex global patterns — to non-technical "curious coffee drinkers," using latte art as the entry point and ending in a real WebGL latte-pour simulator.
The heart in your latte is emergence — and nobody draws it.
▶ Live demo: emergence-in-a-cup.vercel.app
Hero → A Short History → The Micro Level → The Macro Level → The Latte Art Simulator → Recap. Scroll top-to-bottom for the guided presentation, or use the persistent jump-to-section nav.
- Next.js 16 (App Router) · React 19 · TypeScript (strict)
- Tailwind CSS v4 design tokens (espresso/latte palette)
- Framer Motion (
motion) for scroll-driven, reduced-motion-aware animation - Raw-WebGL GPU fluid simulator (Section 5), a direct port of the
PourMyFriends shaders + pipeline
(the actual
.vert/.fragfiles live inshaders/glsl/) - Teaching demos: Canvas2D / SVG (clarity over fidelity)
npm install # if the global npm cache is locked: npm install --cache ./.npm-cache
npm run dev # http://localhost:3000
npm run lint # ESLint (flat config)
npm run typecheck # tsc --noEmit
npm run test # vitest
npm run build # next build (needs network for next/font)
npm run format # prettier --write . (format:check to verify only)CI (.github/workflows/ci.yml) runs lint + typecheck + test + build.
- All app copy traces to the validated research in
content/research/latte-emergence.md; citations are typed incontent/research/citations.ts. No unverified claims. - Code follows
docs/input/typescript-practices.mdcanddocs/input/react-practices.mdc. - See
CLAUDE.mdfor architecture and the design system, andAGENTS.mdfor the Claude Code agent fleet that maintains it. - See
RATIONALE.mdfor the design rationale and video script.
This repo is built to be maintained with Claude Code and a fleet of focused
subagents defined in .claude/agents/. Each agent owns one
area, so changes stay scoped and reviews stay sharp. The full ownership table and
boundaries live in AGENTS.md; this is the short version for getting
started.
The fleet: research-validator (facts + citations), content-writer
(plain-language copy), simulator-engineer (Section 5 WebGL sim + shaders),
teaching-visuals-engineer (Sections 1–4 demos), motion-designer (scroll
animation + reduced motion), design-system-guardian (tokens, type, contrast),
accessibility-auditor (keyboard, semantics, a11y), and presentation-critic
(adversarial reviewer that judges the live build and dispatches fixes).
How to invoke one — ask Claude Code to use the agent by name, e.g.:
> Use the accessibility-auditor to review the simulator controls.
> Have the content-writer tighten the Macro section copy, then research-validator to re-verify.
Claude Code dispatches the named subagent with only its tools and ownership in scope. You direct; the agent reports back; you decide what lands.
The workflow they compose into:
- Research → copy.
research-validatormaintains the validated doc;content-writerderives prose;research-validatorsigns off (every scientific claim must trace to a citation incitations.ts). - Build.
simulator-engineer,teaching-visuals-engineer, andmotion-designerimplement against the validated content and design tokens. - Guard.
design-system-guardianandaccessibility-auditorreview tokens, contrast, typography, reduced motion, keyboard, and semantics. - Critique loop.
presentation-criticreviews the live build against the quality bar, files concrete issues, and routes each to the owning specialist — repeat until it clears the bar.
Boundaries worth remembering: the simulator (Section 5) maximizes visual
fidelity and is simulator-engineer's alone; the teaching demos (Sections 1–4)
maximize conceptual clarity and belong to teaching-visuals-engineer — keep the
two stacks from bleeding into each other. And research-validator gates all copy.
Before merging: npm run lint && npm run typecheck && npm run test && npm run build must be clean (the CI gate), the accessibility-auditor must pass, and all
new copy must trace to the research doc.
Semantic landmarks, keyboard-navigable nav and simulator controls, WCAG AA
contrast, and full prefers-reduced-motion fallbacks. The simulator targets
~60fps, pauses when offscreen, and degrades to a static latte when WebGL is
unavailable.