INTERFACE · 03

Obsidian

Same palette, same readability — extended for Obsidian. Notes that make you want to use the markdown features and come back to read it later.

Install Theme

In context

A vault open with the file explorer on the left, a note in reading mode in the center, and the outline on the right — chrome surfaces sit at #0E170B, the note canvas at #0F180C.

Obsidian, default layout, forest-phosphor.css enabled.
ARCHITECTURE

The variable layer

The snippet has two layers. First, a private --fp-* palette declared on body.theme-dark — these are the tokens the rest of the file references. Second, a remap of Obsidian's own CSS variables to those tokens, so most of the app and its plugins pick up the theme without targeted selectors.

Layer 1 · The private --fp-* palette

  • --fp-bg-editor background
    #0F180C

    note canvas, gutters, terminal-style surface

  • --fp-bg-chrome background
    #0E170B

    tabs, ribbon, status bar — off-canvas chrome

  • --fp-bg-sidebar background
    #101C0C

    file explorer + form inputs

  • --fp-bg-elevated background
    #131C10

    inline-code, blockquote, section headers

  • --fp-bg-selected background
    #1A2C16

    active list row, hover-then-click

  • --fp-border-subtle border
    #1E3119

    default panel + tab borders

  • --fp-border-medium border
    #2E4A29

    hover state, input outline

  • --fp-fg-primary foreground
    #A2EBA1

    body text — design-system ink-primary

  • --fp-fg-heading foreground
    #7CBF78

    subtle labels, --text-muted

  • --fp-fg-muted foreground
    #4E7249

    inactive tabs, placeholders

  • --fp-fg-dim foreground
    #3D5E39

    line numbers, gutter glyphs

  • --fp-phosphor accent
    #7AF8FF

    signature cyan — variables, headings 1-3, internal links, focus

  • --fp-coral accent
    #EA9575

    attention — **bold** prose, unresolved links, errors, this/throw

  • --fp-blue accent
    #77B0FF

    properties, fields, info callouts, code-block property tokens

  • --fp-blue-link accent
    #328EEE

    legacy display-only link color (AA-large only)

  • --fp-magenta accent
    #C07AC8

    concrete shapes — class, struct, enum, decorators, tip / important callouts

  • --fp-orchid accent
    #FFB4E2

    abstract shapes — interface, type, generic, primitives, tags

  • --fp-amber accent
    #E8A030

    structural keywords — function, class, return, import, *italic* prose

  • --fp-yellow-fn accent
    #D1CF32

    callable — functions, methods, external links

  • --fp-yellow accent
    #D4D256

    CSS-specific yellow — id/class selectors, question callouts

  • --fp-white accent
    #E8F0E8

    literals — numbers, booleans, null, lifetimes, delimiters

  • --fp-green-string accent
    #73E165

    string literals in code

  • --fp-green-comment accent
    #5C8656

    comments — italic, dimmer than ink-muted

  • --fp-error status
    #EA9575

    aliased to coral

  • --fp-warning status
    #D4A24A

    gold — destructive actions, warning callouts

  • --fp-success status
    #5AE66A

    success green (a hair cooler than green-string)

  • --fp-info status
    #77B0FF

    aliased to blue — info callouts, info-tone UI states

  • --fp-deprecated accent
    #DD7975

    desaturated coral — deprecated tokens, strikethrough

Layer 2 · Remapping Obsidian's variables

