@stnd/themes
v0.5.1
Published
--- title: "@stnd/themes" status: active maturity: tree type: package tags: - package - stnd ---
Readme
title: "@stnd/themes" status: active maturity: tree type: package tags:
- package
- stnd
@stnd/themes
Temperaments and design variations for the Standard Ecosystem.
Overview
@stnd/themes provides a collection of complete design systems, each with its own typographic context, color palette, and emotional register. These themes are built as Standard modules and can be swapped instantly to change the entire look and feel of an application.
Features
- Scoped Styling: Themes use CSS custom properties scoped to a specific element or the entire page.
- Typographic Context: Each theme defines its own font pairings, line heights, and spacing rhythms.
- Color Palettes: Custom OKLCH color offsets for each temperament.
- Module-Based: Themes are easily loaded and managed via the
@stnd/coreintegration.
Available Themes
- Academic: Scholarly and traditional.
- Editorial: Clean lines and high contrast.
- Humanist: Warm type and organic feel.
- Technical: Code clarity and precision.
- Gallery: Minimalist with generous white space.
- E-Ink: Optimized for e-readers and high-contrast displays.
- And many more: Baroque, Blueprint, Forest, Frank, Occult, etc.
Usage
In your astro.config.mjs:
import { defineConfig } from "astro/config";
import standard from "@stnd/core";
export default defineConfig({
integrations: [
standard({
moduleLoad: [
"@stnd/themes/editorial"
]
})
]
});To apply a theme to a specific element:
<div data-theme="garden">
<!-- Content will use the Garden theme -->
</div>Creating a Theme
To add a new theme to the Standard Ecosystem, create a new directory under packages/themes/<theme-name> and follow these steps:
1. Structure of a Theme Folder
Each theme must contain the following 5 files:
packages/themes/<theme-name>/
├── tokens.yaml # Canonical design token values (Single Source of Truth)
├── index.module.js # Module registration and dependencies
├── <theme-name>.scss # Web-only layout overrides and styling
├── register.js # Theme registration metadata (ID, Label, Description)
└── actions.js # Compass command palette triggers2. File Specifications
tokens.yaml
Specifies metadata and token values. Web-only structural CSS must stay in the .scss file.
meta:
id: reveal
label: Reveal
selector: |-
:root[data-theme="reveal"],
[data-theme="reveal"]
fonts:
- "@stnd/fonts/din-condensed"
- "@stnd/fonts/inter"
tokens:
color-light-background: "#fdfdfc"
color-light-foreground: "#212121"
color-accent: "#d6202c"
font-text: '"Inter", sans-serif'
font-header: '"DIN Condensed", sans-serif'
line-height: "1.2"After creating/updating this file, run the token builder to generate _tokens.generated.scss:
node packages/themes/tools/build-tokens.mjs <theme-name><theme-name>.scss
Sass stylesheet that overrides layout variables or implements theme-specific aesthetics. It must use @use "./tokens.generated";.
@use "./tokens.generated";
:root[data-theme="reveal"],
[data-theme="reveal"] {
background: var(--color-background);
h1 {
font-family: var(--font-header);
text-transform: uppercase;
}
}index.module.js
The module declaration. Defines styles and registers the font packages as dependencies so the loader loads them automatically.
export default {
id: "theme-<theme-name>",
name: "Stnd :: Theme :: <Label>",
description: "Registers the <Label> theme.",
meta: { type: "theme", themeId: "<theme-name>", label: "<Label>" },
styles: ["./<theme-name>.scss"],
dependencies: [
"@stnd/fonts/<font-package-name>"
],
};register.js
Exposes metadata used by the editor/UI theme dropdowns.
export default () => ({
id: "<theme-name>",
name: "<Label>",
description: "<Short description of the theme's mood>",
});actions.js
Registers a command palette action to apply and persist the theme (e.g. trigger ::theme-<theme-name>).
import Log from "@stnd/log";
import { saveVisitorPreferences } from "../../garden/Visitor";
const log = Log({ scope: "CompassTheme<Label>" });
export default [{
trigger: "::theme-<theme-name>",
meta: {
title: "<Label> Theme",
desc: "<Description>",
icon: "palette",
},
action: async () => {
if (typeof document !== "undefined") {
document.documentElement.setAttribute("data-theme", "<theme-name>");
}
await saveVisitorPreferences({ theme: "<theme-name>" });
window.toast("Theme applied", "success");
},
}];3. Registering the Theme in the Ecosystem
To make the theme available in the loader and workspace, you must add it to the dependencies list of the central themes module in packages/modules/themes/index.module.js:
dependencies: [
...
"@stnd/themes/<theme-name>",
]Source of truth & the sync tools (Resolved)
<theme>/tokens.yaml is the ONE source of token values. tools/build-tokens.mjs
regenerates each _tokens.generated.scss from it. Both consumers are downstream:
the web uses @stnd/themes directly, and the Obsidian plugin bundles
themes.generated.js (built from these same _tokens.generated.scss by
apps/stnd-obsidian/build.js). Edit tokens.yaml, never a .generated.scss.
🔄 Bidirectional Synchronization Tools
The historical design drift between Francis's hand-maintained vault notes at Kernel/Themes/* and the package's canonical codebase has been resolved. Two powerful automation scripts have been added under packages/themes/tools/ to enable seamless bidirectional syncing:
1. Export package themes to your vault
To populate your vault's Kernel/Themes/ folder with themes from the package (without overwriting any of your existing custom vault themes):
node packages/themes/tools/convert-themes-to-vault.jsThis parses each package's tokens.yaml and .scss overrides, generates clean Obsidian-friendly theme notes with frontmatter metadata, embeds, and nesting, and writes them into your vault.
2. Import vault modifications back to the package
If you edited design tokens or custom styling rules directly inside your Obsidian vault and want to merge those changes back into the package (centralizing them in git):
node packages/themes/tools/sync-vault-to-packages.jsThis tool:
- Scans
Kernel/Themes/*.mdfiles in your vault that match a package theme name. - Parses the CSS code block, separating the CSS variables (design tokens) from custom rule selectors.
- Merges the updated design tokens back into the package's
tokens.yaml. - Un-indents and updates the package's
<theme>.scsswith the custom layout rules.
After running either tool, simply rebuild the Obsidian plugin to package the latest themes:
# In apps/stnd-obsidian
pnpm run buildWhat's next — open
- [ ] Themes product decision (to discuss) — Francis creates a lot of them (10+), and loves doing so. Do we let users create their own (feature)? Do we ship all themes but only document ~6 of them? How do we manage curation vs. infinity?
- [ ] Terminology — Keep "theme" (like the frontmatter
theme:) rather than "temperament". Align the documentation once confirmed.
