diff --git a/README.md b/README.md index 02ed593..59b9524 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,16 @@ Three core modules form the **ingest → drive → emit** spine: `source` brings events in, `state` decides what happens, and `sink` fans the resulting effects out. Each is a thin seam you can adopt on its own, and none imports another. + ```mermaid +%%{init: {'theme':'base','themeVariables':{'background':'transparent','primaryColor':'#8a929c','primaryBorderColor':'#d9620a','primaryTextColor':'#16191d','lineColor':'#b06a28','defaultLinkColor':'#b06a28','titleColor':'#b5500c','mainBkg':'#8a929c','nodeBorder':'#d9620a','nodeTextColor':'#16191d','labelColor':'#16191d','edgeLabelBackground':'#c0c7cf','altBackground':'#aab1ba','clusterBkg':'#aab1ba','clusterBorder':'#d9620a'}}}%% flowchart LR streams[(external streams)] -->|source| engine[state engine] engine -->|sink| destinations[(destinations)] @@ -59,6 +68,7 @@ folds an event into a new instance and emits effects as plain data, leaving persistence and dispatch to the host. ```mermaid +%%{init: {'theme':'base','themeVariables':{'background':'transparent','primaryColor':'#8a929c','primaryBorderColor':'#d9620a','primaryTextColor':'#16191d','lineColor':'#b06a28','defaultLinkColor':'#b06a28','titleColor':'#b5500c','mainBkg':'#8a929c','nodeBorder':'#d9620a','nodeTextColor':'#16191d','labelColor':'#16191d','edgeLabelBackground':'#c0c7cf','altBackground':'#aab1ba','clusterBkg':'#aab1ba','clusterBorder':'#d9620a'}}}%% stateDiagram-v2 [*] --> Idle Idle --> Working: Start [guard] @@ -74,6 +84,7 @@ Consumes external streams (Kafka, JetStream, Redis, CDC, and more) and drives a machine, with the ack tied to a durable transition so redelivery is safe. ```mermaid +%%{init: {'theme':'base','themeVariables':{'background':'transparent','primaryColor':'#8a929c','primaryBorderColor':'#d9620a','primaryTextColor':'#16191d','lineColor':'#b06a28','defaultLinkColor':'#b06a28','titleColor':'#b5500c','mainBkg':'#8a929c','nodeBorder':'#d9620a','nodeTextColor':'#16191d','labelColor':'#16191d','edgeLabelBackground':'#c0c7cf','altBackground':'#aab1ba','clusterBkg':'#aab1ba','clusterBorder':'#d9620a'}}}%% flowchart LR stream[(stream)] --> decode[decode / codec] --> route["route to (key, event)"] --> fire["Fire on instance"] --> commit[durable commit] --> ack[ack] ``` @@ -84,6 +95,7 @@ Fans emitted effects out to many destinations through a `Manifold`, fire-and-forget; one outlet's failure never stops the rest. ```mermaid +%%{init: {'theme':'base','themeVariables':{'background':'transparent','primaryColor':'#8a929c','primaryBorderColor':'#d9620a','primaryTextColor':'#16191d','lineColor':'#b06a28','defaultLinkColor':'#b06a28','titleColor':'#b5500c','mainBkg':'#8a929c','nodeBorder':'#d9620a','nodeTextColor':'#16191d','labelColor':'#16191d','edgeLabelBackground':'#c0c7cf','altBackground':'#aab1ba','clusterBkg':'#aab1ba','clusterBorder':'#d9620a'}}}%% flowchart LR effect[emitted effect] --> manifold[Manifold] manifold --> a[destination A] diff --git a/docs/astro.config.mjs b/docs/astro.config.mjs index 79fa6ac..12f8bb6 100644 --- a/docs/astro.config.mjs +++ b/docs/astro.config.mjs @@ -2,6 +2,7 @@ import { defineConfig } from 'astro/config'; import starlight from '@astrojs/starlight'; import mermaid from 'astro-mermaid'; +import { crucibleMermaidThemeVariables } from './src/mermaid-theme.mjs'; // GitHub project page: https://stablekernel.github.io/crucible // `site` + `base` must match the Pages URL so generated links and assets resolve. @@ -13,11 +14,27 @@ export default defineConfig({ // Chosen over rehype-mermaid because it needs no headless browser (Playwright) // at build time, keeping the CI `npm run build` step fast and dependency-light. // It registers a remark plugin that transforms mermaid code blocks into a - // hydrated
element. `theme: 'dark'` matches the
- // dark-default Crucible brand; mermaid auto-syncs when the user toggles theme.
+ // hydrated element.
+ //
+ // Theming is centralized in ./src/mermaid-theme.mjs and applied to every
+ // diagram on the site (all stateDiagram-v2 + flowchart blocks, and the
+ // diagrams generated by tools/docsgen). We build on mermaid's `base` theme
+ // because it is the only theme that honors `themeVariables`, and pass the
+ // crucible brand palette through `mermaidConfig` (astro-mermaid forwards it
+ // verbatim to mermaid.initialize()).
+ //
+ // autoTheme is OFF deliberately. When on, the integration swaps in stock
+ // 'dark'/'default' mermaid themes per page mode, which discards most of our
+ // base themeVariables on toggle. astro-mermaid exposes a single mermaidConfig
+ // (no per-mode themeVariables), so to keep one source of truth we render the
+ // dark brand palette in both page modes. Dark charcoal nodes with white text
+ // stay legible on a light page the same way a fenced code block does.
mermaid({
- theme: 'dark',
- autoTheme: true,
+ theme: 'base',
+ autoTheme: false,
+ mermaidConfig: {
+ themeVariables: crucibleMermaidThemeVariables,
+ },
}),
starlight({
title: 'Crucible',
diff --git a/docs/src/mermaid-theme.mjs b/docs/src/mermaid-theme.mjs
new file mode 100644
index 0000000..18b8bdc
--- /dev/null
+++ b/docs/src/mermaid-theme.mjs
@@ -0,0 +1,65 @@
+// Crucible "foundry" mermaid theme — the single source of truth for diagram
+// colors across the docs site (every stateDiagram-v2 + flowchart, plus the
+// diagrams generated by tools/docsgen → ToMermaid).
+//
+// These hexes mirror the brand tokens in src/styles/crucible.css and the
+// %%{init}%% directives in the repo-root README.md. Keep all three in sync.
+//
+// Identity: molten ember/copper accents over a deep steel/charcoal base.
+// The brand is dark-default, so we build on mermaid's `base` theme — the only
+// theme that honors `themeVariables` (see https://mermaid.js.org/config/theming.html)
+// — with `darkMode: true` so derived shades resolve for a dark canvas. Every
+// variable name below is a documented mermaid theme variable; nothing invented.
+export const crucibleMermaidThemeVariables = {
+ darkMode: true,
+ background: '#16191d', // deep steel base canvas
+
+ // Primary nodes: charcoal surface, molten-ember border, white label.
+ primaryColor: '#23272c',
+ primaryBorderColor: '#d9620a', // ember-orange
+ primaryTextColor: '#f4f6f8',
+
+ // Edges / links: copper, with ember-glow reserved for emphasis (titles).
+ lineColor: '#c47a3d', // copper
+ defaultLinkColor: '#c47a3d',
+
+ // Secondary nodes: lighter charcoal panel, copper border.
+ secondaryColor: '#353b42',
+ secondaryBorderColor: '#c47a3d',
+ secondaryTextColor: '#f4f6f8',
+
+ // Tertiary / deep-composite + subgraph fills: nav-dark with a steel hairline.
+ tertiaryColor: '#1b1f24',
+ tertiaryBorderColor: '#2b3036',
+ tertiaryTextColor: '#e3e7ec',
+
+ // Flowchart specifics.
+ mainBkg: '#23272c',
+ nodeBorder: '#d9620a',
+ nodeTextColor: '#f4f6f8',
+ clusterBkg: '#1b1f24', // subgraph background
+ clusterBorder: '#c47a3d',
+ titleColor: '#f6a85b', // ember-glow emphasis on subgraph/diagram titles
+ edgeLabelBackground: '#23272c',
+
+ // stateDiagram-v2 specifics.
+ labelColor: '#f4f6f8',
+ altBackground: '#353b42', // deep composite-state background
+
+ // General text + notes.
+ textColor: '#f4f6f8',
+ noteBkgColor: '#353b42',
+ noteTextColor: '#f4f6f8',
+};
+
+// astro-mermaid passes `mermaidConfig` straight through to mermaid.initialize().
+// We pin `theme: 'base'` here too because base is the only themeVariables-aware
+// theme; the integration spreads this config and (when autoTheme is on) would
+// otherwise swap in stock 'dark'/'default'. We keep autoTheme OFF in the astro
+// config so the dark brand palette renders consistently in both page modes —
+// dark charcoal nodes with white text stay legible on a light page background,
+// the same way a fenced code block does.
+export const crucibleMermaidConfig = {
+ theme: 'base',
+ themeVariables: crucibleMermaidThemeVariables,
+};