Skip to main content

zLLM

Beta

AI-Powered Dynamic Theming

The site you're looking at is the demo.

Type a style into the chat — "dark brutalist", "soft pastels", "neon cyberpunk" — and watch every element on this page transform in real-time through GPT tool calls and CSS variables.

GPT-4o-miniTool UseCSS VariablesStreaming SSE26 TokensWCAG Contrast

Architecture

One tool call reshapes the entire site.

The system is built on a single abstraction: a style schema that defines every visual property as a typed token. The AI writes to it, CSS reads from it, and React never re-renders.

01

Natural language input

User describes a mood, references a brand, or says "surprise me". The message hits /api/chat-style — a streaming SSE endpoint.

02

Agentic tool loop

GPT-4o-mini runs in an agent loop (up to 5 iterations) with a single tool: update_style. It can call the tool multiple times per turn — refining colors, then adjusting layout, then tweaking typography.

03

Schema validation & clamping

Every tool call is validated against a typed schema. Colors must be valid hex. Numbers are clamped to safe ranges (e.g. gridCols: 1–6, dotOpacity: 0–0.35). Invalid tokens are silently dropped.

04

CSS variable injection

Validated tokens are written as --style-* custom properties on document.documentElement. The entire site reads these vars — no prop drilling, no context re-renders. Just CSS cascade.

05

Contrast enforcement

Before writing to the DOM, the system checks WCAG contrast ratios for text-on-background pairs. If a ratio falls below 3.5:1, the text color is auto-adjusted — lightened on dark backgrounds, darkened on light ones.

06

Animated transitions

CSS transitions handle smooth color and layout interpolation. Canvas-based components (dot grid, ASCII marquee) use a MutationObserver to detect style changes and cache new values for the next animation frame.

Style Schema

26 tokens across 6 categories.

Each token is typed (color, length, number, enum), has a default and dark variant, and maps to a CSS custom property. The schema is the single source of truth — shared between the client StyleProvider and the server API route.

Colors6

pageBg, textColor, accent, accentText, dotColor, headerBg

Typography5

fontFamily, fontSize, fontWeight, lineHeight, letterSpacing

Layout6

gridCols, gridGap, pagePadding, contentMaxW, layoutMode, tileMinH

Cards6

cardBg, cardBorderColor, cardBorderWidth, cardShadow, cardBlur, radius

Dots4

dotSize, dotSpacing, dotOpacity, dotColor

Effects3

headerBlur, cardShadow (6 levels), layoutMode (grid/flat/stack)

Design Decisions

Why it works this way.

Why CSS variables instead of React state?

CSS vars update the paint layer without triggering React reconciliation. A single document.documentElement.style.setProperty() call repaints every component that reads that var — zero re-renders, zero virtual DOM diffing. This is what makes transitions feel instant even with 26 tokens changing at once.

Why an agentic loop instead of a single completion?

The model sometimes needs to reason about the current state before deciding on changes. The loop (up to 5 iterations) lets it call update_style, see the result, then refine — like a designer iterating. In practice, most requests resolve in 1–2 iterations.

Why MutationObserver for canvas components?

Canvas elements can't read CSS variables reactively — there's no CSS cascade inside a 2D context. The MutationObserver watches document.documentElement for style/class attribute changes, caches the computed values in refs, and the next requestAnimationFrame picks them up. This avoids calling getComputedStyle 60x/sec.

Why enforce contrast at the provider level?

The AI doesn't always produce accessible color combinations. Rather than constraining the model's creativity, the system lets it generate freely and then enforces WCAG AA contrast (3.5:1) as a post-processing step — adjusting text colors if needed before they hit the DOM.

Stack

Built with.

Next.js 15App framework
OpenAI APIGPT-4o-mini + tool use
Framer MotionAnimations & layout
Tailwind CSSUtility styling
CSS VariablesRuntime theming bridge
Server-Sent EventsStreaming responses