SLOPSHOPPER

Doki Theme Picker

/doki-theme-picker: browse 88 Doki themes and the termcn themes in a pane with a preview. Enter or a click applies the theme to Claude Code and Windows…

newpanecommandtoastprompt
v0.2.3MITupdated 2026-10-06shelmecha/doki-themes
A shopper browsing a rack in a slop shop
Preview · a replayed session in a sandbox
claude · ~/work/app · doki-theme-picker
│ ┃ Themes ✕ › fix the failing auth test and add an audit log call │ ┃ Doki Ram · dark │ ┃ ████████████████ ⏺ Read(src/auth.ts) │ ┃ ████████████████ ⎿ Read 6 lines │ ┃ ⏺ Update(src/auth.ts) │ ┃ PS C:\projects> claude ⎿ Added 2 lines, removed 1 line │ ┃ ● Update(src/theme.ts) ⏺ Bash(bun test) │ ┃ - const theme = 'old' ⎿ 3 pass, 1 fail │ ┃ + const theme = 'ram' │ ┃ ✻ Thinking… ● Done. refresh now rejects expired claims and logs an audit event. │ ┃ Tab/↑↓ move · Enter/click apply · Esc │ ┃ close ✻ Worked for 42s · done 4:20 PM │ ┃ │ ┃ DOKI · DARK (64) › /doki-theme-picker │ ┃ ██ Miia ⎿ doki-theme-picker: Theme picker opened: arrows to move, Enter to │ ┃ ██ Mioda Ibuki Dark │ ┃ ██ Misaka Mikoto │ ┃ ██ Monika Dark │ ┃ ██ Nadeshiko │ ┃ ██ Nakano Miku │ ┃ ██ Nakano Nino │ ┃ ██ Nakano Yotsuba │ ┃ ██ Natsuki Dark │ ┃ ██ Ram │ ┃ ██ Raphtalia │ ┃ ██ Rei ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── › ? for shortcuts

Draws

Pane · Themes
Doki Ram · dark ████████████████ ████████████████ PS C:\projects> claude ● Update(src/theme.ts) - const theme = 'old' + const theme = 'ram' ✻ Thinking… Tab/↑↓ move · Enter/click apply · Esc close DOKI · DARK (64) ██ Miia ██ Mioda Ibuki Dark ██ Misaka Mikoto ██ Monika Dark ██ Nadeshiko ██ Nakano Miku ██ Nakano Nino ██ Nakano Yotsuba ██ Natsuki Dark ██ Ram ██ Raphtalia ██ Rei ██ Rem ██ Rias Crimson ██ Rias Onyx ██ Rimuru Tempest ██ Rory Mercury ██ Ryuko Dark
README

doki-themes

A theme picker for Claude Code on Windows. Type /doki-theme-picker to open a pane with 88 Doki themes (dark and light) and 40 termcn themes. Use the arrow keys to see each theme in the preview at the top of the pane. Press Enter, or click a theme, to apply the theme to Claude Code and Windows Terminal.

Requirements

  • Windows 10 or 11.
  • Claude Code 2.1.289 or later. This is the version we tested. The picker is a mod (a plugin with hook modules), and older versions do not load mods.
  • For the terminal colors: Windows Terminal (the Store build, the Preview build or the unpackaged build). If the picker does not find Windows Terminal, it changes only the Claude Code theme.

Install

In Claude Code, type these two commands:

/plugin marketplace add shelmecha/doki-themes
/plugin install doki-theme-picker@doki-themes

Restart Claude Code. Then type /doki-theme-picker.

Use

Type /doki-theme-picker to open the picker.

KeyAction
Up / Down or TabMove through the list and see the preview
EnterApply the theme
Mouse click on a themeApply that theme
EscClose the picker

To apply a theme without the picker, type its name after the command:

/doki-theme-picker rem
/doki-theme-picker termcn dracula

Claude Code's own /theme command also lists each theme that the picker applied one time. If you pick one of these themes with /theme, the picker sets the Windows Terminal scheme and the accent file at your next prompt.

What the picker changes

When you press Enter, the picker writes only these files:

  • %USERPROFILE%\.claude\themes\<theme>.json: the Claude Code theme.
  • %USERPROFILE%\.claude\settings.json: the theme value.
  • The Windows Terminal settings.json: it adds a color scheme and sets it on one profile. The profile is the one of the tab that runs Claude Code. If the picker cannot find that profile, it uses your default profile.
  • %USERPROFILE%\.claude\mods\theme-accent.json: an accent color that other mods can read. The picker writes this file only if the %USERPROFILE%\.claude\mods folder already exists.

Before it changes settings.json or the Windows Terminal settings, it copies the old file to %USERPROFILE%\.claude\backups\. To undo a change, copy the backup back. The picker does not delete old backups. You can delete them when you do not need them.

Update

/plugin marketplace update doki-themes
/plugin update doki-theme-picker@doki-themes

Restart Claude Code after the update.

Uninstall

/plugin uninstall doki-theme-picker@doki-themes

The uninstall does not change your current theme. To go back to a built-in theme, use /config. To remove all the files that the picker wrote:

  1. Delete the doki-*.json and termcn-*.json files in %USERPROFILE%\.claude\themes\.
  2. In Windows Terminal, open Settings > Color schemes and delete the Doki ... and termcn ... schemes.
  3. Delete %USERPROFILE%\.claude\mods\theme-accent.json, if it exists.

Problems

  • The command is not found after the install. Restart Claude Code. The picker registers its command when a session starts.
  • The Claude Code theme does not change after Enter. Restart Claude Code.
  • The Windows Terminal colors do not change. Make sure that Claude Code runs in Windows Terminal. The picker skips Windows Terminal if its settings.json has comments or trailing commas, because it cannot read that file safely.

For developers

  • Test: claude plugin test .
  • Validate the manifests: claude plugin validate --strict .
  • tsconfig.json extends .claude-plugin/types/tsconfig.json. That folder holds the mod types for your editor, and git ignores it. The test and validate commands work without it.
  • node scripts/build-themes.mjs <path to the Doki Theme VS Code extension> writes hooks/themes.ts.
  • node scripts/build-termcn.mjs writes hooks/termcn-themes.ts.
  • Change version in .claude-plugin/plugin.json for each release. If the version does not change, installed copies do not update.

Credits and license

The theme colors come from the Doki Theme and termcn projects. See CREDITS.md. This repo uses the MIT license. See LICENSE.

