4.1 Architecture
An overview of how @stnd packages compose to power both static sites and server-rendered applications — and how the theme token pipeline flows from author to screen.
The two modes
@stnd is not a framework. It is a set of packages that you compose into an Astro project. The same packages work in both modes — the difference is what you bring at runtime.
graph LR
subgraph Static["Static (SSG)"]
direction TB
V[Local vault / files] --> L["@stnd/loader"]
L --> P["@stnd/press"]
P --> H[HTML + CSS]
H --> CDN[Deploy to CDN]
end
subgraph SSR["Server (SSR)"]
direction TB
R[Request] --> S["@stnd/server"]
S --> DB[(D1 / R2)]
DB --> P2["@stnd/press"]
P2 --> H2[HTML + CSS]
H2 --> Edge[Cloudflare Workers]
end
Shared["@stnd/styles\n@stnd/themes\n@stnd/utils\n@stnd/icon\n@stnd/ui"] -.-> Static
Shared -.-> SSR
Static mode (SSG)
Used by: portfolio, documentation sites, personal blogs.
You write markdown in a local vault. At build time, @stnd/loader reads the files, @stnd/press renders them to HTML with typography transforms, and @stnd/styles + @stnd/themes apply the design system. Output is static HTML deployed to any CDN.
What you get:
@stnd/core— Astro integration, module orchestration@stnd/loader— Vault file discovery and content loading@stnd/press— Markdown → HTML rendering, typography, mermaid, math@stnd/styles— CSS design tokens, golden-ratio scale, color system@stnd/themes— Named theme variations (humanist, editorial, academic, etc.)@stnd/layout— Base/Meta layouts@stnd/icon— Icon system (Iconify, ph, mingcute)@stnd/ui— Reusable components (Astro + Svelte)@stnd/fonts— Curated open-source typefaces
What you don’t need:
@stnd/server(no auth, no sessions)@stnd/account(no users)@stnd/cloudflare(no Workers runtime)
Server mode (SSR)
Used by: stnd.gd (Standard Garden), interactive apps.
Content lives in Cloudflare D1 (metadata) and R2 (markdown files). Requests hit Cloudflare Workers, authenticate via @stnd/account, load content from storage, render through @stnd/press, and serve HTML at the edge.
Additional packages for SSR:
@stnd/server— Auth middleware, CORS, error handling, i18n@stnd/account— Authentication (OAuth, passkeys, magic links, D1)@stnd/cloudflare— Image optimization, Pages Functions@stnd/launcher— Command palette with views and search@stnd/store— Provide/inject service registry for shared state@stnd/ai— AI integration (OpenRouter)@stnd/ingest— Document conversion (DOCX, PDF, HTML → Markdown)
Package layers
graph BT
subgraph SHARED["Shared — No opinionated deps"]
log["@stnd/log"]
utils["@stnd/utils"]
styles["@stnd/styles"]
fonts["@stnd/fonts"]
themes["@stnd/themes"]
end
subgraph CORE["Core — Astro infrastructure"]
core["@stnd/core"]
server["@stnd/server"]
modules["@stnd/modules"]
end
subgraph FEATURE["Feature — Capabilities"]
press["@stnd/press"]
client["@stnd/client"]
ui["@stnd/ui"]
icon["@stnd/icon"]
store["@stnd/store"]
layout["@stnd/layout"]
launcher["@stnd/launcher"]
cloudflare["@stnd/cloudflare"]
account["@stnd/account"]
ai["@stnd/ai"]
ingest["@stnd/ingest"]
end
subgraph TOOLS["Tools"]
lab["@stnd/lab"]
cli["@stnd/cli"]
art["@stnd/art"]
end
CORE --> SHARED
FEATURE --> CORE
FEATURE --> SHARED
TOOLS --> FEATURE
Every package is independent. You only import what you use.
Theme token pipeline
The design system flows from author intent to rendered pixels through a single data path. The canonical token list lives in packages/utils/theme-tokens.js — all consumers read from this one file.
flowchart TD
A["Author writes frontmatter tokens\n(foreground, font-header, accent, ...)"] --> B{Where?}
B -->|Obsidian vault| C["Obsidian plugin reads KNOWN_TOKENS\napplies --key CSS vars in editor"]
B -->|Web editor| D["Writer.astro writes canonical keys\ninto frontmatter"]
B -->|profile.standard.md| E["author-defaults.js extracts CSS vars\nmaps to canonical FM keys"]
C -->|Publish via API| F["PUT /api/publish/slug"]
D --> F
E --> G["mergeAuthorDefaults\n(author defaults + note FM)"]
F --> H["Note model stores\nfrontmatter JSON in D1"]
G --> H
H --> I["Note.inlineStyle getter"]
I --> J["TOKEN_MAP_RAW → sanitize → --key: value\nTOKEN_MAP_QUOTED → sanitize → --key: 'family'"]
J --> K["<html style='--foreground: #1a1a1a;\n--font-header: Georgia; ...'>"]
subgraph Static path
L["Vault files"] --> M["prepareNotePage()"]
M --> N["Same TOKEN_MAP_RAW / QUOTED\nNo sanitization (trusted)"]
N --> K
end
Token categories
| Category | Examples | Sanitizer |
|---|---|---|
| Color seeds | accent, foreground, background |
sanitizeCssColor |
| Light/dark palette | color-light-background, color-dark-accent, color-light-red … |
sanitizeCssColor |
| Font families | font-header, font-text, font-interface, font-monospace |
sanitizeCssFontFamily (quoted) |
| Typography metrics | font-header-weight, optical-ratio, font-density |
sanitizeCssNumber or sanitizeCssValue |
| Fine color | color-header, color-bold, color-italic, color-accent |
sanitizeCssColor |
| Layout | line-width, margin, margin-block |
sanitizeCssNumber |
All tokens follow one rule: the frontmatter key is the CSS custom property name without --.
How tokens get to the page
SSR (stnd.gd): Note model’s inlineStyle getter reads frontmatter → sanitizes each value → emits --key: value pairs → injected as style attribute on <html>.
Static (portfolio): prepareNotePage() in note.ts reads frontmatter → emits --key: value pairs (no sanitization, trusted source) → injected as style attribute on <html>.
Obsidian plugin: applyFrontmatter() reads frontmatter → emits --key: value CSS vars on :root via a <style> element → auto-imports Google Fonts for font tokens.
Attachment lifecycle
When publishing from Obsidian, images are uploaded before the note exists. The system tracks them so cleanup works correctly on delete.
sequenceDiagram
participant O as Obsidian Plugin
participant A as POST /api/publish/attachment
participant P as PUT /api/publish/slug
participant R2 as Cloudflare R2
participant D1 as Cloudflare D1
O->>A: Upload image (file + slug)
A->>R2: PUT {userId}/obsidian/{slug}/{uuid}.ext
A->>D1: INSERT attachments (if note exists)
Note over A,D1: If note doesn't exist yet, row is skipped
O->>P: Publish note (content + title)
P->>D1: Note.create or Note.update
P->>P: backfillAttachments()
P->>D1: Scan content for /cdn/... URLs
P->>D1: INSERT missing attachment rows
Note over P,D1: Now all R2 objects have DB records
O->>P: DELETE /api/publish/slug
P->>D1: SELECT attachments WHERE nano_id = ?
P->>R2: DELETE each attachment by R2 key
P->>D1: DELETE note + edges + attachments
Module system
@stnd/core scans for index.module.js files in your project’s modules/ directory. Each module declares its routes, hooks, config, and launcher commands.
// modules/blog/index.module.js
export default {
id: "blog",
name: "Blog",
routes: [
{ path: "/blog/", entrypoint: "./index.astro" },
{ path: "/blog/[slug]", entrypoint: "./route.astro" },
],
hooks: {
"launcher:view": [
{ trigger: "::new-post", component: "./views/NewPost.svelte" },
],
},
};
Modules are self-contained directories with their own routes, layouts, components, models, and views. @stnd/core wires them together at build time.
Key files
| What | Where |
|---|---|
| Canonical token list | packages/utils/theme-tokens.js |
| CSS sanitizers | packages/utils/css.js |
| Note model (SSR) | apps/stnd.gd/modules/core/models/Note.ts |
| Note helper (static) | apps/portfolio/modules/core/lib/note.ts |
| Author defaults | apps/stnd.gd/modules/core/models/author-defaults.js |
| Obsidian plugin | apps/stnd-obsidian/main.js (orchestrator) + src/core/design-system/ |
| Publish API | apps/stnd.gd/modules/api/routes/api/publish/[slug].ts |
| Attachment API | apps/stnd.gd/modules/api/routes/api/publish/attachment.ts |
| Design system CSS | packages/styles/ |
| Theme variations | packages/themes/ |
Security & Edge Resilience
During the Summer 2026 architectural audit, the edge-native capabilities of the system were formally verified:
- Stateless Authentication: Better-Auth combined with Kysely-D1 is dynamically initialized per request. This definitively prevents the “Worker singleton context leakage” anti-pattern.
- Provide/Inject Topography: The Svelte 5
$stateandnanostoresimplementations via@stnd/storeguarantee that Astro Islands never bleed state across boundaries. - Zero-JS Validation: Adherence to “CSS-First” UI components (
@stnd/ui) ensures that structural payload remains negligible, aligning with the EPA/NASA standards of industrial efficiency.