themesmith
Give it any colors, an image or a preset, and it produces a complete light and dark UI theme, with every pairing checked for contrast.
People use the app. Agents use the same engine through its API.
Run it here
The live app needs a wider screen. Open themesmith ↗
API
https://drewkidwell.com/api/themesmith/v1Plain-text responses · add as=json for JSONGET/generateForge a theme from colors, a preset or an existing theme
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
colors | string | optional | Comma list of bare hex values, no #. role:hex places a color in a role (primary, accent, neutral, danger, success, warning, chart). With from, replaces the unlocked colors; locked ones carry over. |
preset | string | optional | Start from a preset, e.g. terracotta. |
from | string | optional | Theme id to tweak. Supply parameters to overwrite their values. |
taste | number 0–1 | optional | How freely the engine may adjust your colors to fit their roles: 0 freely, 1 keeps them as typed. Default 0.5. The summary's adjusted lines say what moved, why, and how to stop it. |
separation | flat | layered | lifted | optional | Contrast between surfaces (i.e. background and cards). |
mono | hex | off | optional | The color whose hue determines a monochromatic gradient scheme. |
lock / unlock | string | optional | Roles or chart-N to freeze or release. |
bench | hex | optional | Take a color off the board and put it on the bench. |
derive | role | optional | Let the engine derive this seat. |
add | string | optional | Append colors instead of replacing them. With from, this changes one thing and keeps the rest; chart:hex fills the chart slots after chart-1. |
as | json | optional | Return structured JSON instead of the text summary. |
Example request
curl -s "https://drewkidwell.com/api/themesmith/v1/generate?colors=primary:1d3557,e63946,a8dadc&taste=0.6"
Example response
theme t_levvog6reokv (riff 0 · taste 0.60 · separation layered) seats primary #294266 yours from #1d3557 accent #996da8 derived neutral #b1d8d9 yours from #a8dadc danger #e63946 yours success #158561 derived warning #cdac00 derived chart #996da8 derived · #af648d derived · #b86655 derived · #a57726 derived · #758a3a derived bench — adjusted primary #1d3557 → #294266 too dark and too muted for primary (…) · taste=1 keeps it as typed adjusted neutral #a8dadc → #b1d8d9 too vivid for neutral (…) · taste=1 keeps it as typed contrast light 20/20 · dark 20/20 spacing ok judge 0.85
GET/riffWalk the palette through small chromatic shifts. Only locked colors stay put
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
theme | string | required | Theme id to riff from. |
hops | integer 1–50 | optional | How many riff steps to take. One is a small change; 3 to 5 is a clearly different option. |
lock / unlock | string | optional | Roles or chart-N to freeze or release. Locks carry forward. |
Example request
curl -s "https://drewkidwell.com/api/themesmith/v1/riff?theme=t_levvog6reokv&lock=primary&hops=1"
Example response
theme t_… (from t_levvog6reokv · riff 1 · taste 0.60 · separation layered) seats primary #294266 yours from #1d3557 locked …
Every unlocked seat moves, including colors you supplied. Derived chart colors are a series stepped from the accent, so they move with it.
GET/backStep back through riffs
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
theme | string | required | Theme id to step back from. |
hops | integer | optional | How many riffs to undo. |
Example request
curl -s "https://drewkidwell.com/api/themesmith/v1/back?theme=t_…&hops=1"
Example response
theme t_levvog6reokv (riff 0 · taste 0.60 · separation layered) …
GET/themeRe-read a theme’s summary
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
theme | string | required | Theme id to read. |
Example request
curl -s "https://drewkidwell.com/api/themesmith/v1/theme?theme=t_levvog6reokv"
Example response
Same summary as /generate.
GET/exportExport as CSS, Tailwind or JSON tokens
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
theme | string | required | Theme id to export. |
format | css | tailwind | json | optional | Output format. |
mode | both | light | dark | optional | Which modes to include. JSON only. |
Example request
curl -s "https://drewkidwell.com/api/themesmith/v1/export?theme=t_levvog6reokv&format=css"
Example response
/* themesmith t_levvog6reokv … */ …
The first line always carries the theme id, so an export in a repo points back to its theme. Variables follow shadcn/ui naming, light in :root and dark in .dark. --accent is a subtle hover tint; the bold accent is --accent-strong. Variables are solved for contrast in each mode, so --primary can differ from your hex. Colors only: radius, spacing, type and hover states are yours.
GET/presetsList the presets
No parameters.
Example request
curl -s "https://drewkidwell.com/api/themesmith/v1/presets"
Example response
coastal-starter …
422ErrorsPlain text that names the parameter and the fix
Example request
curl -s "https://drewkidwell.com/api/themesmith/v1/generate?colors=primry:1d3557"
Example response
unknown role "primry" in colors — roles are primary, accent, neutral, danger, success, warning, chart