1/** 2 * Fungus 3 * 4 * The grown light's source. Each night chapter carries a colony â an emerald 5 * tint at one edge of the page (colonies.css) â and both design judges found 6 * what that is without anything to cast it: "night is only a gradient; the 7 * only glows are sourceless", "moss light never shows as a light source". A 8 * glow at the edge of a forest at night is foxfire: bracket fungus on a trunk, 9 * lit from its own gills. So the page's edge is the trunk, and the fungus 10 * grows out of it where the colony is, shelves stacked and overlapping, each 11 * with a lit underside and a faint pool of its own light. 12 * 13 * Seeded by the chapter, like the plants, so each colony is its own growth. 14 * Drawn growing rightward from x=0; the right-hand colonies are mirrored in CSS. 15 */ 16import { seedOf, rngOf, round } from './stem/seed.js'; 17 18/* One shelf: a cap bulging out from the trunk, its underside a flatter arc, 19 and the gills along that underside lit. */ 20const shelf = (x, y, w, h, rings = [0.72, 0.46]) => { 21 const cap = `M${round(x)},${round(y - h * 0.62)}` 22 + `C${round(x + w * 0.5)},${round(y - h * 1.18)} ${round(x + w * 1.06)}
22,${round(y - h * 0.62)} ${round(x + w)},${round(y)}` 23 + `C${round(x + w * 0.74)},${round(y + h * 0.14)} ${round(x + w * 0.3)},${round(y + h * 0.2)} ${round(x)},${round(y + h * 0.14)}Z`; 24 const gills = `M${round(x + w)},${round(y)}C${round(x + w * 0.74)},${round(y + h * 0.14)} ${round(x + w * 0.3)},${round(y + h * 0.2)} ${round(x)},${round(y + h * 0.14)}`; 25 // Growth bands: the cap's own outline at earlier sizes, drawn from where 26 // it meets the bark, the rings a bracket lays down as it grows. 27 const bands = rings.map((f) => `M${round(x)},${round(y - h * 0.62 * f)}` 28 + `C${round(x + w * 0.5 * f)},${round(y - h * 1.18 * f)} ${round(x + w * 1.06 * f)},${round(y - h * 0.62 * f)} ${round(x + w * f)},${round(y)}`).join(''); 29 return { cap, gills, bands }; 30}; 31 32/* The bark it grows from: a ragged sliver at the page's edge, so the shelves 33 stand on a trunk and do not float. */ 34const bark = (rand, height) => { 35 const n = 16; 36 const pts = Array.from({ length: n + 1 }, (_, i) => `${round(4 + rand() * 6)},${round((i / n) * height)}`); 37 return `M-2,${round(height * 0.04)}L${pts.slice(1, -1).join('L')}L-2,${round(height * 0.96)}Z`; 38}; 39 40/** 41 * @param {object} spec 42 * @param {string} spec.seed the chapter's id 43 * @param {number} spec.width how far from the edge it may grow, in px 44 * @param {number} spec.height the stretch of edge it grows along, in px 45 * @returns {string} SVG markup 46 */ 47export const fungusSvg = ({ seed, width, height }) => { 48 const rand = rngOf(seedOf(`fungus-${seed}`)); 49 const uid = `fg-${seed.replace(/[^a-z0-9]/gi, '')}`; 50 const count = 3 + Math.floor(rand() * 4); 51 // Shelves climb the trunk in a loose tier, the largest low, each smaller 52 // one above it and reaching less far. 53 // Tiers overlap closely, as brackets do, and each sits a little out from 54 // or in to the bark rather than in one column. 55 let y = height * (0.74 + rand() * 0.1); 56 const shelves = Array.from({ length: count }, (_, i) => { 57 const k = 1 - i / (count + 1); 58 // Now and then a young shelf, much smaller, between the grown ones: 59 // a clump of equals was "five near-identical half-discs". 60 const young = rand() < 0.3 ? 0.35 + rand() * 0.2 : 1; 61 const w = width * (0.4 + rand() * 0.5) * (0.55 + k * 0.45) * young; 62 const h = w * (0.44 + rand() * 0.26); 63 const x = 2 + rand() * width * 0.08; 64 const rings = Array.from({ length: 1 + Math.floor(rand() * 3) }, (_, r) => 0.82 - r * 0.22 - rand() * 0.08); 65 // Each tilts a little on its attachment, up or down. 66 const tilt = (rand() - 0.5) * 16; 67 const s = { ...shelf(x, y, w, h, rings), w, h, y, x, tilt }; 68 y -= h * (0.38 + rand() * 0.5); 69 return s; 70 }).filter((s) => s.y > s.h).reverse(); 71 const pools = shelves.map((s) => `<ellipse cx="${round(s.x + s.w * 0.45)}" cy="${round(s.y + s.h * 0.55)}
71" rx="${round(s.w * 0.9)}" ry="${round(s.h * 1.1)}" fill="url(#${uid}-pool)"/>`).join(''); 72 // Drawn top down, so each lower, larger shelf overlaps the one above it. 73 const caps = shelves.map((s) => `<g transform="rotate(${round(s.tilt)} ${round(s.x)} ${round(s.y)})"><path d="${s.cap}" fill="url(#${uid}-cap)"/>` 74 + `<path d="${s.bands}" fill="none" stroke="var(--fungus-band)" stroke-width="0.9" opacity="0.5"/>` 75 + `<path d="${s.gills}" fill="none" stroke="var(--fungus-lit)" stroke-width="${round(Math.max(1, s.h * 0.07))}" stroke-linecap="round"/></g>`).join(''); 76 // Moss where the shelves meet the bark, and a few spores in their light. 77 const moss = Array.from({ length: 5 + Math.floor(rand() * 5) }, () => { 78 const my = height * (0.2 + rand() * 0.75); 79 const r = 2 + rand() * 5; 80 return `<ellipse cx="${round(r * 0.4)}" cy="${round(my)}" rx="${round(r)}" ry="${round(r * (1.3 + rand()))}" fill="var(--fungus-moss)"/>`; 81 }).join(''); 82 const spores = Array.from({ length: 4 + Math.floor(rand() * 5) }, () => { 83 const s = shelves[Math.floor(rand() * shelves.length)]; 84 return s ? `<circle cx="${round(s.x + s.w * (0.2 + rand() * 0.9))}" cy="${round(s.y + s.h * (0.5 + rand() * 1.4))}" r="${round(0.6 + rand() * 0.9)}" fill="var(--fungus-lit)" opacity="${round(0.35 + rand() * 0.45)}"/>` : ''; 85 }).join('');
86 return `<svg class="fungus-svg" width="${round(width)}" height="${round(height)}" viewBox="0 0 ${round(width)} ${round(height)}" aria-hidden="true" focusable="false"> 87 <defs> 88 <radialGradient id="${uid}-pool"> 89 <stop offset="0" stop-color="var(--fungus-lit)" stop-opacity="0.2"/> 90 <stop offset="0.5" stop-color="var(--fungus-lit)" stop-opacity="0.06"/> 91 <stop offset="1" stop-color="var(--fungus-lit)" stop-opacity="0"/> 92 </radialGradient> 93 <!-- Dark above, where nothing lights the cap, and warming to the 94 lit edge below. --> 95 <linearGradient id="${uid}-cap" x1="0" y1="0" x2="0" y2="1"> 96 <stop offset="0" stop-color="var(--fungus-cap)"/> 97 <stop offset="0.8" stop-color="var(--fungus-cap-lit)"/> 98 </linearGradient> 99 <!-- The trunk's edge, darkening into the page's edge and fading 100 out along it: solid, it read as "a black bar with a 101 ruler-straight edge". --> 102 <linearGradient id="${uid}-bark" x1="0" y1="0" x2="0" y2="1"> 103 <stop offset="0" stop-color="var(--fungus-bark)" stop-opacity="0"/> 104 <stop offset="0.3" stop-color="var(--fungus-bark)" stop-opacity="0.75"/> 105 <stop offset="0.7" stop-color="var(--fungus-bark)" stop-opacity="0.75"/> 106 <stop offset="1" stop-color="var(--fungus-bark)" stop-opacity="0"/> 107 </linearGradient> 108 </defs> 109 ${pools} 110 <path d="${bark(rand, height)}" fill="url(#${uid}-bark)"/> 111 ${moss} 112 ${caps} 113 ${spores} 114 </svg>`; 115};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.