From e0af4e23ae0587ea25d8560f55bf57f419a815e2 Mon Sep 17 00:00:00 2001 From: Jeff Emmett Date: Wed, 25 Feb 2026 19:08:54 -0800 Subject: [PATCH] Restructure MycoStack roots, add interactive effects & data flows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Make Commons Stack the primary root of the MycoStack - Reframe P2P Foundation as both foundation and forward-looking knowledge engine producing convivial knowledge packets → open source protocol toolkits for P4P - Add Data Flows section (trust, resources, favors, capital) with rStack/rSpace links - Move Flow Funding to Tools in Active Research with TBFF from rFunds.online - Lighten starting background and reduce chroma for gentler rainbow fade - Add mouse-interactive mycelial canvas (cursor attraction, spore particles, hypha connection lines, ambient glow) - Add rFunds and rStack to network map and footer Co-Authored-By: Claude Opus 4.6 --- app/globals.css | 6 +- components/footer.tsx | 4 +- components/hero-section.tsx | 4 +- components/legacy-section.tsx | 258 ++++++++++++++++++++++------- components/mycelial-canvas.tsx | 183 ++++++++++++++++++-- components/network-map-section.tsx | 45 +++-- components/scroll-provider.tsx | 17 +- 7 files changed, 412 insertions(+), 105 deletions(-) diff --git a/app/globals.css b/app/globals.css index 2f61025..11113a9 100644 --- a/app/globals.css +++ b/app/globals.css @@ -5,9 +5,9 @@ :root { /* Scroll-driven dynamic colors (set by JS) */ - --scroll-bg: oklch(0.08 0.02 30); - --scroll-fg: oklch(0.85 0.03 80); - --scroll-accent: oklch(0.45 0.12 60); + --scroll-bg: oklch(0.18 0.015 30); + --scroll-fg: oklch(0.88 0.02 80); + --scroll-accent: oklch(0.50 0.10 60); --scroll-depth: 0; /* Static palette tokens */ diff --git a/components/footer.tsx b/components/footer.tsx index de7c3d6..c5c18cb 100644 --- a/components/footer.tsx +++ b/components/footer.tsx @@ -5,11 +5,13 @@ const LINKS = [ { name: "P2P Foundation", url: "https://wiki.p2pfoundation.net/" }, { name: "MycoFi", url: "https://mycofi.earth" }, { name: "Mycopunk", url: "https://mycopunk.xyz" }, + { name: "rFunds", url: "https://rfunds.online" }, + { name: "rStack", url: "https://rstack.org" }, + { name: "(You)rSpace", url: "https://yourspace.online" }, { name: "Undernet", url: "https://undernet.earth" }, { name: "Psilo-Cyber", url: "https://psilo-cyber.net" }, { name: "Compost Capitalism", url: "https://compostcapitalism.xyz" }, { name: "Post-Appitalism", url: "https://post-appitalist.app" }, - { name: "(You)rSpace", url: "https://yourspace.online" }, { name: "Trippin Balls", url: "https://trippinballs.lol" }, ] diff --git a/components/hero-section.tsx b/components/hero-section.tsx index 998c83d..aa92f9d 100644 --- a/components/hero-section.tsx +++ b/components/hero-section.tsx @@ -42,8 +42,8 @@ export function HeroSection() { className="emerge-letter text-sm sm:text-base opacity-40 max-w-xl mx-auto" style={{ animationDelay: "1.5s" }} > - Born from the P2P Foundation and the Commons Stack. - Inoculating the age of the P4P (peer-for-peer) movement. + Rooted in the Commons Stack. Nourished by the P2P Foundation. + Propagating the P4P (peer-for-peer) movement.

{/* Terminal tagline */} diff --git a/components/legacy-section.tsx b/components/legacy-section.tsx index dc3270b..9cf2e50 100644 --- a/components/legacy-section.tsx +++ b/components/legacy-section.tsx @@ -16,42 +16,42 @@ export function LegacySection() { The Roots

- Every network grows from somewhere. Ours grows from the Commons - Stack, the P2P Foundation, and the broader commons movement. + The MycoStack grows from the Commons Stack — its primary root + system — nourished by the knowledge commons of the P2P + Foundation and the broader commons movement.

- {/* P2P Foundation */} + {/* Commons Stack - Primary Root */}

- The P2P Foundation + The Commons Stack

The{" "} - P2P Foundation Wiki - - , started by Michel Bauwens and shaped by - hundreds of contributors, documents the emerging landscape of - peer-to-peer collaboration and commons-based alternatives. Over - 25,000 pages of case studies, theoretical frameworks, policy - proposals, and practical guides — an open knowledge base - that continues to inform projects worldwide. + Commons Stack + {" "} + is the primary root of the MycoStack. Its mission:{" "} + fund and govern the commons. Through pioneering work in + token engineering, augmented bonding curves, and conviction + voting, the Commons Stack and its{" "} + Trusted Seed community developed regenerative + funding mechanisms for commons infrastructure.

- Out of this work came key frameworks:{" "} - commons-based peer production, the{" "} - partner state, and{" "} - cosmo-localism (“design global, manufacture - local”). These ideas didn’t belong to any one person - — they emerged from a network of researchers, practitioners, - and communities building alternatives in the open. + But tools alone aren’t enough. The Commons Stack taught us + that technology must be wrapped in culture — in shared + values, governance practices, and communities of care. The + Trusted Seed wasn’t just a token-holder registry; it was an + experiment in building trust at the speed of consensus. From this + root system, the MycoStack grows outward.

@@ -94,81 +94,133 @@ export function LegacySection() {

- {/* Commons Stack history */} + {/* P2P Foundation - Foundation AND Forward */}

- The Commons Stack + The P2P Foundation

The{" "} - Commons Stack - {" "} - was born from this intellectual tradition. Its mission:{" "} - fund and govern the commons. Through pioneering work in - token engineering, augmented bonding curves, and conviction - voting, the Commons Stack and its{" "} - Trusted Seed community developed regenerative - funding mechanisms for commons infrastructure. + P2P Foundation Wiki + + , started by Michel Bauwens and shaped by + hundreds of contributors, is both the bedrock beneath the + MycoStack and the frontier ahead of it. Over 25,000 pages of + case studies, theoretical frameworks, policy proposals, and + practical guides — an open knowledge base that continues + to inform projects worldwide.

- But tools alone aren’t enough. The Commons Stack taught us - that technology must be wrapped in culture — in shared - values, governance practices, and communities of care. The - Trusted Seed wasn’t just a token-holder registry; it was an - experiment in building trust at the speed of consensus. + Out of this work came key frameworks:{" "} + commons-based peer production, the{" "} + partner state, and{" "} + cosmo-localism (“design global, manufacture + local”). But the P2P Foundation doesn’t just preserve + knowledge — it transforms it. Each iteration of commons + practice feeds back into the knowledge base, refining theories + into{" "} + convivial knowledge packets: living documents + that distill decades of research and practice into actionable + frameworks communities can actually use. +

+

+ These knowledge packets become the seeds of{" "} + open source protocol toolkits — practical + governance, funding, and coordination tools that any community + can adopt, adapt, and contribute back to. The P2P Foundation as + both root system and fruiting body: absorbing nutrients from the + ground, pushing spores into the future.

- {/* Flow Funding */} + {/* Data Flows - New Section */}

- Flow Funding + Data Flows of the Commons

- The Commons Stack pioneered the Augmented Bonding Curve — a - breakthrough in sustainable funding for the commons. Flow Funding - is its natural evolution: less mechanism, more ecology. Where the - ABC created a single reservoir, Flow Funding cultivates{" "} - enmeshed ecologies of inter- and intra-organizational - flow — resources circulating continuously between nested - communities the way nutrients cycle through a forest floor. + The MycoStack recognizes that the dissemination of{" "} + trust, resources,{" "} + favors, and capital are all + data flows — streams that can be made visible, governed + collectively, and managed by communities on self-provisioned + infrastructure.

- At the heart of Flow Funding is a threshold-based model rooted in - the concept of “enoughness” — - enabling an economics of sufficiency rather than accumulation. When - a node in the network has enough, surplus flows onward to where - it’s needed. No hoarding, no artificial scarcity. Just the - continuous circulation that living systems have practiced for - billions of years. + When communities own their own coordination tools, these flows + stop being opaque transactions mediated by extractive platforms + and become transparent, reciprocal exchanges governed by the + people who participate in them. Trust becomes legible. Resources + find their way to where they’re needed. Favors compound + into mutual aid networks. Capital circulates instead of + accumulating.

-

- This is economics as ecology: not designing incentives from above, - but cultivating the conditions for resources to find their own - path — rooted, reciprocal, and regenerative by nature. +

+ +
+

+ Community-Owned Infrastructure for Coordination +

+
+
+ +
+ Open source infrastructure stack for community coordination + — self-hostable, sovereign, interoperable +
+
+
+ +
+ Community-owned digital spaces — where coordination + happens on infrastructure you control +
+
+
+

+ When communities own their stack, every data flow becomes a + commons resource rather than a corporate asset.

- {/* P4P framework */} + {/* P4P Movement */}

The Birth of the @@ -186,9 +238,12 @@ export function LegacySection() { practice.

- Where the original Commons Stack built tools, MycoStack grows - ecosystems. Where P2P described a relational dynamic, P4P demands - a commitment. The mycelium doesn’t just connect — it + The P2P Foundation’s convivial knowledge packets become + the P4P movement’s open source protocol toolkits — + governance patterns, funding mechanisms, and coordination + primitives packaged as commons resources that any community can + deploy. Where P2P described a relational dynamic, P4P demands a + commitment. The mycelium doesn’t just connect — it nourishes.

@@ -239,6 +294,81 @@ export function LegacySection() { + {/* Tools in Active Research */} +
+

+ Tools in Active Research +

+
+

+ Flow Funding — the natural evolution of + the Commons Stack’s Augmented Bonding Curve. Less + mechanism, more ecology. Where the ABC created a single + reservoir, Flow Funding cultivates{" "} + enmeshed ecologies of inter- and intra-organizational + flow — resources circulating continuously between nested + communities the way nutrients cycle through a forest floor. +

+

+ The latest research takes the form of{" "} + Threshold-Based Flow Funding (TBFF), being + developed at{" "} + + rFunds.online + + . TBFF models funding pools as dynamic funnels operating across + three zones: an overflow zone where excess funds + automatically redistribute to connected pools, a{" "} + healthy zone of full flow and balanced + operations, and a critical zone where outflow + restricts to conservation mode. Funnels connect via overflow and + spending edges, creating living networks of resource circulation + governed by thresholds of{" "} + “enoughness” rather than + accumulation. +

+

+ This is economics as ecology: not designing incentives from above, + but cultivating the conditions for resources to find their own + path — rooted, reciprocal, and regenerative by nature. +

+
+ +
+
+ TBFF Zones +
+
+
+
overflow
+
+ Above MAX — surplus redistributes to connected funnels +
+
+
+
healthy
+
+ Normal ops — full flow rate, balanced funding +
+
+
+
critical
+
+ Below MIN — outflow restricted, conservation mode +
+
+
+
+
+ {/* Pillars */}
(null) const hyphaeRef = useRef([]) + const sporesRef = useRef([]) const frameRef = useRef(0) const trailCanvasRef = useRef(null) + const mouseRef = useRef<{ x: number; y: number; active: boolean }>({ + x: 0, + y: 0, + active: false, + }) useEffect(() => { const canvas = canvasRef.current @@ -50,8 +66,28 @@ export function MycelialCanvas() { resize() window.addEventListener("resize", resize) - const w = () => canvas.width / (Math.min(window.devicePixelRatio || 1, 2)) - const h = () => canvas.height / (Math.min(window.devicePixelRatio || 1, 2)) + // Mouse/touch tracking for interactive effects + const onMouseMove = (e: MouseEvent) => { + mouseRef.current.x = e.clientX + mouseRef.current.y = e.clientY + mouseRef.current.active = true + } + const onTouchMove = (e: TouchEvent) => { + if (e.touches.length > 0) { + mouseRef.current.x = e.touches[0].clientX + mouseRef.current.y = e.touches[0].clientY + mouseRef.current.active = true + } + } + const onMouseLeave = () => { + mouseRef.current.active = false + } + window.addEventListener("mousemove", onMouseMove) + window.addEventListener("touchmove", onTouchMove, { passive: true }) + window.addEventListener("mouseleave", onMouseLeave) + + const w = () => canvas.width / Math.min(window.devicePixelRatio || 1, 2) + const h = () => canvas.height / Math.min(window.devicePixelRatio || 1, 2) const createHypha = ( x: number, @@ -62,17 +98,27 @@ export function MycelialCanvas() { x, y, angle, - speed: 1.2 + Math.random() * 0.8 - depth * 0.15, + speed: 1.0 + Math.random() * 0.6 - depth * 0.1, age: 0, - maxAge: 200 + Math.random() * 150 - depth * 20, + maxAge: 250 + Math.random() * 200 - depth * 15, parentX: x, parentY: y, depth, branchCount: 0, }) - // Seed initial hyphae from bottom - const seedCount = Math.max(3, Math.floor(w() / 250)) + const createSpore = (x: number, y: number): Spore => ({ + x, + y, + vx: (Math.random() - 0.5) * 1.5, + vy: (Math.random() - 0.5) * 1.5 - 0.3, + life: 0, + maxLife: 60 + Math.random() * 80, + radius: 1 + Math.random() * 2, + }) + + // Seed initial hyphae from bottom and sides + const seedCount = Math.max(4, Math.floor(w() / 200)) for (let i = 0; i < seedCount; i++) { const x = (w() / (seedCount + 1)) * (i + 1) + (Math.random() - 0.5) * 80 @@ -85,16 +131,29 @@ export function MycelialCanvas() { ) ) } + // Seed a couple from sides + for (let i = 0; i < 2; i++) { + const fromLeft = Math.random() > 0.5 + hyphaeRef.current.push( + createHypha( + fromLeft ? -10 : w() + 10, + h() * (0.4 + Math.random() * 0.4), + fromLeft ? -0.2 + Math.random() * 0.4 : Math.PI - 0.2 + Math.random() * 0.4, + 0 + ) + ) + } const getAccentColor = () => { return ( getComputedStyle(document.documentElement) .getPropertyValue("--scroll-accent") - .trim() || "oklch(0.55 0.18 155)" + .trim() || "oklch(0.55 0.13 155)" ) } let lastSeed = 0 + let lastSporeEmit = 0 const animate = () => { const width = w() @@ -104,10 +163,11 @@ export function MycelialCanvas() { ctx.clearRect(0, 0, width, height) // Fade the trail canvas slowly - trailCtx.fillStyle = "rgba(10, 8, 5, 0.008)" + trailCtx.fillStyle = "rgba(10, 8, 5, 0.006)" trailCtx.fillRect(0, 0, width, height) const accent = getAccentColor() + const mouse = mouseRef.current const alive: Hypha[] = [] for (const hypha of hyphaeRef.current) { @@ -122,6 +182,21 @@ export function MycelialCanvas() { hypha.angle += (Math.random() - 0.5) * 0.12 // Gentle gravitropism (slightly toward vertical) hypha.angle += (-Math.PI / 2 - hypha.angle) * 0.003 + + // Mouse attraction: hyphae gently curve toward cursor + if (mouse.active) { + const dx = mouse.x - hypha.x + const dy = mouse.y - hypha.y + const dist = Math.sqrt(dx * dx + dy * dy) + if (dist < 300 && dist > 20) { + const targetAngle = Math.atan2(dy, dx) + let angleDiff = targetAngle - hypha.angle + if (angleDiff > Math.PI) angleDiff -= Math.PI * 2 + if (angleDiff < -Math.PI) angleDiff += Math.PI * 2 + hypha.angle += angleDiff * 0.015 * (1 - dist / 300) + } + } + hypha.x += Math.cos(hypha.angle) * hypha.speed hypha.y += Math.sin(hypha.angle) * hypha.speed @@ -133,9 +208,9 @@ export function MycelialCanvas() { const ageRatio = hypha.age / hypha.maxAge const opacity = Math.max( 0.05, - (1 - ageRatio * 0.9) * (0.6 - hypha.depth * 0.08) + (1 - ageRatio * 0.9) * (0.6 - hypha.depth * 0.06) ) - const lineWidth = Math.max(0.3, 2.5 - hypha.depth * 0.4 - ageRatio) + const lineWidth = Math.max(0.3, 2.5 - hypha.depth * 0.35 - ageRatio) // Draw on trail canvas for persistence trailCtx.strokeStyle = accent.replace(")", ` / ${opacity * 0.5})`) @@ -154,6 +229,25 @@ export function MycelialCanvas() { ctx.fill() } + // Draw faint connections between nearby hyphae tips + if (ageRatio < 0.5 && hypha.depth < 3) { + for (const other of alive) { + if (other === hypha) continue + const ox = other.x - hypha.x + const oy = other.y - hypha.y + const od = Math.sqrt(ox * ox + oy * oy) + if (od < 80 && od > 10) { + const connOpacity = 0.06 * (1 - od / 80) + ctx.strokeStyle = accent.replace(")", ` / ${connOpacity})`) + ctx.lineWidth = 0.5 + ctx.beginPath() + ctx.moveTo(hypha.x, hypha.y) + ctx.lineTo(other.x, other.y) + ctx.stroke() + } + } + } + // Branching if ( hypha.age > 25 && @@ -171,6 +265,65 @@ export function MycelialCanvas() { alive.push(hypha) } + // Spore particles + const now = Date.now() + // Emit spores near mouse + if (mouse.active && now - lastSporeEmit > 150) { + lastSporeEmit = now + sporesRef.current.push( + createSpore( + mouse.x + (Math.random() - 0.5) * 40, + mouse.y + (Math.random() - 0.5) * 40 + ) + ) + } + + // Emit ambient spores occasionally + if (now - lastSporeEmit > 800 && sporesRef.current.length < 30) { + lastSporeEmit = now + sporesRef.current.push( + createSpore(Math.random() * width, Math.random() * height) + ) + } + + // Update and draw spores + const aliveSpores: Spore[] = [] + for (const spore of sporesRef.current) { + spore.life++ + if (spore.life >= spore.maxLife) continue + + spore.x += spore.vx + spore.y += spore.vy + spore.vx *= 0.98 + spore.vy *= 0.98 + + const lifeRatio = spore.life / spore.maxLife + const sporeOpacity = Math.sin(lifeRatio * Math.PI) * 0.3 + const sporeRadius = spore.radius * (1 - lifeRatio * 0.5) + + ctx.fillStyle = accent.replace(")", ` / ${sporeOpacity})`) + ctx.beginPath() + ctx.arc(spore.x, spore.y, sporeRadius, 0, Math.PI * 2) + ctx.fill() + + aliveSpores.push(spore) + } + sporesRef.current = aliveSpores + + // Mouse glow effect + if (mouse.active) { + const gradient = ctx.createRadialGradient( + mouse.x, mouse.y, 0, + mouse.x, mouse.y, 120 + ) + gradient.addColorStop(0, accent.replace(")", " / 0.06)")) + gradient.addColorStop(1, accent.replace(")", " / 0)")) + ctx.fillStyle = gradient + ctx.beginPath() + ctx.arc(mouse.x, mouse.y, 120, 0, Math.PI * 2) + ctx.fill() + } + // Draw trail canvas behind ctx.drawImage(trailCanvas, 0, 0, width, height) @@ -178,8 +331,7 @@ export function MycelialCanvas() { hyphaeRef.current = alive.length > 500 ? alive.slice(-400) : alive // Periodically seed new roots - const now = Date.now() - if (now - lastSeed > 3000 && alive.length < 350) { + if (now - lastSeed > 2500 && alive.length < 400) { lastSeed = now const x = Math.random() * width hyphaeRef.current.push( @@ -194,6 +346,9 @@ export function MycelialCanvas() { return () => { window.removeEventListener("resize", resize) + window.removeEventListener("mousemove", onMouseMove) + window.removeEventListener("touchmove", onTouchMove) + window.removeEventListener("mouseleave", onMouseLeave) cancelAnimationFrame(frameRef.current) } }, []) @@ -201,8 +356,8 @@ export function MycelialCanvas() { return ( ) } diff --git a/components/network-map-section.tsx b/components/network-map-section.tsx index 55875d1..9840e3d 100644 --- a/components/network-map-section.tsx +++ b/components/network-map-section.tsx @@ -25,7 +25,7 @@ const NODES: NetworkNode[] = [ { name: "Commons Stack", domain: "commonsstack.org", - description: "Fund and govern the commons", + description: "Fund and govern the commons — primary root", x: 50, y: 10, }, @@ -40,57 +40,71 @@ const NODES: NetworkNode[] = [ name: "MycoFi", domain: "mycofi.earth", description: "Mycoeconomics & regenerative currencies", - x: 25, + x: 22, y: 20, }, { name: "Mycopunk", domain: "mycopunk.xyz", description: "Building from beneath the surface", - x: 75, + x: 78, y: 15, }, + { + name: "rFunds", + domain: "rfunds.online", + description: "Threshold-Based Flow Funding research", + x: 32, + y: 30, + }, + { + name: "rStack", + domain: "rstack.org", + description: "Open source community coordination infrastructure", + x: 75, + y: 58, + }, { name: "Compost Capitalism", domain: "compostcapitalism.xyz", description: "Decomposing extractive systems", - x: 12, + x: 10, y: 50, }, { name: "The Undernet", domain: "undernet.earth", description: "Community-owned infrastructure", - x: 88, - y: 45, + x: 90, + y: 40, }, { name: "Post-Appitalism", domain: "post-appitalist.app", description: "Tools beyond extractive platforms", - x: 22, + x: 18, y: 78, }, { name: "(You)rSpace", domain: "yourspace.online", - description: "Spaces that belong to communities", - x: 60, - y: 80, + description: "Community-owned digital spaces", + x: 62, + y: 78, }, { name: "Psilo-Cyber", domain: "psilo-cyber.net", description: "Encrypted mesh networks", - x: 82, + x: 85, y: 72, }, { name: "Trippin Balls", domain: "trippinballs.lol", description: "Expand your perspective", - x: 42, - y: 88, + x: 40, + y: 90, }, ] @@ -101,9 +115,14 @@ const CONNECTIONS: [string, string][] = [ ["mycostack.xyz", "undernet.earth"], ["mycostack.xyz", "compostcapitalism.xyz"], ["mycostack.xyz", "yourspace.online"], + ["mycostack.xyz", "rstack.org"], ["commonsstack.org", "wiki.p2pfoundation.net"], ["commonsstack.org", "mycofi.earth"], ["commonsstack.org", "mycopunk.xyz"], + ["commonsstack.org", "rfunds.online"], + ["rfunds.online", "mycofi.earth"], + ["rstack.org", "yourspace.online"], + ["rstack.org", "undernet.earth"], ["wiki.p2pfoundation.net", "post-appitalist.app"], ["mycofi.earth", "mycopunk.xyz"], ["undernet.earth", "psilo-cyber.net"], diff --git a/components/scroll-provider.tsx b/components/scroll-provider.tsx index 5549464..1a90af5 100644 --- a/components/scroll-provider.tsx +++ b/components/scroll-provider.tsx @@ -5,15 +5,16 @@ import { useEffect } from "react" // Color stops: [scrollPos, bg-L, bg-C, bg-H, fg-L, fg-C, fg-H, accent-L, accent-C, accent-H] // 8 sections: Hero → Legacy → Compost → Mycelium → Undernet → Anastomosis → Emergence → Network Map +// Gentler rainbow fade with lighter start, lower chroma for subtlety const COLOR_STOPS: number[][] = [ - [0.0, 0.08, 0.02, 30, 0.85, 0.03, 80, 0.45, 0.12, 60 ], // Hero: deep soil - [0.10, 0.10, 0.03, 35, 0.84, 0.03, 80, 0.50, 0.13, 50 ], // Legacy: dark warm earth - [0.20, 0.12, 0.04, 40, 0.82, 0.04, 80, 0.55, 0.15, 45 ], // Compost: earth brown - [0.35, 0.16, 0.05, 150, 0.88, 0.05, 145, 0.55, 0.18, 155], // Mycelium: forest green - [0.48, 0.22, 0.04, 200, 0.90, 0.03, 200, 0.50, 0.14, 220], // Undernet: deep blue - [0.60, 0.45, 0.06, 140, 0.15, 0.03, 150, 0.65, 0.18, 145], // Anastomosis: transition - [0.78, 0.85, 0.04, 110, 0.15, 0.04, 100, 0.60, 0.16, 90 ], // Emergence: golden light - [0.92, 0.94, 0.02, 110, 0.12, 0.03, 100, 0.55, 0.18, 155], // Network Map: canopy + [0.0, 0.18, 0.015, 30, 0.88, 0.02, 80, 0.50, 0.10, 60 ], // Hero: warm twilight (lighter) + [0.10, 0.16, 0.018, 40, 0.86, 0.02, 80, 0.52, 0.10, 50 ], // Legacy: warm earth + [0.20, 0.15, 0.025, 50, 0.84, 0.03, 75, 0.55, 0.11, 45 ], // Compost: amber earth + [0.35, 0.18, 0.03, 150, 0.88, 0.03, 145, 0.55, 0.13, 155], // Mycelium: forest green + [0.48, 0.22, 0.025, 210, 0.90, 0.02, 200, 0.52, 0.10, 220], // Undernet: deep teal + [0.60, 0.45, 0.03, 160, 0.15, 0.02, 150, 0.60, 0.12, 145], // Anastomosis: transition + [0.78, 0.82, 0.025, 110, 0.15, 0.03, 100, 0.58, 0.12, 90 ], // Emergence: golden light + [0.92, 0.92, 0.015, 120, 0.12, 0.02, 100, 0.55, 0.13, 155], // Network Map: canopy ] function lerp(a: number, b: number, t: number) {