Tasks 5-7: eval harness, FastAPI backend, Paper & Ink UI- src/eval/ β precision/recall/F1 harness with type-aware comparators,micro/macro F1, CSV + markdown reports, --model benchmark flag- src/api/ β FastAPI backend with /extract, /schemas, /health,request-ID middleware, typed error envelope, injectable extractor- ui/ β Vite + React + TS + Tailwind + Motion + React Three FiberPaper & Ink editorial UI with 3D paper hero, dark/light mode,confidence inkwell, wax-stamp metrics, kinetic typography- 95 passing tests (up from 54); UI is a separate npm workspace
557ab38 | # Ledger UI | |
| The Paper & Ink frontend for the structured-data-extraction API. | |
| ## Stack | |
| - **Vite + React + TypeScript** β fast dev loop, small bundle. | |
| - **Tailwind** β utility layout only. All colors, typography, and design | |
| tokens live as CSS variables in `src/styles/theme.css`, so dark/light mode | |
| is a single attribute flip on `<html data-theme="...">`. | |
| - **Motion** (`motion/react`) β component-level animation. | |
| - **React Three Fiber + drei + three** β the 3D paper sheet in the hero. | |
| - **Google Fonts** β Instrument Serif (display), Geist (UI), JetBrains Mono | |
| (code). All free. | |
| ## Run locally | |
| ```bash | |
| # 1. Install | |
| cd ui | |
| npm install | |
| # 2. Point at the API (in another terminal, from the repo root): | |
| uvicorn src.api.main:app --reload | |
| # 3. Start the dev server | |
| npm run dev | |
| # open http://localhost:5173 | |
| ``` | |
| Vite proxies `/api/*` to `http://localhost:8000`, so no CORS needed in dev. | |
| ## Configuration | |
| - `VITE_API_BASE` (optional) β override the API origin for prod builds. | |
| Defaults to `/api`. | |
| ## Design tokens | |
| Everything visual is in `src/styles/theme.css`: | |
| - `--bg`, `--surface`, `--surface-2`, `--rule` β surfaces + dividers | |
| - `--ink`, `--ink-strong`, `--ink-soft`, `--ink-mute` β text weights | |
| - `--accent`, `--accent-hover`, `--accent-soft` β coral | |
| - `--sage`, `--mustard` β confidence tiers + warnings | |
| To try a color, edit the variable β both modes update simultaneously. | |
| ## Project shape | |
| ``` | |
| ui/ | |
| βββ index.html # font preload + theme priming (no-flash) | |
| βββ src/ | |
| β βββ main.tsx # ReactDOM render | |
| β βββ App.tsx # page composition | |
| β βββ styles/ | |
| β β βββ theme.css # design tokens (light + dark) | |
| β β βββ globals.css # base + grain overlay + focus/cursor | |
| β βββ components/ | |
| β β βββ TopNav.tsx # logo + theme toggle | |
| β β βββ ThemeToggle.tsx # hand-drawn sun/moon | |
| β β βββ CustomCursor.tsx # spring-lag ink dot | |
| β β βββ Hero.tsx # kinetic headline + stats + 3D scene | |
| β β βββ PaperScene.tsx # R3F: floating paper w/ mouse parallax | |
| β β βββ ExtractSection.tsx # workbench (dropzone + results) | |
| β β βββ Dropzone.tsx # drop + browse + doc-type + samples | |
| β β βββ ResultsPanel.tsx # composes the below | |
| β β βββ ConfidenceInkwell.tsx # confidence as an ink vessel | |
| β β βββ MetricsStrip.tsx # cost/latency/tokens/model | |
| β β βββ JsonView.tsx # syntax-highlighted JSON | |
| β β βββ WarningsList.tsx # model-flagged concerns | |
| β β βββ HowItWorks.tsx # three chapters | |
| β β βββ Numbers.tsx # magazine-style data page | |
| β β βββ Footer.tsx # signature line | |
| β βββ hooks/ | |
| β β βββ useTheme.ts # dark/light + localStorage | |
| β β βββ useExtract.ts # upload lifecycle | |
| β βββ lib/ | |
| β β βββ api.ts # thin fetch client + typed error envelope | |
| β β βββ samples.ts # committed sample docs | |
| β βββ types.ts # mirrors src/schemas server-side | |
| βββ public/samples/ # sample_receipt.png, sample_invoice.pdf | |
| ``` | |