Skip to content

Latest commit

 

History

History
165 lines (134 loc) · 8.46 KB

File metadata and controls

165 lines (134 loc) · 8.46 KB

CLAUDE.md — Emergence in a Cup

Guidance for Claude Code (and humans) working in this repo.

Project purpose

An interactive, scroll-driven educational 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 familiar entry point. The payoff is a real, interactive WebGL/GLSL latte-pour simulator. It is also a portfolio submission for an Anthropic engineering assignment.

Audience: zero physics background. A reader should leave able to explain, in plain words: simple rules → complex patterns, sensitivity to initial conditions, laminar flow, and double-diffusive convection — and should have played with the simulator.

The quality bar (non-negotiable)

This should be the best visual presentation of these resources available. If a draft does not clear that bar, iterate until it does. The presentation-critic agent is empowered to say "not good enough" and dispatch fixes to the specialist agents.

Hard requirements: reading comfort (generous type, strong hierarchy, calm pacing); accessibility (keyboard nav, semantic landmarks, WCAG AA contrast, prefers-reduced-motion fallback); the simulator targets ~60fps and degrades gracefully (static fallback when WebGL2 is unavailable).

Section structure (scroll-driven guided presentation)

  1. Hero — "the heart in your latte is emergence in a cup."
  2. A Short History — origins (Italy + Seattle/Schomer, Lupi), microfoam, heart/rosetta/tulip.
  3. The Micro Level — the "agents": microfoam, crema, density, buoyancy, surface tension → simple local rules.
  4. The Macro Level — emergence; sensitivity to initial conditions; laminar flow & viscoelastic boundaries; double-diffusive convection.
  5. The Latte Art Simulator — the real WebGL pour sim (pour height, speed, angle, flow rate, milk temp…).
  6. Recap — ties simulator behavior back to the named concepts.

Architecture & directory layout

  • Stack: Next.js 16 (App Router) · React 19 · TypeScript (strict) · Tailwind CSS v4 · motion (Framer Motion) for scroll animation · a faithful raw-WebGL port of the PourMyFriends fluid sim for the simulator · shadcn/ui conventions (cn(), new-york, lucide). Fully static/client; no backend, db, or auth.
app/                 App Router (one long scroll page + section anchors), layout, globals.css
  research/          /research page — renders the validated research doc (markdown viewer)
components/
  sections/          Hero, History, Micro, Macro, Simulator, Recap
  demos/             Sections 1–4 teaching micro-demos (SVG / Canvas2D / CSS)
  simulator/         Section 5 WebGL fluid sim (raw-WebGL), controls, fallback
  nav/               persistent jump-to-section nav + scroll progress
  research/          markdown-viewer for the /research page
  ui/                shared primitives (shadcn conventions) — buttons, reveal, citations, demo figure
content/
  research/          latte-emergence.md (VALIDATED) + citations.ts (typed)
  sections/          typed TS content modules (copy + citation refs)
lib/                 utils (cn, canvas/observer helpers), hooks
shaders/             GLSL ported from the PourMyFriends approach (raw-string imports)
.claude/agents/      the agent fleet
docs/input/          source material + the TS/React rule files

Design tokens (espresso / latte)

Defined as Tailwind v4 @theme tokens in app/globals.css. RGB values are derived directly from the PourMyFriends fluid-shader uniforms:

Token (--color-…) Hex Use
espresso #381F0D deepest brown / near-black
espresso-ink #241308 body text
crema #7A4A24 primary accent
crema-deep #40261A crema tint
milk #FFFAF5 surfaces/cards
foam #EBE0D1 borders/dividers
cream #F7EFE4 page background
milk-rim #73471F warm rim accent / focus ring
rim-shadow #594738 shadow band
specular #FFF7EB highlights
muted #6B5341 muted text (AA on cream)

Use as bg-espresso, text-muted, border-foam, etc. Always verify AA contrast.

Content & research conventions (graded)

  • All app copy must trace to content/research/latte-emergence.md. No unverified scientific claim ships. Section copy lives in typed TS modules under content/sections/*.ts and references citation IDs from content/research/citations.ts — never hardcode prose or citations inline in JSX.
  • Teaching analogies (e.g. "laminar flow," "microfoam is weakly elastic") are labelled as analogies and not presented as cited measurements — see the research doc §4 and §6.
  • The research-validator agent owns content/research/ and citation quality.

Code conventions (enforced)

Follow docs/input/typescript-practices.mdc and docs/input/react-practices.mdc (committed to the repo). Key points:

  • TS strict; interface over type for object shapes; no any (ESLint error → use unknown + guards); TSDoc on exported types/functions/ props; functions with >2 params take a single typed object param.
  • React: named exports for components (no default exports except Next app/** pages/layouts, which require them); no React.FC; pure components; import hooks from "react"; useCallback/useMemo only where it earns its keep; refs are escape hatches (the simulator is the main legit user).
  • Tailwind: utility-first with complete static class names (never string-concatenate classes); inline style only for truly dynamic values (scroll transforms, simulator readouts); use cn() from @/lib/utils.
  • Naming: files kebab-case (fluid-simulator.tsx); components PascalCase; hooks useX; constants SCREAMING_SNAKE_CASE.

Scroll-animation approach

motion (Framer Motion): whileInView/useScroll for reveals and pinned sequences; IntersectionObserver for nav active-state and lazy-mounting the simulator. All motion is gated behind useReducedMotion() — reduced-motion users get static content, no parallax/auto-play. Animation should feel like an intentional guided presentation, never gratuitous.

Simulator architecture

A GPU "stable fluids" Navier–Stokes solver, ported directly from PourMyFriends (raw WebGL): dual-resolution sim/dye grids, a milk+crema dye model (R = milk, G = crema), MacCormack advection, a circular cup mask, and the full latte-art display shading (foam absorption, valley/petal darkening, beveled ceramic rim, specular). The actual .vert/.frag files live in shaders/glsl/* (imported as raw strings via a Turbopack rule in next.config.ts); the JS pipeline is in components/simulator/fluid-engine.ts, with DEFAULT_SIM_CONFIG matching the original's parameters and palette. A React hook (use-fluid-simulator.ts) drives it: pointer pouring, a scripted demo pour (so it's alive on first load), offscreen pause, and WebGL feature detection. Fallback: a static SVG latte when WebGL is unavailable or prefers-reduced-motion is set. Owned by simulator-engineer.

Run / build / deploy

npm run dev         # local dev (http://localhost:3000)
npm run lint        # ESLint (flat config)
npm run typecheck   # tsc --noEmit
npm run test        # vitest run
npm run build       # next build (production)
npm run format      # prettier --write .

Validate with lint + typecheck + test + build after each major step (this is also the CI gate, .github/workflows/ci.yml). Deployed to Vercel at https://emergence-in-a-cup.vercel.app/ (zero-config Next.js; production = public URL). Repo is private; grant access to ehsanik per the assignment.

Note: in sandboxed shells, npm install may need a project-local cache (npm install --cache ./.npm-cache) and next build needs network for next/font/google.

Agent fleet

See AGENTS.md and .claude/agents/*. Specialists: research-validator, content-writer, simulator-engineer, teaching-visuals-engineer, motion-designer, design-system-guardian, accessibility-auditor, presentation-critic (adversarial reviewer / dispatcher).