Themes
A theme sets the colors textweaver uses for the page, text, headings, links, code, and highlights such as the word being spoken. Every theme is checked for contrast, and no theme shows anything by color alone: highlights are also bold, underlined, italic, or reversed, so they stay visible in any color setting and with color turned off.
This guide covers choosing a theme, the built-in themes, following your system's light or dark setting, terminal colors, and writing your own theme.
Galaxy, the default
Galaxy is textweaver's default theme and the first in the list. It is star's default theme, carried over faithfully: a dark theme modeled on Obsidian's dark mode, with light gray text on a near-black page and purple accents.
- Page
#1e1e1e, text#dadada. - Headings in lavender, violet, periwinkle, and teal.
- Links in purple (
#a882ff), always underlined. - The word being spoken is dark text on a lavender band, in bold, inside an underlined sentence, in the terminal and in the app alike.
One color changed from star: dim text (hints, line numbers, quotes) is #858585 instead of #7d7d7d, because star's gray measured 4.0 to 1 against the page and the minimum is 4.5 to 1.
Galaxy's light partner is Galaxy Light. When textweaver follows your system's appearance, it switches between the two.
Choosing a theme
- Press F5 to move to the next theme. textweaver says the theme's name.
- Start with a theme for one session:
textweaver --theme sepia notes.md
- Set it for good in
settings.toml, under[display]:
[display]
theme = "nord"
Names ignore case. star's older names still work (obsidian means Galaxy). If a name is not found, textweaver uses Galaxy and tells you so.
settings.toml is in textweaver's configuration folder: on Windows %APPDATA%\leavesofgrass\textweaver\config, on macOS ~/Library/Application Support/org.leavesofgrass.textweaver, on Linux ~/.config/textweaver. Setting TEXTWEAVER_HOME puts everything under one folder instead.
The built-in themes
They are grouped here by kind. All but Lamplight are star's palettes; Lamplight is textweaver's own.
Not every theme has to meet the WCAG AA contrast level, as long as some do.
- Must meet AA. Galaxy, Galaxy Light, Contrast, and High Contrast. The two high-contrast themes reach 7 to 1. Where one of star's colors fell short in these four, it was moved by the smallest change that passes, and the theme file lists every change.
- Every other theme keeps star's colors exactly. Its theme file says whether it meets AA.
- Meets AA: Amber, Catppuccin Mocha, Dracula, Gruvbox Dark, Gruvbox Light, Kanagawa, Lamplight, Rose Pine, Sepia, and Tokyo Night.
- Falls short on some colors, often the dim text: Dark, Everforest Dark, Light, Monokai, Nord, One Dark, One Light, Phosphor, Solarized Dark, and Solarized Light.
If you read by sight and need strong contrast, choose one of the themes that meets AA.
F5 goes through the themes that meet AA first, with light and dark partners side by side: Galaxy, Galaxy Light, High Contrast, Contrast, Lamplight, Sepia, Gruvbox Dark, Gruvbox Light, Tokyo Night, Catppuccin Mocha, Dracula, Rose Pine, Kanagawa, and Amber. Then come the ten below AA: One Dark, One Light, Dark, Light, Solarized Dark, Solarized Light, Nord, Everforest Dark, Monokai, and Phosphor. Your own themes come after them.
When F5 picks a theme below AA, it says so in words after the name, for example "Theme One Dark. Below AA: 2 checks fall short."
Dark themes:
- Galaxy: purple accents on near black; the default.
- One Dark: the One Dark editor palette.
- Dark: star's original dark theme.
- Phosphor: green monochrome, like an old terminal.
- Dracula.
- Nord: cool arctic blues.
- Solarized Dark.
- Gruvbox Dark: warm retro colors.
- Tokyo Night.
- Catppuccin Mocha: soft pastels.
- Monokai.
- Amber: amber text on near black.
- Everforest Dark: soft greens.
- Rose Pine: muted rose and pine.
- Kanagawa.
- Lamplight: a soft, warm dark theme with low glare. Body text meets AAA (7.4 to 1) at about 60 percent of Galaxy's contrast, and the spoken word and sentence are an orange and blue pair. Its file has
tags = ["soft"].
Light themes:
- Galaxy Light: purple accents on white; Galaxy's partner.
- One Light.
- Light: star's original light theme.
- Solarized Light.
- Sepia: dark brown text on warm, paper-colored tones.
- Gruvbox Light.
High-contrast themes, where every text color reaches 7 to 1 or more:
- Contrast: pure yellow and cyan on black.
- High Contrast: softer colors for low vision, all well above 7 to 1.
Light and dark partners: Galaxy and Galaxy Light, One Dark and One Light, Dark and Light, Solarized Dark and Solarized Light, Gruvbox Dark and Gruvbox Light.
Following your system's appearance
When following is on and you have not picked a theme yourself, textweaver matches your system at startup:
- In dark mode, it uses your theme's dark partner, or Galaxy.
- In light mode, it uses your theme's light partner, or Galaxy Light.
- In high-contrast mode (Windows contrast themes, macOS Increase Contrast, GNOME High Contrast), it uses High Contrast.
Choosing a theme yourself stops following, as in star. It reads these settings: on Windows, the app light or dark mode and the contrast theme switch; on macOS, Appearance and Increase Contrast; on Linux, GNOME's color scheme and high-contrast settings, or GTK_THEME.
Terminal colors
textweaver uses as many colors as your terminal offers:
- Full color (Windows Terminal, most modern terminals): the theme's exact colors.
- 256 colors: the nearest colors the terminal has, chosen so every pair still meets the contrast minimum.
- 16 colors: the terminal decides what its 16 colors look like, so textweaver paints the page itself (black for dark themes, white for light) and uses only colors that stay readable in the common terminal color sets. Faint bands, such as the sentence band, are left out; the underline still shows the sentence. On light themes, headings are underlined instead of bold, because some terminals brighten bold text until it fades.
- No color: attributes only. Headings bold, links underlined, quotes italic, the spoken word in reverse video, the sentence underlined.
Inside tmux, and over SSH, a terminal usually gets 256 colors even when the terminal itself has full color. Set TEXTWEAVER_COLOR=truecolor if yours passes full color through.
With full color or 256 colors, the title and status lines sit on the panel color, so the spoken word's band is the one strong color on the screen; with 16 colors or none they keep reverse video. The reading ruler's mask draws the text outside the band in a color most of the way toward the page, the same mask the window draws; with 16 colors or none it uses the terminal's dim attribute.
To turn color off, set the NO_COLOR environment variable to any value, such as 1. To choose a level yourself, set TEXTWEAVER_COLOR to truecolor, 256, 16, or none. For example, in a Linux or macOS shell:
export TEXTWEAVER_COLOR=256
In a Windows command prompt:
set TEXTWEAVER_COLOR=256
textweaver never changes your terminal's own colors or cursor.
HTML output
Documents converted to HTML use textweaver's themes as CSS properties named --tw- and the color's key (--tw-background, --tw-dim-text): Galaxy, or Galaxy Light when the reader's system asks for light, and High Contrast when it asks for more contrast. A browser with a Windows contrast theme on uses its own colors. Links are underlined, and keyboard focus always shows a ring with a thin inner line.
A theme supplies colors only. The page's font, size, spacing, and line length come from your reading settings when you convert, so a theme written for an earlier version keeps working and a page looks like the reader whatever its colors; see how the page is set.
Highlighted code borrows the theme's text roles: keywords take the heading 2 color and are bold, comments take the dim text color and are italic, strings take the quote color, numbers heading 4, function names heading 1, and type names heading 3. Code blocks sit on the page background, where the theme's contrast check holds every one of these roles to the text floor; the terminal reader draws them the same way. textweaver's tests measure every color pair the page draws, in every built-in theme that meets WCAG AA, with the same checker described under contrast checks.
Writing your own theme
A theme is a small text file in TOML format. Put it in a folder called themes inside the configuration folder above, with a name ending in .toml. textweaver loads every theme there when it starts; your themes come after the built-in ones when you press F5.
The shortest theme
Two colors are enough. Everything else is worked out from them:
[theme]
name = "midnight"
[colors]
background = "#101820"
text = "#e8e8e8"
Colors are written as # and six hexadecimal digits (red, green, blue), or three digits for short.
Changing one thing in a built-in theme
Start from a built-in theme and change only what you want:
[theme]
name = "my-galaxy"
inherits = "galaxy"
[colors]
heading1 = "#e0d0ff"
Anything you leave out comes from the theme you inherit from. Styles are copied as they are, so if you change a color that a highlight uses (heading 1 is also the spoken-word band), set that highlight too.
To start from a complete copy instead, copy a built-in theme's file (in textweaver's source, crates/textweaver-theme/themes/) and change name.
Everything a theme can set
[theme]: name (letters, digits, and hyphens; the file name is used if it is missing), display_name (the name read aloud), kind (dark, light, or high-contrast; high contrast raises the text minimum to 7 to 1), description, author, counterpart (the light or dark partner), and inherits.
[colors]: background, surface (lists and panels), text, dim_text (hints, line numbers, rules; used on the page only), heading1 to heading6, link, code, code_background, quote, and error.
[colors] can also set fifteen interface colors. You rarely need to: each is worked out from your theme's own colors when it loads, and adjusted until it passes its check. A theme that inherits another works them out again from its own colors, unless the other theme set them in its file.
- Fills:
raised(buttons, fields, the selected row). - Text:
panel_dim_text(muted text on panels),on_accent(text on the accent), anddisabled(unavailable controls, 3 to 1). - Lines and marks, each 3 to 1 against what is beside them:
control_border,accent,caret,focus_inner(the thin line between a control and its focus ring),difficult_word,syllable_mark,misspelling, andlint. - Bands behind text:
ruler(the reading line) andruler_band(the rows around it). - Decoration only:
border(panel edges and dividers).
[theme] tags is a list of words describing a theme, such as tags = ["soft"].
[styles.NAME], one table each for selection, spoken_word, spoken_sentence, find_hit, current_find_hit, bookmark, note, status_bar, and focus. Each can set:
foreground: the text color inside the highlight.background: the band color, or"none"for no band.attributes: a list of"bold","italic","underline", and"reverse".
For example:
[styles.spoken_word]
foreground = "#101820"
background = "#ffd166"
attributes = ["bold"]
[[user_highlights]], repeated for each color you can highlight text with; each has a name and the same three keys:
[[user_highlights]]
name = "yellow"
background = "#5a4d10"
attributes = ["bold"]
Keys textweaver does not know are kept, so a theme written for a newer version still loads.
The highlights you make take their colors from your highlight palette, [[highlight.palette]] in your settings, not from the theme: each name has its own color and shape, so two names never differ by color alone (see Highlight colors). In the terminal reader the palette color is the band, with black or white text, whichever reads better on it. A theme's first [[user_highlights]] entry is the band only where the terminal shows 16 colors or none; each name's shape still tells them apart there.
Contrast checks
When textweaver loads your theme, it measures every color against what it sits on. Text needs 4.5 to 1 (7 to 1 in a high-contrast theme); the focus band needs 3 to 1 against the page. The spoken word's band needs 3 to 1 against the page and against the sentence's band, so the word stands out within its sentence. The sentence's band has no minimum: it is a soft tint, and the underline is what marks the sentence. Every highlight needs at least one attribute, and the spoken word must differ from its sentence, and the current find match from the others, by attribute and not only by color.
A theme that falls short still loads. textweaver tells you what to fix, for example: "Theme Midnight: 1 of 61 checks fail. Dim text on background: 4.0 to 1, needs 4.5 to 1."
If a file has a mistake, textweaver skips that file, loads the rest, and says which key or line is wrong, for example: "midnight.toml was not loaded: colors.text: "white" is not a color; write it as #rrggbb, for example #1e1e1e."
Previewing a theme
From textweaver's source folder, this prints a theme's contrast report and the colors each part gets at every terminal level, as plain text:
cargo run -p textweaver-theme --example preview -- galaxy
To preview your own theme file, give its path:
cargo run -p textweaver-theme --example preview -- path/to/midnight.toml
Add --swatch to also print sample lines in color, for sighted checking.
See also
- Reading aids: the ruler, RSVP, and bionic reading, which use the theme's colors.
- Settings: the
[display]settings. - Converting documents: HTML output uses these themes.
- ADR-0020: Themes: the design and the contrast rules. Its status update records which themes must meet AA.
- Interactive pages: the pages in
docs/site/use Galaxy and Galaxy Light. - Documentation index