From 4607ce0adf25a2be78a522642b24d4381a165101 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sun, 24 May 2026 03:01:36 +0100 Subject: [PATCH] Add Quartz knowledge base site --- .github/workflows/deploy-quartz.yml | 24 ++ .gitignore | 2 + Mimir Vault.md | 8 - index.md | 12 + scripts/quartz/quartz.ps1 | 50 +++ site/README.md | 17 + site/quartz.config.ts | 184 ++++++++++ site/quartz.layout.ts | 70 ++++ site/quartz/components/MimirMasthead.tsx | 97 ++++++ .../components/MimirOverviewSidebar.tsx | 57 +++ site/quartz/components/MimirThemeLock.tsx | 13 + site/quartz/styles/custom.scss | 326 ++++++++++++++++++ static/epiphany-graph/assets/elk.js | 1 + static/epiphany-graph/assets/react.js | 1 + static/epiphany-graph/assets/viewer.css | 1 + static/epiphany-graph/assets/viewer.js | 11 + static/epiphany-graph/viewer.html | 14 + 17 files changed, 880 insertions(+), 8 deletions(-) create mode 100644 .github/workflows/deploy-quartz.yml create mode 100644 index.md create mode 100644 scripts/quartz/quartz.ps1 create mode 100644 site/README.md create mode 100644 site/quartz.config.ts create mode 100644 site/quartz.layout.ts create mode 100644 site/quartz/components/MimirMasthead.tsx create mode 100644 site/quartz/components/MimirOverviewSidebar.tsx create mode 100644 site/quartz/components/MimirThemeLock.tsx create mode 100644 site/quartz/styles/custom.scss create mode 100644 static/epiphany-graph/assets/elk.js create mode 100644 static/epiphany-graph/assets/react.js create mode 100644 static/epiphany-graph/assets/viewer.css create mode 100644 static/epiphany-graph/assets/viewer.js create mode 100644 static/epiphany-graph/viewer.html diff --git a/.github/workflows/deploy-quartz.yml b/.github/workflows/deploy-quartz.yml new file mode 100644 index 0000000..56b82cf --- /dev/null +++ b/.github/workflows/deploy-quartz.yml @@ -0,0 +1,24 @@ +name: Deploy Quartz + +on: + push: + branches: + - main + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: pages + cancel-in-progress: true + +jobs: + deploy: + uses: GameCult/GameCult-Quartz/.github/workflows/quartz-pages.yml@main + with: + content-dir: . + overlay-dir: site + output-dir: quartz-site/public diff --git a/.gitignore b/.gitignore index 0dcce20..4398cb7 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,8 @@ config/audio-field.json logs/ *.log *.tmp +.quartz-build/ +quartz-site/ calibration/runs/ artifacts/drivers/ artifacts/asio/ diff --git a/Mimir Vault.md b/Mimir Vault.md index 6d03a6e..ec25b5d 100644 --- a/Mimir Vault.md +++ b/Mimir Vault.md @@ -50,11 +50,3 @@ corpus. ## Persistence And Identity - [Mimir Face](docs/mimir-face.md) -- [Scratch](state/scratch.md) -- [AGENTS](AGENTS.md) - -## Branding - -- [Mimir Face Prompts](assets/branding/mimir-face-prompts.md) -- [Mimir Icon Prompts](assets/branding/mimir-icon-prompts.md) - diff --git a/index.md b/index.md new file mode 100644 index 0000000..574bc3a --- /dev/null +++ b/index.md @@ -0,0 +1,12 @@ +# Mimir + +Mimir is the local realtime field machine: cameras, microphones, speakers, timing +signals, and runtime evidence pulled into one coherent OBS-facing surface. + +## Start Here + +- [Current System Map](notes/current-system-map.md) +- [Perfect Machine Domain Index](docs/perfect-machine-domain-index.md) +- [Code Algorithm Map](docs/code-algorithm-map.md) +- [Implementation Plan](docs/implementation-plan.md) +- [Study Reading Guide](research/perfect-machine-study-2026-05-23/reading-guide.md) diff --git a/scripts/quartz/quartz.ps1 b/scripts/quartz/quartz.ps1 new file mode 100644 index 0000000..56ab4cf --- /dev/null +++ b/scripts/quartz/quartz.ps1 @@ -0,0 +1,50 @@ +param( + [ValidateSet("build", "dev")] + [string]$Command = "dev" +) + +$ErrorActionPreference = "Stop" + +$repoRoot = Split-Path -Parent (Split-Path -Parent $PSScriptRoot) +$sharedQuartzRoot = if ($env:GAMECULT_QUARTZ_ROOT) { + $env:GAMECULT_QUARTZ_ROOT +} else { + Join-Path (Split-Path -Parent $repoRoot) "GameCult-Quartz" +} +$portableNodeRoot = Join-Path $repoRoot ".tools\node-v24.15.0-win-x64" +$portableNode = Join-Path $portableNodeRoot "node.exe" + +if (Test-Path $portableNode) { + $node = $portableNode + $env:PATH = "$portableNodeRoot;$env:PATH" +} else { + $nodeCommand = Get-Command node -ErrorAction SilentlyContinue + if (-not $nodeCommand) { + throw "node was not found. Install Node.js or restore the portable runtime under .tools." + } + + $node = $nodeCommand.Source +} + +$env:npm_config_cache = Join-Path $repoRoot ".npm-cache" + +if (-not (Test-Path $sharedQuartzRoot)) { + throw "GameCult-Quartz was not found at '$sharedQuartzRoot'. Clone it beside this repo or set GAMECULT_QUARTZ_ROOT." +} + +$buildScript = Join-Path $sharedQuartzRoot "scripts\build-site.mjs" + +if (-not (Test-Path $buildScript)) { + throw "GameCult-Quartz build script was not found at '$buildScript'." +} + +$scriptArgs = @( + $buildScript, + $Command, + "--siteRoot", $repoRoot, + "--overlayDir", "site", + "--contentDir", ".", + "--outputDir", "quartz-site/public" +) + +& $node @scriptArgs diff --git a/site/README.md b/site/README.md new file mode 100644 index 0000000..d67aeba --- /dev/null +++ b/site/README.md @@ -0,0 +1,17 @@ +# Mimir Quartz Site + +Quartz overlay for the future `https://mimir.gamecult.org` knowledge base. +The content source is the repo root Obsidian vault; this `site/` directory owns +presentation, navigation, and static-site wiring. + +The site follows the shared GameCult-Quartz deployment pattern: + +- content directory: repo root (`.`) +- overlay directory: `site` +- output directory: `quartz-site/public` +- GitHub Pages host: `gamecult.github.io` +- custom domain: `mimir.gamecult.org` + +The overlay intentionally excludes source/build/runtime folders from publishing +while keeping the docs, research notes, handoff notes, and vault index visible. + diff --git a/site/quartz.config.ts b/site/quartz.config.ts new file mode 100644 index 0000000..ca9f1cc --- /dev/null +++ b/site/quartz.config.ts @@ -0,0 +1,184 @@ +import { QuartzConfig } from "./quartz/cfg"; +import * as Plugin from "./quartz/plugins"; +import { QuartzEmitterPlugin } from "./quartz/plugins/types"; +import { Fragment, h } from "preact"; + +const MimirMeta: QuartzEmitterPlugin = () => ({ + name: "MimirMeta", + async *emit() {}, + async *partialEmit() {}, + externalResources: () => ({ + additionalHead: [ + () => + h(Fragment, {}, [ + h("meta", { + property: "twitter:domain", + content: "mimir.gamecult.org", + }), + h("meta", { + property: "og:url", + content: "https://mimir.gamecult.org/", + }), + h("meta", { + property: "twitter:url", + content: "https://mimir.gamecult.org/", + }), + ]), + ], + }), +}); + +const config: QuartzConfig = { + configuration: { + pageTitle: "Mimir", + pageTitleSuffix: "", + enableSPA: true, + enablePopovers: true, + analytics: null, + locale: "en-GB", + baseUrl: "mimir.gamecult.org", + ignorePatterns: [ + ".git", + ".github", + ".obsidian", + ".quartz-build", + ".voidbot", + "AGENTS.md", + "assets/branding", + "assets/branding/**", + "artifacts", + "artifacts/**", + "bin", + "bin/**", + "calibration", + "calibration/**", + "config", + "config/**", + "faust", + "faust/**", + "logs", + "logs/**", + "native/**/build", + "native/**/target", + "node_modules", + "node_modules/**", + "obj", + "obj/**", + "quartz-site", + "quartz-site/**", + "research/**/mirrors", + "research/**/mirrors/**", + "scripts", + "scripts/**", + "site", + "site/**", + "src", + "src/**", + "state", + "state/**", + "target", + "target/**", + "tools", + "tools/**", + "**/*.slnx", + "**/*.csproj", + "**/*.vcxproj", + "**/*.filters", + "**/*.tlog", + "**/*.obj", + "**/*.dll", + "**/*.exe", + "**/*.lib", + "**/*.exp", + "**/*.jsonl", + "**/*.yaml", + "**/*.yml", + "**/*.toml", + "**/*.lock", + ], + defaultDateType: "modified", + theme: { + fontOrigin: "googleFonts", + cdnCaching: true, + typography: { + header: { + name: "Montserrat", + weights: [100, 200, 300, 400, 600], + }, + title: { + name: "Montserrat", + weights: [100, 200, 300], + }, + body: { + name: "Ubuntu", + weights: [300, 400, 500, 700], + includeItalic: true, + }, + code: "IBM Plex Mono", + }, + colors: { + lightMode: { + light: "#05090d", + lightgray: "#111a20", + gray: "#6d8792", + darkgray: "#c4dce5", + dark: "#f3fbff", + secondary: "#64b7ff", + tertiary: "#9bd887", + highlight: "rgba(100, 183, 255, 0.14)", + textHighlight: "#9bd88755", + }, + darkMode: { + light: "#05090d", + lightgray: "#111a20", + gray: "#6d8792", + darkgray: "#c4dce5", + dark: "#f3fbff", + secondary: "#64b7ff", + tertiary: "#9bd887", + highlight: "rgba(100, 183, 255, 0.14)", + textHighlight: "#9bd88755", + }, + }, + }, + }, + plugins: { + transformers: [ + Plugin.FrontMatter(), + Plugin.CreatedModifiedDate({ + priority: ["frontmatter", "git", "filesystem"], + }), + Plugin.SyntaxHighlighting({ + theme: { + light: "github-dark", + dark: "github-dark", + }, + keepBackground: false, + }), + Plugin.ObsidianFlavoredMarkdown({ enableInHtmlEmbed: false }), + Plugin.GitHubFlavoredMarkdown(), + Plugin.TableOfContents(), + Plugin.CrawlLinks({ markdownLinkResolution: "shortest" }), + Plugin.Description(), + Plugin.Latex({ renderEngine: "katex" }), + ], + filters: [Plugin.RemoveDrafts()], + emitters: [ + Plugin.AliasRedirects(), + Plugin.ComponentResources(), + Plugin.ContentPage(), + Plugin.FolderPage(), + Plugin.ContentIndex({ + enableSiteMap: false, + enableRSS: false, + }), + Plugin.Assets(), + Plugin.Static(), + MimirMeta(), + Plugin.NotFoundPage(), + Plugin.CustomOgImages(), + ], + }, +}; + +export default config; diff --git a/site/quartz.layout.ts b/site/quartz.layout.ts new file mode 100644 index 0000000..ef1c810 --- /dev/null +++ b/site/quartz.layout.ts @@ -0,0 +1,70 @@ +import { PageLayout, SharedLayout } from "./quartz/cfg"; +import * as Component from "./quartz/components"; +import MimirMasthead from "./quartz/components/MimirMasthead"; +import MimirOverviewSidebar from "./quartz/components/MimirOverviewSidebar"; +import MimirThemeLock from "./quartz/components/MimirThemeLock"; + +const MimirGraphShell = Component.GameCultGraphSpaShell({ + stylesheetHref: + "/static/epiphany-graph/assets/viewer.css?v=graph-mimir-20260524", + moduleSrc: "/static/epiphany-graph/assets/viewer.js?v=graph-mimir-20260524", +}); + +export const sharedPageComponents: SharedLayout = { + head: Component.Head(), + header: [MimirThemeLock(), MimirMasthead(), Component.Search()], + afterBody: [ + Component.ConditionalRender({ + component: MimirGraphShell, + condition: (page) => + page.fileData.slug === "Mimir-Vault" || page.fileData.slug === "index", + }), + ], + footer: Component.Footer({ + links: {}, + }), +}; + +export const defaultContentPageLayout: PageLayout = { + beforeBody: [ + Component.ConditionalRender({ + component: Component.Breadcrumbs({ + rootName: "Mimir", + showCurrentPage: false, + showRoot: false, + }), + condition: (page) => + page.fileData.slug !== "Mimir-Vault" && page.fileData.slug !== "index", + }), + Component.ConditionalRender({ + component: Component.ArticleTitle(), + condition: (page) => + !page.fileData.slug?.endsWith("/index") && + page.fileData.slug !== "Mimir-Vault", + }), + Component.ConditionalRender({ + component: Component.ContentMeta(), + condition: (page) => + !page.fileData.slug?.endsWith("/index") && + page.fileData.slug !== "Mimir-Vault", + }), + ], + afterBody: [], + left: [MimirOverviewSidebar()], + right: [ + Component.DesktopOnly(Component.TableOfContents()), + Component.Backlinks(), + ], +}; + +export const defaultListPageLayout: PageLayout = { + beforeBody: [ + Component.Breadcrumbs({ + rootName: "Mimir", + showCurrentPage: false, + showRoot: false, + }), + ], + left: [], + right: [], +}; diff --git a/site/quartz/components/MimirMasthead.tsx b/site/quartz/components/MimirMasthead.tsx new file mode 100644 index 0000000..52407e6 --- /dev/null +++ b/site/quartz/components/MimirMasthead.tsx @@ -0,0 +1,97 @@ +import { + QuartzComponent, + QuartzComponentConstructor, + QuartzComponentProps, +} from "./types"; +import { FullSlug, resolveRelative } from "../util/path"; + +type Route = { + label: string; + slug: FullSlug; + matches: string[]; +}; + +const routes: Route[] = [ + { + label: "Home", + slug: "Mimir-Vault" as FullSlug, + matches: ["Mimir-Vault", "index"], + }, + { + label: "Docs", + slug: "docs/perfect-machine-domain-index" as FullSlug, + matches: ["docs"], + }, + { + label: "Runtime", + slug: "notes/current-system-map" as FullSlug, + matches: ["notes", "state"], + }, + { + label: "Research", + slug: "research/perfect-machine-study-2026-05-23/reading-guide" as FullSlug, + matches: ["research"], + }, + { label: "Native", slug: "native/README" as FullSlug, matches: ["native"] }, +]; + +function isMatch(currentSlug: string, prefix: string) { + return currentSlug === prefix || currentSlug.startsWith(`${prefix}/`); +} + +function pickActiveRoute(currentSlug: string) { + return routes + .flatMap((route) => + route.matches + .filter((prefix) => isMatch(currentSlug, prefix)) + .map((prefix) => ({ route, prefixLength: prefix.length })), + ) + .sort((a, b) => b.prefixLength - a.prefixLength)[0]?.route; +} + +export default (() => { + const MimirMasthead: QuartzComponent = ({ + fileData, + }: QuartzComponentProps) => { + const currentSlug = fileData.slug ?? ("Mimir-Vault" as FullSlug); + const activeRoute = pickActiveRoute(currentSlug); + + return ( +
+ +
+

