Overview
Tinte is an AI-powered theme editor that generates beautiful, consistent themes for shadcn/ui using semantic color palettes in OKLCH color space. Live-edit your design tokens with real-time preview, intelligent color format preservation, and AI-assisted theme generation.
🏆 Winner of 3rd Place at Vercel × Midudev Hackathon
Tinte provides a floating ball UI that expands into a full theme editor, supporting HEX, RGB, HSL, OKLCH, and LCH color formats with automatic format preservation.
Components
Theme Editor
Live theme editor with AI generation, format preservation, and real-time preview.
tinte editor
Features: AI theme generation, OKLCH/HEX/RGB/HSL/LCH support, live preview, format preservation
import { TinteEditor } from "@elements/tinte";
export default function App() {
return (
<div>
<YourApp />
<TinteEditor />
</div>
);
}Quick Start
1. Install
bunx shadcn@latest add @elements/tinte-editorThis installs:
- TinteEditor - Main floating theme editor component
- ColorInput - Color picker with format switching
- TinteLogo - Tinte logo component
- API Routes - Endpoints for reading/writing globals.css
2. Add to Layout
// app/layout.tsx
import { TinteEditor } from "@elements/tinte";
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
{children}
<TinteEditor />
</body>
</html>
);
}3. Start Editing
Click the floating purple ball in the bottom-right corner to open the theme editor.
Features
🎨 Real-time Color Editing
Edit any shadcn/ui design token with instant visual feedback. Changes apply immediately to your UI.
🌈 Color Format Preservation
Automatically preserves your original color format:
- OKLCH → stays OKLCH
- HEX → stays HEX
- RGB → stays RGB
- HSL → stays HSL
- LCH → stays LCH
🎯 Format Switching
Click the format button next to any color input to cycle through formats:
HEX → RGB → HSL → OKLCH → LCH → HEX
🌓 Light/Dark Mode Toggle
Switch between light and dark mode to edit theme variables for each mode independently.
📦 Organized Token Groups
Tokens are organized into semantic groups:
- Background & Text - Core surface colors
- Cards & Surfaces - Muted and accent colors
- Interactive Elements - Primary and secondary colors
- Forms & States - Input, border, ring, destructive
- Charts - Data visualization colors
- Sidebar - Sidebar-specific tokens
💾 Save to globals.css
Save your changes directly to app/globals.css with one click.
🔄 Reload Theme
Reset to the current values in app/globals.css at any time.
Configuration
Conditional Rendering (Recommended)
Only show the theme editor in development:
// app/layout.tsx
import { TinteEditor } from "@elements/tinte";
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
{children}
{process.env.NODE_ENV === "development" && <TinteEditor />} // [!code
highlight]
</body>
</html>
);
}Color Input Component
Use the ColorInput component standalone:
import ColorInput from "@/components/color-input";
export default function CustomForm() {
const [color, setColor] = useState("oklch(0.7 0.15 180)");
return (
<ColorInput
value={color}
onChange={setColor}
/>
);
}Features:
- Color wheel picker
- Text input with validation
- Format toggle button
- Click-outside to close
Client-Side Architecture
The theme editor works entirely in the browser without requiring server-side API routes:
- Read Theme: Reads CSS variables directly from
document.documentElementusinggetComputedStyle() - Write Theme: Applies theme changes by injecting a
<style>element into the DOM - Live Preview: Changes are instantly visible across both light and dark modes
- No Server Required: Perfect for static sites, v0, and serverless deployments
Token Reference
Background & Text
| Token | Description |
|---|---|
--background | Main background color |
--foreground | Main text color |
--card | Card background |
--card-foreground | Card text |
--popover | Popover background |
--popover-foreground | Popover text |
Cards & Surfaces
| Token | Description |
|---|---|
--muted | Muted background |
--muted-foreground | Muted text |
--accent | Accent background |
--accent-foreground | Accent text |
Interactive Elements
| Token | Description |
|---|---|
--primary | Primary button background |
--primary-foreground | Primary button text |
--secondary | Secondary button background |
--secondary-foreground | Secondary button text |
Forms & States
| Token | Description |
|---|---|
--destructive | Destructive action background |
--destructive-foreground | Destructive action text |
--input | Input border |
--ring | Focus ring |
--border | Border color |
Charts
| Token | Description |
|---|---|
--chart-1 through --chart-5 | Chart data colors |
Sidebar
| Token | Description |
|---|---|
--sidebar-background | Sidebar background |
--sidebar-foreground | Sidebar text |
--sidebar-primary | Sidebar primary background |
--sidebar-primary-foreground | Sidebar primary text |
--sidebar-accent | Sidebar accent background |
--sidebar-accent-foreground | Sidebar accent text |
--sidebar-border | Sidebar border |
--sidebar-ring | Sidebar focus ring |
How It Works
- Read Theme - Reads CSS variables from DOM using
getComputedStyle() - Parse Variables - Extracts all
--*CSS custom properties - Live Updates - Changes apply to
document.documentElement.style - Save - Injects updated theme as
<style>element in DOM
Color Format Details
OKLCH (Recommended)
--primary: oklch(0.7 0.15 270);Benefits: Perceptually uniform, wide gamut, human-readable
HEX
--primary: #6366f1;Benefits: Compact, widely supported, familiar
RGB
--primary: rgb(99, 102, 241);Benefits: Direct browser support, alpha channel
HSL
--primary: hsl(239, 84%, 67%);Benefits: Intuitive (hue, saturation, lightness)
LCH
--primary: lch(55% 75 270);Benefits: Perceptually uniform like OKLCH
Best Practices
- Test Both Modes - Always verify light and dark mode
- Use OKLCH - For consistent color manipulation across modes
- Semantic Tokens - Edit tokens, not component colors directly
- Export Themes - Copy CSS from Raw CSS tab to save themes
- Browser DevTools - Use inspector to verify applied variables
Troubleshooting
Colors not updating: Hard refresh the page (Cmd/Ctrl + Shift + R)
Format not preserved: Ensure color value is valid CSS
Floating ball hidden: Check z-index conflicts (ball uses z-50)
Theme resets on reload: Changes are DOM-only, copy CSS to persist
Production Safe
✅ No Security Concerns: Works entirely in the browser without server access. Safe for production, v0, and static sites.
Keyboard Shortcuts
| Key | Action |
|---|---|
Esc | Close theme editor |
Tab | Navigate between inputs |
Enter | Apply color in input field |
Dependencies
- culori - Color conversion and manipulation
- @uiw/react-color - Color picker wheel component
- @uiw/color-convert - Color format conversions
- lucide-react - Icons (X, RotateCw, Save)
- sonner - Toast notifications