// SVG chord diagram — 6 strings × 5 visible frets // Props: // frets[] — [s6…s1]: fret number or 'x' (muted) // fingers[] — [s6…s1]: finger 1-4, 0 = open/barre indicator // barre — { fret, fromStr, toStr } or null // baseFret — which fret number is at the top of the diagram (1 = standard) // label — caption below the box const STRINGS = 6 const ROWS = 5 // visible frets const SX = 32 // left margin (open/mute indicators) const SY = 28 // top margin (nut / baseFret label) const GX = 26 // gap between strings const GY = 22 // gap between frets const DOT_R = 9 // dot radius const W = SX + GX * (STRINGS - 1) + 24 // total width const H = SY + GY * ROWS + 20 // total height function strX(s) { return SX + (STRINGS - 1 - s) * GX } // s=0 is s6 (low E, leftmost) function fretY(f) { return SY + f * GY } // f=0 is above first fret, f=1…5 are fret centers export default function ChordBox({ frets, fingers, barre, baseFret = 1, label }) { const isOpen = baseFret === 1 // Map fret numbers to diagram row (0-indexed from top) function toRow(absF) { return absF - baseFret + 1 // fret at baseFret → row 1 (center of first fret) } // Barre bar: draw a rounded rect across strings function renderBarre() { if (!barre) return null const row = toRow(barre.fret) if (row < 1 || row > ROWS) return null const x1 = strX(STRINGS - barre.toStr) // toStr is highest string number = leftmost const x2 = strX(STRINGS - barre.fromStr) // fromStr is lowest string number = rightmost const cy = fretY(row) - GY / 2 return ( ) } return (
{/* ── Nut or baseFret indicator ── */} {isOpen ? ( ) : ( {baseFret} )} {/* ── Fret lines ── */} {Array.from({ length: ROWS + 1 }, (_, i) => ( ))} {/* ── String lines ── */} {Array.from({ length: STRINGS }, (_, s) => ( ))} {/* ── Barre ── */} {renderBarre()} {/* ── Dots + open/mute indicators ── */} {frets.map((f, s) => { const cx = strX(STRINGS - 1 - s) if (f === 'x') { return ( × ) } if (f === 0) { return ( ) } const row = toRow(f) if (row < 1 || row > ROWS) return null const cy = fretY(row) - GY / 2 const finger = fingers?.[s] ?? 0 return ( {finger > 0 && ( {finger} )} ) })} {/* ── String name labels ── */} {['e','B','G','D','A','E'].map((n, i) => ( {n} ))} {label && (

{label}

)}
) }