+ + Mimir + +

+

+ Realtime cameras, microphones, chirplets, and field evidence + organized into one coherent stream machine. +

+
+ +
+ ); + }; + + return MimirMasthead; +}) satisfies QuartzComponentConstructor; diff --git a/site/quartz/components/MimirOverviewSidebar.tsx b/site/quartz/components/MimirOverviewSidebar.tsx new file mode 100644 index 0000000..ae6b47f --- /dev/null +++ b/site/quartz/components/MimirOverviewSidebar.tsx @@ -0,0 +1,57 @@ +import { + QuartzComponent, + QuartzComponentConstructor, + QuartzComponentProps, +} from "./types"; +import { FullSlug, resolveRelative } from "../util/path"; + +type SidebarLink = { + label: string; + slug: FullSlug; +}; + +const links: SidebarLink[] = [ + { label: "Current System Map", slug: "notes/current-system-map" as FullSlug }, + { label: "Code Algorithm Map", slug: "docs/code-algorithm-map" as FullSlug }, + { + label: "Perfect Machine Domain Index", + slug: "docs/perfect-machine-domain-index" as FullSlug, + }, + { + label: "Study Reading Guide", + slug: "research/perfect-machine-study-2026-05-23/reading-guide" as FullSlug, + }, + { + label: "Calibration Session Spec", + slug: "research/perfect-machine-study-2026-05-23/calibration-session-spec" as FullSlug, + }, + { + label: "Fensalir Integration Map", + slug: "research/perfect-machine-study-2026-05-23/fensalir-integration-map" as FullSlug, + }, +]; + +export default (() => { + const MimirOverviewSidebar: QuartzComponent = ({ + fileData, + }: QuartzComponentProps) => { + const currentSlug = fileData.slug ?? ("Mimir-Vault" as FullSlug); + + return ( + + ); + }; + + return MimirOverviewSidebar; +}) satisfies QuartzComponentConstructor; diff --git a/site/quartz/components/MimirThemeLock.tsx b/site/quartz/components/MimirThemeLock.tsx new file mode 100644 index 0000000..03cd914 --- /dev/null +++ b/site/quartz/components/MimirThemeLock.tsx @@ -0,0 +1,13 @@ +import { QuartzComponent, QuartzComponentConstructor } from "./types"; + +export default (() => { + const MimirThemeLock: QuartzComponent = () => ( + + + + + +
+ +