Loremaster — Devlog Part 1 of 3: The Vault Made Visible
Been quiet on the tool front but I've been building something I've wanted for a long time. Meet Loremaster (codename, not final name) — a local companion dashboard for my Obsidian D&D vault. It's read-mostly, runs at localhost:8000, and turns 100+ scattered markdown notes into a browseable, type-aware world reference.
This is Part 1 of the devlog. Part 2 covers the DM-at-the-table screen. This one is about the foundation: how the vault got structured, and how every note type earned its own layout.
The problem
Obsidian is great for writing, but I run Echoes of the Dreaming Stone and my world Elystraea has grown — 40+ locations, dozens of NPCs, a pantheon, organizations, lore artifacts, and a growing pile of session notes. Finding anything mid-session meant fumbling through folders, hitting Cmd+O, guessing filenames. Obsidian shows me the note. It doesn't show me the world.
I wanted a browser that understood what kind of note I was looking at. A city should look different than a god. A player character card should surface AC and HP; a lore artifact should surface its owner and creator. Same underlying notes — different faces.
The stack (honestly)
Python + FastAPI, server-rendered HTML, no build step, no JavaScript framework. Point it at your vault folder, run uvicorn app:app --reload, open localhost:8000. That's it. Every screen is server-rendered from your actual .md files with YAML frontmatter — no database, no sync, no accounts. The vault stays the source of truth; Loremaster just reads it.
Read-mostly by design: it writes back to your notes only through an explicit tagging wizard for folders you've opted in. The rest is display.
The foundation: type-aware everything
The core idea is that every note declares a type: in its frontmatter (npc, pc, location, organization, lore, extraplanar, session, recap, etc.), and Loremaster dispatches to a rendering tailored for that type. So a type: npc note gets a portrait-left dossier with combat stats and faction chips; a type: location note gets a map-banner layout with geographic ancestry.
The type system is folder-proof — you can move a note anywhere in your vault and as long as type: is set, it shows up in the right place.
Locations: the first big test
Locations are hierarchical (a city sits in a region sits in a realm sits in a continent sits in a world), so they got three views:
- Grid: flat, searchable cards with a color-coded breadcrumb trail
- Grouped: cards clustered under a chosen tier (group by Realm / Region / City)
- Tree: the indented outline
The tree has one clever bit I'm proud of: it's realm-aware. Geographic parent chains climb through continent → world, but if a region belongs to a realm (like Stonecrest Valley belonging to Dwarven Lands), the tree "jumps" to nest it under the realm at the boundary where geography would leave the realm. So the tree reads as political governance (Realm → Region → City → Village) while the grid stays geographic. Two views, same data, different lenses.
Every tier got its own color: Realm rose, Region periwinkle, City amber, Village tan, Geographic Feature teal, City Ruin red, Point of Interest green. Colors carry through breadcrumbs, card labels, and tree badges — same tier looks the same everywhere.
The dossier system
Every character-type note (NPC, PC, Companion, and later Pantheon entities) got the same layout: portrait-left rail with an Identity panel underneath, main column with tailored sections. The zones are defined per-type in code, so an NPC's dossier has zones like "Physicality / Combat / Personality" while a PC's has "Class & Level / Allegiance / Combat / Roleplay."
The lesson I learned the hard way here: build against real frontmatter, never guessed field names. Every time I guessed at what fields you'd have (class_level? char_class?), I built it and had to redo it. Every time I asked for one real note and built against that, it landed first try. This became the pattern for every subsequent type — send me one real note, get it right immediately.
Player Characters
PCs got their own section mirroring NPCs — card grid with search + Class/Race/Faction filters, plus a Grid / By Campaign toggle so all your parties can live in one section without stepping on each other. Each card shows portrait, character name, "Level N Race Class," ":performing_arts: played by [player]," faction chips, and AC/HP/INIT tiles. The By Campaign view clusters PCs under campaign headers so I can see all my parties at a glance.
Campaign is shown both as a card label AND as a filter dropdown — solves the "which party is this?" problem without adding another mode to manage.
Pantheon (divine and extraplanar)
Gods, archfey, demon lords, elementals, genies — all the beings that aren't quite mortal NPCs. Given a dedicated type (extraplanar) with a schema I designed around what actually matters for a divine being: divine rank, pantheon, domains, portfolio, symbols, holy weapon, home plane, seat of power, worshippers, allies, enemies, artifacts, avatar form. The dossier zones mirror those groupings directly.
The card grid at /entities filters by type (Deity / Warlock Patron / Archdevil / etc.), rank, alignment, and pantheon. Sehanine appears as "Greater Deity · The Dawn War Pantheon" with Light/Life/War domain chips. Asmodeus as "Archdevil · The Lords of the Nine." One layout that scales from a single deity to a full pantheon.
Societies (organizations)
Organizations don't have a geographic hierarchy of their own, but they have headquarters — and headquarters are locations. So the org tree nests an organization under its HQ location, then climbs that location's chain capped at realm (never continent or world). The result: one realm-rooted tree per realm, with organizations sitting under whatever tier they call home — a city, a village, a region, or the realm itself directly.
A guild HQ'd in Glimmerstone Hold sits under Stonecrest Valley under Dwarven Lands. The Dwarven Crown, HQ'd directly in the realm, sits right at the top. Realm is always derived from the HQ chain, never stored on the org — so the org itself doesn't need to know its realm; the location tells us.
Chronicles (lore)
Lore is flat — an artifact has no parent artifact — so no tree. But it does have categories: artifacts now, cosmology and historical timelines later. So Chronicles got Grid + Grouped-by-category + a tree-styled List view that groups chronicles under their category headers (Artifact / Cosmology / Historical Timeline) with owner badges next to each.
The Moonveil Prism note has a full rich body (embedded artifact image, "Corrupted Use / Why It Works" headings, dozens of wikilinks) — all rendered inline in the dossier with clickable links and foldable headings.
Header pills
Body headings inside every note render as color-coded pills sized by level. H1 largest and gold, H2 rose, H3 periwinkle, H4 teal, H5 sage, H6 muted. Each is click-to-collapse. The visual hierarchy makes it easy to navigate a long note — you can see the outline at a glance, fold what you don't need. Nothing collapsed by default; every note opens fully expanded.
Folds persist per-note in the browser's localStorage. Fold a section, come back later, it's still folded. Fold it in another note — that note is unaffected.
The unglamorous stuff
Not everything was a big feature. Some of the most valuable work was fixing small papercuts:
- Wikilinks in chips: card pills were showing the literal
[[Brackets]]syntax instead of clean text. Fixed at the source — one helper strips wikilinks so anywhere frontmatter list values (factions, domains, allies) become chips, they read cleanly. ==highlight==support: Obsidian's highlight syntax now renders as a crimson inline pill with a d20 icon, since I use it to mark "roll initiative" or "ask for a Perception check" cues in my session notes. Distinct enough from the header pills that the eye locks onto it as a thing to do at the table.- Ampersands, escape bugs, layout quirks: fixed as they came up.
Where this leaves things
Every note type in my vault now has a home. The main sections are:
- NPCs — card grid + dossier
- Player Characters — card grid, dossier, campaign filter + group toggle
- Pantheon — card grid + dossier for divine/extraplanar beings
- Locations — grid / grouped / realm-aware tree
- Societies — grid / grouped / HQ-rooted tree capped at realm
- Chronicles — grid / grouped / tree-styled list by category
All type-aware, all filterable, all searchable, all cross-linked.
That's the foundation. Part 2 is about turning this into a live DM screen for running actual sessions — the unified Sessions section, the "previously on…" recap panel, the dynamic side panel that shows only the NPCs/locations currently on screen, and the tool iframes for the NPC Conjurer and Loot Roller. That one's next.