MYCELIUM · build note
Field notes on the field guide

How Mycelium
was made

A short, honest account of designing and building an interactive fungi field guide — the illustrations drawn entirely in code, the network that grows as you read, and the three rounds of critique that got it there.

01Brief & concept

A university-press book that came alive

The brief asked for an interactive field guide to fungi: a cream/forest/ochre naturalist palette, hand-drawn-feel mushroom illustrations, organically morphing shapes, a "mycelial network" canvas that spreads as you scroll, and spore-print dividers. Fraunces for display, Karla for text.

The organizing idea was restraint with one quiet wonder underneath it. A field guide is a calm, print-first object — generous margins, careful captions, the confidence to leave space. So the page reads mostly like a beautiful book. The wonder is what the book can't show on paper: the living network below the forest floor. Everything animated had to earn its place against that stillness.

To make the concept feel real rather than decorative, I invented a plausible brand — The Mycological Understory Society, publishing "Vol. IV · Understory Papers" — and wrote every word as copy, not filler: six full species accounts with habitat, season, spore print, and an edibility verdict that occasionally warns you off ("whether it wants to feed you or fell you").

02Design decisions

Where the choices were made

Typography as the illustration frame

Fraunces carries the whole voice. Its optical-size and SOFT/WONK axes let display headings feel drawn and slightly wonky — botanical, not corporate — while text-size settings stay legible. Karla, a humanist grotesque, keeps the body warm and quiet so the serif can be the character.

The design is mostly the whitespace and the type. Motion is the exception, not the rule.

A committed palette

Everything runs on CSS custom properties: cream paper, deep-forest ink, ochre and rust for the fungi, gold for the network glow. A multiply-blended SVG grain sits over the whole page so the "paper" never reads as flat screen-white. The dark network section inverts the palette — forest field, gold hyphae — so the one moment of spectacle is set apart from the calm reading around it.

Illustration over stock

Every mushroom is a hand-authored SVG. The trick to making vector shapes feel drawn is to refuse geometric perfection: wobble the outlines, add a faint pen-stroke pass over the fill, and layer real anatomy — a gill fringe under the cap, warts, a bulbous volva, honeycomb pits, concentric bracket bands.

index.html · a hand-wobbled species (Fly Agaric)
// faint pen-line pass reused across every illustration
const pen = 'stroke="#2b2417" stroke-opacity=".55" fill="none"';

// gill fringe under the cap — reads as a real amanita
<path d="M52 96 C70 106 130 106 148 96 L142 110 …Z" fill="#f0e5c9"/>
<g stroke="#cbb98d">${Array.from({length:13}).map((_,i)=>{
   const x = 60 + i*6.4;        // evenly-spaced blades
   return `<path d="M${x} 101 l1 10"/>`;
}).join('')}</g>
03Signature techniques

The three things worth stealing

1 · Mycelium that grows by branching

The centrepiece is a canvas "wood wide web." The first version was a mistake worth admitting (see the passes below); the version that shipped is a recursive hyphal-growth algorithm. A handful of hub "trees" each send out roots, and every segment curves via a perpendicular control point, then spawns one to three thinner children at a spread angle. Segments carry an order (their generation) so that on scroll the web can grow outward from the trunks, front by front.

index.html · recursive hypha, drawn as curved segments
function grow(x, y, ang, len, depth, ord){
  if (depth <= 0 || len < 9) return;
  const ex = x + Math.cos(ang)*len, ey = y + Math.sin(ang)*len;
  // curved control point, offset perpendicular to the run
  const perp = ang + Math.PI/2, bend = rnd(-len*.32, len*.32);
  segments.push({ x0:x, y0:y, x1:ex, y1:ey, order:ord, grow:0,
              cx: (x+ex)/2 + Math.cos(perp)*bend,
              cy: (y+ey)/2 + Math.sin(perp)*bend });
  // branch into 1–3 thinner, shorter children
  const kids = depth > 3 ? (Math.random()<.75?2:3) : (Math.random()<.6?2:1);
  for (let k=0; k<kids; k++)
    grow(ex, ey, ang + rnd(.35,.95)*(k%2?1:-1), len*rnd(.62,.82), depth-1, ord+1);
}

