Add Zyphos Quartz site
This commit is contained in:
parent
4f0b3ba3d3
commit
caacae52bb
15 changed files with 788 additions and 9 deletions
24
.github/workflows/deploy-quartz.yml
vendored
Normal file
24
.github/workflows/deploy-quartz.yml
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
name: Deploy Quartz
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
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: Eusocial Interbeing
|
||||
overlay-dir: site
|
||||
output-dir: quartz-site/public
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -22,3 +22,5 @@ state/scratch-compaction-*.md
|
|||
/.rag/
|
||||
/.tools/
|
||||
/.npm-cache/
|
||||
/.quartz-build/
|
||||
/quartz-site/
|
||||
|
|
|
|||
|
|
@ -1,24 +1,33 @@
|
|||
# Eusocial Interbeing
|
||||
# Zyphos
|
||||
|
||||
This setting centers on eusocial inter-species dynamics: civilizations that do not merely live in ecosystems, but negotiate with reproductive sites, memory-bearing forests, immune networks, migratory herds, pollinating castes, fungal archives, and engineered idea-organisms.
|
||||
*A close-binary living world for the Aquarium demo, with names waiting for Weksa to earn them.*
|
||||
|
||||
Zyphos is one member of a tightly bound terrestrial binary. Its slightly smaller twin, [[World/Zyphos Umbros Binary System|Umbros]], hangs in the sky as a fixed planetary presence. The primary star is dim, the habitable zone is close, and the biosphere has learned to treat light as a scarce civic resource rather than wallpaper.
|
||||
|
||||
This site collects the setting work behind the Zyphos demo: the physics-constrained world model, the mutable-memory biosphere, the civilizations shaped by ecological contracts, the Aquarium rendering surface, and the future Weksa language work that will name the world from inside its inhabitants' ontologies.
|
||||
|
||||
## Core Premise
|
||||
|
||||
On one continent, the [[Airawa]] once lived in tight ecological reciprocity with [[Mother Trees]]. Their societies stored communal memory in tree networks that demanded nutrients, ritual labor, and political deference in return. One Airawa tribe created the [[Biological Memetic Engine]] to break that dependency. The tool worked too well. It became the foundation of the [[Airawa Empire]], a eugenics-obsessed biopunk state whose rulers can impose doctrine through the continent's connected living networks.
|
||||
Zyphos life is founded on [[Ecology/Mutable Memory Endosymbiosis|mutable memory endosymbiosis]]. Every cell carries a memory-bearing symbiont. Sentience is not reserved for human-shaped minds; it gradients through cells, tissues, organisms, colonies, routes, forests, reefs, and landscapes.
|
||||
|
||||
On another continent, where Airawa never evolved or migrated, the [[Sa'auei'a]] developed a highly advanced nomadic civilization. They organize in squad-sized family units, keep [[Breeding Grounds]] sacred and communal, and bargain with ecologies that remember generosity.
|
||||
On one continent, the [[Species/Airawa|Airawa]] once lived in tight ecological reciprocity with [[Species/Mother Trees|Mother Trees]]. Their societies stored communal memory in tree networks that demanded nutrients, ritual labor, and political deference in return. One Airawa tribe created the [[Technologies/Biological Memetic Engine|Biological Memetic Engine]] to break that dependency. The tool worked too well. It became the foundation of the [[Civilizations/Airawa Empire|Airawa Empire]], a eugenics-obsessed biopunk state whose rulers can impose doctrine through the continent's connected living networks.
|
||||
|
||||
## Main Paths
|
||||
On another continent, where Airawa never evolved or migrated, the [[Species/Sa'auei'a|Sa'auei'a]] developed a highly advanced nomadic civilization. They organize in squad-sized family units, keep [[Ecology/Breeding Grounds|Breeding Grounds]] sacred and communal, and bargain with ecologies that remember generosity.
|
||||
|
||||
## Project Surfaces
|
||||
|
||||
- [[World/Zyphos Simulation Brief]]
|
||||
- [[World/Zyphos Umbros Binary System]]
|
||||
- [[Ecology/Mutable Memory Endosymbiosis]]
|
||||
- [[Ecology/Zyphos Biosphere Examples]]
|
||||
- [[World/index]]
|
||||
- [[Ecology/index]]
|
||||
- [[Species/index]]
|
||||
- [[Civilizations/index]]
|
||||
- [[Ecology/index]]
|
||||
- [[Technologies/index]]
|
||||
- [[Conflicts/index]]
|
||||
- [[Themes/index]]
|
||||
- [[Inspirations/index]]
|
||||
|
||||
## Current Design Rule
|
||||
|
||||
Every major institution should be legible as an ecological deal, a reproductive pressure, a memory technology, or a path-dependent consequence. If it is just a normal state wearing wet architecture, cut it until the wound has a purpose.
|
||||
|
||||
Physics is design authority. If the orbital math or energy budget tightens the image, the world bends. The bruise is usually where the better idea lives.
|
||||
|
|
|
|||
BIN
Eusocial Interbeing/static/icon.png
Normal file
BIN
Eusocial Interbeing/static/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2 KiB |
|
|
@ -5,3 +5,10 @@ An Obsidian vault for an original biopolitical ecology setting: two continents,
|
|||
The project is loosely inspired by Avatar's underused ecological network premise, Sue Burke's plant-negotiation fiction, and Harry Turtledove's path-dependent technology arguments. It is not an Avatar fan setting. The useful corpse has been composted. We move on.
|
||||
|
||||
Start at [[Eusocial Interbeing/index]].
|
||||
|
||||
## Site
|
||||
|
||||
The Zyphos public site is a GitHub Pages Quartz site using the same deployment
|
||||
shape as Aetheria. Vault content lives under `Eusocial Interbeing/`; the Quartz
|
||||
overlay lives under `site/`; the workflow publishes to GitHub Pages for
|
||||
`zyphos.gamecult.org`.
|
||||
|
|
|
|||
15
site/README.md
Normal file
15
site/README.md
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
# Zyphos Quartz Site
|
||||
|
||||
Quartz overlay for the future `https://zyphos.gamecult.org` GitHub Pages site.
|
||||
The content source is the vault directory `Eusocial Interbeing/`; this `site/`
|
||||
directory only owns presentation, navigation, and static site assets.
|
||||
|
||||
The site follows the same deployment pattern as `AetheriaLore`:
|
||||
|
||||
- content directory: `Eusocial Interbeing`
|
||||
- overlay directory: `site`
|
||||
- output directory: `quartz-site/public`
|
||||
- GitHub Pages host: `gamecult.github.io`
|
||||
- custom domain: `zyphos.gamecult.org`
|
||||
|
||||
DNS should point `zyphos.gamecult.org` at GitHub Pages, not Yggdrasil.
|
||||
141
site/quartz.config.ts
Normal file
141
site/quartz.config.ts
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
import { QuartzConfig } from "./quartz/cfg"
|
||||
import * as Plugin from "./quartz/plugins"
|
||||
import { QuartzEmitterPlugin } from "./quartz/plugins/types"
|
||||
import { Fragment, h } from "preact"
|
||||
import { zyphosHeroScript } from "./quartz/components/ZyphosHeroScript"
|
||||
|
||||
const ZyphosFavicons: QuartzEmitterPlugin = () => ({
|
||||
name: "ZyphosFavicons",
|
||||
async *emit() {},
|
||||
async *partialEmit() {},
|
||||
externalResources: () => ({
|
||||
additionalHead: [
|
||||
() =>
|
||||
h(Fragment, {}, [
|
||||
h("meta", { property: "twitter:domain", content: "zyphos.gamecult.org" }),
|
||||
h("meta", { property: "og:url", content: "https://zyphos.gamecult.org/" }),
|
||||
h("meta", { property: "twitter:url", content: "https://zyphos.gamecult.org/" }),
|
||||
]),
|
||||
],
|
||||
}),
|
||||
})
|
||||
|
||||
const ZyphosHeroResources: QuartzEmitterPlugin = () => ({
|
||||
name: "ZyphosHeroResources",
|
||||
async *emit() {},
|
||||
async *partialEmit() {},
|
||||
externalResources: () => ({
|
||||
js: [
|
||||
{
|
||||
script: zyphosHeroScript,
|
||||
loadTime: "afterDOMReady",
|
||||
contentType: "inline",
|
||||
spaPreserve: true,
|
||||
},
|
||||
],
|
||||
}),
|
||||
})
|
||||
|
||||
const config: QuartzConfig = {
|
||||
configuration: {
|
||||
pageTitle: "Zyphos",
|
||||
pageTitleSuffix: "",
|
||||
enableSPA: true,
|
||||
enablePopovers: true,
|
||||
analytics: null,
|
||||
locale: "en-GB",
|
||||
baseUrl: "zyphos.gamecult.org",
|
||||
ignorePatterns: [
|
||||
"private",
|
||||
"templates",
|
||||
".obsidian",
|
||||
"Inspirations",
|
||||
"Inspirations/**",
|
||||
],
|
||||
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: "#07110f",
|
||||
lightgray: "#16251f",
|
||||
gray: "#668077",
|
||||
darkgray: "#bdd4ca",
|
||||
dark: "#effcf8",
|
||||
secondary: "#ffae58",
|
||||
tertiary: "#8edfb0",
|
||||
highlight: "rgba(142, 223, 176, 0.14)",
|
||||
textHighlight: "#ffae5855",
|
||||
},
|
||||
darkMode: {
|
||||
light: "#07110f",
|
||||
lightgray: "#16251f",
|
||||
gray: "#668077",
|
||||
darkgray: "#bdd4ca",
|
||||
dark: "#effcf8",
|
||||
secondary: "#ffae58",
|
||||
tertiary: "#8edfb0",
|
||||
highlight: "rgba(142, 223, 176, 0.14)",
|
||||
textHighlight: "#ffae5855",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
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(),
|
||||
ZyphosFavicons(),
|
||||
ZyphosHeroResources(),
|
||||
Plugin.NotFoundPage(),
|
||||
Plugin.CustomOgImages(),
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
export default config
|
||||
53
site/quartz.layout.ts
Normal file
53
site/quartz.layout.ts
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
import { PageLayout, SharedLayout } from "./quartz/cfg"
|
||||
import * as Component from "./quartz/components"
|
||||
import ZyphosMasthead from "./quartz/components/ZyphosMasthead"
|
||||
import ZyphosOverviewSidebar from "./quartz/components/ZyphosOverviewSidebar"
|
||||
import ZyphosThemeLock from "./quartz/components/ZyphosThemeLock"
|
||||
|
||||
export const sharedPageComponents: SharedLayout = {
|
||||
head: Component.Head(),
|
||||
header: [ZyphosThemeLock(), ZyphosMasthead(), Component.Search()],
|
||||
afterBody: [],
|
||||
footer: Component.Footer({
|
||||
links: {},
|
||||
}),
|
||||
}
|
||||
|
||||
export const defaultContentPageLayout: PageLayout = {
|
||||
beforeBody: [
|
||||
Component.ConditionalRender({
|
||||
component: Component.Breadcrumbs({
|
||||
rootName: "Zyphos",
|
||||
showCurrentPage: false,
|
||||
showRoot: false,
|
||||
}),
|
||||
condition: (page) => page.fileData.slug !== "index",
|
||||
}),
|
||||
Component.ConditionalRender({
|
||||
component: Component.ArticleTitle(),
|
||||
condition: (page) => !page.fileData.slug?.endsWith("/index") && page.fileData.slug !== "index",
|
||||
}),
|
||||
Component.ConditionalRender({
|
||||
component: Component.ContentMeta(),
|
||||
condition: (page) => !page.fileData.slug?.endsWith("/index") && page.fileData.slug !== "index",
|
||||
}),
|
||||
],
|
||||
afterBody: [],
|
||||
left: [ZyphosOverviewSidebar()],
|
||||
right: [
|
||||
Component.DesktopOnly(Component.TableOfContents()),
|
||||
Component.Backlinks(),
|
||||
],
|
||||
}
|
||||
|
||||
export const defaultListPageLayout: PageLayout = {
|
||||
beforeBody: [
|
||||
Component.Breadcrumbs({
|
||||
rootName: "Zyphos",
|
||||
showCurrentPage: false,
|
||||
showRoot: false,
|
||||
}),
|
||||
],
|
||||
left: [],
|
||||
right: [],
|
||||
}
|
||||
118
site/quartz/components/ZyphosHeroScript.tsx
Normal file
118
site/quartz/components/ZyphosHeroScript.tsx
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
import { QuartzComponent, QuartzComponentConstructor } from "./types"
|
||||
|
||||
export const zyphosHeroScript = String.raw`
|
||||
function bootZyphosHero() {
|
||||
const home = document.querySelector("body[data-slug='index'] article")
|
||||
if (!home || home.querySelector(".zyphos-hero-canvas")) return
|
||||
|
||||
const canvas = document.createElement("canvas")
|
||||
canvas.className = "zyphos-hero-canvas"
|
||||
canvas.setAttribute("aria-hidden", "true")
|
||||
home.prepend(canvas)
|
||||
|
||||
const context = canvas.getContext("2d")
|
||||
|
||||
function resize() {
|
||||
const rect = home.getBoundingClientRect()
|
||||
const ratio = Math.min(window.devicePixelRatio || 1, 2)
|
||||
canvas.width = Math.max(1, Math.floor(rect.width * ratio))
|
||||
canvas.height = Math.floor(Math.min(window.innerHeight * 0.72, 620) * ratio)
|
||||
canvas.style.height = Math.floor(canvas.height / ratio) + "px"
|
||||
context.setTransform(ratio, 0, 0, ratio, 0, 0)
|
||||
}
|
||||
|
||||
function drawPlanet(x, y, radius, colors, time, shadow) {
|
||||
const gradient = context.createRadialGradient(x - radius * 0.32, y - radius * 0.35, 0, x, y, radius)
|
||||
gradient.addColorStop(0, colors[0])
|
||||
gradient.addColorStop(0.5, colors[1])
|
||||
gradient.addColorStop(1, colors[2])
|
||||
context.fillStyle = gradient
|
||||
context.beginPath()
|
||||
context.arc(x, y, radius, 0, Math.PI * 2)
|
||||
context.fill()
|
||||
|
||||
const eclipse = context.createRadialGradient(x + Math.cos(time) * radius * 0.3, y, 0, x, y, radius * 1.2)
|
||||
eclipse.addColorStop(0, shadow)
|
||||
eclipse.addColorStop(1, "rgba(0, 0, 0, 0)")
|
||||
context.fillStyle = eclipse
|
||||
context.beginPath()
|
||||
context.arc(x, y, radius, 0, Math.PI * 2)
|
||||
context.fill()
|
||||
|
||||
context.strokeStyle = "rgba(142, 223, 176, 0.18)"
|
||||
for (let i = 0; i < 5; i += 1) {
|
||||
context.beginPath()
|
||||
context.ellipse(x, y + Math.sin(i * 1.6) * radius * 0.42, radius * (0.44 + i * 0.05), radius * 0.08, i * 0.28, 0, Math.PI * 2)
|
||||
context.stroke()
|
||||
}
|
||||
}
|
||||
|
||||
function frame(now) {
|
||||
const width = canvas.clientWidth
|
||||
const height = canvas.clientHeight
|
||||
const t = now * 0.00025
|
||||
context.clearRect(0, 0, width, height)
|
||||
|
||||
const star = context.createRadialGradient(width * 0.78, height * 0.18, 0, width * 0.78, height * 0.18, width * 0.55)
|
||||
star.addColorStop(0, "rgba(255, 174, 88, 0.22)")
|
||||
star.addColorStop(1, "rgba(255, 174, 88, 0)")
|
||||
context.fillStyle = star
|
||||
context.fillRect(0, 0, width, height)
|
||||
|
||||
context.strokeStyle = "rgba(115, 198, 227, 0.11)"
|
||||
for (let i = 0; i < 7; i += 1) {
|
||||
const y = height * (0.2 + i * 0.09) + Math.sin(t * 2 + i) * 6
|
||||
context.beginPath()
|
||||
context.moveTo(0, y)
|
||||
context.bezierCurveTo(width * 0.35, y - 30, width * 0.62, y + 36, width, y - 12)
|
||||
context.stroke()
|
||||
}
|
||||
|
||||
const zr = Math.min(width, height) * 0.21
|
||||
const zx = width * 0.68
|
||||
const zy = height * 0.62
|
||||
const ur = zr * 0.62
|
||||
const ux = zx - zr * 1.85
|
||||
const uy = zy - zr * 0.7
|
||||
|
||||
context.strokeStyle = "rgba(239, 252, 248, 0.15)"
|
||||
context.beginPath()
|
||||
context.moveTo(ux, uy)
|
||||
context.lineTo(zx, zy)
|
||||
context.stroke()
|
||||
|
||||
drawPlanet(ux, uy, ur, ["#7d8899", "#2c3a4a", "#070b11"], t + 1.2, "rgba(0, 0, 0, 0.6)")
|
||||
drawPlanet(zx, zy, zr, ["#c7f7d0", "#28726c", "#06131b"], t, "rgba(0, 0, 0, 0.42)")
|
||||
|
||||
context.fillStyle = "rgba(142, 223, 176, 0.62)"
|
||||
for (let i = 0; i < 56; i += 1) {
|
||||
const angle = i * 2.399 + t * 0.35
|
||||
const r = zr * (0.18 + ((i * 37) % 100) / 140)
|
||||
const x = zx + Math.cos(angle) * r * 0.82
|
||||
const y = zy + Math.sin(angle) * r * 0.38
|
||||
const pulse = 1 + Math.sin(now * 0.002 + i) * 0.8
|
||||
context.beginPath()
|
||||
context.arc(x, y, Math.max(0.7, pulse), 0, Math.PI * 2)
|
||||
context.fill()
|
||||
}
|
||||
|
||||
requestAnimationFrame(frame)
|
||||
}
|
||||
|
||||
resize()
|
||||
window.addEventListener("resize", resize)
|
||||
requestAnimationFrame(frame)
|
||||
}
|
||||
|
||||
document.addEventListener("nav", bootZyphosHero)
|
||||
document.addEventListener("DOMContentLoaded", bootZyphosHero)
|
||||
bootZyphosHero()
|
||||
`
|
||||
|
||||
export default (() => {
|
||||
const ZyphosHeroScript: QuartzComponent = () => (
|
||||
<script dangerouslySetInnerHTML={{ __html: zyphosHeroScript }} />
|
||||
)
|
||||
|
||||
return ZyphosHeroScript
|
||||
}) satisfies QuartzComponentConstructor
|
||||
83
site/quartz/components/ZyphosMasthead.tsx
Normal file
83
site/quartz/components/ZyphosMasthead.tsx
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
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: "index" as FullSlug,
|
||||
matches: ["index"],
|
||||
},
|
||||
{
|
||||
label: "World",
|
||||
slug: "World/index" as FullSlug,
|
||||
matches: ["World"],
|
||||
},
|
||||
{
|
||||
label: "Biosphere",
|
||||
slug: "Ecology/index" as FullSlug,
|
||||
matches: ["Ecology", "Species"],
|
||||
},
|
||||
{
|
||||
label: "Civilizations",
|
||||
slug: "Civilizations/index" as FullSlug,
|
||||
matches: ["Civilizations", "Technologies", "Conflicts", "Themes"],
|
||||
},
|
||||
]
|
||||
|
||||
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 ZyphosMasthead: QuartzComponent = ({ fileData }: QuartzComponentProps) => {
|
||||
const currentSlug = fileData.slug ?? ("index" as FullSlug)
|
||||
const activeRoute = pickActiveRoute(currentSlug)
|
||||
|
||||
return (
|
||||
<section class="zyphos-titlebar">
|
||||
<div class="zyphos-titlebar-copy">
|
||||
<p class="zyphos-titlebar-title">
|
||||
<a href={resolveRelative(currentSlug, "index" as FullSlug)}>Zyphos</a>
|
||||
</p>
|
||||
<p class="zyphos-titlebar-tagline">
|
||||
A close-binary living world rendered through Aquarium and named through Weksa.
|
||||
</p>
|
||||
</div>
|
||||
<nav class="zyphos-titlebar-nav" aria-label="Zyphos sections">
|
||||
{routes.map((route) => {
|
||||
const active = activeRoute?.slug === route.slug
|
||||
return (
|
||||
<a
|
||||
href={resolveRelative(currentSlug, route.slug)}
|
||||
class={active ? "zyphos-nav-chip active" : "zyphos-nav-chip"}
|
||||
>
|
||||
{route.label}
|
||||
</a>
|
||||
)
|
||||
})}
|
||||
</nav>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
return ZyphosMasthead
|
||||
}) satisfies QuartzComponentConstructor
|
||||
37
site/quartz/components/ZyphosOverviewSidebar.tsx
Normal file
37
site/quartz/components/ZyphosOverviewSidebar.tsx
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types"
|
||||
import { FullSlug, resolveRelative } from "../util/path"
|
||||
|
||||
type SidebarLink = {
|
||||
label: string
|
||||
slug: FullSlug
|
||||
}
|
||||
|
||||
const links: SidebarLink[] = [
|
||||
{ label: "Zyphos Simulation Brief", slug: "World/Zyphos-Simulation-Brief" as FullSlug },
|
||||
{ label: "Zyphos Umbros Binary System", slug: "World/Zyphos-Umbros-Binary-System" as FullSlug },
|
||||
{ label: "Mutable Memory Endosymbiosis", slug: "Ecology/Mutable-Memory-Endosymbiosis" as FullSlug },
|
||||
{ label: "Zyphos Biosphere Examples", slug: "Ecology/Zyphos-Biosphere-Examples" as FullSlug },
|
||||
{ label: "Biological Memetic Engine", slug: "Technologies/Biological-Memetic-Engine" as FullSlug },
|
||||
]
|
||||
|
||||
export default (() => {
|
||||
const ZyphosOverviewSidebar: QuartzComponent = ({ fileData }: QuartzComponentProps) => {
|
||||
const currentSlug = fileData.slug ?? ("index" as FullSlug)
|
||||
|
||||
return (
|
||||
<aside class="zyphos-overview" aria-label="Zyphos overview">
|
||||
<p class="zyphos-overview-title">Project Surface</p>
|
||||
<p class="zyphos-overview-copy">
|
||||
Setting canon lives here. Aquarium renders the demo. Weksa will earn the names.
|
||||
</p>
|
||||
<nav>
|
||||
{links.map((link) => (
|
||||
<a href={resolveRelative(currentSlug, link.slug)}>{link.label}</a>
|
||||
))}
|
||||
</nav>
|
||||
</aside>
|
||||
)
|
||||
}
|
||||
|
||||
return ZyphosOverviewSidebar
|
||||
}) satisfies QuartzComponentConstructor
|
||||
13
site/quartz/components/ZyphosThemeLock.tsx
Normal file
13
site/quartz/components/ZyphosThemeLock.tsx
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
import { QuartzComponent, QuartzComponentConstructor } from "./types"
|
||||
|
||||
export default (() => {
|
||||
const ZyphosThemeLock: QuartzComponent = () => (
|
||||
<script
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `document.documentElement.setAttribute("saved-theme", "dark")`,
|
||||
}}
|
||||
/>
|
||||
)
|
||||
|
||||
return ZyphosThemeLock
|
||||
}) satisfies QuartzComponentConstructor
|
||||
274
site/quartz/styles/custom.scss
Normal file
274
site/quartz/styles/custom.scss
Normal file
|
|
@ -0,0 +1,274 @@
|
|||
@use "./base.scss";
|
||||
@use "./variables.scss" as *;
|
||||
|
||||
:root,
|
||||
:root[saved-theme="light"],
|
||||
:root[saved-theme="dark"] {
|
||||
color-scheme: dark;
|
||||
}
|
||||
|
||||
body {
|
||||
background:
|
||||
radial-gradient(circle at 76% 12%, rgba(255, 174, 88, 0.18), transparent 18%),
|
||||
radial-gradient(circle at 18% 10%, rgba(142, 223, 176, 0.12), transparent 24%),
|
||||
radial-gradient(circle at 50% 0%, rgba(115, 198, 227, 0.14), transparent 28%),
|
||||
linear-gradient(180deg, #03070d 0%, #07110f 46%, #091712 100%);
|
||||
color: var(--darkgray);
|
||||
}
|
||||
|
||||
.page {
|
||||
position: relative;
|
||||
max-width: 1680px;
|
||||
padding: 0 1.2rem 2.5rem;
|
||||
}
|
||||
|
||||
.page::before {
|
||||
content: "";
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
pointer-events: none;
|
||||
background-image:
|
||||
linear-gradient(rgba(142, 223, 176, 0.035) 1px, transparent 1px),
|
||||
linear-gradient(90deg, rgba(142, 223, 176, 0.035) 1px, transparent 1px);
|
||||
background-size: 28px 28px;
|
||||
mask-image: linear-gradient(180deg, rgba(0, 0, 0, 0.72), transparent 95%);
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.page > #quartz-body .center,
|
||||
.page > #quartz-body footer {
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
.page > #quartz-body .left.sidebar {
|
||||
gap: 0;
|
||||
padding: 2.4rem 1rem 0 0;
|
||||
background: transparent;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
backdrop-filter: none;
|
||||
}
|
||||
|
||||
.page > #quartz-body .center > .page-header {
|
||||
margin-top: 2.4rem;
|
||||
}
|
||||
|
||||
.page > #quartz-body .center header {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) auto;
|
||||
gap: 1rem 1.25rem;
|
||||
align-items: start;
|
||||
margin: 0 0 1rem;
|
||||
padding: 1rem 1.15rem 1.05rem;
|
||||
border: 1px solid rgba(142, 223, 176, 0.14);
|
||||
border-radius: 22px;
|
||||
background:
|
||||
radial-gradient(circle at 82% 50%, rgba(255, 174, 88, 0.16), transparent 22%),
|
||||
linear-gradient(135deg, rgba(7, 12, 19, 0.98), rgba(10, 22, 18, 0.95));
|
||||
box-shadow:
|
||||
0 20px 44px rgba(0, 0, 0, 0.24),
|
||||
inset 0 1px 0 rgba(255, 255, 255, 0.03);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.page > #quartz-body .center header > .search {
|
||||
max-width: 9rem;
|
||||
width: 100%;
|
||||
justify-self: end;
|
||||
}
|
||||
|
||||
.zyphos-titlebar {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.75rem;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.zyphos-titlebar-copy {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.18rem;
|
||||
}
|
||||
|
||||
.zyphos-titlebar-title,
|
||||
.zyphos-titlebar-title a {
|
||||
margin: 0;
|
||||
color: var(--dark);
|
||||
font-family: var(--titleFont);
|
||||
font-size: clamp(2.1rem, 4vw, 3.3rem);
|
||||
font-weight: 200;
|
||||
line-height: 0.92;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.zyphos-titlebar-tagline {
|
||||
margin: 0;
|
||||
color: rgba(189, 212, 202, 0.84);
|
||||
font-family: var(--titleFont);
|
||||
font-size: 0.88rem;
|
||||
font-weight: 200;
|
||||
letter-spacing: 0.02em;
|
||||
line-height: 1.4;
|
||||
max-width: 68ch;
|
||||
}
|
||||
|
||||
.zyphos-titlebar-nav {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.6rem;
|
||||
}
|
||||
|
||||
.zyphos-nav-chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
min-height: 2.15rem;
|
||||
padding: 0.3rem 0.8rem;
|
||||
border-radius: 999px;
|
||||
border: 1px solid rgba(142, 223, 176, 0.18);
|
||||
background: rgba(142, 223, 176, 0.07);
|
||||
color: #e2f6ee;
|
||||
font-family: var(--titleFont);
|
||||
font-size: 0.92rem;
|
||||
font-weight: 300;
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
|
||||
.zyphos-nav-chip:hover,
|
||||
.zyphos-nav-chip.active {
|
||||
background: rgba(255, 174, 88, 0.16);
|
||||
border-color: rgba(255, 174, 88, 0.42);
|
||||
color: #fff3e8;
|
||||
}
|
||||
|
||||
.article-title,
|
||||
article > h1,
|
||||
article > h2,
|
||||
article > h3,
|
||||
article > h4,
|
||||
article > h5,
|
||||
article > h6 {
|
||||
font-family: var(--titleFont);
|
||||
letter-spacing: 0.015em;
|
||||
}
|
||||
|
||||
.article-title {
|
||||
margin: 0;
|
||||
font-size: clamp(2rem, 3vw, 2.85rem);
|
||||
font-weight: 200;
|
||||
line-height: 0.96;
|
||||
}
|
||||
|
||||
.page > #quartz-body .center > article {
|
||||
position: relative;
|
||||
background:
|
||||
linear-gradient(180deg, rgba(10, 18, 16, 0.98), rgba(8, 14, 22, 0.96)),
|
||||
linear-gradient(180deg, rgba(142, 223, 176, 0.02), rgba(255, 174, 88, 0.02));
|
||||
border: 1px solid rgba(142, 223, 176, 0.1);
|
||||
border-radius: 24px;
|
||||
box-shadow:
|
||||
0 24px 52px rgba(0, 0, 0, 0.26),
|
||||
inset 0 1px 0 rgba(255, 255, 255, 0.03);
|
||||
padding: 1.45rem 1.7rem 1.9rem;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
body[data-slug="index"] .page > #quartz-body .center > article {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.zyphos-hero-canvas {
|
||||
display: block;
|
||||
width: calc(100% + 3.4rem);
|
||||
margin: 0 -1.7rem 1.35rem;
|
||||
min-height: 360px;
|
||||
border-bottom: 1px solid rgba(142, 223, 176, 0.12);
|
||||
background: #03070d;
|
||||
}
|
||||
|
||||
.page > #quartz-body .right.sidebar {
|
||||
gap: 1rem;
|
||||
padding: 2.4rem 0 0 1rem;
|
||||
background: transparent;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
backdrop-filter: none;
|
||||
}
|
||||
|
||||
.toc,
|
||||
.backlinks,
|
||||
.zyphos-overview {
|
||||
border: 1px solid rgba(142, 223, 176, 0.11);
|
||||
border-radius: 20px;
|
||||
background:
|
||||
linear-gradient(180deg, rgba(10, 18, 16, 0.88), rgba(8, 14, 22, 0.82));
|
||||
box-shadow:
|
||||
0 18px 40px rgba(0, 0, 0, 0.2),
|
||||
inset 0 1px 0 rgba(255, 255, 255, 0.03);
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.zyphos-overview-title {
|
||||
margin: 0 0 0.35rem;
|
||||
color: var(--secondary);
|
||||
font-family: var(--titleFont);
|
||||
font-size: 0.78rem;
|
||||
letter-spacing: 0.14em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.zyphos-overview-copy {
|
||||
margin: 0 0 0.9rem;
|
||||
color: rgba(189, 212, 202, 0.78);
|
||||
font-size: 0.9rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.zyphos-overview nav {
|
||||
display: grid;
|
||||
gap: 0.45rem;
|
||||
}
|
||||
|
||||
.zyphos-overview a {
|
||||
display: block;
|
||||
color: #e5f7ef;
|
||||
border: 1px solid rgba(142, 223, 176, 0.12);
|
||||
border-radius: 14px;
|
||||
padding: 0.55rem 0.65rem;
|
||||
background: rgba(142, 223, 176, 0.05);
|
||||
}
|
||||
|
||||
.zyphos-overview a:hover {
|
||||
border-color: rgba(255, 174, 88, 0.36);
|
||||
background: rgba(255, 174, 88, 0.1);
|
||||
}
|
||||
|
||||
article strong {
|
||||
color: #f2fff8;
|
||||
}
|
||||
|
||||
article table {
|
||||
border-color: rgba(142, 223, 176, 0.16);
|
||||
}
|
||||
|
||||
article tr,
|
||||
article td,
|
||||
article th {
|
||||
border-color: rgba(142, 223, 176, 0.12);
|
||||
}
|
||||
|
||||
@media all and not ($desktop) {
|
||||
.page > #quartz-body .center header {
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
}
|
||||
|
||||
.page > #quartz-body .center header > .search {
|
||||
justify-self: stretch;
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
.zyphos-hero-canvas {
|
||||
width: calc(100% + 2rem);
|
||||
margin-inline: -1rem;
|
||||
}
|
||||
}
|
||||
|
|
@ -4,3 +4,4 @@
|
|||
{"ts":"2026-05-18T00:31:00+01:00","type":"design_doctrine","status":"accepted","note":"Zyphos worldbuilding should bend to physics rather than bending physics for spectacle. Orbital mechanics, energy budget, eclipse geometry, climate, and biosphere constraints are design pressure that should make the setting more specific and grounded."}
|
||||
{"ts":"2026-05-18T00:46:00+01:00","type":"biosphere_foundation","status":"accepted","note":"Zyphos cells have a mitochondria-like endosymbiont for mutable memory storage and intercellular transmission. Sentience and memory exchange exist in gradients from cells through organisms, colonies, ecosystems, and landscapes; Earth analogue species must be derived from this substrate rather than imported unchanged."}
|
||||
{"ts":"2026-05-18T01:08:00+01:00","type":"biosphere_examples_and_naming_sync","status":"accepted","note":"First Zyphos biosphere examples should brighten the world through low-energy functional signals: light-return flashes, eclipse guidance, memory-contract routes, and organisms whose beauty is work. Future inhabitant-language names should be coordinated through Weksa from speaker ontology and language-project state, not direct English substitution."}
|
||||
{"ts":"2026-05-18T01:29:00+01:00","type":"site_surface","status":"accepted","note":"The Zyphos public site belongs inside the Eusocial Interbeing repo rather than a separate repo, because the vault owns the worldbuilding content that will form most of the site. The site should deploy as GitHub Pages Quartz like Aetheria, with DNS pointing zyphos.gamecult.org at gamecult.github.io rather than spending Yggdrasil on static hosting."}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ invariants:
|
|||
- Do not import Avatar, Semiosis, or Turtledove proper nouns into setting canon.
|
||||
key_files:
|
||||
entrypoint: Eusocial Interbeing/index.md
|
||||
zyphos_site_overlay: site/quartz.config.ts
|
||||
zyphos_site_layout: site/quartz.layout.ts
|
||||
mutable_memory_endosymbiosis: Eusocial Interbeing/Ecology/Mutable Memory Endosymbiosis.md
|
||||
zyphos_biosphere_examples: Eusocial Interbeing/Ecology/Zyphos Biosphere Examples.md
|
||||
zyphos_umbros_binary_system: Eusocial Interbeing/World/Zyphos Umbros Binary System.md
|
||||
|
|
|
|||
Loading…
Reference in a new issue