Hearth
v0.2.1A 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, and Warp — 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 ⌘K ⌘T (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 ⌘K ⌘T (Ctrl on Windows and Linux) and choose a Hearth.
- Download hearth.json — one file carrying all six variants.
- Move it into Zed's themes folder,
~/.config/zed/themes/on macOS and Linux. - Pick a Hearth from Zed's theme selector.
The repo's zed/ folder also installs with zed: install dev extension. An extension-store listing is planned.
- Download the six 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.
Teal and Azure change the terminal's cyan pair — Warp doesn't expose editor syntax scopes. A listing in Warp's own theme repo is in review.
- 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 base palette is identical across flavors; only functions and types take on the accent hue. 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
Changelog
What’s new in Hearth, from new homes to small refinements.
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.
v0.1.2
Changed
- Simplified the public README and Marketplace description.