Lesson 8 of 8 · 58 min
AI in the UI + machine coding + capstone
Streaming AI UI patterns (protocols, batched tokens, conversation state, cancel/regenerate, citations, tool safety), machine-coding time-box strategy, and a self-scored FE system-design capstone mock with full rubric.
Lesson 8 · Capstone
AI in the UI + machine coding + mock
Engineering AI surfaces — not becoming an LLM course
Streaming protocols
- 01fetch + ReadableStream — flexible; parse SSE or newline JSON yourself.
- 02SSE — natural for token streams; EventSource or fetch stream.
- 03WebSocket — bidirectional agent control, tool events, multiplex.
- 04Pick by: bidirectional need, infra, proxy support, backpressure story.
1async function streamChat(body: unknown, onToken: (t: string) => void, signal: AbortSignal) {2 const res = await fetch('/api/chat', {3 method: 'POST',4 body: JSON.stringify(body),5 signal,6 })7 if (!res.ok || !res.body) throw new Error('stream failed')8 const reader = res.body.getReader()9 const dec = new TextDecoder()10 let buf = ''11 for (;;) {12 const { done, value } = await reader.read()13 if (done) break14 buf += dec.decode(value, { stream: true })15 // parse SSE lines / frames; onToken(piece)16 // keep parser robust to partial frames17 }18}Conversation state as data
1type Turn =2 | { id: string; role: 'user'; content: string }3 | { id: string; role: 'assistant'; content: string; status: 'streaming'|'done'|'error'|'cancelled'; citations?: Cite[] }4 | { id: string; role: 'tool'; name: string; input: unknown; output?: unknown; status: 'running'|'done'|'error' }56type Thread = {7 id: string8 turns: Turn[]9 // branch: parentId + alternative threads if you support forks10}Agentic controls & provenance
- 01Cancel — AbortController; mark turn cancelled; keep partial text optional.
- 02Regenerate — truncate from assistant turn; resubmit with same user context.
- 03Edit & rerun — rewrite user turn; drop later turns or fork branch.
- 04Citations — inline markers + source list; links; hover previews; never invent hrefs.
- 05Tool trace panel — collapsible timeline for power users; hide by default on mobile.
- 06Tool safety — validate tool JSON with Zod; run tools server-side; allowlist actions; never treat model text as instructions for privileged ops.
Key idea
Optimistic UX for variable latency
INP and a11y on streams
- 01Batch token appends (rAF / every N chars) to avoid 1 React commit per token on huge replies.
- 02aria-live polite for completion — not each token.
- 03Focus management: do not steal focus every chunk; offer “jump to latest.”
- 04Reduced motion: less shimmer on thinking indicators.
- 05Virtualize long threads; streaming is a high-frequency input pipeline.
1function useBatchedText() {2 const [text, setText] = useState('')3 const buf = useRef('')4 const raf = useRef(0)5 const push = (chunk: string) => {6 buf.current += chunk7 if (!raf.current) {8 raf.current = requestAnimationFrame(() => {9 raf.current = 010 setText(t => t + buf.current)11 buf.current = ''12 })13 }14 }15 return { text, push, setText }16}Common mistake
“Streaming UI is just setState on each token.”
Machine-coding patterns (time-box strategy)
- 01Autocomplete — debounce, abort, keyboard, a11y roles (you already designed it).
- 02Infinite list — cursor, observer, skeleton, error retry.
- 03Tabs / modal — roving tabindex / focus trap — show a11y fluency.
- 04Simple kanban — columns state, drag optional with keyboard alternative (2.5.7).
- 05Carousel — index state, buttons, aria-roledescription, reduced motion.
1MACHINE CODING 60–90m CLOCK20–8m Clarify acceptance criteria + edge cases; write a mini checklist38–35m Happy path vertical slice (renders + core interaction)435–55m Edge cases: empty, error, loading, keyboard555–70m Polish: a11y attributes, basic CSS, disable double submit670–90m Tests if required; narrate tradeoffs; clean dead code78Always: controlled state diagram in comments if stuck9Never: silent coding for 20 minutes without talkingCapstone mock — FE system design
1CAPSTONE RUBRIC21. Requirements elicitation — written; signed off by “PM”32. System design — ADRs (rendering, state model, perf budget)43. Implementation — clean decomposition; tests at boundaries54. Observability — log + metric + trace wired65. A11y & perf audits — axe + Lighthouse + RUM plan76. Demo — 5-minute Loom that tells the *why* before the *what*89PDP sketch:10 SEO + LCP image; variant picker a11y; cart multi-tab BroadcastChannel;11 RSC shell + client add-to-cart; revalidate on price; CLS on gallery.12Inbox sketch:13 URL selection; infinite thread list; mark read optimistic; push via SSE;14 badge derived from cache; keyboard list navigation.15Autocomplete sketch:16 scale, cache, analytics privacy, a11y APG — you already know this.Track synthesis — what you can claim
- 01Own a surface with eight production dimensions and a real definition of done.
- 02Pass React/Next batteries: re-renders, RSC boundaries, revalidate layers, hydration.
- 03Place state in four buckets; compose components without god files.
- 04Diagnose LCP/INP/CLS and pick rendering modes from constraints.
- 05Design a11y into widgets; steward DS tokens and gates.
- 06Drive FE system design for chat, dashboard, collab, feed, autocomplete (RADIO).
- 07Ship streaming AI UI without melting INP or accessibility.
AI UI — failure modes and senior signals
- 01Parser fragility — partial SSE frames crash JSON.parse. Buffer lines; tolerate incomplete fences.
- 02Per-token setState — main-thread thrash. Batch with rAF.
- 03Live region spam — SR unusable. Announce completion only.
- 04No cancel — runaway cost and stuck pending UI. AbortController + cancelled status.
- 05Tool output as HTML — XSS. Treat as data; render structured UI from validated JSON.
- 06Prompt injection via tool results — never elevate model text to privileged instructions; allowlist server-side tools.
- 01Q: SSE vs WebSocket for chat tokens? SSE (or fetch streams) fits unidirectional token streams with simple infra and automatic reconnect stories. WebSocket wins when you need multiplexed bidirectional control (cancel, tool events, collaborative agent state) on one connection. Many products start with fetch streams and add WS only when control plane needs grow.
- 02Q: How do you model regenerate and branch? Turns are data. Regenerate truncates or forks from an assistant index and starts a new streaming turn. Branch keeps alternate threads keyed by parentId. Component-local strings cannot represent this without pain. Discriminated unions make tool traces and citations first-class.
- 03Q: What is the machine-coding clock for a senior? Clarify acceptance criteria first (8m), vertical slice happy path (to ~35m), then empty/error/loading/keyboard (to ~55m), then polish and tests. Narrate continuously. Keyboard and disabled double-submit beat pixel-perfect CSS in the last ten minutes.
- 04Q: Capstone self-score rule of thumb? If architecture is a 5 but NFRs were never named, ownership score collapses. Unprompted perf budget, a11y path, and failure modes are the L1 bar this track trained. Re-run the mock until four of six dimensions are ≥4.
1// Capstone week plan (solo)2// Day 1: RADIO writeup + state model + acceptance criteria3// Day 2: vertical slice streaming UI + cancel4// Day 3: citations/tool panel + a11y pass5// Day 4: machine-coding kata under timer (autocomplete or modal)6// Day 5: 45m system-design mock on unseen prompt; score rubric; gap list78// Metrics to log on AI UI9// ttft_ms, tokens_per_sec_client, cancel_rate, parse_error_rate, inp_composerCapstone assembly — AI UI + machine coding + mock
- 01AI UI week-1 — fetch stream parser, cancel, batched text, turn list UI.
- 02AI UI week-2 — regenerate/edit, citations, tool trace panel, a11y pass.
- 03Kata rotation — autocomplete · infinite list · tabs/modal · carousel.
- 04Mock rotation — chat · feed · collab · PDP · inbox.
- 05Pass bar — ≥4/5 on four of six capstone axes + cold L2 battery sample.
1// Minimal turn reducer sketch2type Action =3 | { type: 'user_send'; id: string; content: string }4 | { type: 'assistant_start'; id: string }5 | { type: 'assistant_token'; id: string; chunk: string }6 | { type: 'assistant_done'; id: string }7 | { type: 'cancel'; id: string }8 | { type: 'regenerate'; fromIndex: number }910// regenerate: slice turns to fromIndex; dispatch assistant_startCheckpoint
Best reason to batch token updates with requestAnimationFrame while streaming?
Checkpoint
How should conversation regenerate be modeled?
Checkpoint
Machine-coding: 10 minutes left, happy path works, no keyboard support on a custom listbox. What do you do?
Checkpoint
E-comm PDP multi-tab cart: user adds item in tab A; tab B still shows empty. Strong FE fix?
Checkpoint
Capstone self-score: strong architecture, no NFRs named. What happens on the senior rubric?
Ready to run a 45-minute FE system design mock and a streaming AI UI deep dive without notes?
Takeaways
- AI UI: stream parsers, batched paints, cancel/regenerate, citations, turns as data.
- Protect INP and a11y under streaming load — no per-token announce spam.
- Machine coding: clarify, vertical slice, edges, keyboard, narrate.
- Capstone: requirements · architecture · NFRs · a11y · perf · failures.
- You now have the product FE craft loop — schedule real mocks and re-score.
Track complete. Revisit L2 Qs weekly and run one FE system-design mock before each loop.
Sources
Free to read · better with Enzo
Learn it with Enzo
Save your progress, answer the checkpoints, and let Enzo quiz you on what you just read.