Case Study
Building with
Claude API
+ Nodus Design System
This case study covers two things: the Agent Chat Interface reference implementation, and the Anthropic SDK integration pattern with the four Nodus DS components that map to the layers above the API. The reference page is a standalone demonstration. It replays a scripted thread, makes no model call and does not import those components. Three of the four ship in the package; ModelSelector is in the repo but is not exported from the package root.
Reference page
What the reference page does.
It replays a hard-coded thread of six messages on timers and shows a typing indicator before each agent reply. Three of the agent replies carry an inline spec card: an MIT card, an action item and an approval card whose Approve and Deny buttons update local state. Text typed into the input gets one fixed reply after 1.4 seconds. The claude-sonnet-4-6 label in its header is text; nothing calls a model.
Integration pattern (illustrative)
Five layers. One rendering pipeline.
This is how the components are designed to sit in a Claude API integration, from API call to rendered UI. The reference page does not implement it, and nothing in this repo wires all five layers together.
Streams a reply through the Anthropic SDK. In this repo, app/api/sandbox/route.ts streams text deltas with client.messages.stream on claude-haiku-4-5-20251001, but only under `npm run dev` with NODE_ENV=development — a deployed build answers 503 and never imports the SDK. app/api/copilotkit/route.ts no longer calls the Claude API directly at all: in development it spawns the developer's own `claude` CLI login, with no fixed model name; a deployed build answers 503 there too. No route here defines tools, so tool use is part of the API but not exercised by this repo.
Renders the content string you pass it, with a state of streaming, complete or error. Kinds are code, markdown and text, with an optional diff view and copy button. While streaming it sets aria-live=polite. Your code feeds it from the stream.
Shows one tool call: its name, input and output as JSON blocks, a status of pending, running, done or error, and an optional duration. It is collapsible, and starts closed when defaultCollapsed is set.
Takes segments (label and token count) and a limit, and draws a segmented bar with role=meter. By default it warns at 80% of the limit and flags critical at 95% (warnAt and criticalAt props). You read the counts from the API's usage field and pass them in.
Takes a list of options (id, name, context window, capabilities, cost tier and latency tier) and renders a dropdown or a comparison panel. The list is yours to supply. Source is components/ai/ModelSelector.tsx; it is not exported from the package root.
Implementation (illustrative)
Three steps.
Install the SDK
Create the streaming client
Pass stream state into the components
Token Economics
Context window in context.
ContextWindowMeter draws the segments and limit you pass it. The numbers below are sample values, not measurements from a session: 24,382 of 200,000 tokens, 12.2%.
Accessibility
Contrast computed. Behavior cited.
Contrast ratios are computed from the token values the Agent Chat page renders, in light and dark, with the WCAG relative-luminance formula. The two pairs that sit on a primary color have a second row for wide-gamut (Display P3) displays, where the light theme uses richer primaries; the neutral pairs are the same on both. tests/case-study-contrast.test.ts recomputes every figure from tokens/bauhaus.css and fails if this page drifts. The other rows name the file that implements the behavior, and the last one is a gap.
Contrast — primary text on raised surface (agent bubble)
sRGB, light / dark. WCAG AA requires 4.5:1
Contrast — secondary text on raised surface
sRGB, light / dark. WCAG AA requires 4.5:1
Contrast — inverse text on temporal (user bubble)
sRGB, light / dark. WCAG AA requires 4.5:1
Contrast — inverse text on agency (Approve button)
sRGB, light / dark. WCAG AA requires 4.5:1
Contrast — inverse text on temporal, wide-gamut display (user bubble)
Display P3, light / dark, read in Chromium with color-gamut: p3 emulated. The wide-gamut primaries in tokens/bauhaus.css apply to the light theme only, so dark is the sRGB figure. WCAG AA requires 4.5:1
Contrast — inverse text on agency, wide-gamut display (Approve button)
Display P3, light / dark, read in Chromium with color-gamut: p3 emulated. The wide-gamut primaries in tokens/bauhaus.css apply to the light theme only, so dark is the sRGB figure. WCAG AA requires 4.5:1
Streaming announcements
StreamingArtifact sets aria-live=polite and aria-busy while streaming. The reference page has no live region.
Keyboard operation
The reference page uses a native input and buttons, and Enter sends. It adds no Arrow or Escape handling.
Reduced motion
A global rule in app/globals.css shortens every animation and transition under prefers-reduced-motion.
Focus indicator
The global :focus-visible ring is a 2px outline with 2px offset. The reference page's text input sets outline: none inline, so it shows no ring.
Awards Submission
Exhibit A for the agent era.
This case study is submitted as the primary exhibit for the Awwwards SOTD and CSS Design Awards nominations. The Agent Chat Interface reference implementation shows the rendered-UI end of that integration: a scripted thread with inline spec cards, with no API call behind it. It is a standalone demonstration page; three of the four components described here ship in the package.
StreamingArtifact, ContextWindowMeter, and FunctionCallVisualizer are components for streamed model output, token budgets and tool calls.