Turn any image into a UI theme — entirely in your browser.
Drop an image, get a polished palette with WCAG contrast checks, preview a generated theme on a live dashboard, and copy ready-to-paste CSS variables. No uploads. No backend. No tracking.
:root { --color-primary: ... } ready to paste.localStorage, with one-click apply and delete.aria-live status, respects prefers-reduced-motion.npm install
npm run dev
Open http://localhost:5173 and drop in any image — a photo, a screenshot, an artwork.
| Command | What it does |
|---|---|
npm run dev |
Start the Vite dev server with hot reload |
npm run check |
Type-check the project with svelte-check |
npm run build |
Produce a production build |
npm run preview |
Serve the production build locally to verify |
src/lib/color/extractPalette.ts)count × saturation_boost × lightness_penalty — popular but characterful colors win; muddy near-black / near-white buckets are softened.Everything runs synchronously off the main thread in a few ms — small image, small math.
src/lib/color/theme.ts)src/lib/color/contrast.ts)WCAG-style relative luminance and contrast-ratio math, used both to pick text colors and to render the per-swatch ratio badges.
$state, $derived, $props)color-mix() for live themingNo runtime dependencies beyond the SvelteKit toolchain.
src/
├── app.css Global tokens, body gradient, reduced-motion
├── app.html SvelteKit shell + meta
├── lib/
│ ├── color/
│ │ ├── contrast.ts WCAG luminance, contrast, HSL <-> RGB helpers
│ │ ├── extractPalette.ts Canvas-based palette extraction
│ │ └── theme.ts Palette -> theme tokens
│ ├── components/
│ │ ├── ColorCard.svelte One swatch (click to copy)
│ │ ├── CopyButton.svelte Reusable copy-to-clipboard
│ │ ├── CssVariablesPanel.svelte CSS export with macOS window chrome
│ │ ├── ImageDropzone.svelte Drop / pick / replace image
│ │ ├── ModeToggle.svelte Preview light/dark toggle
│ │ ├── PaletteGrid.svelte Responsive grid of ColorCards
│ │ ├── SavedPalettes.svelte Local history with apply/delete
│ │ └── ThemePreview.svelte Live dashboard mockup
│ └── types.ts Shared types (ThemeTokens, SavedPalette, ...)
└── routes/
├── +layout.svelte
└── +page.svelte The whole app — composed of the components above
This is a pure client-side app — every route is static, no server code. Two easy targets:
@sveltejs/adapter-auto will swap in @sveltejs/adapter-vercel automatically. No configuration needed.@sveltejs/adapter-static in svelte.config.js for a fully static export..ase / Tailwind config / SCSS variables.MIT — do whatever, just don't sue.