1/** 2 * Read vine 3 * 4 * How far down the descent a reader is, grown along the header's lower edge. 5 * It was a 2px rule that filled, and at night a design judge read it as "a 6 * full-width 1px light line â a hard mechanical edge on an organic page" and 7 * "a thin line, not a vein". So it is a tendril: tapering from its root at the 8 * left, wandering a little, and putting out a leaf at the start of each 9 * chapter, so the chapters passed are leaves already grown. navCurrent.js 10 * reveals it to the reader's depth; this only draws it at full length. 11 */ 12import { round } from './stem/seed.js'; 13import { leaf } from './stem/geometry.js'; 14 15/** 16 * @param {object} spec 17 * @param {number} spec.width the header's width, in px 18 * @param {number} spec.height the band it grows in, in px 19 * @param {number[]} spec.nodes where each chapter starts, as fractions of the run 20 * @returns {string} SVG markup 21 */ 22export const vineSvg = ({ width, height, nodes }) => { 23 const mid = height / 2; 24 const steps = Math.max(24, Math.round(width / 24)); 25 // Two slow waves, so it wanders rather than oscillates. 26 const y = (t) => mid + Math.sin(t * Math.PI * 7.3) * height * 0.09 + Math.sin(1.7 + t * Math.PI * 17.9) * height * 0.04; 27 const half = (t) => 1.15 * (1 - t) + 0.35; 28 const pts = Array.from({ length: steps + 1 }, (_, i) => i / steps); 29 const down = pts.map((t) => `${round(t * width)},${round(y(t) - half(t))}`); 30 const up = [...pts].reverse().map((t) => `${round(t * width)},${round(y(t) + half(t))}`); 31 const stem = `M${down.join('L')}L${up.join('L')}Z`; 32 // A leaf at each chapter, turned alternately into the bar and out of it, 33 // lying along the stem rather than across it (across, they read as a 34 // ruler's ticks), and shrinking a little along the run as a shoot's do. 35 const leaves = nodes.map((f, k) => { 36 const x = f * width; 37 const side = k % 2 ? 1 : -1; 38 const len = height * (0.62 - f * 0.14); 39 return `<path d="${leaf(x, y(f), side * 0.62, len, len * 0.34)}" fill="url(#read-vine)"/>`; 40 }).join('');
41 return `<svg width="${round(width)}" height="${round(height)}" viewBox="0 0 ${round(width)} ${round(height)}" aria-hidden="true" focusable="false"> 42 <defs> 43 <linearGradient id="read-vine" gradientUnits="userSpaceOnUse" x1="0" y1="0" x2="${round(width)}" y2="0"> 44 <stop offset="0" stop-color="var(--vine-root)"/> 45 <stop offset="0.62" stop-color="var(--vine-mid)"/> 46 <stop offset="1" stop-color="var(--vine-tip)"/> 47 </linearGradient> 48 </defs> 49 <path d="${stem}" fill="url(#read-vine)"/> 50 ${leaves} 51 </svg>`; 52};
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.