Scroll position sets a growth front; each segment eases its own grow value toward that front and is drawn as a partial quadratic curve, with a bright mote at its advancing tip. Line width tapers with generation, so trunks are bold and the finest threads are hairlines — which is exactly how mycelium looks.

2 · Blobs that morph like living tissue

The soft background shapes aren't static SVGs. Eight points on a circle each breathe on their own sine offset, and the path is rebuilt every frame through their midpoints so the curve stays smooth — an organic wobble instead of a rigid ellipse.

index.html · per-frame organic path interpolation
for (let i=0; i<n; i++){
  const ang = (i/n)*Math.PI*2;
  const rr  = base + Math.sin(ts/speed + seeds[i]) * amp;  // each point breathes
  pts.push([ cx + Math.cos(ang)*rr, cy + Math.sin(ang)*rr ]);
}
// rebuild the path through the midpoints for a smooth closed curve
el.setAttribute('d', buildSmoothPath(pts));

3 · Spore prints made of maths

The section dividers are real spore prints: a few hundred dots sprayed from a centre with a gaussian-ish falloff (dense and dark at the core, sparse at the edges), flattened vertically the way a cap deposits them on paper. Same function, different accent colour per divider.

A small honesty: nothing here is an image file. Every mushroom, every blob, every dot, and the whole network are drawn in code — SVG and <canvas>. The only external requests are the two Google Fonts.
04Assets & provenance

What's real, and where it came from

  • Illustrations — six species, one anatomy plate, four lifecycle icons, and the brandmark, all authored by hand as SVG path data. No stock, no AI image generation, no assets/ folder needed.
  • The network & hero motes — generated live in <canvas> with requestAnimationFrame, paused on document.hidden.
  • Paper grain — an inline feTurbulence SVG data-URI, multiply-blended. No texture image.
  • Type — Fraunces & Karla via Google Fonts (preconnect + display=swap). This build note also loads JetBrains Mono for the code blocks.
  • Copy — written for this build. The species facts are broadly accurate naturalist detail; treat the guide as design, not foraging advice.
05The three passes

What critique found, and what changed

Each pass followed the same loop: screenshot top, middle, and bottom at both 1440×900 and 390×844, read every frame like a hostile art director, fix everything, then add one deliberate complexity upgrade.

Pass one

The network was the problem

FoundThe first "network" connected random nodes with straight lines to their nearest neighbours. It read as a star-map constellation, not living mycelium. The fly-agaric cap met its stem with a hard flat edge. On mobile, the scroll hint overlapped a button and the eyebrow line widowed.
ChangedRebuilt the canvas around the recursive branching algorithm above — curved threads, tapering generations, growth fronts. This was the single biggest upgrade of the build: a constellation became a dense branching web.
Pass two

Charm and legibility

FoundThe fly agaric still felt like clip-art; the network legend sat directly on top of hyphae and was hard to read.
ChangedAdded a gill fringe and a fuller stem to the amanita so it reads botanically; shortened the eyebrow and hid the scroll hint on small screens; gave the legend a glassmorphic backing. Upgrade: a subtle background layer of faint static filaments behind the growing web for depth.
Pass three

Atmosphere and life

FoundThe hero was handsome but static; nothing rewarded lingering on it.
ChangedAdded drifting spore motes across the hero with gentle mouse parallax on the ambient blobs, plus a three-tap easter-egg spore burst on the logo. Verified zero console errors at both viewports with no horizontal overflow.
06Reproduce this

A checklist to build one like it

  • Commit to a palette in custom properties and lay a multiply-blended noise grain over everything — screen-white is the giveaway of an unfinished page.
  • Draw your illustrations in code and wobble them. A faint shared pen-stroke pass plus one layer of real anatomy turns flat vectors into something that reads as hand-drawn.
  • Make one hero interaction, and make it structural. A recursive branching system with an order per element lets you grow it on scroll for almost free.
  • Tie animation to the reader. Ease values toward a scroll-derived target; pause every loop on document.hidden; honour prefers-reduced-motion.
  • Write real copy. Invent a brand, give it a voice, and never ship lorem ipsum.
  • Screenshot and critique in passes. Read your own renders harshly at 1440 and 390; fix, then add one deliberate upgrade each round.
The rebuild you're least proud to admit is usually the one that makes the piece.

That's the whole thing. The source is a single self-contained index.html — no build step, no framework. Go back to the guide →