Hearth
v0.3.0A warm color theme that keeps the interface calm and lights the code with a single ember.
import type { Ember } from "./hearth";
// Warm syntax: orange plus one accent.
export function kindle(
embers: Ember[],
intensity = 1.5,
): Ember[] {
return embers.filter((ember) => {
const heat =
ember.temperature * intensity;
return heat > 400;
});
}
const lit = kindle(hearth.embers);
console.log(`${lit.length} glowing`);from dataclasses import dataclass
@dataclass
class Ember:
temperature: float
glowing: bool = False
def kindle(
embers: list[Ember],
intensity: float = 1.5,
) -> list[Ember]:
for ember in embers:
heat = (
ember.temperature
* intensity
)
ember.glowing = heat > 400
return embers#[derive(Debug)]
struct Ember {
temperature: f32,
glowing: bool,
}
fn kindle(
embers: &mut [Ember],
intensity: f32,
) {
for ember in embers {
let heat = ember.temperature
* intensity;
ember.glowing = heat > 400.0;
}
}package hearth
type Ember struct {
Temperature float64
Glowing bool
}
func Kindle(
embers []Ember,
intensity float64,
) []Ember {
for i := range embers {
temp := embers[i].Temperature
heat := temp * intensity
embers[i].Glowing = heat > 400
}
return embers
}:root {
--ember: oklch(0.659 0.194 37.5);
--hearth: oklch(0.2 0.01 60);
}
.hearth {
color: var(--ember);
background: var(--hearth);
border-radius: 0.75rem;
}
@media (hover: hover) {
.ember {
opacity: 0.9;
}
}import type { Ember } from "./hearth";
// Warm syntax: orange plus one accent.
export function kindle(
embers: Ember[],
intensity = 1.5,
): Ember[] {
return embers.filter((ember) => {
const heat =
ember.temperature * intensity;
return heat > 400;
});
}
const lit = kindle(hearth.embers);
console.log(`${lit.length} glowing`);from dataclasses import dataclass
@dataclass
class Ember:
temperature: float
glowing: bool = False
def kindle(
embers: list[Ember],
intensity: float = 1.5,
) -> list[Ember]:
for ember in embers:
heat = (
ember.temperature
* intensity
)
ember.glowing = heat > 400
return embers#[derive(Debug)]
struct Ember {
temperature: f32,
glowing: bool,
}
fn kindle(
embers: &mut [Ember],
intensity: f32,
) {
for ember in embers {
let heat = ember.temperature
* intensity;
ember.glowing = heat > 400.0;
}
}package hearth
type Ember struct {
Temperature float64
Glowing bool
}
func Kindle(
embers []Ember,
intensity float64,
) []Ember {
for i := range embers {
temp := embers[i].Temperature
heat := temp * intensity
embers[i].Glowing = heat > 400
}
return embers
}:root {
--ember: oklch(0.659 0.194 37.5);
--hearth: oklch(0.2 0.01 60);
}
.hearth {
color: var(--ember);
background: var(--hearth);
border-radius: 0.75rem;
}
@media (hover: hover) {
.ember {
opacity: 0.9;
}
}import type { Ember } from "./hearth";
// Warm syntax: orange plus one accent.
export function kindle(
embers: Ember[],
intensity = 1.5,
): Ember[] {
return embers.filter((ember) => {
const heat =
ember.temperature * intensity;
return heat > 400;
});
}
const lit = kindle(hearth.embers);
console.log(`${lit.length} glowing`);from dataclasses import dataclass
@dataclass
class Ember:
temperature: float
glowing: bool = False
def kindle(
embers: list[Ember],
intensity: float = 1.5,
) -> list[Ember]:
for ember in embers:
heat = (
ember.temperature
* intensity
)
ember.glowing = heat > 400
return embers#[derive(Debug)]
struct Ember {
temperature: f32,
glowing: bool,
}
fn kindle(
embers: &mut [Ember],
intensity: f32,
) {
for ember in embers {
let heat = ember.temperature
* intensity;
ember.glowing = heat > 400.0;
}
}package hearth
type Ember struct {
Temperature float64
Glowing bool
}
func Kindle(
embers []Ember,
intensity float64,
) []Ember {
for i := range embers {
temp := embers[i].Temperature
heat := temp * intensity
embers[i].Glowing = heat > 400
}
return embers
}:root {
--ember: oklch(0.659 0.194 37.5);
--hearth: oklch(0.2 0.01 60);
}
.hearth {
color: var(--ember);
background: var(--hearth);
border-radius: 0.75rem;
}
@media (hover: hover) {
.ember {
opacity: 0.9;
}
}A quiet base
Backgrounds, text, and comments stay in calm neutrals; the warmth lives in the code. Nothing competes with what you're reading.
One accent, on purpose
Keywords carry a single orange ember. Azure and Teal add just one cool hue — on functions and types — so structure pops without a rainbow.
Beyond the editor
VS Code, Cursor, Zed, Warp, and Ghostty — and the same theme files highlight code anywhere Shiki runs, including this page.
Install
Editor, terminal, or docs — pick where Hearth lives next.
- Install from the terminal — or search Hearth in the Extensions panel and click Install.
- Open the theme picker with then (Ctrl on Windows and Linux) and choose a Hearth.
- In Cursor, open the Extensions panel, search Hearth, and click Install.
- You can also find Hearth on Open VSX.
- To sideload instead, download
hearth-latest.vsix, then choose Install from VSIX… from the Extensions panel's ⋯ menu. - Open the theme picker with then (Ctrl on Windows and Linux) and choose a Hearth.
- In Zed, open Extensions with (Ctrl on Windows and Linux), search Hearth, and click Install.
- Open the theme picker with then (Ctrl on Windows and Linux) and choose a Hearth.
- Download the light and dark themes from the repo's warp folder.
- Move them into
~/.warp/themes/hearth/. - Restart Warp if the themes don't show up, then pick a Hearth from the theme picker.
Warp doesn't expose editor syntax scopes, so Hearth ships one complete ANSI palette in light and dark. A listing in Warp's own theme repo is in review.
- Download the light and dark themes from the repo's ghostty folder.
- Move them into
~/.config/ghostty/themes/. - Add
theme = hearth-dark(orhearth-light) to your~/.config/ghostty/config, then reload with (Ctrl on Linux).
To follow your system appearance automatically, pair both variants: theme = dark:hearth-dark,light:hearth-light.
- Grab any of the six theme files from the themes folder — they're plain VS Code theme JSON.
- Pass one to Shiki as a
theme:
highlight.ts
import { codeToHtml } from "shiki";
import hearthDark from "./hearth-dark.json";
const html = await codeToHtml(code, {
lang: "ts",
theme: hearthDark,
});Six variants
Three flavors, each a light and dark pair. Every card below is rendered in its own theme — whatever mode you're viewing in.
Hearth
Duotone. One orange ember, functions and types left neutral.
warmth.ts
type Theme = "light" | "dark";
export function warmth(theme: Theme): number {
const base = theme === "dark" ? 0.1 : 0.98;
return Math.round(base * 100);
}warmth.ts
type Theme = "light" | "dark";
export function warmth(theme: Theme): number {
const base = theme === "dark" ? 0.1 : 0.98;
return Math.round(base * 100);
}Hearth Azure
The same base, clear blue on functions and types.
warmth.ts
type Theme = "light" | "dark";
export function warmth(theme: Theme): number {
const base = theme === "dark" ? 0.1 : 0.98;
return Math.round(base * 100);
}warmth.ts
type Theme = "light" | "dark";
export function warmth(theme: Theme): number {
const base = theme === "dark" ? 0.1 : 0.98;
return Math.round(base * 100);
}Hearth Teal
The same base, teal on functions and types.
warmth.ts
type Theme = "light" | "dark";
export function warmth(theme: Theme): number {
const base = theme === "dark" ? 0.1 : 0.98;
return Math.round(base * 100);
}warmth.ts
type Theme = "light" | "dark";
export function warmth(theme: Theme): number {
const base = theme === "dark" ? 0.1 : 0.98;
return Math.round(base * 100);
}The palette
The editor palette's base is identical across flavors; only functions and types take on the accent hue. The terminal carries one shared ANSI set. Every value is the real one from the theme files — click to copy.
Base — shared by every flavor
- Backgroundeditor surface
- Foregroundplain text
- Commentmuted, low-contrast
- Keywordthe orange ember
- Stringwarm brown
- Constantnumbers & literals
Accent — what each flavor changes
- Hearthkeywords; functions and types stay neutral
- Hearth Azurefunctions, with a lighter tint on types
- Hearth Tealfunctions, with a lighter tint on types
Normal — the eight base colors
- Blackbackground base
- Redember
- Greenmoss
- Yellowamber
- BlueAzure anchor
- Magentamuted magenta
- CyanTeal anchor
- Whiteforeground text
Bright — bold text and highlights
- Blackbackground base
- Redember
- Greenmoss
- Yellowamber
- BlueAzure anchor
- Magentamuted magenta
- CyanTeal anchor
- Whiteforeground text
Changelog
What’s new in Hearth, from new homes to small refinements.
v0.3.0
Added
- Added dedicated light and dark Ghostty themes, including automatic system appearance pairing instructions.
Changed
- Rebuilt the shared terminal colors as a complete semantic ANSI palette for shell prompts and CLI tools, anchored by Hearth Azure and Teal.
- Consolidated Warp into dedicated light and dark terminal themes while keeping all six variants for editors. Existing Azure or Teal terminal users should switch to the corresponding Hearth Dark or Hearth Light theme.
- Added explicit shared workbench colors for top-mounted activity bars, command centers, and active or inactive window borders in Cursor and VS Code.
- Changed modified-file decorations to warm brown and moved the Hearth-orange active-tab indicator from the top edge to the bottom edge.
v0.2.1
Changed
- Replaced the composite theme preview with one full-size Cursor screenshot for each variant, making the differences easier to compare in extension listings.
v0.2.0
Added
- Added Zed and Warp versions of all six Hearth variants.
- Added a stable hearth-latest.vsix package name for Cursor and other sideloaded installations.
Changed
- Removed the middle-dot separator from the Azure and Teal variant names.
- Updated the public description and installation documentation to reflect the full VS Code, Cursor, Zed, Warp, and Shiki family.