Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ Color themes for [Kettu](https://github.com/KettuAI/Kettu). Kettu lists them in
| [Catppuccin](themes/catppuccin.json) | Latte and Mocha | [Catppuccin](https://github.com/catppuccin/catppuccin) | MIT |
| [Gruvbox](themes/gruvbox.json) | Light and dark | [Pavel Pertsev](https://github.com/morhetz/gruvbox) | MIT |
| [Nord](themes/nord.json) | Light and dark | [Arctic Ice Studio](https://github.com/nordtheme/nord) | MIT |
| [Paper](themes/paper.json) | Light and dark | [Kettu](https://github.com/KettuAI/Kettu) | MIT |
| [Rosé Pine](themes/rose-pine.json) | Dawn and Main | [Rosé Pine](https://github.com/rose-pine/rose-pine-theme) | MIT |
| [Solarized](themes/solarized.json) | Light and dark | [Ethan Schoonover](https://github.com/altercation/solarized) | MIT |
| [Tokyo Night](themes/tokyo-night.json) | Light and Night | [enkia](https://github.com/tokyo-night/tokyo-night-vscode-theme) | MIT |

Each keeps its palette's published colors. Where one is too faint for text on its own surfaces, under 4.5:1, the theme uses the same hue a shade lighter or darker for text. Solarized keeps its body text tone, so Kettu marks its tile with a contrast warning.
Paper is Kettu's former built-in look: warm paper colors with Source Serif 4 for prose and headings and Inter for the interface. The others each keep their palette's published colors. Where one is too faint for text on its own surfaces, under 4.5:1, the theme uses the same hue a shade lighter or darker for text. Solarized keeps its body text tone, so Kettu marks its tile with a contrast warning.

## Adding a theme

Expand Down Expand Up @@ -42,6 +43,7 @@ A theme here needs a license that lets anyone use and share it, and names the pa
```

- A color a variant leaves out keeps Kettu's own.
- `fonts`, which both variants share, may name a face for `ui`, `prose` (the agent's replies and headings) and `code`: `system`, `inter`, `source-serif-4` or `jetbrains-mono`, and for `code` only `system` or `jetbrains-mono`. Kettu ships each of them; a role left out keeps Kettu's own.
- Colors are hex, `rgb()`, `hsl()`, `oklch()`, `oklab()` or `transparent`; nothing else, such as `var()` or color names.
- A file is at most 256 KB.

Expand Down
35 changes: 35 additions & 0 deletions index.json
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,41 @@
}
}
},
{
"id": "paper",
"name": "Paper",
"author": "Kettu",
"version": "1.0.0",
"license": "MIT",
"file": "themes/paper.json",
"sha256": "4b0680014dc9a51acb67353dfca6e61ee3e6038d22caf6bb10c2181c19480bb1",
"preview": {
"light": {
"bg-app": "#fdfcf9",
"bg-sidebar": "#efede6",
"bg-surface": "#ffffff",
"bg-subtle": "#f2f0e9",
"bg-selected": "rgb(28 27 24 / 7.5%)",
"border-default": "rgb(28 27 24 / 12%)",
"border-subtle": "rgb(28 27 24 / 7.5%)",
"border-strong": "rgb(28 27 24 / 20%)",
"primary-from": "#2e2d29",
"primary-to": "#1c1b18"
},
"dark": {
"bg-app": "#1c1b18",
"bg-sidebar": "#121110",
"bg-surface": "#262521",
"bg-subtle": "#2a2925",
"bg-selected": "rgb(244 243 238 / 9%)",
"border-default": "rgb(244 243 238 / 10%)",
"border-subtle": "rgb(244 243 238 / 6.5%)",
"border-strong": "rgb(244 243 238 / 18%)",
"primary-from": "#f4f3ee",
"primary-to": "#e3e1d9"
}
}
},
{
"id": "rose-pine",
"name": "Rosé Pine",
Expand Down
29 changes: 28 additions & 1 deletion scripts/build-index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ const TOKENS = new Set([
'mark',
'checker',
'agent-opencode',
'agent-pi',
'agent-other',
'heat-hue',
'heat-0',
Expand Down Expand Up @@ -112,7 +113,23 @@ const PREVIEW_TOKENS = [
'primary-to',
]

const FIELDS = ['kettuTheme', 'name', 'author', 'version', 'license', 'source', 'light', 'dark']
const FIELDS = [
'kettuTheme',
'name',
'author',
'version',
'license',
'source',
'fonts',
'light',
'dark',
]
// The faces a theme may choose for each kind of text, all of them shipped with Kettu.
const FONTS = {
ui: ['system', 'inter', 'source-serif-4', 'jetbrains-mono'],
prose: ['system', 'inter', 'source-serif-4', 'jetbrains-mono'],
code: ['system', 'jetbrains-mono'],
}
const VERSION = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/
const CODE_THEME = /^[a-z0-9-]{1,64}$/
const CONTROL = /[\u0000-\u001f\u007f]/
Expand Down Expand Up @@ -203,6 +220,16 @@ function checkTheme(fileName, raw) {
throw new Error('has a source that is not an https URL')
}

if (raw.fonts !== undefined) {
if (!isRecord(raw.fonts)) throw new Error('fonts is not an object')
for (const [role, face] of Object.entries(raw.fonts)) {
if (!Object.hasOwn(FONTS, role)) throw new Error(`fonts.${role} is not text Kettu sets`)
if (!FONTS[role].includes(face)) {
throw new Error(`fonts.${role} is not one of ${FONTS[role].join(', ')}`)
}
}
}

const preview = {}
for (const mode of MODES) {
const variant = raw[mode]
Expand Down
183 changes: 183 additions & 0 deletions themes/paper.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
{
"kettuTheme": 1,
"name": "Paper",
"author": "Kettu",
"version": "1.0.0",
"license": "MIT",
"source": "https://github.com/KettuAI/Kettu",
"fonts": {
"ui": "inter",
"prose": "source-serif-4",
"code": "jetbrains-mono"
},
"light": {
"colors": {
"bg-app": "#fdfcf9",
"bg-sidebar": "#efede6",
"bg-surface": "#ffffff",
"bg-subtle": "#f2f0e9",
"bg-code-inline": "rgb(28 27 24 / 6.5%)",
"bg-code-block": "#f7f5ef",
"bg-hover": "rgb(28 27 24 / 5%)",
"bg-selected": "rgb(28 27 24 / 7.5%)",
"queue-back": "#f2f0ea",
"border-default": "rgb(28 27 24 / 12%)",
"border-subtle": "rgb(28 27 24 / 7.5%)",
"border-strong": "rgb(28 27 24 / 20%)",
"text-primary": "#1c1b18",
"text-secondary": "#55534c",
"text-tertiary": "#68655d",
"text-placeholder": "#6e6b63",
"text-disabled": "#a9a69d",
"icon-default": "#68655d",
"attention": "#a3441c",
"attention-dot": "#d2622f",
"danger": "#ac3b2d",
"success": "#2e7550",
"merged": "#6f4c8e",
"info": "#2d5e91",
"warning": "#8a6212",
"link": "#2d5e91",
"link-hover": "#234a73",
"danger-tint": "#fbf6f6",
"danger-border": "#eed8d5",
"success-tint": "#f2f7f5",
"info-tint": "#f2f5f8",
"warning-tint": "#f8f6f1",
"info-tint-hover": "#eaeff4",
"focus": "rgb(45 94 145 / 55%)",
"selection": "rgb(45 94 145 / 18%)",
"edit-ring": "#2a79d7",
"edit-selection": "#b3d6fe",
"primary-from": "#2e2d29",
"primary-to": "#1c1b18",
"primary-hover-from": "#3b3934",
"primary-hover-to": "#292824",
"primary-ring": "#1c1b18",
"primary-highlight": "rgb(255 255 255 / 12%)",
"primary-foreground": "#ffffff",
"scrollbar-thumb": "rgb(28 27 24 / 20%)",
"scrim": "rgb(28 27 24 / 14%)",
"viewer-scrim": "oklch(0.14 0.004 85 / 92%)",
"mark": "oklch(0.88 0.14 92 / 55%)",
"checker": "rgb(28 27 24 / 5%)",
"agent-opencode": "oklch(0.6 0.008 85)",
"agent-pi": "oklch(0.852 0.114 83.4)",
"agent-other": "oklch(0.8 0.008 85)",
"heat-hue": "#55534c",
"heat-0": "rgb(28 27 24 / 5.5%)",
"context-1": "oklch(0.52 0.09 250)",
"context-2": "oklch(0.56 0.07 190)",
"context-3": "oklch(0.52 0.09 310)",
"context-4": "oklch(0.68 0.11 75)",
"context-5": "oklch(0.56 0.09 155)",
"context-6": "oklch(0.56 0.1 25)",
"context-7": "oklch(0.6 0.02 85)",
"terminal-background": "#fdfcf9",
"terminal-foreground": "#1c1b18",
"terminal-cursor": "#1c1b18",
"terminal-selection": "rgb(45 94 145 / 18%)",
"ansi-black": "#1c1b18",
"ansi-red": "#ac3b2d",
"ansi-green": "#2e7550",
"ansi-yellow": "#8a6212",
"ansi-blue": "#2d5e91",
"ansi-magenta": "#6f4c8e",
"ansi-cyan": "#23707a",
"ansi-white": "#6d6a62",
"ansi-bright-black": "#75726a",
"ansi-bright-red": "#c24e3b",
"ansi-bright-green": "#3c8a5e",
"ansi-bright-yellow": "#a0761a",
"ansi-bright-blue": "#3b74ae",
"ansi-bright-magenta": "#8660a6",
"ansi-bright-cyan": "#2f8590",
"ansi-bright-white": "#a9a69d"
}
},
"dark": {
"colors": {
"bg-app": "#1c1b18",
"bg-sidebar": "#121110",
"bg-surface": "#262521",
"bg-subtle": "#2a2925",
"bg-code-inline": "rgb(244 243 238 / 8.5%)",
"bg-code-block": "#181715",
"bg-hover": "rgb(244 243 238 / 5.5%)",
"bg-selected": "rgb(244 243 238 / 9%)",
"queue-back": "#201f1c",
"border-default": "rgb(244 243 238 / 10%)",
"border-subtle": "rgb(244 243 238 / 6.5%)",
"border-strong": "rgb(244 243 238 / 18%)",
"text-primary": "#eceae3",
"text-secondary": "#bab7ad",
"text-tertiary": "#9a978f",
"text-placeholder": "#95928a",
"text-disabled": "#5e5c56",
"icon-default": "#9a978f",
"attention": "#e8916a",
"attention-dot": "#e8916a",
"danger": "#ea8a7d",
"success": "#7dc196",
"merged": "#b798d4",
"info": "#80aada",
"warning": "#d9b463",
"link": "#80aada",
"link-hover": "#a6c4e8",
"danger-tint": "#3a2f2a",
"danger-border": "#593f39",
"success-tint": "#2f352d",
"info-tint": "#2f3234",
"warning-tint": "#383328",
"info-tint-hover": "#34393d",
"focus": "rgb(128 170 218 / 60%)",
"selection": "rgb(128 170 218 / 28%)",
"edit-ring": "#3a8ee6",
"edit-selection": "#3f638b",
"primary-from": "#f4f3ee",
"primary-to": "#e3e1d9",
"primary-hover-from": "#ffffff",
"primary-hover-to": "#eceae3",
"primary-ring": "#d4d1c8",
"primary-highlight": "rgb(255 255 255 / 60%)",
"primary-foreground": "#262521",
"scrollbar-thumb": "rgb(244 243 238 / 20%)",
"scrim": "rgb(0 0 0 / 32%)",
"viewer-scrim": "oklch(0.14 0.004 85 / 92%)",
"mark": "oklch(0.8 0.13 88 / 32%)",
"checker": "rgb(244 243 238 / 7%)",
"agent-opencode": "oklch(0.74 0.008 85)",
"agent-pi": "oklch(0.749 0.115 84.2)",
"agent-other": "oklch(0.46 0.008 85)",
"heat-hue": "#bab7ad",
"heat-0": "rgb(244 243 238 / 6.5%)",
"context-1": "oklch(0.72 0.08 250)",
"context-2": "oklch(0.74 0.06 190)",
"context-3": "oklch(0.72 0.08 310)",
"context-4": "oklch(0.78 0.1 75)",
"context-5": "oklch(0.74 0.08 155)",
"context-6": "oklch(0.74 0.09 25)",
"context-7": "oklch(0.7 0.02 85)",
"terminal-background": "#1c1b18",
"terminal-foreground": "#eceae3",
"terminal-cursor": "#eceae3",
"terminal-selection": "rgb(128 170 218 / 28%)",
"ansi-black": "#3a3833",
"ansi-red": "#ea8a7d",
"ansi-green": "#7dc196",
"ansi-yellow": "#d9b463",
"ansi-blue": "#80aada",
"ansi-magenta": "#b798d4",
"ansi-cyan": "#79c2c2",
"ansi-white": "#d9d6cd",
"ansi-bright-black": "#6e6b63",
"ansi-bright-red": "#f2a497",
"ansi-bright-green": "#97d3ac",
"ansi-bright-yellow": "#e8c77e",
"ansi-bright-blue": "#9dc0e8",
"ansi-bright-magenta": "#cbb0e2",
"ansi-bright-cyan": "#97d6d6",
"ansi-bright-white": "#f4f3ee"
}
}
}