Restructure MycoStack roots, add interactive effects & data flows

- 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 <noreply@anthropic.com>
This commit is contained in:
Jeff Emmett 2026-02-25 19:08:54 -08:00
parent 465320623e
commit e0af4e23ae
7 changed files with 412 additions and 105 deletions

View File

@ -5,9 +5,9 @@
:root { :root {
/* Scroll-driven dynamic colors (set by JS) */ /* Scroll-driven dynamic colors (set by JS) */
--scroll-bg: oklch(0.08 0.02 30); --scroll-bg: oklch(0.18 0.015 30);
--scroll-fg: oklch(0.85 0.03 80); --scroll-fg: oklch(0.88 0.02 80);
--scroll-accent: oklch(0.45 0.12 60); --scroll-accent: oklch(0.50 0.10 60);
--scroll-depth: 0; --scroll-depth: 0;
/* Static palette tokens */ /* Static palette tokens */

View File

@ -5,11 +5,13 @@ const LINKS = [
{ name: "P2P Foundation", url: "https://wiki.p2pfoundation.net/" }, { name: "P2P Foundation", url: "https://wiki.p2pfoundation.net/" },
{ name: "MycoFi", url: "https://mycofi.earth" }, { name: "MycoFi", url: "https://mycofi.earth" },
{ name: "Mycopunk", url: "https://mycopunk.xyz" }, { 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: "Undernet", url: "https://undernet.earth" },
{ name: "Psilo-Cyber", url: "https://psilo-cyber.net" }, { name: "Psilo-Cyber", url: "https://psilo-cyber.net" },
{ name: "Compost Capitalism", url: "https://compostcapitalism.xyz" }, { name: "Compost Capitalism", url: "https://compostcapitalism.xyz" },
{ name: "Post-Appitalism", url: "https://post-appitalist.app" }, { name: "Post-Appitalism", url: "https://post-appitalist.app" },
{ name: "(You)rSpace", url: "https://yourspace.online" },
{ name: "Trippin Balls", url: "https://trippinballs.lol" }, { name: "Trippin Balls", url: "https://trippinballs.lol" },
] ]

View File

@ -42,8 +42,8 @@ export function HeroSection() {
className="emerge-letter text-sm sm:text-base opacity-40 max-w-xl mx-auto" className="emerge-letter text-sm sm:text-base opacity-40 max-w-xl mx-auto"
style={{ animationDelay: "1.5s" }} style={{ animationDelay: "1.5s" }}
> >
Born from the P2P Foundation and the Commons Stack. Rooted in the Commons Stack. Nourished by the P2P Foundation.
Inoculating the age of the P4P (peer-for-peer) movement. Propagating the P4P (peer-for-peer) movement.
</p> </p>
{/* Terminal tagline */} {/* Terminal tagline */}

View File

@ -16,42 +16,42 @@ export function LegacySection() {
The Roots The Roots
</h2> </h2>
<p className="text-lg sm:text-xl opacity-70 max-w-2xl mx-auto"> <p className="text-lg sm:text-xl opacity-70 max-w-2xl mx-auto">
Every network grows from somewhere. Ours grows from the Commons The MycoStack grows from the Commons Stack &mdash; its primary root
Stack, the P2P Foundation, and the broader commons movement. system &mdash; nourished by the knowledge commons of the P2P
Foundation and the broader commons movement.
</p> </p>
</div> </div>
{/* P2P Foundation */} {/* Commons Stack - Primary Root */}
<div className="section-reveal max-w-3xl mx-auto space-y-6"> <div className="section-reveal max-w-3xl mx-auto space-y-6">
<h3 className="font-serif text-2xl sm:text-3xl font-semibold"> <h3 className="font-serif text-2xl sm:text-3xl font-semibold">
The P2P Foundation The Commons Stack
</h3> </h3>
<div className="space-y-4 text-base leading-relaxed opacity-80"> <div className="space-y-4 text-base leading-relaxed opacity-80">
<p> <p>
The{" "} The{" "}
<a <a
href="https://wiki.p2pfoundation.net/" href="https://commonsstack.org"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className="domain-link" className="domain-link"
> >
P2P Foundation Wiki Commons Stack
</a> </a>{" "}
, started by Michel Bauwens and shaped by is the primary root of the MycoStack. Its mission:{" "}
hundreds of contributors, documents the emerging landscape of <em>fund and govern the commons</em>. Through pioneering work in
peer-to-peer collaboration and commons-based alternatives. Over token engineering, augmented bonding curves, and conviction
25,000 pages of case studies, theoretical frameworks, policy voting, the Commons Stack and its{" "}
proposals, and practical guides &mdash; an open knowledge base <strong>Trusted Seed</strong> community developed regenerative
that continues to inform projects worldwide. funding mechanisms for commons infrastructure.
</p> </p>
<p> <p>
Out of this work came key frameworks:{" "} But tools alone aren&rsquo;t enough. The Commons Stack taught us
<strong>commons-based peer production</strong>, the{" "} that technology must be wrapped in culture &mdash; in shared
<strong>partner state</strong>, and{" "} values, governance practices, and communities of care. The
<strong>cosmo-localism</strong> (&ldquo;design global, manufacture Trusted Seed wasn&rsquo;t just a token-holder registry; it was an
local&rdquo;). These ideas didn&rsquo;t belong to any one person experiment in building trust at the speed of consensus. From this
&mdash; they emerged from a network of researchers, practitioners, root system, the MycoStack grows outward.
and communities building alternatives in the open.
</p> </p>
</div> </div>
</div> </div>
@ -94,81 +94,133 @@ export function LegacySection() {
</p> </p>
</div> </div>
{/* Commons Stack history */} {/* P2P Foundation - Foundation AND Forward */}
<div <div
className="section-reveal max-w-3xl mx-auto space-y-6" className="section-reveal max-w-3xl mx-auto space-y-6"
style={{ transitionDelay: "0.15s" }} style={{ transitionDelay: "0.12s" }}
> >
<h3 className="font-serif text-2xl sm:text-3xl font-semibold"> <h3 className="font-serif text-2xl sm:text-3xl font-semibold">
The Commons Stack The P2P Foundation
</h3> </h3>
<div className="space-y-4 text-base leading-relaxed opacity-80"> <div className="space-y-4 text-base leading-relaxed opacity-80">
<p> <p>
The{" "} The{" "}
<a <a
href="https://commonsstack.org" href="https://wiki.p2pfoundation.net/"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className="domain-link" className="domain-link"
> >
Commons Stack P2P Foundation Wiki
</a>{" "} </a>
was born from this intellectual tradition. Its mission:{" "} , started by Michel Bauwens and shaped by
<em>fund and govern the commons</em>. Through pioneering work in hundreds of contributors, is both the bedrock beneath the
token engineering, augmented bonding curves, and conviction MycoStack and the frontier ahead of it. Over 25,000 pages of
voting, the Commons Stack and its{" "} case studies, theoretical frameworks, policy proposals, and
<strong>Trusted Seed</strong> community developed regenerative practical guides &mdash; an open knowledge base that continues
funding mechanisms for commons infrastructure. to inform projects worldwide.
</p> </p>
<p> <p>
But tools alone aren&rsquo;t enough. The Commons Stack taught us Out of this work came key frameworks:{" "}
that technology must be wrapped in culture &mdash; in shared <strong>commons-based peer production</strong>, the{" "}
values, governance practices, and communities of care. The <strong>partner state</strong>, and{" "}
Trusted Seed wasn&rsquo;t just a token-holder registry; it was an <strong>cosmo-localism</strong> (&ldquo;design global, manufacture
experiment in building trust at the speed of consensus. local&rdquo;). But the P2P Foundation doesn&rsquo;t just preserve
knowledge &mdash; it transforms it. Each iteration of commons
practice feeds back into the knowledge base, refining theories
into{" "}
<strong>convivial knowledge packets</strong>: living documents
that distill decades of research and practice into actionable
frameworks communities can actually use.
</p>
<p>
These knowledge packets become the seeds of{" "}
<strong>open source protocol toolkits</strong> &mdash; 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.
</p> </p>
</div> </div>
</div> </div>
{/* Flow Funding */} {/* Data Flows - New Section */}
<div <div
className="section-reveal max-w-3xl mx-auto space-y-6" className="section-reveal max-w-3xl mx-auto space-y-6"
style={{ transitionDelay: "0.18s" }} style={{ transitionDelay: "0.15s" }}
> >
<h3 className="font-serif text-2xl sm:text-3xl font-semibold"> <h3 className="font-serif text-2xl sm:text-3xl font-semibold">
Flow Funding Data Flows of the Commons
</h3> </h3>
<div className="space-y-4 text-base leading-relaxed opacity-80"> <div className="space-y-4 text-base leading-relaxed opacity-80">
<p> <p>
The Commons Stack pioneered the Augmented Bonding Curve &mdash; a The MycoStack recognizes that the dissemination of{" "}
breakthrough in sustainable funding for the commons. Flow Funding <strong>trust</strong>, <strong>resources</strong>,{" "}
is its natural evolution: less mechanism, more ecology. Where the <strong>favors</strong>, and <strong>capital</strong> are all
ABC created a single reservoir, Flow Funding cultivates{" "} data flows &mdash; streams that can be made visible, governed
<em>enmeshed ecologies</em> of inter- and intra-organizational collectively, and managed by communities on self-provisioned
flow &mdash; resources circulating continuously between nested infrastructure.
communities the way nutrients cycle through a forest floor.
</p> </p>
<p> <p>
At the heart of Flow Funding is a threshold-based model rooted in When communities own their own coordination tools, these flows
the concept of <strong>&ldquo;enoughness&rdquo;</strong> &mdash; stop being opaque transactions mediated by extractive platforms
enabling an economics of sufficiency rather than accumulation. When and become transparent, reciprocal exchanges governed by the
a node in the network has enough, surplus flows onward to where people who participate in them. Trust becomes legible. Resources
it&rsquo;s needed. No hoarding, no artificial scarcity. Just the find their way to where they&rsquo;re needed. Favors compound
continuous circulation that living systems have practiced for into mutual aid networks. Capital circulates instead of
billions of years. accumulating.
</p> </p>
<p> </div>
This is economics as ecology: not designing incentives from above,
but cultivating the conditions for resources to find their own <div className="glass-card p-6 sm:p-8 space-y-4">
path &mdash; rooted, reciprocal, and regenerative by nature. <h4 className="font-serif text-lg font-semibold opacity-70">
Community-Owned Infrastructure for Coordination
</h4>
<div className="grid gap-4 sm:grid-cols-2 font-mono text-sm">
<div className="space-y-1">
<div className="font-serif text-base font-semibold not-italic">
<a
href="https://rstack.org"
target="_blank"
rel="noopener noreferrer"
className="domain-link"
>
rStack
</a>
</div>
<div className="opacity-60">
Open source infrastructure stack for community coordination
&mdash; self-hostable, sovereign, interoperable
</div>
</div>
<div className="space-y-1">
<div className="font-serif text-base font-semibold not-italic">
<a
href="https://yourspace.online"
target="_blank"
rel="noopener noreferrer"
className="domain-link"
>
(You)rSpace
</a>
</div>
<div className="opacity-60">
Community-owned digital spaces &mdash; where coordination
happens on infrastructure you control
</div>
</div>
</div>
<p className="text-sm opacity-50 pt-2">
When communities own their stack, every data flow becomes a
commons resource rather than a corporate asset.
</p> </p>
</div> </div>
</div> </div>
{/* P4P framework */} {/* P4P Movement */}
<div <div
className="section-reveal max-w-3xl mx-auto space-y-6" className="section-reveal max-w-3xl mx-auto space-y-6"
style={{ transitionDelay: "0.24s" }} style={{ transitionDelay: "0.20s" }}
> >
<h3 className="font-serif text-3xl sm:text-4xl md:text-5xl font-bold text-center"> <h3 className="font-serif text-3xl sm:text-4xl md:text-5xl font-bold text-center">
The Birth of the The Birth of the
@ -186,9 +238,12 @@ export function LegacySection() {
practice. practice.
</p> </p>
<p> <p>
Where the original Commons Stack built tools, MycoStack grows The P2P Foundation&rsquo;s convivial knowledge packets become
ecosystems. Where P2P described a relational dynamic, P4P demands the P4P movement&rsquo;s open source protocol toolkits &mdash;
a commitment. The mycelium doesn&rsquo;t just connect &mdash; it 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&rsquo;t just connect &mdash; it
nourishes. nourishes.
</p> </p>
</div> </div>
@ -239,6 +294,81 @@ export function LegacySection() {
</div> </div>
</div> </div>
{/* Tools in Active Research */}
<div
className="section-reveal max-w-3xl mx-auto space-y-6"
style={{ transitionDelay: "0.22s" }}
>
<h3 className="font-serif text-2xl sm:text-3xl font-semibold">
Tools in Active Research
</h3>
<div className="space-y-4 text-base leading-relaxed opacity-80">
<p>
<strong>Flow Funding</strong> &mdash; the natural evolution of
the Commons Stack&rsquo;s Augmented Bonding Curve. Less
mechanism, more ecology. Where the ABC created a single
reservoir, Flow Funding cultivates{" "}
<em>enmeshed ecologies</em> of inter- and intra-organizational
flow &mdash; resources circulating continuously between nested
communities the way nutrients cycle through a forest floor.
</p>
<p>
The latest research takes the form of{" "}
<strong>Threshold-Based Flow Funding (TBFF)</strong>, being
developed at{" "}
<a
href="https://rfunds.online"
target="_blank"
rel="noopener noreferrer"
className="domain-link"
>
rFunds.online
</a>
. TBFF models funding pools as dynamic funnels operating across
three zones: an <strong>overflow zone</strong> where excess funds
automatically redistribute to connected pools, a{" "}
<strong>healthy zone</strong> of full flow and balanced
operations, and a <strong>critical zone</strong> where outflow
restricts to conservation mode. Funnels connect via overflow and
spending edges, creating living networks of resource circulation
governed by thresholds of{" "}
<strong>&ldquo;enoughness&rdquo;</strong> rather than
accumulation.
</p>
<p>
This is economics as ecology: not designing incentives from above,
but cultivating the conditions for resources to find their own
path &mdash; rooted, reciprocal, and regenerative by nature.
</p>
</div>
<div className="glass-card p-6 space-y-3 font-mono text-sm">
<div className="font-serif text-base font-semibold not-italic opacity-70">
TBFF Zones
</div>
<div className="grid gap-2 sm:grid-cols-3">
<div className="space-y-1">
<div className="opacity-50">overflow</div>
<div className="opacity-70 text-xs">
Above MAX &mdash; surplus redistributes to connected funnels
</div>
</div>
<div className="space-y-1">
<div style={{ color: "var(--mycelium-green)" }}>healthy</div>
<div className="opacity-70 text-xs">
Normal ops &mdash; full flow rate, balanced funding
</div>
</div>
<div className="space-y-1">
<div style={{ color: "var(--compost-amber)" }}>critical</div>
<div className="opacity-70 text-xs">
Below MIN &mdash; outflow restricted, conservation mode
</div>
</div>
</div>
</div>
</div>
{/* Pillars */} {/* Pillars */}
<div <div
className="section-reveal grid gap-6 sm:grid-cols-2 max-w-3xl mx-auto" className="section-reveal grid gap-6 sm:grid-cols-2 max-w-3xl mx-auto"
@ -255,7 +385,7 @@ export function LegacySection() {
}, },
{ {
title: "Evolve", title: "Evolve",
text: "Update the theoretical frameworks for current conditions. Bridge Web3 and traditional commons movements. Experiment with emerging technologies in service of collective flourishing.", text: "Update the theoretical frameworks for current conditions. Distill research into convivial knowledge packets. Transform insights into open source protocol toolkits that communities can deploy.",
}, },
{ {
title: "Propagate", title: "Propagate",

View File

@ -15,11 +15,27 @@ interface Hypha {
branchCount: number branchCount: number
} }
interface Spore {
x: number
y: number
vx: number
vy: number
life: number
maxLife: number
radius: number
}
export function MycelialCanvas() { export function MycelialCanvas() {
const canvasRef = useRef<HTMLCanvasElement>(null) const canvasRef = useRef<HTMLCanvasElement>(null)
const hyphaeRef = useRef<Hypha[]>([]) const hyphaeRef = useRef<Hypha[]>([])
const sporesRef = useRef<Spore[]>([])
const frameRef = useRef<number>(0) const frameRef = useRef<number>(0)
const trailCanvasRef = useRef<HTMLCanvasElement | null>(null) const trailCanvasRef = useRef<HTMLCanvasElement | null>(null)
const mouseRef = useRef<{ x: number; y: number; active: boolean }>({
x: 0,
y: 0,
active: false,
})
useEffect(() => { useEffect(() => {
const canvas = canvasRef.current const canvas = canvasRef.current
@ -50,8 +66,28 @@ export function MycelialCanvas() {
resize() resize()
window.addEventListener("resize", resize) window.addEventListener("resize", resize)
const w = () => canvas.width / (Math.min(window.devicePixelRatio || 1, 2)) // Mouse/touch tracking for interactive effects
const h = () => canvas.height / (Math.min(window.devicePixelRatio || 1, 2)) 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 = ( const createHypha = (
x: number, x: number,
@ -62,17 +98,27 @@ export function MycelialCanvas() {
x, x,
y, y,
angle, angle,
speed: 1.2 + Math.random() * 0.8 - depth * 0.15, speed: 1.0 + Math.random() * 0.6 - depth * 0.1,
age: 0, age: 0,
maxAge: 200 + Math.random() * 150 - depth * 20, maxAge: 250 + Math.random() * 200 - depth * 15,
parentX: x, parentX: x,
parentY: y, parentY: y,
depth, depth,
branchCount: 0, branchCount: 0,
}) })
// Seed initial hyphae from bottom const createSpore = (x: number, y: number): Spore => ({
const seedCount = Math.max(3, Math.floor(w() / 250)) 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++) { for (let i = 0; i < seedCount; i++) {
const x = const x =
(w() / (seedCount + 1)) * (i + 1) + (Math.random() - 0.5) * 80 (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 = () => { const getAccentColor = () => {
return ( return (
getComputedStyle(document.documentElement) getComputedStyle(document.documentElement)
.getPropertyValue("--scroll-accent") .getPropertyValue("--scroll-accent")
.trim() || "oklch(0.55 0.18 155)" .trim() || "oklch(0.55 0.13 155)"
) )
} }
let lastSeed = 0 let lastSeed = 0
let lastSporeEmit = 0
const animate = () => { const animate = () => {
const width = w() const width = w()
@ -104,10 +163,11 @@ export function MycelialCanvas() {
ctx.clearRect(0, 0, width, height) ctx.clearRect(0, 0, width, height)
// Fade the trail canvas slowly // 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) trailCtx.fillRect(0, 0, width, height)
const accent = getAccentColor() const accent = getAccentColor()
const mouse = mouseRef.current
const alive: Hypha[] = [] const alive: Hypha[] = []
for (const hypha of hyphaeRef.current) { for (const hypha of hyphaeRef.current) {
@ -122,6 +182,21 @@ export function MycelialCanvas() {
hypha.angle += (Math.random() - 0.5) * 0.12 hypha.angle += (Math.random() - 0.5) * 0.12
// Gentle gravitropism (slightly toward vertical) // Gentle gravitropism (slightly toward vertical)
hypha.angle += (-Math.PI / 2 - hypha.angle) * 0.003 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.x += Math.cos(hypha.angle) * hypha.speed
hypha.y += Math.sin(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 ageRatio = hypha.age / hypha.maxAge
const opacity = Math.max( const opacity = Math.max(
0.05, 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 // Draw on trail canvas for persistence
trailCtx.strokeStyle = accent.replace(")", ` / ${opacity * 0.5})`) trailCtx.strokeStyle = accent.replace(")", ` / ${opacity * 0.5})`)
@ -154,6 +229,25 @@ export function MycelialCanvas() {
ctx.fill() 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 // Branching
if ( if (
hypha.age > 25 && hypha.age > 25 &&
@ -171,6 +265,65 @@ export function MycelialCanvas() {
alive.push(hypha) 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 // Draw trail canvas behind
ctx.drawImage(trailCanvas, 0, 0, width, height) ctx.drawImage(trailCanvas, 0, 0, width, height)
@ -178,8 +331,7 @@ export function MycelialCanvas() {
hyphaeRef.current = alive.length > 500 ? alive.slice(-400) : alive hyphaeRef.current = alive.length > 500 ? alive.slice(-400) : alive
// Periodically seed new roots // Periodically seed new roots
const now = Date.now() if (now - lastSeed > 2500 && alive.length < 400) {
if (now - lastSeed > 3000 && alive.length < 350) {
lastSeed = now lastSeed = now
const x = Math.random() * width const x = Math.random() * width
hyphaeRef.current.push( hyphaeRef.current.push(
@ -194,6 +346,9 @@ export function MycelialCanvas() {
return () => { return () => {
window.removeEventListener("resize", resize) window.removeEventListener("resize", resize)
window.removeEventListener("mousemove", onMouseMove)
window.removeEventListener("touchmove", onTouchMove)
window.removeEventListener("mouseleave", onMouseLeave)
cancelAnimationFrame(frameRef.current) cancelAnimationFrame(frameRef.current)
} }
}, []) }, [])
@ -201,8 +356,8 @@ export function MycelialCanvas() {
return ( return (
<canvas <canvas
ref={canvasRef} ref={canvasRef}
className="fixed inset-0 pointer-events-none" className="fixed inset-0"
style={{ zIndex: 0, opacity: 0.55 }} style={{ zIndex: 0, opacity: 0.6, pointerEvents: "none" }}
/> />
) )
} }

View File

@ -25,7 +25,7 @@ const NODES: NetworkNode[] = [
{ {
name: "Commons Stack", name: "Commons Stack",
domain: "commonsstack.org", domain: "commonsstack.org",
description: "Fund and govern the commons", description: "Fund and govern the commons — primary root",
x: 50, x: 50,
y: 10, y: 10,
}, },
@ -40,57 +40,71 @@ const NODES: NetworkNode[] = [
name: "MycoFi", name: "MycoFi",
domain: "mycofi.earth", domain: "mycofi.earth",
description: "Mycoeconomics & regenerative currencies", description: "Mycoeconomics & regenerative currencies",
x: 25, x: 22,
y: 20, y: 20,
}, },
{ {
name: "Mycopunk", name: "Mycopunk",
domain: "mycopunk.xyz", domain: "mycopunk.xyz",
description: "Building from beneath the surface", description: "Building from beneath the surface",
x: 75, x: 78,
y: 15, 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", name: "Compost Capitalism",
domain: "compostcapitalism.xyz", domain: "compostcapitalism.xyz",
description: "Decomposing extractive systems", description: "Decomposing extractive systems",
x: 12, x: 10,
y: 50, y: 50,
}, },
{ {
name: "The Undernet", name: "The Undernet",
domain: "undernet.earth", domain: "undernet.earth",
description: "Community-owned infrastructure", description: "Community-owned infrastructure",
x: 88, x: 90,
y: 45, y: 40,
}, },
{ {
name: "Post-Appitalism", name: "Post-Appitalism",
domain: "post-appitalist.app", domain: "post-appitalist.app",
description: "Tools beyond extractive platforms", description: "Tools beyond extractive platforms",
x: 22, x: 18,
y: 78, y: 78,
}, },
{ {
name: "(You)rSpace", name: "(You)rSpace",
domain: "yourspace.online", domain: "yourspace.online",
description: "Spaces that belong to communities", description: "Community-owned digital spaces",
x: 60, x: 62,
y: 80, y: 78,
}, },
{ {
name: "Psilo-Cyber", name: "Psilo-Cyber",
domain: "psilo-cyber.net", domain: "psilo-cyber.net",
description: "Encrypted mesh networks", description: "Encrypted mesh networks",
x: 82, x: 85,
y: 72, y: 72,
}, },
{ {
name: "Trippin Balls", name: "Trippin Balls",
domain: "trippinballs.lol", domain: "trippinballs.lol",
description: "Expand your perspective", description: "Expand your perspective",
x: 42, x: 40,
y: 88, y: 90,
}, },
] ]
@ -101,9 +115,14 @@ const CONNECTIONS: [string, string][] = [
["mycostack.xyz", "undernet.earth"], ["mycostack.xyz", "undernet.earth"],
["mycostack.xyz", "compostcapitalism.xyz"], ["mycostack.xyz", "compostcapitalism.xyz"],
["mycostack.xyz", "yourspace.online"], ["mycostack.xyz", "yourspace.online"],
["mycostack.xyz", "rstack.org"],
["commonsstack.org", "wiki.p2pfoundation.net"], ["commonsstack.org", "wiki.p2pfoundation.net"],
["commonsstack.org", "mycofi.earth"], ["commonsstack.org", "mycofi.earth"],
["commonsstack.org", "mycopunk.xyz"], ["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"], ["wiki.p2pfoundation.net", "post-appitalist.app"],
["mycofi.earth", "mycopunk.xyz"], ["mycofi.earth", "mycopunk.xyz"],
["undernet.earth", "psilo-cyber.net"], ["undernet.earth", "psilo-cyber.net"],

View File

@ -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] // 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 // 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[][] = [ 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.0, 0.18, 0.015, 30, 0.88, 0.02, 80, 0.50, 0.10, 60 ], // Hero: warm twilight (lighter)
[0.10, 0.10, 0.03, 35, 0.84, 0.03, 80, 0.50, 0.13, 50 ], // Legacy: dark warm earth [0.10, 0.16, 0.018, 40, 0.86, 0.02, 80, 0.52, 0.10, 50 ], // Legacy: warm earth
[0.20, 0.12, 0.04, 40, 0.82, 0.04, 80, 0.55, 0.15, 45 ], // Compost: earth brown [0.20, 0.15, 0.025, 50, 0.84, 0.03, 75, 0.55, 0.11, 45 ], // Compost: amber earth
[0.35, 0.16, 0.05, 150, 0.88, 0.05, 145, 0.55, 0.18, 155], // Mycelium: forest green [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.04, 200, 0.90, 0.03, 200, 0.50, 0.14, 220], // Undernet: deep blue [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.06, 140, 0.15, 0.03, 150, 0.65, 0.18, 145], // Anastomosis: transition [0.60, 0.45, 0.03, 160, 0.15, 0.02, 150, 0.60, 0.12, 145], // Anastomosis: transition
[0.78, 0.85, 0.04, 110, 0.15, 0.04, 100, 0.60, 0.16, 90 ], // Emergence: golden light [0.78, 0.82, 0.025, 110, 0.15, 0.03, 100, 0.58, 0.12, 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.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) { function lerp(a: number, b: number, t: number) {