The "clean layer" — most of Obsidian (and any plugin that reads Obsidian's CSS vars) cascades correctly once these are remapped. Targeted selectors only appear where the variable layer can't reach.

Obsidian variableMaps toNote
--background-primary--fp-bg-editornote body canvas
--background-secondary--fp-bg-sidebarsidebar column
--background-secondary-alt--fp-bg-chromechrome surfaces
--background-modifier-border-focus--fp-phosphorcyan focus ring
--text-normal--fp-fg-primarybody text
--text-muted--fp-fg-headingObsidian's "muted" maps to the brighter heading-green
--text-faint--fp-fg-mutedplaceholders, inactive labels
--text-accent--fp-phosphorcyan signature
--interactive-accent--fp-phosphorprimary buttons, switches
--link-color--fp-phosphorbase link var — Obsidian reads this for internal links (cyan); external links are overridden separately by --link-external-color
--link-external-color--fp-yellow-fnexternal links share the callable role
--link-unresolved-color--fp-coralbroken / new internal links — coral attention, 75% opacity
--h1-color … --h3-color--fp-phosphortop three heading levels are cyan
--h4-color … --h5-color--fp-fg-headingsubordinate headings step down to heading-green
--h6-color--fp-fg-mutedlowest level fades to muted
--tag-color--fp-orchidtags are abstract — orchid pink, like an interface or generic
--code-keyword--fp-amberstructural keywords — function, class, return, import
--code-function--fp-yellow-fncallable — functions and methods
--code-property--fp-blueobject keys, fields, attributes
--code-value--fp-whiteliteral values — numbers, booleans, null
--code-tag--fp-amberHTML tags — structural, like function
--code-imports--fp-amberimport statements — structural
--code-string--fp-green-stringstring literals in code blocks — bright green
--code-comment--fp-green-commentcomments — darker italic green, distinct from string literals
--code-important--fp-coral!important / error-weight tokens — coral attention
--bold-color--fp-coral**bold** prose carries attention weight
--italic-color--fp-amber*italic* prose maps to the structural accent
--blockquote-border-color--fp-phosphorblockquote left rule
MARKDOWN

Markdown elements

Both edit-mode CodeMirror classes (.cm-strong, .cm-em, .cm-link…) and read-mode .markdown-rendered selectors are styled together, so the colors don't shift when you toggle preview.

phosphor-field-notes.md md
# Phosphor field notes

A few observations after a week of running the snippet.

- Cyan is the cursor — your eye finds it first.
- **Coral** carries bold weight; *amber* carries italic.
- [[Day one]] notes link back; [[Day zero]] is unresolved.

> Notes are read more than they are written.
> Tune the body first.

```ts
const ink = palette.ink.primary;
```

> [!tip] Pair with a serif body
> Long sessions favor a slightly warm reading face.

> [!warning] Snippet, not theme
> Drop into `.obsidian/snippets/`, not `themes/`.

>[!note] Enjoy Reading and Writing
>One of my favorite features of Obsidian is the ability to create an
>interface to organize my thoughts in a way that helps me
>__articulate__ my thoughts in a way that requires deep thinking -
>>[!tip] And...
>>When done properly, it makes it easier for me to come back through
>>them to *understand them again*!
ElementColorSelector
h1 / h2 / h3 #7AF8FF.cm-header-1, .markdown-rendered h1
h4 / h5 #7CBF78.cm-header-4, .markdown-rendered h4
h6 #4E7249.cm-header-6, .markdown-rendered h6
**bold** #EA9575.cm-strong, .markdown-rendered strong
*italic* #E8A030.cm-em, .markdown-rendered em
inline `code` #7AF8FF.cm-inline-code, code:not(pre code)
#tag #FFB4E2.cm-hashtag, .tag
> blockquote #7CBF78.markdown-rendered blockquote
[external](…) #D1CF32.cm-link, a.external-link
[[wikilink]] #7AF8FF.internal-link, .cm-hmd-internal-link
[[broken]] #EA9575.internal-link.is-unresolved
- list / 1. ordered #7AF8FF.markdown-rendered li::marker
| table | #7AF8FF.markdown-rendered th
CODE

Fenced code blocks

Obsidian uses Prism.js, which has coarser scopes than the VS Code TextMate grammar — a few distinctions collapse, but the visually important mappings are preserved or compensated for. Fenced blocks share the same --fp-bg-elevated (#131C10) surface as inline code; the structural differences are a 6px radius and 1em padding instead of inline's 4px radius and tight em-padding.

comment / prolog
// note #5C8656

darker than --text-muted, italicized

keyword / storage / atrule
function #E8A030

amber — structural: function, class, return, import, CSS @-rules

operator / entity
=> #A2EBA1

foreground — operators read with the language flow

punctuation
{ } ; #A2EBA1

foreground — brackets, semicolons, commas should not shout

string / regex / attr-value
"phosphor" #73E165

string literals, attr values, regex bodies

number / boolean
42 true #E8F0E8

near-white — literal data values

constant / symbol
PHOSPHOR #7AF8FF

cyan — named constants and macro symbols

function / method
render() #D1CF32

yellow — callable: declarations and calls share the role

builtin
console #7AF8FF

cyan — built-in objects/functions group with variables

class-name / namespace
class Palette #C07AC8

magenta — concrete shapes you instantiate

interface / type-name
interface User #FFB4E2

orchid — abstract shapes: interface, type alias, generic

property / attr-name
fp.ink #77B0FF

blue — object keys, fields, HTML attrs

tag
<section> #E8A030

amber — HTML tags are structural, like function

variable
userId #7AF8FF

cyan — what is this thing

parameter
depth #A2EBA1

foreground italic — labels for incoming values, read with the language

decorator / annotation
@inject #C07AC8

magenta italic — concrete attached metadata

CSS selector (.id / #class)
.is-active #D4D256

CSS-specific yellow — id and class selectors

CSS pseudo-class
:hover #FFB4E2

orchid italic — abstract contract on a selector

CSS hex / color
#7AF8FF #E8F0E8

white — literal value, like a number

inserted
+ added #5AE66A

diff +

deleted
- removed #D4A24A

diff − — gold, never red

invalid / deprecated
oldFn #EA9575

coral — invalid underlined, deprecated strikethrough

CALLOUTS

Callout colors

Forest Phosphor groups Obsidian's built-in callout types into 9 color families, one palette color each. Every family derives four surfaces from a single color. From a chosen hex, we derive a --callout-color: R, G, B triplet. The label is the raw hex equivalent at full opacity, the background tints at rgba(…, 0.08), the border firms up at rgba(…, 0.35), and an inset glow blooms at rgba(…, 0.04). One source, four layers.

#64C8FF -> 100, 200, 255
note

bluer phosphor — separates from code surfaces

#77B0FF -> 119, 176, 255
info, todo

function-blue — generic context

#C07AC8 -> 192, 122, 200
tip, hint, important

magenta — recommendations, key takeaways

#5AE66A -> 90, 230, 106
success, check, done

success-green — completed items

#D4D256 -> 212, 210, 86
question, help, faq

yellow — open questions

#D4A24A -> 212, 162, 74
warning, caution, attention

gold — non-blocking caveats

#EA9575 -> 234, 149, 117
failure, fail, missing, danger, error, bug

coral — breaking, errors, bugs

#C07AC8 -> 192, 122, 200
example

magenta — same family as tip / important

#7CBF78 -> 124, 191, 120
quote, cite

heading-green italic — blends with blockquotes

CHROME

UI chrome

Three workbench surfaces, each painted directly because Obsidian’s variable layer doesn’t reach them.

--fp-bg-chrome
#0E170B

tabs, ribbon, status bar strip

--fp-bg-editor
#0F180C

note canvas, active tab bg

--fp-bg-sidebar
#101C0C

file explorer, side splits

--fp-bg-elevated
#131C10

hover state, caret line bg

--fp-bg-selected
#1A2C16

active file row, click target

--fp-fg-heading
#7CBF78

idle ribbon icons, secondary labels

--fp-phosphor
#7AF8FF

active tab border-top, active file text, status bar main text

focusBorder
#7AF8FF80

phosphor @ 50% — focus ring on modals and inputs

.cm-cursor
#FFFFFF

pure white — only non-palette accent in the theme

.cm-selectionBackground
#4A7ACC

#4A7ACC40 — cool blue selection highlight

SETUP

Install

Below, you can download the raw ForestPhosphor.css file. This is a CSS snippet, not a community theme. It lives in .obsidian/snippets/ and toggles on alongside whatever base theme you're running. Use the default Obsidian theme with this Snippet to get the intended look and feel; it has not been tested with any other theme and may have conflicts or visual bugs if you layer it on top of something with heavy overrides.

install.sh bash
# 1. Find your vault path. Then:
cd "/path/to/your-vault/.obsidian/snippets"

# 2. Drop the snippet in (mkdir -p first if snippets/ doesn't exist yet)
mkdir -p .
curl -O https://github.com/Steven-Theuerl/forest-phosphor-obsidian/blob/trunk/ForestPhosphor.css

# 3. In Obsidian:
#    Settings → Appearance → CSS snippets → reload (refresh icon)
#    → toggle "ForestPhosphor" on

# 4. Make sure base appearance is dark
#    Settings → Appearance → Base color scheme → Dark

Where to find .obsidian/snippets/: it's hidden inside your vault folder. On macOS you can press Cmd-Shift-. in Finder to reveal dot-folders, or use the path bar in any terminal. Obsidian itself will mkdir the snippets folder the first time you open Appearance → CSS snippets.

TIPS & TROUBLESHOOTING

Tips & troubleshooting

The snippet does not set fonts. Pick yours under Obsidian → Settings → Appearance. Two free and recommended pairing fonts match the iTerm profile — Ioskeley-Mono for code, and iA Writer Quattro for all body content outside of codeblocks; but of course, use whatever you like.