Files
jules 286e2daf95 feat: initial commit — crema-app-aifirst-template
Hybrid traditional + AI-first webapp scaffold. Sibling to crema-app-template,
adds the AI assistant surface, command bus, scripts dialog, and virtual
cursor.

What's pre-wired:
- 6 routes: Overview, Resources, Activity, Assistant, Library, Settings
- Collapsible rail + appbar + avatar dropdown shell (template code, not a lib)
- Mobile sheet at <md
- /assistant: streaming chat via @crema/llm-ui, mock fallback, model selector,
  token meter, retry probe, stop-while-streaming, persistent UI Control toggle
- /settings: editable LM Studio endpoint + context window + response cap, with
  test-connection button
- Markdown rendering for assistant replies; ```action``` blocks rendered as a
  small "Ran N actions" pill
- ⌘⇧P script runner dialog + Play icon in the appbar
- Two demo scripts in public/scripts/
- mightypix theme as default, scoped via <AppShell theme="mightypix">

Libs wired in tsconfig + app.css:
- @crema/action-bus (the bus, parser, runner, cursor, provider, ws, llm-bridge)
- @crema/llm-ui, @crema/chat-ui, @crema/aifirst-ui, @crema/notification-ui
- lib-theme-mightypix

Docs:
- README.md — pitch + quick start + structure
- docs/AI_FIRST.md — full system tour (data-action contract, bus, DSL, scripts,
  cursor, LLM integration)
- app/components/layout/THEME_CONTRACT.md — every CSS variable a theme must declare
- CLAUDE.md — orientation for an LLM working in the repo

Genericized from comfy-cloud (the original prototype):
- Brand defaults to "App" / Sparkles icon (override via app/lib/identity.ts)
- User defaults to a stub (swap useUser() for real auth)
- localStorage namespace is "crema.*" (was "comfy.*")

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 18:31:46 +10:00

4.9 KiB

Theme contract

Every Crema theme (lib-theme-*) must declare these CSS variables so the shell, AI surfaces, and shadcn primitives render correctly. Missing a variable won't crash anything — it'll just look wrong (transparent backgrounds, missing borders, broken focus rings, etc.).

A theme is a single CSS file that declares variables under :root for light mode and under .dark for dark mode. Themes may also @import url(...) font packages at the top of the file — they ship self-contained.

The shell expects the theme to be the first import in the consuming app's entry CSS, so any embedded font URLs land at the top of the resolved output (CSS spec requires @import before any other rules).

Required tokens

Surfaces

Token Used for
--background Page background
--foreground Default text color
--card Card surfaces, inputs, dropdowns
--card-foreground Text on cards
--popover Popover/menu surfaces
--popover-foreground Text on popovers
--muted Subtle backgrounds (hover states, toolbars, code blocks)
--muted-foreground Subtle text (timestamps, hints, labels)
--accent Hover/focus highlight on items
--accent-foreground Text on accent backgrounds

Brand & status

Token Used for
--primary Brand color, primary buttons, active nav, ripple
--primary-foreground Text on primary surfaces
--secondary Secondary buttons
--secondary-foreground Text on secondary
--destructive Errors, sign-out, destructive menu items
--success Confirmations
--success-foreground Text on success surfaces

Borders, inputs, focus

Token Used for
--border Dividers, default borders
--input Input field borders
--ring Focus rings

Sidebar (rail)

Token Used for
--sidebar Rail background
--sidebar-foreground Rail text
--sidebar-primary Active nav background
--sidebar-primary-foreground Active nav text
--sidebar-accent Rail hover
--sidebar-accent-foreground Text on rail hover
--sidebar-border Rail borders
--sidebar-ring Rail focus ring
Token Used for
--chart-1--chart-5 Chart series colors; --chart-3 doubles as warning amber
--syntax-keyword, --syntax-string, --syntax-number, --syntax-comment, --syntax-function, --syntax-type Code-block highlighting

Typography

Token Used for
--font-heading Heading font stack
--font-sans Default UI font stack
--font-ai-prose Assistant prose (the AI surface uses this for replies)
--font-mono Code, tabular numbers

Type scale

Each pair declares a size and matching line height:

  • --text-display-size / --text-display-lh
  • --text-headline-size / --text-headline-lh
  • --text-title-size / --text-title-lh
  • --text-body-size / --text-body-lh
  • --text-label-size / --text-label-lh
  • --text-caption-size / --text-caption-lh

Motion

Token Used for
--duration-fast, --duration-base, --duration-slow, --duration-slower, --duration-spring Animation lengths
--ease-standard, --ease-emphasized, --ease-decelerate, --ease-accelerate Standard easing curves
--ease-spring-gentle, --ease-spring-snappy, --ease-spring-bouncy Spring curves

Radii & elevation

Token Used for
--radius Base radius (sm/md/lg/xl/2xl computed from this in app.css)
--elevation-0--elevation-5 Shadow scale
--border-width-thin, --border-width-base, --border-width-thick, --border-width-heavy Stroke widths

Scoping conventions

  • :root { … } — theme defaults (light mode).
  • .dark { … } — dark-mode overrides.
  • [data-theme="<name>"] { … } — alternate-scoped theme. Only needed if a theme should coexist with another on the same page (e.g. an AI surface uses a different theme than the rest of the app). Single-theme apps don't need this scope.

Adding a new theme

  1. Clone any existing theme as a starting point — lib-theme-mightypix is a good reference because it's complete.
  2. Edit tokens (and font @import url if changing fonts).
  3. Update the consuming app's app.css:
    @import "../../lib-theme-<your-name>/theme.css";   /* CREMA:THEME */
    @import "tailwindcss";
    ...
    
  4. Done. Components automatically pick up the new look — no changes needed in any TSX file.

Multi-theme apps (e.g. mightypix on AI surfaces only)

If a theme defines [data-theme="<name>"] instead of (or in addition to) :root, you can switch surfaces per route via the shell's theme prop:

<AppShell title="Assistant" theme="mightypix"></AppShell>

The shell wraps itself in data-theme={theme} so the alt theme's tokens cascade through that subtree only.