Source 5 files
hooks/register.tsx 438 lines
1import { atom, read, update } from 'claude-code'
2import type { EngineInterface, Register } from 'claude-code'
3
4import type { DokiTheme } from '../types'
5import {
6  findTheme,
7  ordered,
8  preferenceOf,
9  slugOfPreference,
10  sourceLabel,
11  stamp,
12  swatchCells,
13  toAccent,
14  toClaudeTheme,
15  toWtScheme,
16  updateClaudeSettings,
17  updateWtSettings,
18  windowStart,
19} from './theme'
20
21const PANE = 'doki-theme-picker'
22const COMMAND = 'doki-theme-picker'
23const PREVIEW_ROWS = 11 // title, 2 swatch rows, 5 mock-terminal rows (with padding), hint, 2 spacers
24// Windows Terminal settings under %LOCALAPPDATA%: the Store build, the Preview build, the unpackaged build.
25const WT_SETTINGS = [
26  'Packages/Microsoft.WindowsTerminal_8wekyb3d8bbwe/LocalState/settings.json',
27  'Packages/Microsoft.WindowsTerminalPreview_8wekyb3d8bbwe/LocalState/settings.json',
28  'Microsoft/Windows Terminal/settings.json',
29]
30
31const highlight = atom({ plugin: 'doki-theme-picker', key: 'highlight' } as const, '')
32const current = atom({ plugin: 'doki-theme-picker', key: 'current' } as const, '')
33// The theme whose scheme and accent were last written, for follow() when there is no accent file.
34const followed = atom({ plugin: 'doki-theme-picker', key: 'followed' } as const, '')
35
36const LIST = ordered()
37// The rows the list draws, group headers included: what the window slides over.
38type Row = { kind: 'header'; label: string } | { kind: 'theme'; theme: DokiTheme }
39const ROWS: Row[] = []
40// The header row each row sits under, so the sticky header can name the source.
41const HEADER_OF: number[] = []
42for (const source of ['doki', 'termcn'] as const) {
43  for (const dark of [true, false]) {
44    const group = LIST.filter(t => (t.source ?? 'doki') === source && t.dark === dark)
45    if (group.length === 0) continue
46    const header = ROWS.length
47    ROWS.push({ kind: 'header', label: `${source.toUpperCase()} · ${dark ? 'DARK' : 'LIGHT'} (${group.length})` })
48    HEADER_OF.push(header)
49    for (const theme of group) {
50      ROWS.push({ kind: 'theme', theme })
51      HEADER_OF.push(header)
52    }
53  }
54}
55const FALLBACK = findTheme('ram') ?? LIST[0]!
56
57// The body height the last render saw: the hooks need it to know which rows a window holds.
58let bodyRows = 30
59
60/** The rows the window draws around `slug`, one of them taken for the sticky group header. */
61function windowAround(slug: string, rows: number = bodyRows): { start: number; visible: Row[]; buttons: string[] } {
62  const size = Math.max(6, rows - PREVIEW_ROWS)
63  const rowIndex = ROWS.findIndex(row => row.kind === 'theme' && row.theme.slug === slug)
64  const start = windowStart(rowIndex, ROWS.length, size - 1)
65  const visible = ROWS.slice(start, start + size - 1)
66  const buttons = visible.flatMap(row => (row.kind === 'theme' ? [row.theme.slug] : []))
67  return { start, visible, buttons }
68}
69
70/**
71 * The ring is tracked by SLOT, not by theme. Every button is keyed `slot-<n>`, n the place among the drawn buttons.
72 * The engine keeps the ring on the same slot when the window slides, and when several keys arrive before a redraw
73 * (a burst, a fast typist) it works out each "next button" from the SLOT the ring still holds in the old drawing.
74 * Names from that old drawing are stale then (observed 2026-10-04: 8 Downs sent 8 ui.focus events that all named
75 * the same theme, so the highlight moved 1 row). A slot is the same in every drawing, so the move is
76 * (slot named) - (slot the ring is on): one Down is +1 however many redraws are still pending.
77 */
78const slotKey = (slot: number) => `slot-${slot}`
79const slotOfKey = (element: string | undefined) => {
80  const match = /^slot-(\d+)$/.exec(element ?? '')
81  return match ? Number(match[1]) : -1
82}
83/** The slot `slug` takes among the buttons of the window drawn around it. */
84const slotOfTheme = (slug: string) => windowAround(slug).buttons.indexOf(slug)
85
86// The slot the engine's ring sits on, as this module last set it or was told.
87let ringSlot = -1
88// Moves arrive one at a time: each reads the ring slot and the highlight the one before left.
89let queue: Promise<unknown> = Promise.resolve()
90function inOrder<T>(job: () => Promise<T>): Promise<T> {
91  const run = queue.then(job, job)
92  queue = run.catch(() => undefined)
93  return run
94}
95
96/** Moves the highlight to `slug`; says which slot the ring must take so it sits on that theme in the new window. */
97async function moveHighlight($: EngineInterface, slug: string): Promise<number> {
98  await update($, highlight, () => slug)
99  ringSlot = slotOfTheme(slug)
100  return ringSlot
101}
102
103async function home($: EngineInterface): Promise<string> {
104  return ((await $.env.get('USERPROFILE')) ?? (await $.env.get('HOME')) ?? '').replace(/\\/g, '/')
105}
106
107async function readOr($: EngineInterface, path: string): Promise<string | undefined> {
108  try {
109    if (!(await $.fs.exists(path))) return undefined
110    const text = await $.fs.read(path)
111    return typeof text === 'string' ? text : undefined
112  } catch {
113    return undefined
114  }
115}
116
117/** Copies a user file to ~/.claude/backups/<name>.<stamp> before it is changed. */
118async function backup($: EngineInterface, root: string, path: string, name: string, text: string): Promise<string> {
119  const target = `${root}/.claude/backups/${name}.${stamp(new Date())}`
120  await $.fs.write(target, text)
121  return target
122}
123
124/** The theme preference in the user settings.json, as `custom:doki-ram`; undefined when there is none. */
125async function currentPreference($: EngineInterface): Promise<unknown> {
126  const settings = await readOr($, `${await home($)}/.claude/settings.json`)
127  try {
128    return (JSON.parse(settings ?? '{}') as { theme?: unknown }).theme
129  } catch {
130    return undefined
131  }
132}
133
134async function currentSlug($: EngineInterface): Promise<string> {
135  return slugOfPreference(await currentPreference($))
136}
137
138/** Writes the theme everywhere it shows: Claude Code, Windows Terminal, the shared accent file. */
139async function apply($: EngineInterface, theme: DokiTheme): Promise<string[]> {
140  const root = await home($)
141  const notes: string[] = []
142  const preference = preferenceOf(theme)
143
144  // 1. The Claude Code theme file (hot-reloaded from ~/.claude/themes).
145  const themeFile = `${preference.replace(/^custom:/, '')}.json`
146  const themePath = `${root}/.claude/themes/${themeFile}`
147  const oldTheme = await readOr($, themePath)
148  if (oldTheme !== undefined) await backup($, root, themePath, themeFile, oldTheme)
149  await $.fs.write(themePath, JSON.stringify(toClaudeTheme(theme), null, 2) + '\n')
150  notes.push(`theme file ${themePath}`)
151
152  // 2. Switch Claude Code to it: the /config row first, then make sure settings.json agrees.
153  // The /config row takes only the built-in themes, so a refusal is expected; settings.json does the switch.
154  try {
155    const { deny } = await $.config.set({ key: 'theme', value: preference })
156    if (!deny) notes.push('config.set theme')
157  } catch (error) {
158    notes.push(`config.set failed (${String(error).slice(0, 80)})`)
159  }
160  const settingsPath = `${root}/.claude/settings.json`
161  const settings = await readOr($, settingsPath)
162  try {
163    if (settings === undefined) {
164      // A fresh install can have no user settings.json yet: make one that holds only the theme.
165      await $.fs.write(settingsPath, JSON.stringify({ theme: preference }, null, 2) + '\n')
166      notes.push('settings.json theme')
167    } else if ((JSON.parse(settings) as { theme?: unknown }).theme !== preference) {
168      const next = updateClaudeSettings(settings, preference)
169      await backup($, root, settingsPath, 'settings.json', settings)
170      await $.fs.write(settingsPath, next)
171      notes.push('settings.json theme')
172    }
173  } catch (error) {
174    notes.push(`settings.json skipped (${String(error).slice(0, 80)})`)
175  }
176
177  // 3 and 4. Windows Terminal and the accent file.
178  notes.push(...(await applyOutside($, root, theme)))
179
180  await update($, followed, () => theme.slug)
181  await update($, current, () => theme.slug)
182  $.ui.toast(`Theme: ${sourceLabel(theme)} ${theme.name}`)
183  return notes
184}
185
186/** What Claude Code's own theme setting does not reach: the Windows Terminal scheme and the accent file. */
187async function applyOutside($: EngineInterface, root: string, theme: DokiTheme): Promise<string[]> {
188  const notes: string[] = []
189  // 3. Windows Terminal: the scheme, set on the profile of the tab Claude Code runs in.
190  const local = ((await $.env.get('LOCALAPPDATA')) ?? '').replace(/\\/g, '/')
191  let wtPath = ''
192  let wt: string | undefined
193  for (const candidate of local ? WT_SETTINGS : []) {
194    wt = await readOr($, `${local}/${candidate}`)
195    if (wt !== undefined) {
196      wtPath = `${local}/${candidate}`
197      break
198    }
199  }
200  if (wt !== undefined) {
201    try {
202      const next = updateWtSettings(wt, toWtScheme(theme), await $.env.get('WT_PROFILE_ID'))
203      await backup($, root, wtPath, 'wt-settings.json', wt)
204      await $.fs.write(wtPath, next)
205      notes.push('Windows Terminal scheme')
206    } catch (error) {
207      notes.push(`Windows Terminal skipped (${String(error).slice(0, 80)})`)
208    }
209  } else {
210    notes.push('Windows Terminal not found, skipped')
211  }
212
213  // 4. The accent other mods draw with. Written only when ~/.claude/mods already exists, so a
214  // person without local mods gets no extra folder.
215  try {
216    if (await $.fs.exists(`${root}/.claude/mods`)) {
217      await $.fs.write(`${root}/.claude/mods/theme-accent.json`, JSON.stringify(toAccent(theme), null, 2) + '\n')
218      notes.push('accent file')
219    }
220  } catch (error) {
221    notes.push(`accent file skipped (${String(error).slice(0, 80)})`)
222  }
223  return notes
224}
225
226/**
227 * Claude Code's /theme picked a theme: if it is one of ours, bring the Windows Terminal
228 * scheme and the accent file along, so both commands leave the same result. Does nothing when the
229 * accent file already holds the theme.
230 */
231async function follow($: EngineInterface, preference: unknown): Promise<string[]> {
232  const theme = findTheme(slugOfPreference(preference))
233  if (!theme) return []
234  const root = await home($)
235  if (await $.fs.exists(`${root}/.claude/mods`)) {
236    const accent = await readOr($, `${root}/.claude/mods/theme-accent.json`)
237    if (accent === JSON.stringify(toAccent(theme), null, 2) + '\n') return []
238  } else if ((await read($, followed)) === theme.slug) {
239    // No accent file to compare with: the last theme this session followed stands in for it.
240    return []
241  }
242  const notes = await applyOutside($, root, theme)
243  await update($, followed, () => theme.slug)
244  await update($, current, () => theme.slug)
245  return notes
246}
247
248const openPicker = async ($: EngineInterface) => {
249  const now = (await read($, current)) || (await currentSlug($))
250  await update($, current, () => now)
251  const start = findTheme(now)?.slug ?? FALLBACK.slug
252  await update($, highlight, () => start)
253  ringSlot = slotOfTheme(start)
254  return $.ui.open({ id: PANE, title: 'Themes', focus: true, closeOnEscape: true, columns: 48 })
255}
256
257export const register: Register = on => {
258  on('session.start', async ($, e, next) => {
259    await update($, current, () => '')
260    const atStart = await currentSlug($)
261    await update($, followed, was => was || atStart)
262    await $.command.register({
263      name: COMMAND,
264      description: 'Pick a Doki or termcn theme for Claude Code and Windows Terminal (arrows + Enter)',
265      argumentHint: '[theme name]',
266    })
267    return next(e)
268  })
269
270  on('command.run', { command: COMMAND }, async ($, e) => {
271    const query = e.args.trim()
272    if (query) {
273      const theme = findTheme(query)
274      if (!theme) return { text: `No theme matches "${query}". Run /${COMMAND} to browse.`, exitCode: 1 }
275      const notes = await apply($, theme)
276      return { text: `Theme: ${sourceLabel(theme)} ${theme.name} (${notes.join('; ')})` }
277    }
278    const opened = await openPicker($)
279    return { text: opened.isPlaced ? 'Theme picker opened: arrows to move, Enter to apply.' : 'Theme picker is waiting for room.' }
280  })
281
282  // Claude Code's /theme writes settings.json only and raises no event (seen live 2026-10-06): check at each prompt.
283  // A slash command another plugin answers may not reach this hook; the next typed prompt does.
284  on('prompt.submit', async ($, e, next) => {
285    try {
286      await follow($, await currentPreference($))
287    } catch {
288      // Never block a prompt over a theme.
289    }
290    return next(e)
291  })
292
293  // The person's Tab, arrows or click moved the ring onto a slot: move the highlight by the slots it travelled.
294  on('ui.focus', { requestId: PANE }, async ($, e, next) => {
295    const slot = slotOfKey(e.element)
296    if (slot < 0) return next(e)
297    if (e.origin.kind !== 'person') {
298      // The first drawing's autoFocus, or this module's own redirect: the ring is where it says, unless refused.
299      const result = await next(e)
300      if (!result.deny) ringSlot = slot
301      return result
302    }
303    return inOrder(async () => {
304      const slug = (await read($, highlight)) || FALLBACK.slug
305      const from = ringSlot >= 0 ? ringSlot : slotOfTheme(slug)
306      const index = Math.max(0, LIST.findIndex(t => t.slug === slug))
307      // The engine wraps its ring past either end of the buttons it holds (a Down on the last slot lands on slot 0), and
308      // a burst can outrun a drawing that has fewer buttons than the new window: a jump of nearly a window's height
309      // is that wrap, one press in the other direction. (A click never comes here: it raises only ui.press.)
310      const wrap = Math.max(2, Math.max(6, bodyRows - PREVIEW_ROWS) - 4)
311      const travelled = slot - from <= -wrap ? 1 : slot - from >= wrap ? -1 : slot - from
312      const target = LIST[Math.max(0, Math.min(LIST.length - 1, index + travelled))]!
313      if (target.slug === slug) {
314        // Nothing to move (the end of the list, or the same slot): keep the ring where it was.
315        return next(from === slot ? e : { ...e, element: slotKey(from) })
316      }
317      const was = ringSlot
318      const to = await moveHighlight($, target.slug)
319      const result = await next({ ...e, element: slotKey(to) })
320      if (result.deny) {
321        // The engine's drawing has no such slot yet: the ring stayed. Ask again once the next drawing brings it.
322        ringSlot = was
323        void $.ui.focus({ requestId: PANE, key: slotKey(to) }).catch(() => undefined)
324      }
325      return result
326    })
327  })
328
329  // If the engine reads an arrow as a scroll (the list overflowed), move the highlight instead.
330  on('ui.scroll', { requestId: PANE }, async ($, e, next) => {
331    if (e.origin.kind !== 'person' || e.pointer !== undefined || e.by === 0) return next(e)
332    return inOrder(async () => {
333      const slug = (await read($, highlight)) || FALLBACK.slug
334      const index = Math.max(0, LIST.findIndex(t => t.slug === slug))
335      const target = LIST[Math.max(0, Math.min(LIST.length - 1, index + e.by))]!
336      const was = ringSlot
337      const to = await moveHighlight($, target.slug)
338      // Bring the ring along; a refusal leaves the highlight moved (Enter applies the highlight, not the ring).
339      // The ring then stays on its old slot: track that, so Enter there is not read as a click.
340      void $.ui
341        .focus({ requestId: PANE, key: slotKey(to) })
342        .then(result => {
343          if (result.deny && ringSlot === to) ringSlot = was
344        })
345        .catch(() => undefined)
346      return {}
347    })
348  })
349
350  on('ui.render', { component: 'Pane', requestId: PANE }, async ($, e) => {
351    const { Box, Text, Button } = $.ui.resolve(e)
352    const slug = await read($, highlight)
353    const chosen = await read($, current)
354    const theme = findTheme(slug) ?? FALLBACK
355    const c = theme.colors
356
357    let swatch = null
358    if (e.surface === 'terminal') {
359      const { Raster } = $.ui.resolve(e)
360      const strip = swatchCells(theme, 2)
361      swatch = <Raster key="swatch" columns={strip.columns} rows={strip.rows} cells={strip.cells} />
362    }
363
364    bodyRows = e.props.scroll.bodyRows
365    // One row is kept for a sticky group header, so DARK / LIGHT always shows above the window.
366    const { start, visible } = windowAround(theme.slug, bodyRows)
367    const top = visible[0]
368    const sticky = top && top.kind === 'theme' ? ROWS[HEADER_OF[start]!]! : null
369
370    let slotNumber = -1
371    return (
372      <Box flexDirection="column" paddingX={1}>
373        <Text color={c.accent} bold>
374          {sourceLabel(theme)} {theme.name} · {theme.dark ? 'dark' : 'light'}
375          {theme.slug === chosen ? ' · current' : ''}
376        </Text>
377        {swatch}
378        <Box key="mock" flexDirection="column" backgroundColor={c.bg} paddingX={1} marginTop={1}>
379          <Box flexDirection="row">
380            <Text color={c.fg} backgroundColor={c.bg}>
381              PS C:\projects&gt;{' '}
382            </Text>
383            <Text color={c.accent} backgroundColor={c.bg}>
384              claude
385            </Text>
386          </Box>
387          <Text color={c.accent} backgroundColor={c.bg}>
388            ● Update(src/theme.ts)
389          </Text>
390          <Text color={c.red} backgroundColor={c.bg}>
391            - const theme = 'old'
392          </Text>
393          <Text color={c.green} backgroundColor={c.bg}>
394            + const theme = '{theme.slug}'
395          </Text>
396          <Text color={c.muted} backgroundColor={c.bg}>
397            ✻ Thinking…
398          </Text>
399        </Box>
400        <Text color={c.subtle}>Tab/↑↓ move · Enter/click apply · Esc close</Text>
401        <Text> </Text>
402        {sticky && sticky.kind === 'header' && (
403          <Text color={c.muted} bold>
404            {sticky.label}
405          </Text>
406        )}
407        {visible.map(row => {
408          if (row.kind !== 'header') slotNumber += 1
409          return row.kind === 'header' ? (
410            <Text color={c.muted} bold>
411              {row.label}
412            </Text>
413          ) : (
414            <Box key={`r-${slotKey(slotNumber)}`} flexDirection="row" gap={1}>
415              <Text color={row.theme.colors.accent}>██</Text>
416              <Button
417                key={slotKey(slotNumber)}
418                label={`${row.theme.slug === chosen ? '●' : ' '}  ${row.theme.name}`}
419                plain
420                autoFocus={row.theme.slug === theme.slug ? true : undefined}
421                onPress={async press => {
422                  // Enter presses the slot the ring is on: it applies the theme the header names (the highlight),
423                  // because during a burst the row under the ring can be stale. A click raises only ui.press, for the
424                  // slot clicked, with no ui.focus (observed 2026-10-06): a press off the ring is a click on this row.
425                  const clicked = slotOfKey(press.element) !== ringSlot
426                  const named = clicked ? row.theme : (findTheme(await read($, highlight)) ?? row.theme)
427                  await apply($, named)
428                  await $.ui.close({ id: PANE })
429                }}
430              />
431            </Box>
432          )
433        })}
434      </Box>
435    )
436  })
437}
438
hooks/theme.ts 351 lines
1// Pure conversion: a Doki theme -> Claude Code theme JSON, Windows Terminal scheme, shared accent record.
2import type { Accent, DokiTheme, TermcnRaw } from '../types'
3import { TERMCN_RAW } from './termcn-themes'
4import { THEMES as DOKI_THEMES } from './themes'
5
6export const WT_PROFILE_GUID = '{61c54bbd-c2c6-5271-96e7-009a87ff44bf}'
7
8// Doki "Ram": the default theme, and the fallback when the accent file is missing.
9export const RAM_ACCENT: Accent = {
10  name: 'Ram',
11  dark: true,
12  accent: '#e594bf',
13  accent2: '#a1e9ff',
14  muted: '#ab7b9d',
15  text: '#F8F8F2',
16  subtle: '#666879',
17}
18
19// Tokens that must stay with the daltonized (color-blind-safe) base: never overridden.
20export const PROTECTED_TOKEN = /^(diff|success$|error$)/
21
22type Rgb = [number, number, number]
23
24const parse = (hex: string): Rgb => [1, 3, 5].map(i => parseInt(hex.slice(i, i + 2), 16)) as Rgb
25const format = (rgb: readonly number[]): string =>
26  '#' + rgb.map(v => Math.max(0, Math.min(255, Math.round(v))).toString(16).padStart(2, '0')).join('')
27
28/** Blend `a` toward `b` by `t` (0..1). */
29export function mix(a: string, b: string, t: number): string {
30  const A = parse(a)
31  const B = parse(b)
32  return format(A.map((v, i) => v + ((B[i] ?? v) - v) * t))
33}
34
35/** Shift HSL lightness by `delta` (-1..1), keeping hue and saturation. */
36export function lightness(hex: string, delta: number): string {
37  const [r, g, b] = parse(hex).map(v => v / 255) as Rgb
38  const max = Math.max(r, g, b)
39  const min = Math.min(r, g, b)
40  let h = 0
41  let s = 0
42  let l = (max + min) / 2
43  if (max !== min) {
44    const d = max - min
45    s = l > 0.5 ? d / (2 - max - min) : d / (max + min)
46    h = max === r ? (g - b) / d + (g < b ? 6 : 0) : max === g ? (b - r) / d + 2 : (r - g) / d + 4
47    h /= 6
48  }
49  l = Math.max(0, Math.min(1, l + delta))
50  if (s === 0) return format([l * 255, l * 255, l * 255])
51  const q = l < 0.5 ? l * (1 + s) : l + s - l * s
52  const p = 2 * l - q
53  const channel = (t: number) => {
54    if (t < 0) t += 1
55    if (t > 1) t -= 1
56    if (t < 1 / 6) return p + (q - p) * 6 * t
57    if (t < 1 / 2) return q
58    if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6
59    return p
60  }
61  return format([channel(h + 1 / 3) * 255, channel(h) * 255, channel(h - 1 / 3) * 255])
62}
63
64/** Relative luminance (0..1) of a #rrggbb color. */
65export function luminance(hex: string): number {
66  const [r, g, b] = parse(hex).map(v => {
67    const s = v / 255
68    return s <= 0.03928 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4
69  }) as Rgb
70  return 0.2126 * r + 0.7152 * g + 0.0722 * b
71}
72
73/** WCAG contrast ratio (1..21) between two #rrggbb colors. */
74export function contrast(a: string, b: string): number {
75  const [hi, lo] = [luminance(a), luminance(b)].sort((x, y) => y - x) as [number, number]
76  return (hi + 0.05) / (lo + 0.05)
77}
78
79// The lowest contrast a termcn theme's subtle text gets against its background.
80// Doki themes' own subtle colors have a median of about 3.0.
81export const SUBTLE_CONTRAST = 2.5
82
83/** The first blend of bg toward fg that reaches SUBTLE_CONTRAST: dim, but still readable. */
84function readableSubtle(bg: string, fg: string): string {
85  for (let t = 0.05; t < 1; t += 0.05) {
86    const c = mix(bg, fg, t)
87    if (contrast(bg, c) >= SUBTLE_CONTRAST) return c
88  }
89  return fg
90}
91
92/** A termcn theme as the picker's theme: termcn has no ANSI palette, so the roles stand in for it. */
93export function toTermcnTheme(raw: TermcnRaw): DokiTheme {
94  const k = raw.colors
95  const dark = luminance(k.background) < 0.5
96  return {
97    name: raw.name,
98    slug: `termcn-${raw.slug}`,
99    dark,
100    source: 'termcn',
101    colors: {
102      bg: k.background,
103      fg: k.foreground,
104      accent: k.accent,
105      muted: k.mutedForeground,
106      // termcn `muted` is a background tint, not a text color: as subtle text it was near-invisible.
107      subtle: readableSubtle(k.background, k.foreground),
108      selection: k.selection,
109      widget: lightness(k.background, dark ? 0.04 : -0.04),
110      cursor: k.focusRing,
111      red: k.error,
112      green: k.success,
113      yellow: k.warning,
114      blue: k.info,
115      magenta: k.secondary,
116      cyan: k.info,
117      error: k.error,
118      interface: k.info,
119      purple: k.primary,
120      func: k.primary,
121      constant: k.success,
122      cls: k.warning,
123      bool: k.accent,
124    },
125  }
126}
127
128export const THEMES: readonly DokiTheme[] = [...DOKI_THEMES, ...TERMCN_RAW.map(toTermcnTheme)]
129
130/** The label a theme goes by in names and toasts: "Doki Ram", "termcn Dracula". */
131export const sourceLabel = (theme: DokiTheme): string => (theme.source === 'termcn' ? 'termcn' : 'Doki')
132
133/** The Claude Code theme preference for a theme: custom:doki-ram, custom:termcn-dracula. */
134export const preferenceOf = (theme: DokiTheme): string => (theme.source === 'termcn' ? `custom:${theme.slug}` : `custom:doki-${theme.slug}`)
135
136export type ClaudeTheme = { name: string; base: 'dark-daltonized' | 'light-daltonized'; overrides: Record<string, string> }
137
138/** The same tokens ~/.claude/themes/doki-ram.json sets, sourced from the theme's own colors. */
139export function toClaudeTheme(theme: DokiTheme): ClaudeTheme {
140  const c = theme.colors
141  // Dark themes lift message backgrounds toward light; light themes push them toward dark.
142  const lift = (d: number) => lightness(c.bg, theme.dark ? d : -d)
143  return {
144    name: `${sourceLabel(theme)} ${theme.name}`,
145    base: theme.dark ? 'dark-daltonized' : 'light-daltonized',
146    overrides: {
147      claude: c.accent,
148      text: c.fg,
149      inverseText: c.widget,
150      inactive: c.muted,
151      subtle: c.subtle,
152      suggestion: c.interface,
153      permission: c.purple,
154      remember: c.func,
155      warning: c.yellow,
156      merged: c.purple,
157      promptBorder: c.selection,
158      planMode: c.cyan,
159      autoAccept: c.func,
160      bashBorder: c.yellow,
161      ide: c.constant,
162      fastMode: c.cls,
163      effortUltra: c.bool,
164      userMessageBackground: lift(0.033),
165      userMessageBackgroundHover: lift(0.065),
166      bashMessageBackgroundColor: mix(c.bg, c.yellow, 0.03),
167      memoryBackgroundColor: mix(c.bg, c.purple, 0.065),
168      selectionBg: c.selection,
169      rate_limit_fill: c.accent,
170      rate_limit_empty: lift(0.08),
171      briefLabelYou: c.interface,
172      briefLabelClaude: c.accent,
173    },
174  }
175}
176
177export type WtScheme = Record<string, string>
178
179/**
180 * Windows Terminal color scheme. Doki ships 6 terminal.ansi* colors (red..cyan); the rest
181 * come from the same keys the hand-made "Doki Ram" scheme used.
182 */
183export function toWtScheme(theme: DokiTheme): WtScheme {
184  const c = theme.colors
185  const up = (hex: string) => hex.toUpperCase()
186  return {
187    name: `${sourceLabel(theme)} ${theme.name}`,
188    background: up(c.bg),
189    foreground: up(c.fg),
190    cursorColor: up(c.cursor),
191    selectionBackground: up(c.selection),
192    black: up(theme.dark ? c.widget : c.fg),
193    red: up(c.red),
194    green: up(c.green),
195    yellow: up(c.yellow),
196    blue: up(c.blue),
197    purple: up(c.func),
198    cyan: up(c.cyan),
199    white: up(theme.dark ? c.fg : c.widget),
200    brightBlack: up(c.subtle),
201    brightRed: up(c.error),
202    brightGreen: up(c.constant),
203    brightYellow: up(c.cls),
204    brightBlue: up(c.purple),
205    brightPurple: up(c.bool),
206    brightCyan: up(c.interface),
207    brightWhite: theme.dark ? '#FFFFFF' : up(c.bg),
208  }
209}
210
211export function toAccent(theme: DokiTheme): Accent {
212  const c = theme.colors
213  return { name: theme.name, dark: theme.dark, accent: c.accent, accent2: c.interface, muted: c.muted, text: c.fg, subtle: c.subtle }
214}
215
216/** Reads the accent file's text; anything missing or malformed falls back to Ram. */
217export function parseAccent(text: string | undefined): Accent {
218  try {
219    const raw = JSON.parse(text ?? '') as Partial<Accent>
220    const hex = (v: unknown, fallback: string) => (typeof v === 'string' && /^#[0-9a-fA-F]{6}$/.test(v) ? v : fallback)
221    return {
222      name: typeof raw.name === 'string' ? raw.name : RAM_ACCENT.name,
223      dark: typeof raw.dark === 'boolean' ? raw.dark : RAM_ACCENT.dark,
224      accent: hex(raw.accent, RAM_ACCENT.accent),
225      accent2: hex(raw.accent2, RAM_ACCENT.accent2),
226      muted: hex(raw.muted, RAM_ACCENT.muted),
227      text: hex(raw.text, RAM_ACCENT.text),
228      subtle: hex(raw.subtle, RAM_ACCENT.subtle),
229    }
230  } catch {
231    return RAM_ACCENT
232  }
233}
234
235/** "vanilla", "Doki Mai Dark", "mai dark", "termcn dracula", "custom:termcn-nord", or bare "nord" -> the theme. */
236export function findTheme(query: string, themes: readonly DokiTheme[] = THEMES): DokiTheme | undefined {
237  const key = query
238    .trim()
239    .toLowerCase()
240    .replace(/^custom:/, '')
241    .replace(/^doki[\s-]+/, '')
242    .replace(/[^a-z0-9]+/g, '-')
243    .replace(/^-|-$/g, '')
244  if (!key) return undefined
245  // Doki names win; a bare termcn name ("nord") is tried as "termcn-nord" after them.
246  const termcn = `termcn-${key}`
247  return (
248    themes.find(t => t.slug === key) ??
249    themes.find(t => t.slug === termcn) ??
250    themes.find(t => t.slug.startsWith(key)) ??
251    themes.find(t => t.slug.startsWith(termcn))
252  )
253}
254
255/** The slug in a theme preference ("custom:doki-ram" -> "ram", "custom:termcn-nord" -> "termcn-nord"), or "" for a built-in theme. */
256export function slugOfPreference(preference: unknown): string {
257  if (typeof preference !== 'string') return ''
258  if (preference.startsWith('custom:doki-')) return preference.slice('custom:doki-'.length)
259  return preference.startsWith('custom:termcn-') ? preference.slice('custom:'.length) : ''
260}
261
262/** Doki, then termcn; within each, dark first, then light, each by name: the order the picker lists them in. */
263export function ordered(themes: readonly DokiTheme[] = THEMES): DokiTheme[] {
264  const rank = (t: DokiTheme) => (t.source === 'termcn' ? 1 : 0)
265  return [...themes].sort((a, b) => rank(a) - rank(b) || Number(b.dark) - Number(a.dark) || a.name.localeCompare(b.name))
266}
267
268/** The first index of a `size`-row window over `count` rows that keeps `index` in its middle. */
269export function windowStart(index: number, count: number, size: number): number {
270  if (count <= size) return 0
271  const start = index - Math.floor(size / 2)
272  return Math.max(0, Math.min(count - size, start))
273}
274
275/** Gives freshly serialized `text` the line endings (CRLF or LF) and final newline (or none) of `original`. */
276export function matchStyle(original: string, text: string): string {
277  const eol = original.includes('\r\n') ? '\r\n' : '\n'
278  const body = text.replace(/\r?\n$/, '').replace(/\r?\n/g, eol)
279  return /\r?\n$/.test(original) ? body + eol : body
280}
281
282/**
283 * Adds or replaces `scheme` (by name) and points one profile at it. Returns the new file text.
284 * The profile: `current` (Windows Terminal's WT_PROFILE_ID, the tab Claude Code runs in), else the
285 * default profile (a guid or a name), else Windows PowerShell.
286 */
287export function updateWtSettings(text: string, scheme: WtScheme, current?: string | null): string {
288  const settings = JSON.parse(text) as {
289    defaultProfile?: unknown
290    schemes?: WtScheme[]
291    profiles?: { list?: Array<Record<string, unknown>> }
292  }
293  const list = settings.profiles?.list ?? []
294  const same = (a: unknown, b: unknown) => typeof a === 'string' && typeof b === 'string' && a.toLowerCase() === b.toLowerCase()
295  const profile = [current, settings.defaultProfile, WT_PROFILE_GUID]
296    .map(want => list.find(p => same(p.guid, want) || same(p.name, want)))
297    .find(p => p !== undefined)
298  if (!profile) throw new Error('Windows Terminal profile not found')
299  const schemes = (settings.schemes ?? []).filter(s => s.name !== scheme.name)
300  settings.schemes = [...schemes, scheme]
301  profile.colorScheme = scheme.name
302  return matchStyle(text, JSON.stringify(settings, null, 4))
303}
304
305/**
306 * Sets the top-level "theme" key of Claude Code's settings.json text. Edits that one line in place
307 * when it can (a one-line diff); otherwise re-serializes in the file's own line endings.
308 */
309export function updateClaudeSettings(text: string, preference: string): string {
310  const line = /^( {2}"theme"\s*:\s*)"(?:[^"\\\r\n]|\\.)*"/gm
311  if ((text.match(line) ?? []).length === 1) {
312    const edited = text.replace(line, (_all, head: string) => `${head}${JSON.stringify(preference)}`)
313    try {
314      if ((JSON.parse(edited) as { theme?: unknown }).theme === preference) return edited
315    } catch {
316      // fall through to a full rewrite
317    }
318  }
319  const settings = JSON.parse(text) as Record<string, unknown>
320  settings.theme = preference
321  return matchStyle(text, JSON.stringify(settings, null, 2))
322}
323
324/**
325 * A Raster strip of the theme's colors: row 1 the UI colors, row 2 the terminal colors.
326 * Each swatch is `width` full-block cells in that color.
327 */
328export function swatchCells(theme: DokiTheme, width = 2): { columns: number; rows: number; cells: string } {
329  const c = theme.colors
330  const rows = [
331    [c.bg, c.fg, c.accent, c.muted, c.subtle, c.selection, c.interface, c.purple],
332    [c.red, c.green, c.yellow, c.blue, c.func, c.cyan, c.constant, c.cls],
333  ]
334  const columns = rows[0]!.length * width
335  const words: number[] = []
336  for (const row of rows) {
337    for (const hex of row) {
338      const color = parseInt(hex.slice(1, 7), 16)
339      for (let i = 0; i < width; i++) words.push(0x2588, color, 0x01000000)
340    }
341  }
342  const bytes = new Uint8Array(new Uint32Array(words).buffer)
343  let binary = ''
344  for (const b of bytes) binary += String.fromCharCode(b)
345  return { columns, rows: rows.length, cells: btoa(binary) }
346}
347
348export function stamp(date: Date): string {
349  return date.toISOString().replace(/[:.]/g, '-')
350}
351
hooks/termcn-themes.ts 47 lines
1// Generated by scripts/build-termcn.mjs from the termcn registry (https://termcn.dev/r/registry.json).
2// Source: https://github.com/shadcn-labs/termcn - licence: MIT (Copyright (c) 2026 Aniket Pawar). Do not edit by hand.
3import type { TermcnRaw } from '../types'
4
5export const TERMCN_RAW: readonly TermcnRaw[] = [
6  {"name":"AMOLED","slug":"amoled","colors":{"accent":"#ff4081","background":"#000000","error":"#ff1744","focusRing":"#b388ff","foreground":"#ffffff","info":"#18ffff","muted":"#1a1a1a","mutedForeground":"#888888","primary":"#b388ff","secondary":"#333333","selection":"#b388ff","success":"#00ff88","warning":"#ffea00"}},
7  {"name":"Aura","slug":"aura","colors":{"accent":"#ff6767","background":"#15141b","error":"#ff6767","focusRing":"#a277ff","foreground":"#edecee","info":"#82e2ff","muted":"#242329","mutedForeground":"#6d6a7e","primary":"#a277ff","secondary":"#2a2834","selection":"#a277ff","success":"#61ffca","warning":"#ffca85"}},
8  {"name":"Ayu","slug":"ayu","colors":{"accent":"#f2856f","background":"#0f1419","error":"#f58572","focusRing":"#3fb7e3","foreground":"#d6dae0","info":"#66c6f1","muted":"#1e2229","mutedForeground":"#5a6673","primary":"#3fb7e3","secondary":"#242a33","selection":"#3fb7e3","success":"#78d05c","warning":"#e4a75c"}},
9  {"name":"Carbonfox","slug":"carbonfox","colors":{"accent":"#ff8389","background":"#393939","error":"#ff8389","focusRing":"#be95ff","foreground":"#f2f4f8","info":"#78a9ff","muted":"#2d2d2d","mutedForeground":"#6f6f6f","primary":"#33b1ff","secondary":"#454545","selection":"#33b1ff","success":"#42be65","warning":"#f1c21b"}},
10  {"name":"Catppuccin","slug":"catppuccin","colors":{"accent":"#F38BA8","background":"#1E1E2E","error":"#F38BA8","focusRing":"#CBA6F7","foreground":"#CDD6F4","info":"#89B4FA","muted":"#313244","mutedForeground":"#6C7086","primary":"#CBA6F7","secondary":"#89B4FA","selection":"#313244","success":"#A6E3A1","warning":"#F9E2AF"}},
11  {"name":"Catppuccin Frappe","slug":"catppuccin-frappe","colors":{"accent":"#f4b8e4","background":"#303446","error":"#e78284","focusRing":"#ca9ee6","foreground":"#c6d0f5","info":"#81c8be","muted":"#232330","mutedForeground":"#949cb8","primary":"#8da4e2","secondary":"#414559","selection":"#8da4e2","success":"#a6d189","warning":"#e5c890"}},
12  {"name":"Catppuccin Macchiato","slug":"catppuccin-macchiato","colors":{"accent":"#f5bde6","background":"#24273a","error":"#ed8796","focusRing":"#c6a0f6","foreground":"#cad3f5","info":"#8bd5ca","muted":"#1b1e2b","mutedForeground":"#939ab7","primary":"#8aadf4","secondary":"#363a4f","selection":"#8aadf4","success":"#a6da95","warning":"#eed49f"}},
13  {"name":"Cobalt2","slug":"cobalt2","colors":{"accent":"#2affdf","background":"#193549","error":"#ff0088","focusRing":"#2affdf","foreground":"#ffffff","info":"#ff9d00","muted":"#0d1b2a","mutedForeground":"#adb7c9","primary":"#0088ff","secondary":"#284156","selection":"#0088ff","success":"#9eff80","warning":"#ffc600"}},
14  {"name":"Cursor","slug":"cursor","colors":{"accent":"#88c0d0","background":"#181818","error":"#e34671","focusRing":"#82d2ce","foreground":"#e4e4e4","info":"#81a1c1","muted":"#0d0d0d","mutedForeground":"#636363","primary":"#88c0d0","secondary":"#242424","selection":"#88c0d0","success":"#3fa266","warning":"#f1b467"}},
15  {"name":"Default","slug":"default","colors":{"accent":"#8B5CF6","background":"#000000","error":"#EF4444","focusRing":"#8B5CF6","foreground":"#FFFFFF","info":"#3B82F6","muted":"#374151","mutedForeground":"#9CA3AF","primary":"#7C3AED","secondary":"#6B7280","selection":"#7C3AED","success":"#10B981","warning":"#F59E0B"}},
16  {"name":"Dracula","slug":"dracula","colors":{"accent":"#FF79C6","background":"#282A36","error":"#FF5555","focusRing":"#BD93F9","foreground":"#F8F8F2","info":"#8BE9FD","muted":"#44475A","mutedForeground":"#6272A4","primary":"#BD93F9","secondary":"#6272A4","selection":"#44475A","success":"#50FA7B","warning":"#F1FA8C"}},
17  {"name":"Everforest","slug":"everforest","colors":{"accent":"#d699b6","background":"#2d353b","error":"#e67e80","focusRing":"#d699b6","foreground":"#d3c6aa","info":"#83c092","muted":"#1f252a","mutedForeground":"#7a8478","primary":"#a7c080","secondary":"#373e44","selection":"#a7c080","success":"#a7c080","warning":"#e69875"}},
18  {"name":"Flexoki","slug":"flexoki","colors":{"accent":"#8b7ec8","background":"#100f0f","error":"#d14d41","focusRing":"#879a39","foreground":"#cecdc3","info":"#3aa99f","muted":"#0a0a0a","mutedForeground":"#6f6e69","primary":"#da702c","secondary":"#1a1916","selection":"#da702c","success":"#879a39","warning":"#da702c"}},
19  {"name":"GitHub","slug":"github","colors":{"accent":"#39c5cf","background":"#0d1117","error":"#f85149","focusRing":"#58a6ff","foreground":"#c9d1d9","info":"#d29922","muted":"#161b22","mutedForeground":"#8b949e","primary":"#58a6ff","secondary":"#21262d","selection":"#58a6ff","success":"#3fb950","warning":"#e3b341"}},
20  {"name":"Gruvbox","slug":"gruvbox","colors":{"accent":"#fb4934","background":"#282828","error":"#fb4934","focusRing":"#fb4934","foreground":"#ebdbb2","info":"#d3869b","muted":"#1d2021","mutedForeground":"#928374","primary":"#83a598","secondary":"#32302f","selection":"#83a598","success":"#b8bb26","warning":"#fabd2f"}},
21  {"name":"High Contrast","slug":"high-contrast","colors":{"accent":"#00FFFF","background":"#000000","error":"#FF4444","focusRing":"#FFFF00","foreground":"#FFFFFF","info":"#00CCFF","muted":"#1A1A1A","mutedForeground":"#CCCCCC","primary":"#FFFFFF","secondary":"#FFFF00","selection":"#FFFFFF","success":"#00FF00","warning":"#FFFF00"}},
22  {"name":"High Contrast Light","slug":"high-contrast-light","colors":{"accent":"#004499","background":"#FFFFFF","error":"#CC0000","focusRing":"#0000CC","foreground":"#000000","info":"#004499","muted":"#F0F0F0","mutedForeground":"#444444","primary":"#000000","secondary":"#6600CC","selection":"#000000","success":"#006600","warning":"#884400"}},
23  {"name":"Kanagawa","slug":"kanagawa","colors":{"accent":"#d27e99","background":"#1f1f28","error":"#e82424","focusRing":"#957fbb","foreground":"#dcd7ba","info":"#76946a","muted":"#16161f","mutedForeground":"#727169","primary":"#7e9cd8","secondary":"#292a3f","selection":"#7e9cd8","success":"#98bb6c","warning":"#d7a657"}},
24  {"name":"Lucent Orng","slug":"lucent-orng","colors":{"accent":"#fff7f1","background":"#2a1a15","error":"#e06c75","focusRing":"#ec5b2b","foreground":"#eeeeee","info":"#56b6c2","muted":"#1a100d","mutedForeground":"#808080","primary":"#ec5b2b","secondary":"#3d2521","selection":"#ec5b2b","success":"#6ba1e6","warning":"#ec5b2b"}},
25  {"name":"Material","slug":"material","colors":{"accent":"#89ddff","background":"#263238","error":"#f07178","focusRing":"#c792ea","foreground":"#eeffff","info":"#ffcb6b","muted":"#1a2327","mutedForeground":"#546e7a","primary":"#82aaff","secondary":"#37474f","selection":"#82aaff","success":"#c3e88d","warning":"#ffcb6b"}},
26  {"name":"Matrix","slug":"matrix","colors":{"accent":"#c770ff","background":"#0a0e0a","error":"#ff4b4b","focusRing":"#c770ff","foreground":"#62ff94","info":"#30b3ff","muted":"#050805","mutedForeground":"#8ca391","primary":"#2eff6a","secondary":"#0f140f","selection":"#2eff6a","success":"#62ff94","warning":"#e6ff57"}},
27  {"name":"Mercury","slug":"mercury","colors":{"accent":"#8da4f5","background":"#171721","error":"#fc92b4","focusRing":"#8da4f5","foreground":"#dddde5","info":"#77becf","muted":"#101018","mutedForeground":"#9d9da8","primary":"#8da4f5","secondary":"#1e1e28","selection":"#8da4f5","success":"#77c599","warning":"#fc9b6f"}},
28  {"name":"Monokai","slug":"monokai","colors":{"accent":"#FD971F","background":"#272822","error":"#F92672","focusRing":"#A6E22E","foreground":"#F8F8F2","info":"#66D9E8","muted":"#3E3D32","mutedForeground":"#75715E","primary":"#A6E22E","secondary":"#66D9E8","selection":"#49483E","success":"#A6E22E","warning":"#E6DB74"}},
29  {"name":"Night Owl","slug":"night-owl","colors":{"accent":"#f78c6c","background":"#011627","error":"#ef5350","focusRing":"#c792ea","foreground":"#d6deeb","info":"#82aaff","muted":"#010c15","mutedForeground":"#637777","primary":"#82aaff","secondary":"#021a2b","selection":"#82aaff","success":"#c5e478","warning":"#ecc48d"}},
30  {"name":"Nord","slug":"nord","colors":{"accent":"#81A1C1","background":"#2E3440","error":"#BF616A","focusRing":"#88C0D0","foreground":"#ECEFF4","info":"#5E81AC","muted":"#3B4252","mutedForeground":"#4C566A","primary":"#88C0D0","secondary":"#4C566A","selection":"#3B4252","success":"#A3BE8C","warning":"#EBCB8B"}},
31  {"name":"OC-2","slug":"oc-2","colors":{"accent":"#edb2f1","background":"#1f1f1f","error":"#fc533a","focusRing":"#edb2f1","foreground":"#f1ece8","info":"#edb2f1","muted":"#141414","mutedForeground":"#707070","primary":"#fab283","secondary":"#262626","selection":"#fab283","success":"#12c905","warning":"#fcd53a"}},
32  {"name":"One Dark","slug":"one-dark","colors":{"accent":"#C678DD","background":"#282C34","error":"#E06C75","focusRing":"#61AFEF","foreground":"#ABB2BF","info":"#56B6C2","muted":"#3E4451","mutedForeground":"#5C6370","primary":"#61AFEF","secondary":"#C678DD","selection":"#3E4451","success":"#98C379","warning":"#E5C07B"}},
33  {"name":"One Dark Pro","slug":"one-dark-pro","colors":{"accent":"#e06c75","background":"#1e222a","error":"#e06c75","focusRing":"#c678dd","foreground":"#abb2bf","info":"#56b6c2","muted":"#15181f","mutedForeground":"#5c6370","primary":"#61afef","secondary":"#2c313a","selection":"#61afef","success":"#98c379","warning":"#e5c07b"}},
34  {"name":"OpenCode","slug":"opencode","colors":{"accent":"#9d7cd8","background":"#0a0a0a","error":"#e06c75","focusRing":"#9d7cd8","foreground":"#eeeeee","info":"#56b6c2","muted":"#050505","mutedForeground":"#808080","primary":"#fab283","secondary":"#151515","selection":"#fab283","success":"#7fd88f","warning":"#f5a742"}},
35  {"name":"Orng","slug":"orng","colors":{"accent":"#fff7f1","background":"#0a0a0a","error":"#e06c75","focusRing":"#ec5b2b","foreground":"#eeeeee","info":"#56b6c2","muted":"#050505","mutedForeground":"#808080","primary":"#ec5b2b","secondary":"#151515","selection":"#ec5b2b","success":"#6ba1e6","warning":"#ec5b2b"}},
36  {"name":"Osaka Jade","slug":"osaka-jade","colors":{"accent":"#549e6a","background":"#111c18","error":"#ff5345","focusRing":"#2dd5b7","foreground":"#c1c497","info":"#2dd5b7","muted":"#0a110f","mutedForeground":"#53685b","primary":"#2dd5b7","secondary":"#1a2921","selection":"#2dd5b7","success":"#549e6a","warning":"#e5c736"}},
37  {"name":"Palenight","slug":"palenight","colors":{"accent":"#89ddff","background":"#292d3e","error":"#f07178","focusRing":"#c792ea","foreground":"#a6accd","info":"#f78c6c","muted":"#1e2130","mutedForeground":"#676e95","primary":"#82aaff","secondary":"#383d4f","selection":"#82aaff","success":"#c3e88d","warning":"#ffcb6b"}},
38  {"name":"Rose Pine","slug":"rose-pine","colors":{"accent":"#ebbcba","background":"#191724","error":"#eb6f92","focusRing":"#31748f","foreground":"#e0def4","info":"#9ccfd8","muted":"#100f18","mutedForeground":"#6e6a86","primary":"#9ccfd8","secondary":"#262330","selection":"#9ccfd8","success":"#31748f","warning":"#f6c177"}},
39  {"name":"Shades of Purple","slug":"shades-of-purple","colors":{"accent":"#FF628C","background":"#2D2B55","error":"#EC3A37","focusRing":"#4D21FC","foreground":"#A599E9","info":"#9EFFFF","muted":"#1E1E3F","mutedForeground":"#B362FF","primary":"#FB94FF","secondary":"#1E1E3F","selection":"#4D21FC","success":"#3AD900","warning":"#FF9D00"}},
40  {"name":"Solarized","slug":"solarized","colors":{"accent":"#CB4B16","background":"#002B36","error":"#DC322F","focusRing":"#268BD2","foreground":"#839496","info":"#2AA198","muted":"#073642","mutedForeground":"#586E75","primary":"#268BD2","secondary":"#2AA198","selection":"#073642","success":"#859900","warning":"#B58900"}},
41  {"name":"Synthwave '84","slug":"synthwave-84","colors":{"accent":"#b084eb","background":"#262335","error":"#fe4450","focusRing":"#ff7edb","foreground":"#ffffff","info":"#ff8b39","muted":"#1a1a24","mutedForeground":"#848bbd","primary":"#36f9f6","secondary":"#35334a","selection":"#36f9f6","success":"#72f1b8","warning":"#fede5d"}},
42  {"name":"Tokyo Night","slug":"tokyo-night","colors":{"accent":"#BB9AF7","background":"#24283B","error":"#F7768E","focusRing":"#7AA2F7","foreground":"#C0CAF5","info":"#7DCFFF","muted":"#1F2335","mutedForeground":"#565F89","primary":"#7AA2F7","secondary":"#BB9AF7","selection":"#364A82","success":"#9ECE6A","warning":"#E0AF68"}},
43  {"name":"Vercel","slug":"vercel","colors":{"accent":"#8e4ec6","background":"#000000","error":"#e5484d","focusRing":"#f75590","foreground":"#ededed","info":"#52a8ff","muted":"#0a0a0a","mutedForeground":"#878787","primary":"#0070f3","secondary":"#1a1a1a","selection":"#0070f3","success":"#46a758","warning":"#ffb224"}},
44  {"name":"Vesper","slug":"vesper","colors":{"accent":"#ff8080","background":"#101010","error":"#ff8080","focusRing":"#a0a0a0","foreground":"#ffffff","info":"#ffc799","muted":"#080808","mutedForeground":"#8b8b8b","primary":"#ffc799","secondary":"#181818","selection":"#ffc799","success":"#99ffe4","warning":"#ffc799"}},
45  {"name":"Zenburn","slug":"zenburn","colors":{"accent":"#93e0e3","background":"#3f3f3f","error":"#cc9393","focusRing":"#f0dfaf","foreground":"#dcdccc","info":"#dfaf8f","muted":"#2f2f2f","mutedForeground":"#9f9f9f","primary":"#8cd0d3","secondary":"#4f4f4f","selection":"#8cd0d3","success":"#7f9f7f","warning":"#f0dfaf"}},
46]
47
hooks/themes.ts 94 lines
1// Generated by scripts/build-themes.mjs from unthrottled.doki-theme-88.1.18. Do not edit by hand.
2import type { DokiTheme } from '../types'
3
4export const THEMES: readonly DokiTheme[] = [
5  {"name":"Aqua","slug":"aqua","dark":true,"colors":{"bg":"#262940","fg":"#F8F8F2","accent":"#578CDA","muted":"#7b8bab","subtle":"#61647b","selection":"#4C637A","widget":"#2a2d44","cursor":"#578CDA","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#f4fa8c","purple":"#6893f3","func":"#578CDA","constant":"#48ffd6","cls":"#8dc6ef","bool":"#988F9A"}},
6  {"name":"Astolfo","slug":"astolfo","dark":true,"colors":{"bg":"#1a1c19","fg":"#F8F8F2","accent":"#d58d9c","muted":"#957a4d","subtle":"#8e856e","selection":"#501C1C","widget":"#181917","cursor":"#d58d9c","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#ff2525","interface":"#cd5257","purple":"#f6ebb7","func":"#efa554","constant":"#a7a0d1","cls":"#f5c9fc","bool":"#d776ae"}},
7  {"name":"Asuna Dark","slug":"asuna-dark","dark":true,"colors":{"bg":"#1b1b1b","fg":"#F8F8F2","accent":"#99202c","muted":"#7a3f41","subtle":"#5d5051","selection":"#531616","widget":"#1e1e1e","cursor":"#99202c","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#FFD86E","purple":"#FCA57E","func":"#579DFA","constant":"#86dbfd","cls":"#7ECAFA","bool":"#e0474b"}},
8  {"name":"Azuki","slug":"azuki","dark":true,"colors":{"bg":"#2e221f","fg":"#F8F8F2","accent":"#e9b14e","muted":"#b0a17f","subtle":"#6c635a","selection":"#684e29","widget":"#2d221f","cursor":"#e9b14e","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#e0f6bf","purple":"#96f3fd","func":"#ffe845","constant":"#efacfc","cls":"#c4ff8d","bool":"#ffad46"}},
9  {"name":"Chocola","slug":"chocola","dark":true,"colors":{"bg":"#2c2729","fg":"#F8F8F2","accent":"#f771a3","muted":"#b0a17f","subtle":"#6c5a63","selection":"#6a3849","widget":"#2c2428","cursor":"#f771a3","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#ff2525","interface":"#F6E9CB","purple":"#48eae4","func":"#f689f6","constant":"#96b7fb","cls":"#f8835f","bool":"#FF357C"}},
10  {"name":"Christmas Chocola","slug":"christmas-chocola","dark":true,"colors":{"bg":"#3a141d","fg":"#F8F8F2","accent":"#FFFFFE","muted":"#56b36f","subtle":"#6d816c","selection":"#1f422d","widget":"#37131b","cursor":"#FFFFFE","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#ff1212","interface":"#ffe3cd","purple":"#ebc190","func":"#f16e7f","constant":"#96b7fb","cls":"#e3ecf8","bool":"#f06b7e"}},
11  {"name":"Cinnamon","slug":"cinnamon","dark":true,"colors":{"bg":"#343277","fg":"#F8F8F2","accent":"#54e255","muted":"#dfe19f","subtle":"#ffffff","selection":"#3a6c75","widget":"#37357f","cursor":"#54e255","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#b3a9ff","purple":"#FFD448","func":"#60ff62","constant":"#8bc1f8","cls":"#d0a2fa","bool":"#53dac7"}},
12  {"name":"Coconut","slug":"coconut","dark":true,"colors":{"bg":"#312b3a","fg":"#F8F8F2","accent":"#d2b503","muted":"#b0a17f","subtle":"#605a6c","selection":"#255b82","widget":"#312c3a","cursor":"#d2b503","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#F6E9CB","purple":"#48eae4","func":"#9bf8ff","constant":"#50b5d1","cls":"#f689f6","bool":"#b897f6"}},
13  {"name":"Darkness Dark","slug":"darkness-dark","dark":true,"colors":{"bg":"#0a0904","fg":"#F8F8F2","accent":"#e99745","muted":"#7c7262","subtle":"#666879","selection":"#553919","widget":"#090802","cursor":"#e99745","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#4593f5","purple":"#3492b1","func":"#f4fa8c","constant":"#86dbfd","cls":"#d53a4a","bool":"#ffba2f"}},
14  {"name":"Echidna","slug":"echidna","dark":true,"colors":{"bg":"#121014","fg":"#F8F8F2","accent":"#ECECEC","muted":"#75aaab","subtle":"#6f7779","selection":"#274540","widget":"#171519","cursor":"#ECECEC","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#f4fa8c","purple":"#BD93F9","func":"#7ceec8","constant":"#86dbfd","cls":"#EFA554","bool":"#8b8b8b"}},
15  {"name":"Emilia Dark","slug":"emilia-dark","dark":true,"colors":{"bg":"#492d5a","fg":"#F8F8F2","accent":"#a53ba0","muted":"#a775ab","subtle":"#666879","selection":"#5C3378","widget":"#4c2e5c","cursor":"#a53ba0","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#FDEFA2","purple":"#C1A2F8","func":"#AE7BFF","constant":"#FFB9A7","cls":"#FF9CD6","bool":"#EF69C3"}},
16  {"name":"Essex","slug":"essex","dark":true,"colors":{"bg":"#001d39","fg":"#F8F8F2","accent":"#D53232","muted":"#ad9e6e","subtle":"#5d7685","selection":"#480F0F","widget":"#00203e","cursor":"#D53232","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#ff0505","interface":"#f3b085","purple":"#eec45e","func":"#2D96EA","constant":"#78DBEF","cls":"#B5AAEE","bool":"#EE4C4C"}},
17  {"name":"Gasai Yuno","slug":"gasai-yuno","dark":true,"colors":{"bg":"#150713","fg":"#F8F8F2","accent":"#ffa0b2","muted":"#ab5555","subtle":"#796675","selection":"#602b50","widget":"#1a0717","cursor":"#ffa0b2","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#F6E3CC","purple":"#39e6a6","func":"#efa2da","constant":"#34a7d1","cls":"#EFA554","bool":"#e0474b"}},
18  {"name":"Genos","slug":"genos","dark":true,"colors":{"bg":"#313234","fg":"#F8F8F2","accent":"#ddc7a1","muted":"#ad9e6e","subtle":"#80755d","selection":"#605d51","widget":"#252627","cursor":"#ddc7a1","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#ff2525","interface":"#FF984B","purple":"#FFE35C","func":"#8dff4b","constant":"#EA7777","cls":"#B39CFF","bool":"#8ACAFF"}},
19  {"name":"Gray","slug":"gray","dark":true,"colors":{"bg":"#35393b","fg":"#F8F8F2","accent":"#4ed4b0","muted":"#b0a17f","subtle":"#556c6a","selection":"#295043","widget":"#363b3d","cursor":"#4ed4b0","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#F6E9CB","purple":"#61ead9","func":"#84D0FF","constant":"#ec9cb2","cls":"#89acf6","bool":"#9f73ea"}},
20  {"name":"Hanekawa Tsubasa","slug":"hanekawa-tsubasa","dark":true,"colors":{"bg":"#100d11","fg":"#F8F8F2","accent":"#7660A4","muted":"#988ccb","subtle":"#777495","selection":"#5a3b5d","widget":"#0f0d10","cursor":"#7660A4","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#F6E3CC","purple":"#7ceec8","func":"#9a97f4","constant":"#86dbfd","cls":"#e39656","bool":"#d55fde"}},
21  {"name":"Hatsune Miku","slug":"hatsune-miku","dark":true,"colors":{"bg":"#2f3635","fg":"#F8F8F2","accent":"#53b0b4","muted":"#73999b","subtle":"#666879","selection":"#4c7a76","widget":"#2c3333","cursor":"#53b0b4","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#B5F6BA","purple":"#95C8FA","func":"#FF9CEA","constant":"#86dbfd","cls":"#F6E9CB","bool":"#7BF8E1"}},
22  {"name":"Hayase Nagatoro","slug":"hayase-nagatoro","dark":true,"colors":{"bg":"#151515","fg":"#F8F8F2","accent":"#d2824e","muted":"#7e5b37","subtle":"#5d5550","selection":"#5d3e2f","widget":"#1a1a1a","cursor":"#d2824e","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#ff2525","interface":"#95acbd","purple":"#5cd7d7","func":"#E3A70E","constant":"#d776ae","cls":"#D233A2","bool":"#6d7fd4"}},
23  {"name":"Hinata Shoyo","slug":"hinata-shoyo","dark":true,"colors":{"bg":"#201c37","fg":"#F8F8F2","accent":"#f58d02","muted":"#ba804b","subtle":"#55596c","selection":"#6a473d","widget":"#24203c","cursor":"#f58d02","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#FFC32F","purple":"#84D0FF","func":"#49FF51","constant":"#ec9cb2","cls":"#61ead9","bool":"#ab77ff"}},
24  {"name":"Hiro","slug":"hiro","dark":true,"colors":{"bg":"#16171A","fg":"#F8F8F2","accent":"#3877d1","muted":"#8ad0bf","subtle":"#4F5D76","selection":"#1d4a88","widget":"#16171a","cursor":"#3877d1","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#ff0000","interface":"#FDB8EB","purple":"#89CCEC","func":"#61ead9","constant":"#83F57F","cls":"#EA517A","bool":"#6a96e9"}},
25  {"name":"Hiro x Zero Two","slug":"hiro-x-zero-two","dark":true,"colors":{"bg":"#150b24","fg":"#F8F8F2","accent":"#c93939","muted":"#5d89c2","subtle":"#5F4E65","selection":"#29466c","widget":"#0f071a","cursor":"#c93939","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#ff2525","interface":"#7EACF8","purple":"#FF96FD","func":"#b68cfd","constant":"#9CA2FF","cls":"#5FFF9F","bool":"#ec377e"}},
26  {"name":"Ishtar Dark","slug":"ishtar-dark","dark":true,"colors":{"bg":"#110F10","fg":"#F8F8F2","accent":"#f5c443","muted":"#866e45","subtle":"#6c6d5b","selection":"#553919","widget":"#0d0b0c","cursor":"#f5c443","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#a18649","purple":"#357fbf","func":"#f5c443","constant":"#86dbfd","cls":"#7C7C82","bool":"#db974d"}},
27  {"name":"Jabami Yumeko","slug":"jabami-yumeko","dark":true,"colors":{"bg":"#050000","fg":"#F8F8F2","accent":"#8a1820","muted":"#7e2a2a","subtle":"#97706f","selection":"#390c10","widget":"#0b0000","cursor":"#8a1820","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#F6E3CC","purple":"#42E66C","func":"#b48fec","constant":"#e4ff10","cls":"#7092ea","bool":"#e0474b"}},
28  {"name":"Jahy","slug":"jahy","dark":true,"colors":{"bg":"#1b102e","fg":"#F8F8F2","accent":"#874488","muted":"#ad9e6e","subtle":"#656079","selection":"#452346","widget":"#1e1430","cursor":"#874488","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#ff2525","interface":"#f3b085","purple":"#eec45e","func":"#9581EC","constant":"#EA7797","cls":"#E77FD5","bool":"#D53232"}},
29  {"name":"Kanna","slug":"kanna","dark":true,"colors":{"bg":"#1a1426","fg":"#F8F8F2","accent":"#46459e","muted":"#9d79c2","subtle":"#6a6679","selection":"#492744","widget":"#1a1526","cursor":"#46459e","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#FAF7BA","purple":"#FF357C","func":"#69ecf5","constant":"#86dbfd","cls":"#6AADFF","bool":"#d285fd"}},
30  {"name":"Katsuragi Misato","slug":"katsuragi-misato","dark":true,"colors":{"bg":"#382536","fg":"#F8F8F2","accent":"#c2383e","muted":"#8c72a9","subtle":"#666879","selection":"#5a293f","widget":"#3d2536","cursor":"#c2383e","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#FAF7BA","purple":"#FF357C","func":"#42E66C","constant":"#86dbfd","cls":"#6AADFF","bool":"#BD84DD"}},
31  {"name":"Kirino","slug":"kirino","dark":true,"colors":{"bg":"#121e1c","fg":"#F8F8F2","accent":"#6cb3b5","muted":"#b0a17f","subtle":"#657978","selection":"#3d213e","widget":"#121e1c","cursor":"#6cb3b5","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#ff2525","interface":"#F6E9CB","purple":"#eec45e","func":"#8bd9ff","constant":"#EA7797","cls":"#E77FD5","bool":"#49e7d0"}},
32  {"name":"Konata","slug":"konata","dark":true,"colors":{"bg":"#355082","fg":"#F8F8F2","accent":"#4bcf4c","muted":"#addfa9","subtle":"#ffffff","selection":"#3a6c75","widget":"#314978","cursor":"#4bcf4c","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#fc9ee6","purple":"#fffd9b","func":"#60ff62","constant":"#f6be8b","cls":"#cda8fa","bool":"#ffc9d7"}},
33  {"name":"Mai Dark","slug":"mai-dark","dark":true,"colors":{"bg":"#242448","fg":"#F8F8F2","accent":"#fee3cf","muted":"#7cab9c","subtle":"#61647b","selection":"#235161","widget":"#25254e","cursor":"#fee3cf","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#EFA554","purple":"#F9B2FF","func":"#b772de","constant":"#FFEEA6","cls":"#61dba0","bool":"#50cefb"}},
34  {"name":"Maika","slug":"maika","dark":true,"colors":{"bg":"#24062f","fg":"#F8F8F2","accent":"#bc5d71","muted":"#79b7c1","subtle":"#70677b","selection":"#3d1535","widget":"#20052a","cursor":"#bc5d71","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#e09cf3","purple":"#f6e7ba","func":"#55daff","constant":"#86dbfd","cls":"#50cefb","bool":"#e42b54"}},
35  {"name":"Makise Kurisu","slug":"makise-kurisu","dark":true,"colors":{"bg":"#170a0b","fg":"#F8F8F2","accent":"#8F60B5","muted":"#843030","subtle":"#624849","selection":"#391717","widget":"#1a0e0e","cursor":"#8F60B5","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF0000","interface":"#4593f5","purple":"#FF8C74","func":"#DEC4AA","constant":"#86dbfd","cls":"#EC5D61","bool":"#BD93F9"}},
36  {"name":"Maple Dark","slug":"maple-dark","dark":true,"colors":{"bg":"#2d1d1d","fg":"#F8F8F2","accent":"#46ab79","muted":"#bfb38c","subtle":"#6c5b55","selection":"#295043","widget":"#2f1b1b","cursor":"#46ab79","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#ff2525","interface":"#F6E9CB","purple":"#4fe1a9","func":"#ad8cee","constant":"#ec93a1","cls":"#ee7fdc","bool":"#FFD448"}},
37  {"name":"Megumin","slug":"megumin","dark":true,"colors":{"bg":"#2c2126","fg":"#F8F8F2","accent":"#a73035","muted":"#75595d","subtle":"#7b7373","selection":"#563036","widget":"#2a1f24","cursor":"#a73035","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#ffd866","purple":"#BA6462","func":"#e4ff10","constant":"#FC79BB","cls":"#FF8A5F","bool":"#a28a92"}},
38  {"name":"Miia","slug":"miia","dark":true,"colors":{"bg":"#310e19","fg":"#F8F8F2","accent":"#d6a53e","muted":"#b19e78","subtle":"#a87975","selection":"#5b3225","widget":"#3a1020","cursor":"#d6a53e","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#e2d9bd","purple":"#c05388","func":"#efa2da","constant":"#34a7d1","cls":"#FFB86C","bool":"#39e6a6"}},
39  {"name":"Mioda Ibuki Dark","slug":"mioda-ibuki-dark","dark":true,"colors":{"bg":"#191b1d","fg":"#F8F8F2","accent":"#5395b4","muted":"#ab8d9f","subtle":"#666879","selection":"#452735","widget":"#17191b","cursor":"#5395b4","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#f4fa8c","purple":"#5ea7ff","func":"#ff69df","constant":"#86dbfd","cls":"#8daeef","bool":"#8b8b8b"}},
40  {"name":"Misaka Mikoto","slug":"misaka-mikoto","dark":true,"colors":{"bg":"#0b173a","fg":"#F8F8F2","accent":"#3eb7e5","muted":"#70bfbc","subtle":"#5d6680","selection":"#05649c","widget":"#0b1633","cursor":"#3eb7e5","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#ff2525","interface":"#A2EEFC","purple":"#FFE35C","func":"#f3b085","constant":"#EA7797","cls":"#8BEF85","bool":"#57e1ee"}},
41  {"name":"Monika Dark","slug":"monika-dark","dark":true,"colors":{"bg":"#1d2115","fg":"#F8F8F2","accent":"#388E3C","muted":"#3b753d","subtle":"#697966","selection":"#30432B","widget":"#1D2115","cursor":"#388E3C","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#94CFFF","purple":"#ABFFAF","func":"#60E769","constant":"#FF8FCA","cls":"#FFEA82","bool":"#3eae5d"}},
42  {"name":"Nadeshiko","slug":"nadeshiko","dark":true,"colors":{"bg":"#2c1f26","fg":"#F8F8F2","accent":"#78c6d0","muted":"#7ea5c1","subtle":"#6a5a6c","selection":"#553854","widget":"#2f2128","cursor":"#78c6d0","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#F6E9CB","purple":"#61c1ea","func":"#ff8bfd","constant":"#AE9AFF","cls":"#61ead9","bool":"#ec9cb2"}},
43  {"name":"Nakano Miku","slug":"nakano-miku","dark":true,"colors":{"bg":"#244158","fg":"#F8F8F2","accent":"#A5F3FA","muted":"#addfa9","subtle":"#b9dfb6","selection":"#498192","widget":"#24445b","cursor":"#A5F3FA","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#fffeaf","purple":"#4BABFF","func":"#fc9ee6","constant":"#da8d97","cls":"#ba92f3","bool":"#60ff62"}},
44  {"name":"Nakano Nino","slug":"nakano-nino","dark":true,"colors":{"bg":"#1c191d","fg":"#F8F8F2","accent":"#d45575","muted":"#ab8d9f","subtle":"#666879","selection":"#452735","widget":"#1f1a1f","cursor":"#d45575","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#ff2525","interface":"#F6E3CC","purple":"#68c4ee","func":"#fc9ee6","constant":"#ff858c","cls":"#5ea7ff","bool":"#7ceec8"}},
45  {"name":"Nakano Yotsuba","slug":"nakano-yotsuba","dark":true,"colors":{"bg":"#200909","fg":"#F8F8F2","accent":"#e86a44","muted":"#c08865","subtle":"#F8E3D7","selection":"#622316","widget":"#110c15","cursor":"#e86a44","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#ff2525","interface":"#F6E3CC","purple":"#39e6a6","func":"#fc9ee6","constant":"#9DACF6","cls":"#ffba2f","bool":"#ff858c"}},
46  {"name":"Natsuki Dark","slug":"natsuki-dark","dark":true,"colors":{"bg":"#35102c","fg":"#F8F8F2","accent":"#E94686","muted":"#b74170","subtle":"#796675","selection":"#602b50","widget":"#2f0a27","cursor":"#E94686","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#F6E9CB","purple":"#9DC0FF","func":"#E94686","constant":"#9286FD","cls":"#FF9CD6","bool":"#FF9CD6"}},
47  {"name":"Ram","slug":"ram","dark":true,"colors":{"bg":"#342c34","fg":"#F8F8F2","accent":"#e594bf","muted":"#ab7b9d","subtle":"#666879","selection":"#7a546f","widget":"#2b252b","cursor":"#e594bf","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#a1e9ff","purple":"#9d8df6","func":"#e88def","constant":"#85FFEF","cls":"#FBFF90","bool":"#ef57bf"}},
48  {"name":"Raphtalia","slug":"raphtalia","dark":true,"colors":{"bg":"#1e1710","fg":"#F8F8F2","accent":"#8a3c3d","muted":"#bfb38c","subtle":"#6c5f55","selection":"#5c3915","widget":"#1c140f","cursor":"#8a3c3d","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#ff2525","interface":"#FDC78C","purple":"#fd9144","func":"#4fe1a9","constant":"#8097e3","cls":"#FFD448","bool":"#f19992"}},
49  {"name":"Rei","slug":"rei","dark":true,"colors":{"bg":"#191b1f","fg":"#F8F8F2","accent":"#b53241","muted":"#7da1c2","subtle":"#666879","selection":"#25435a","widget":"#131514","cursor":"#b53241","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#f44747","interface":"#F6E3CC","purple":"#45e68a","func":"#ef596f","constant":"#86dbfd","cls":"#6AADFF","bool":"#788a8b"}},
50  {"name":"Rem","slug":"rem","dark":true,"colors":{"bg":"#2c2d34","fg":"#F8F8F2","accent":"#578CDA","muted":"#7b8bab","subtle":"#666879","selection":"#4C637A","widget":"#25262b","cursor":"#578CDA","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#F0A1FF","purple":"#9d8df6","func":"#8dc6ef","constant":"#85FFEF","cls":"#FBFF90","bool":"#6893f3"}},
51  {"name":"Rias Crimson","slug":"rias-crimson","dark":true,"colors":{"bg":"#3E1010","fg":"#F8F8F2","accent":"#e03943","muted":"#cdacac","subtle":"#cdb0b0","selection":"#822e2e","widget":"#3d1313","cursor":"#e03943","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#9BBEE3","purple":"#eea367","func":"#fbf96e","constant":"#86dbfd","cls":"#e03392","bool":"#C04750"}},
52  {"name":"Rias Onyx","slug":"rias-onyx","dark":true,"colors":{"bg":"#100000","fg":"#F8F8F2","accent":"#7C171F","muted":"#6e2727","subtle":"#97706f","selection":"#390c10","widget":"#100000","cursor":"#7C171F","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#F6E3CC","purple":"#b2dbe3","func":"#C04750","constant":"#E356A7","cls":"#5a84dd","bool":"#27c0b4"}},
53  {"name":"Rimuru Tempest","slug":"rimuru-tempest","dark":true,"colors":{"bg":"#1c171d","fg":"#F8F8F2","accent":"#d7cf8b","muted":"#b0a17f","subtle":"#675a6c","selection":"#29466c","widget":"#211c22","cursor":"#d7cf8b","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#ff2525","interface":"#77C2FF","purple":"#FF96FD","func":"#FDEA25","constant":"#9CA2FF","cls":"#FFA38F","bool":"#5FFF9F"}},
54  {"name":"Rory Mercury","slug":"rory-mercury","dark":true,"colors":{"bg":"#141417","fg":"#F8F8F2","accent":"#b53241","muted":"#843030","subtle":"#796666","selection":"#502121","widget":"#18181b","cursor":"#b53241","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF8484","interface":"#58A0F8","purple":"#7F8E90","func":"#FF4556","constant":"#86dbfd","cls":"#BD93F9","bool":"#e0474b"}},
55  {"name":"Ryuko Dark","slug":"ryuko-dark","dark":true,"colors":{"bg":"#2b3238","fg":"#F8F8F2","accent":"#a73035","muted":"#6e707a","subtle":"#666879","selection":"#563036","widget":"#2b3238","cursor":"#a73035","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#efa554","purple":"#99B6D5","func":"#e4ff10","constant":"#86dbfd","cls":"#6893f3","bool":"#e0474b"}},
56  {"name":"Sagiri","slug":"sagiri","dark":true,"colors":{"bg":"#0a3b36","fg":"#F8F8F2","accent":"#5eabb8","muted":"#eae99a","subtle":"#ffffff","selection":"#052421","widget":"#0a3f39","cursor":"#5eabb8","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#53dac7","purple":"#F1A4FA","func":"#42FA71","constant":"#82BAFF","cls":"#9FBBFF","bool":"#FFD448"}},
57  {"name":"Satsuki Dark","slug":"satsuki-dark","dark":true,"colors":{"bg":"#242729","fg":"#F8F8F2","accent":"#f03022","muted":"#af543f","subtle":"#596570","selection":"#5d2626","widget":"#212427","cursor":"#f03022","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#ff2525","interface":"#F6E9CB","purple":"#46F263","func":"#e4ff10","constant":"#96b7fb","cls":"#6893f3","bool":"#e24a3e"}},
58  {"name":"Sayori Dark","slug":"sayori-dark","dark":true,"colors":{"bg":"#111b2d","fg":"#F8F8F2","accent":"#00BCD4","muted":"#3a9fb1","subtle":"#666879","selection":"#234164","widget":"#0e1b2f","cursor":"#00BCD4","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#ff0000","interface":"#FF89BA","purple":"#FFF37C","func":"#01CFE7","constant":"#A486FD","cls":"#52FFA3","bool":"#3F77EF"}},
59  {"name":"Shima Rin","slug":"shima-rin","dark":true,"colors":{"bg":"#2b303b","fg":"#F8F8F2","accent":"#6688ad","muted":"#b0a17f","subtle":"#5a626c","selection":"#4f3a4e","widget":"#2e343e","cursor":"#6688ad","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#F6E9CB","purple":"#61ead9","func":"#8bd9ff","constant":"#ec9cb2","cls":"#89acf6","bool":"#ea73d6"}},
60  {"name":"Sonoda Umi","slug":"sonoda-umi","dark":true,"colors":{"bg":"#15173c","fg":"#F8F8F2","accent":"#EFA554","muted":"#6878c2","subtle":"#5e5e79","selection":"#272A59","widget":"#191b44","cursor":"#EFA554","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#FFF6B3","purple":"#BD84DD","func":"#EFA554","constant":"#86dbfd","cls":"#78F5F0","bool":"#58b7ff"}},
61  {"name":"Takanashi Rikka","slug":"takanashi-rikka","dark":true,"colors":{"bg":"#1e1928","fg":"#F8F8F2","accent":"#dd2a62","muted":"#bd7e99","subtle":"#8e6e7b","selection":"#761d3a","widget":"#1d1926","cursor":"#dd2a62","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#ff2525","interface":"#FFB4F8","purple":"#8C92FC","func":"#65CDFA","constant":"#F9FC88","cls":"#67F5C4","bool":"#de4371"}},
62  {"name":"Tohsaka Rin","slug":"tohsaka-rin","dark":true,"colors":{"bg":"#161415","fg":"#F8F8F2","accent":"#4c9697","muted":"#86a4ab","subtle":"#847878","selection":"#501F1F","widget":"#1b191a","cursor":"#4c9697","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#C20000","interface":"#72F8B5","purple":"#e0474b","func":"#69e0f5","constant":"#86dbfd","cls":"#EFA554","bool":"#859395"}},
63  {"name":"Vanilla","slug":"vanilla","dark":true,"colors":{"bg":"#2b2c3d","fg":"#F8F8F2","accent":"#9debff","muted":"#b0a17f","subtle":"#5a5e6c","selection":"#374872","widget":"#292a3a","cursor":"#9debff","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#F6E9CB","purple":"#6a96e9","func":"#9bf8ff","constant":"#5ddeda","cls":"#9d8df6","bool":"#FFD448"}},
64  {"name":"Yukihira Soma","slug":"yukihira-soma","dark":true,"colors":{"bg":"#09192b","fg":"#F8F8F2","accent":"#d13358","muted":"#6e89ad","subtle":"#5d6c80","selection":"#4f1d27","widget":"#0c1c2e","cursor":"#d13358","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#ff1717","interface":"#4BFF75","purple":"#8ACAFF","func":"#EA7777","constant":"#FFA6E1","cls":"#FF984B","bool":"#FFEF41"}},
65  {"name":"Yukinoshita Yukino","slug":"yukinoshita-yukino","dark":true,"colors":{"bg":"#1f2126","fg":"#F8F8F2","accent":"#2d6382","muted":"#456186","subtle":"#545e6d","selection":"#2d3b55","widget":"#282a2f","cursor":"#2d6382","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#F6E3CC","purple":"#ead979","func":"#84D0FF","constant":"#86dbfd","cls":"#9DACF6","bool":"#e0474b"}},
66  {"name":"Yuri Dark","slug":"yuri-dark","dark":true,"colors":{"bg":"#422D5A","fg":"#F8F8F2","accent":"#AB47BC","muted":"#9d52ab","subtle":"#6f6679","selection":"#663995","widget":"#442e5c","cursor":"#AB47BC","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#B6B3FF","purple":"#F1FF86","func":"#DC74FF","constant":"#86FDB6","cls":"#FF9CD6","bool":"#B17BFD"}},
67  {"name":"Zero Two Dark Obsidian","slug":"zero-two-dark-obsidian","dark":true,"colors":{"bg":"#17070e","fg":"#F8F8F2","accent":"#1ecd86","muted":"#5c9077","subtle":"#53615B","selection":"#174a2e","widget":"#150a0e","cursor":"#1ecd86","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF0000","interface":"#39e6a6","purple":"#B9F8BC","func":"#66FA36","constant":"#2FAAF6","cls":"#FFD448","bool":"#FDB8EB"}},
68  {"name":"Zero Two Dark Rose","slug":"zero-two-dark-rose","dark":true,"colors":{"bg":"#310f0f","fg":"#F8F8F2","accent":"#e4dad4","muted":"#b19e78","subtle":"#a87975","selection":"#531e1e","widget":"#300d0e","cursor":"#e4dad4","red":"#E356A7","green":"#42E66C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#e2d9bd","purple":"#C04750","func":"#efa2da","constant":"#34a7d1","cls":"#FFB86C","bool":"#39e6a6"}},
69  {"name":"Asuna Light","slug":"asuna-light","dark":false,"colors":{"bg":"#fcfcfc","fg":"#4D4D4A","accent":"#a61d0d","muted":"#a25252","subtle":"#aaaaaa","selection":"#e9b4b8","widget":"#fdfdfd","cursor":"#a61d0d","red":"#E356A7","green":"#38B85C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#a61d0d","purple":"#0d5fa6","func":"#2527B1","constant":"#4C94D6","cls":"#C68741","bool":"#a61d0d"}},
70  {"name":"Beatrice","slug":"beatrice","dark":false,"colors":{"bg":"#FFE5F1","fg":"#4D4D4A","accent":"#78A5EB","muted":"#dd87a1","subtle":"#aaaaaa","selection":"#fcc9f2","widget":"#FFE0F0","cursor":"#78A5EB","red":"#E356A7","green":"#38B85C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#ff5555","interface":"#DC872E","purple":"#7C75EF","func":"#5c84da","constant":"#4C94D6","cls":"#df81b8","bool":"#C869A3"}},
71  {"name":"C.C.","slug":"c-c","dark":false,"colors":{"bg":"#C4EA8A","fg":"#4D4D4A","accent":"#68ac17","muted":"#358969","subtle":"#507433","selection":"#92d564","widget":"#caec92","cursor":"#68ac17","red":"#E356A7","green":"#38B85C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF0817","interface":"#CB5A29","purple":"#098776","func":"#009507","constant":"#2B57A7","cls":"#7748B7","bool":"#0803A5"}},
72  {"name":"Darkness Light","slug":"darkness-light","dark":false,"colors":{"bg":"#FFFEF9","fg":"#4D4D4A","accent":"#F5C83C","muted":"#aaaaaa","subtle":"#aaaaaa","selection":"#fff3b4","widget":"#FFFEF9","cursor":"#F5C83C","red":"#E356A7","green":"#38B85C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#005CC5","purple":"#3492b1","func":"#b6323f","constant":"#005CC5","cls":"#c79c19","bool":"#E36207"}},
73  {"name":"Emilia Light","slug":"emilia-light","dark":false,"colors":{"bg":"#fbf0ff","fg":"#4D4D4A","accent":"#82357d","muted":"#8864ac","subtle":"#aaaaaa","selection":"#c7a0d2","widget":"#fbf0ff","cursor":"#82357d","red":"#E356A7","green":"#38B85C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#0CA87E","purple":"#7C75EF","func":"#7D2DD2","constant":"#4C94D6","cls":"#cb70a5","bool":"#90468c"}},
74  {"name":"Ishtar Light","slug":"ishtar-light","dark":false,"colors":{"bg":"#fffefb","fg":"#4D4D4A","accent":"#f5a821","muted":"#5078a5","subtle":"#aaaaaa","selection":"#fff5c7","widget":"#fffefb","cursor":"#f5a821","red":"#E356A7","green":"#38B85C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#a18649","purple":"#0d5fa6","func":"#9c3123","constant":"#4C94D6","cls":"#131f3b","bool":"#db974d"}},
75  {"name":"Mai Light","slug":"mai-light","dark":false,"colors":{"bg":"#FAF2F1","fg":"#4D4D4A","accent":"#4f5287","muted":"#6564ac","subtle":"#aaaaaa","selection":"#d3d5f1","widget":"#fff7f6","cursor":"#4f5287","red":"#E356A7","green":"#38B85C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#d27f2d","purple":"#C869A3","func":"#BA2BB2","constant":"#4C94D6","cls":"#4f5287","bool":"#7C75EF"}},
76  {"name":"Maple Light","slug":"maple-light","dark":false,"colors":{"bg":"#ffd091","fg":"#4D4D4A","accent":"#923A4E","muted":"#763530","subtle":"#693434","selection":"#ec9e74","widget":"#fdcd8f","cursor":"#923A4E","red":"#E356A7","green":"#38B85C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#208D3B","purple":"#007972","func":"#810808","constant":"#005CC5","cls":"#7748B7","bool":"#B03F0F"}},
77  {"name":"Mioda Ibuki Light","slug":"mioda-ibuki-light","dark":false,"colors":{"bg":"#ffeefd","fg":"#4D4D4A","accent":"#DA46A7","muted":"#5ca4d4","subtle":"#aaaaaa","selection":"#8EDBFF","widget":"#ffeefd","cursor":"#DA46A7","red":"#E356A7","green":"#38B85C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#3193D7","purple":"#4174b3","func":"#DA46A7","constant":"#2F6AAD","cls":"#cb70a5","bool":"#C869A3"}},
78  {"name":"Monika Light","slug":"monika-light","dark":false,"colors":{"bg":"#f2fff0","fg":"#4D4D4A","accent":"#388E3C","muted":"#3b753d","subtle":"#8CAA8E","selection":"#a9ecac","widget":"#f2fff0","cursor":"#388E3C","red":"#E356A7","green":"#38B85C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#da832e","purple":"#6D71DC","func":"#20AF6F","constant":"#4C94D6","cls":"#9A9E20","bool":"#2BBA37"}},
79  {"name":"Nakano Ichika","slug":"nakano-ichika","dark":false,"colors":{"bg":"#E3CCFD","fg":"#4D4D4A","accent":"#7F5EF5","muted":"#9160cd","subtle":"#8541b3","selection":"#f1b7d6","widget":"#e2c9fa","cursor":"#7F5EF5","red":"#E356A7","green":"#38B85C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#ff000f","interface":"#8747CE","purple":"#3E6DE5","func":"#C95FC0","constant":"#251CDE","cls":"#BF1010","bool":"#5815CE"}},
80  {"name":"Nakano Itsuki","slug":"nakano-itsuki","dark":false,"colors":{"bg":"#FFBEBE","fg":"#4D4D4A","accent":"#4f52c4","muted":"#b1483d","subtle":"#D07E72","selection":"#f4665a","widget":"#fcc1c1","cursor":"#4f52c4","red":"#E356A7","green":"#38B85C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#ff000f","interface":"#2D4DC2","purple":"#602C93","func":"#BF1010","constant":"#33618E","cls":"#8D2D1B","bool":"#B6159D"}},
81  {"name":"Natsuki Light","slug":"natsuki-light","dark":false,"colors":{"bg":"#FFE5F1","fg":"#4D4D4A","accent":"#E94686","muted":"#dd87a1","subtle":"#aaaaaa","selection":"#fcc9f2","widget":"#FFE0F0","cursor":"#E94686","red":"#E356A7","green":"#38B85C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#ff5555","interface":"#DC872E","purple":"#7C75EF","func":"#EE5687","constant":"#4C94D6","cls":"#df81b8","bool":"#C869A3"}},
82  {"name":"Ryuko Light","slug":"ryuko-light","dark":false,"colors":{"bg":"#ffffff","fg":"#4D4D4A","accent":"#169ef2","muted":"#1f79a1","subtle":"#344f69","selection":"#74adec","widget":"#f5f6f7","cursor":"#169ef2","red":"#E356A7","green":"#38B85C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#ff2525","interface":"#0F92E3","purple":"#007972","func":"#EE5C09","constant":"#005CC5","cls":"#7748B7","bool":"#B03F0F"}},
83  {"name":"Satsuki Light","slug":"satsuki-light","dark":false,"colors":{"bg":"#ffffff","fg":"#4D4D4A","accent":"#275AB3","muted":"#1f45a1","subtle":"#344f69","selection":"#748fec","widget":"#f5f6f7","cursor":"#275AB3","red":"#E356A7","green":"#38B85C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#ff2525","interface":"#0F92E3","purple":"#79074c","func":"#1136b9","constant":"#005CC5","cls":"#7748B7","bool":"#13a78c"}},
84  {"name":"Sayori Light","slug":"sayori-light","dark":false,"colors":{"bg":"#f0faff","fg":"#4D4D4A","accent":"#00bcd4","muted":"#64a6ac","subtle":"#aaaaaa","selection":"#a9c8ec","widget":"#f0faff","cursor":"#00bcd4","red":"#E356A7","green":"#38B85C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#E59584","purple":"#9f69dc","func":"#2e7093","constant":"#4C94D6","cls":"#EF5D99","bool":"#3F77EF"}},
85  {"name":"Senko","slug":"senko","dark":false,"colors":{"bg":"#FFE7CD","fg":"#4D4D4A","accent":"#cb3752","muted":"#b87157","subtle":"#CD9774","selection":"#f4ac96","widget":"#fce2c6","cursor":"#cb3752","red":"#E356A7","green":"#38B85C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#ff000f","interface":"#3492b1","purple":"#4B72D7","func":"#D9732E","constant":"#E734A8","cls":"#3451b1","bool":"#BF1010"}},
86  {"name":"Shigure","slug":"shigure","dark":false,"colors":{"bg":"#e9e9ff","fg":"#4D4D4A","accent":"#5e1f7f","muted":"#584484","subtle":"#38336b","selection":"#5756a2","widget":"#dad9ff","cursor":"#5e1f7f","red":"#E356A7","green":"#38B85C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF0707","interface":"#208D3B","purple":"#5E037E","func":"#C209A9","constant":"#005CC5","cls":"#7748B7","bool":"#410cb2"}},
87  {"name":"Tohru","slug":"tohru","dark":false,"colors":{"bg":"#ffe090","fg":"#4D4D4A","accent":"#d23c4b","muted":"#763530","subtle":"#693434","selection":"#ec9e74","widget":"#f6d988","cursor":"#d23c4b","red":"#E356A7","green":"#38B85C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#005CC5","purple":"#176B82","func":"#aa2537","constant":"#005CC5","cls":"#0E8D61","bool":"#A74503"}},
88  {"name":"Tomori Nao","slug":"tomori-nao","dark":false,"colors":{"bg":"#efe7de","fg":"#4D4D4A","accent":"#276fd8","muted":"#608bcd","subtle":"#417db3","selection":"#b7c6ef","widget":"#f1e7de","cursor":"#276fd8","red":"#E356A7","green":"#38B85C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF0817","interface":"#296FCB","purple":"#098776","func":"#A80675","constant":"#C26010","cls":"#7748B7","bool":"#030BA0"}},
89  {"name":"Yuri Light","slug":"yuri-light","dark":false,"colors":{"bg":"#f3f0ff","fg":"#4D4D4A","accent":"#ab74cb","muted":"#8864ac","subtle":"#aaaaaa","selection":"#ada0d2","widget":"#f5f0ff","cursor":"#ab74cb","red":"#E356A7","green":"#38B85C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#2DA0D2","purple":"#D579D0","func":"#95348C","constant":"#4C94D6","cls":"#c26a9d","bool":"#7C75EF"}},
90  {"name":"Yuzuriha Inori","slug":"yuzuriha-inori","dark":false,"colors":{"bg":"#FFA772","fg":"#4D4D4A","accent":"#ba1515","muted":"#894935","subtle":"#743333","selection":"#EC7F54","widget":"#f8a56e","cursor":"#ba1515","red":"#E356A7","green":"#38B85C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF0817","interface":"#413AC1","purple":"#0B6374","func":"#B11095","constant":"#2B57A7","cls":"#7748B7","bool":"#99101B"}},
91  {"name":"Zero Two Light Lily","slug":"zero-two-light-lily","dark":false,"colors":{"bg":"#fcfcfc","fg":"#4D4D4A","accent":"#A62210","muted":"#5282a2","subtle":"#aaaaaa","selection":"#e9b4b8","widget":"#fafafa","cursor":"#A62210","red":"#E356A7","green":"#38B85C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#0EAAAF","purple":"#A62210","func":"#E356A7","constant":"#0d5fa6","cls":"#117aa6","bool":"#0da661"}},
92  {"name":"Zero Two Light Sakura","slug":"zero-two-light-sakura","dark":false,"colors":{"bg":"#ffe6ee","fg":"#4D4D4A","accent":"#A62210","muted":"#42a373","subtle":"#BB9BB1","selection":"#c1e9d4","widget":"#ffe5ef","cursor":"#A62210","red":"#E356A7","green":"#38B85C","yellow":"#EFA554","blue":"#9B6BDF","magenta":"#E64747","cyan":"#75D7EC","error":"#FF5555","interface":"#E356A7","purple":"#A62210","func":"#109757","constant":"#0d5fa6","cls":"#0F9497","bool":"#5236B4"}},
93]
94
types/index.d.ts 58 lines
1export type DokiColors = {
2  bg: string
3  fg: string
4  accent: string
5  muted: string
6  subtle: string
7  selection: string
8  widget: string
9  cursor: string
10  red: string
11  green: string
12  yellow: string
13  blue: string
14  magenta: string
15  cyan: string
16  error: string
17  interface: string
18  purple: string
19  func: string
20  constant: string
21  cls: string
22  bool: string
23}
24
25/** Where a theme comes from. Doki themes leave `source` off. termcn slugs carry a "termcn-" prefix. */
26export type ThemeSource = 'doki' | 'termcn'
27
28export type DokiTheme = { name: string; slug: string; dark: boolean; colors: DokiColors; source?: ThemeSource }
29
30/** The termcn color keys the picker maps from (hooks/termcn-themes.ts, generated). */
31export type TermcnColors = Record<
32  'accent' | 'background' | 'error' | 'focusRing' | 'foreground' | 'info' | 'muted' | 'mutedForeground' | 'primary' | 'secondary' | 'selection' | 'success' | 'warning',
33  string
34>
35
36export type TermcnRaw = { name: string; slug: string; colors: TermcnColors }
37
38/** The shared accent file (~/.claude/mods/theme-accent.json) that other mods can read. */
39export type Accent = {
40  name: string
41  dark: boolean
42  accent: string
43  accent2: string
44  muted: string
45  text: string
46  subtle: string
47}
48
49declare module 'claude-code' {
50  interface PluginState {
51    /**
52     * highlight: the slug under the focus ring; current: the slug last applied;
53     * followed: the slug whose Windows Terminal scheme and accent were last written.
54     */
55    'doki-theme-picker': { highlight: string; current: string; followed: string }
56  }
57}
58