From 1eb0e19673d6420c982a63f5e07f13482b078eab Mon Sep 17 00:00:00 2001 From: Sterling Archer Date: Sat, 13 Jun 2026 21:40:05 -0700 Subject: [PATCH] Add numbered gold circles above hand emoji fingertips --- guitar-teacher.jsx | 295 ++++++++++++++++++++++++++++++++++++--------- index.html | 91 +++++--------- 2 files changed, 267 insertions(+), 119 deletions(-) diff --git a/guitar-teacher.jsx b/guitar-teacher.jsx index d4862aa..e877b0b 100644 --- a/guitar-teacher.jsx +++ b/guitar-teacher.jsx @@ -35,9 +35,9 @@ function autoCorrelate(buf, sr) { } const CHORDS = { - Em:{ dots:[{s:1,f:2,n:"2"},{s:2,f:2,n:"3"}], open:[3,4,5], muted:[], label:"x x 0 2 2 0" }, - Am:{ dots:[{s:4,f:2,n:"1"},{s:3,f:2,n:"2"},{s:2,f:2,n:"3"}], open:[4,5], muted:[0], label:"x 0 2 2 1 0" }, - G: { dots:[{s:0,f:3,n:"2"},{s:5,f:3,n:"4"},{s:1,f:2,n:"1"},{s:4,f:2,n:"3"}], open:[2,3], muted:[], label:"3 2 0 0 3 3" }, + Em:{ dots:[{s:2,f:2,n:"2"},{s:3,f:2,n:"3"}], open:[0,1,4,5], muted:[], label:"0 0 2 2 0 0" }, + Am:{ dots:[{s:2,f:2,n:"2"},{s:3,f:2,n:"3"},{s:4,f:2,n:"1"}], open:[1,5], muted:[0], label:"x 0 2 2 1 0" }, + G: { dots:[{s:0,f:3,n:"2"},{s:1,f:2,n:"1"},{s:4,f:3,n:"3"},{s:5,f:3,n:"4"}], open:[2,3], muted:[], label:"3 2 0 0 3 3" }, C: { dots:[{s:1,f:3,n:"3"},{s:2,f:2,n:"2"},{s:4,f:1,n:"1"}], open:[3,5], muted:[0], label:"x 3 2 0 1 0" }, D: { dots:[{s:3,f:2,n:"1"},{s:4,f:3,n:"3"},{s:5,f:2,n:"2"}], open:[2], muted:[0,1], label:"x x 0 2 3 2" }, }; @@ -130,52 +130,60 @@ function ChordDiagram({ name }) { const sh = CHORDS[name]; if (!sh) return null; - const NUM_FRETS=5, NS=6, W=320, H=200; - const TOP=44, BOT=H-24, LEFT=44, RIGHT=W-12; + // Three columns left of nut: + // col1=12 (string letter), col2=34 (open/muted symbol), nut at LEFT=60 + const NUM_FRETS=5, NS=6, W=320, H=210; + const TOP=44, BOT=H-22, LEFT=60, RIGHT=W-10; const strGap=(BOT-TOP)/(NS-1); const fretGap=(RIGHT-LEFT)/NUM_FRETS; const STRING_LABELS=["E","A","D","G","B","e"]; - - // Build note list from chord shape: open strings + fretted dots - const notes = []; - sh.open.forEach(s=>{ notes.push({str:s, fret:0, label:"o", muted:false}); }); - sh.muted.forEach(s=>{ notes.push({str:s, fret:-1, label:"x", muted:true}); }); - sh.dots.forEach(({s,f,n})=>{ notes.push({str:s, fret:f, label:n, muted:false, finger:true}); }); + const COL_LABEL=12, COL_MARKER=36; return (
{name}
+ {/* Nut */} + {/* Frets */} {Array.from({length:NUM_FRETS+1},(_,f)=>( ))} + {/* Strings */} {Array.from({length:NS},(_,s)=>( + stroke={C.string} strokeWidth={s===0?2:s===5?0.8:1.2}/> ))} + {/* Col 1: string name labels */} {STRING_LABELS.map((n,s)=>( - {n} + {n} ))} + {/* Col 2: open or muted markers */} + {Array.from({length:NS},(_,s)=>{ + const cy=TOP+s*strGap; + const isOpen = sh.open.includes(s); + const isMuted = sh.muted.includes(s); + if(isOpen) return ( + + + + ); + if(isMuted) return ( + + + + + ); + return null; + })} + {/* Fret numbers */} {Array.from({length:NUM_FRETS},(_,f)=>( {f+1} ))} - {sh.muted.map(s=>{ - const cy=TOP+s*strGap; - return ( - - - - - ); - })} - {sh.open.map(s=>( - - ))} + {/* Fretted finger dots */} {sh.dots.map(({s,f,n},i)=>{ const cx = LEFT+(f-0.5)*fretGap; const cy = TOP+s*strGap; @@ -802,6 +810,62 @@ function SongSearch({ detected, listening, onStartMic }) { ); } +function ChordPractice({ chords, detected, onTarget }) { + const CHORD_ROOTS = {Em:"E2", Am:"A2", G:"G2", C:"C3", D:"D3"}; + const KUDOS = ["Sounds good!","Nice strum!","That sounds right!","Great job!","Keep it up!","Well done!"]; + const [activeChord, setActiveChord] = useState(null); + const [heard, setHeard] = useState({}); + const [kudos, setKudos] = useState({}); + + useEffect(()=>{ + if (activeChord) onTarget(CHORD_ROOTS[activeChord]); + else onTarget(null); + },[activeChord]); + + useEffect(()=>{ + if (!detected || !activeChord || heard[activeChord]) return; + const root = CHORD_ROOTS[activeChord]; + if (detected === root) { + setHeard(h=>({...h,[activeChord]:true})); + setKudos(k=>({...k,[activeChord]:KUDOS[Math.floor(Math.random()*KUDOS.length)]})); + } + },[detected, activeChord, heard]); + + return ( +
+
+ Tap a chord to practice it, then strum on your guitar: +
+
+ {chords.map(name=>( + + ))} +
+ {activeChord && ( +
+ +
+ {heard[activeChord] + ? 🎸 {kudos[activeChord]} + : Strum the {activeChord} chord - listening for the root note ({CHORD_ROOTS[activeChord]})} +
+
+ )} +
+ ); +} + + const LESSONS = [ {title:"How to Hold a Guitar", eyebrow:"Lesson 1 - Getting Started", next:"Next: Reading Tab"}, {title:"Reading Guitar Tab", eyebrow:"Lesson 2 - Tab Basics", next:"Next: Your First Notes"}, @@ -820,36 +884,151 @@ function LessonBody({ id, detected, onTarget, listening, onStartMic }) { Sit with the guitar waist on your right leg. Back straight, neck angled slightly up. Thumb behind the neck, fingers curling over the fretboard.

Your strumming hand hovers over the soundhole. For now use your thumb, sweeping downward across the strings.

+

Finger numbering

+

Throughout this app, the gold circles on chord diagrams show you which finger to use. Here is how they are numbered:

+
+ + {/* Palm base */} + + + {/* Thumb - angled left */} + + + {/* Index finger */} + + {/* Middle finger - tallest */} + + {/* Ring finger */} + + {/* Pinky */} + + + {/* Knuckle lines */} + + + + + + + + + + {/* Gold circles on fingertips with numbers */} + {/* Index = 1 */} + + + 1 + + {/* Middle = 2 */} + + + 2 + + {/* Ring = 3 */} + + + 3 + + {/* Pinky = 4 */} + + + 4 + + {/* Labels below fingers */} + Index + Middle + Ring + Pinky + + {/* Thumb label */} + Thumb + (not numbered) + +
+ When a chord diagram shows a 1 on a string, press that string with your index finger. 2 = middle, 3 = ring, 4 = pinky. +

Strings thick to thin: E A D G B e - remember with "Elephants And Donkeys Grow Big Ears."

); - if (id === 1) return ( -
-

Tab shows you exactly where to put your fingers. No music theory needed. Each line is a string, numbers are frets.

-
- {[ - {s:"e",v:["--","0","--","--","--","3","--"]}, - {s:"B",v:["--","--","0","--","--","3","--"]}, - {s:"G",v:["--","--","--","0","--","0","--"]}, - {s:"D",v:["--","--","--","--","--","0","--"]}, - {s:"A",v:["--","--","--","--","--","2","--"]}, - {s:"E",v:["0","--","--","--","--","3","--"]}, - ].map(({s,v})=>( -
- {s} - | - {v.map((val,i)=>( - =5?C.amber:C.text,fontWeight:val!=="--"?600:400}}> - {val} - + if (id === 1) { + // Wider left margin: label col at 14, marker col at 34, nut at 64 + const NUM_FRETS=5, NS=6, W=340, H=210; + const TOP=44, BOT=H-24, LEFT=64, RIGHT=W-10; + const strGap=(BOT-TOP)/(NS-1); + const fretGap=(RIGHT-LEFT)/NUM_FRETS; + const LABELS=["E","A","D","G","B","e"]; + const markers=[ + {s:0,type:"open"},{s:1,type:"muted"},{s:2,type:"muted"}, + {s:3,type:"muted"},{s:4,type:"open"},{s:5,type:"open"} + ]; + return ( +
+

+ Each line is a string on your guitar. Numbers tell you which fret to press. 0 means open - no fingers needed. +

+
+
Example - a G chord
+ + {/* Nut */} + + {/* Fret lines */} + {Array.from({length:NUM_FRETS+1},(_,f)=>( + ))} -
- ))} + {/* Strings */} + {Array.from({length:NS},(_,s)=>( + + ))} + {/* String name labels - col 1 */} + {LABELS.map((n,s)=>( + {n} + ))} + {/* Open/muted markers - col 2 */} + {markers.map(({s,type})=>{ + const cy=TOP+s*strGap, cx=38; + if(type==="open") return ( + + + 0 + + ); + return ( + + + + + ); + })} + {/* Fret numbers */} + {Array.from({length:NUM_FRETS},(_,f)=>( + {f+1} + ))} + {/* Fretted dots */} + {[{s:0,f:3,n:"3"},{s:1,f:2,n:"2"},{s:4,f:2,n:"1"},{s:5,f:3,n:"4"}].map(({s,f,n},i)=>{ + const cx=LEFT+(f-0.5)*fretGap, cy=TOP+s*strGap; + return ( + + + + {n} + + ); + })} + +
+ 0 = open string (no fingers). A number = press that fret. X = don't play that string. +

+ The top string (E) is the thickest - closest to you when holding the guitar. The bottom (e) is the thinnest. +

- Read left to right. 0 = open string. 2 = press 2nd fret. Numbers stacked vertically = chord. -
- ); + ); + } const [stringsComplete, setStringsComplete] = useState(false); if (id === 2) return (
@@ -865,19 +1044,15 @@ function LessonBody({ id, detected, onTarget, listening, onStartMic }) { ); if (id === 3) return (
-

Em is the easiest chord on guitar. Only 2 fingers. Am uses 3 fingers in a similar shape.

-
- -
+

Em is the easiest chord on guitar. Only 2 fingers. Am uses 3 fingers in a similar shape. Tap one to see the fingering, then strum it - the mic will confirm!

+ Em: middle finger 2nd fret A string, ring finger 2nd fret D string. Strum all 6 strings.
); if (id === 4) return (
-

G, C, and D unlock hundreds of songs. Together with Em and Am you have most of what you need.

-
- -
+

G, C, and D unlock hundreds of songs. Tap each chord to see the fingering and strum it - the mic will confirm when it hears you!

+ Classic progression: G - D - Em - C. Drill the transitions slowly, accuracy before speed.
); diff --git a/index.html b/index.html index e027127..677cede 100644 --- a/index.html +++ b/index.html @@ -907,65 +907,38 @@ function LessonBody({ id, detected, onTarget, listening, onStartMic }) {

Finger numbering

Throughout this app, the gold circles on chord diagrams show you which finger to use. Here is how they are numbered:

-
- - {/* Palm base */} - - - {/* Thumb - angled left */} - - - {/* Index finger */} - - {/* Middle finger - tallest */} - - {/* Ring finger */} - - {/* Pinky */} - - - {/* Knuckle lines */} - - - - - - - - - - {/* Gold circles on fingertips with numbers */} - {/* Index = 1 */} - - - 1 - - {/* Middle = 2 */} - - - 2 - - {/* Ring = 3 */} - - - 3 - - {/* Pinky = 4 */} - - - 4 - - {/* Labels below fingers */} - Index - Middle - Ring - Pinky - - {/* Thumb label */} - Thumb - (not numbered) - +
+
+ {/* Gold numbers above fingers - positioned to align with emoji fingertips */} +
+ {[ + {num:"1", ml:0}, + {num:"2", ml:8}, + {num:"3", ml:6}, + {num:"4", ml:4}, + ].map(({num,ml})=>( +
+
+ {num} +
+
+
+ ))} +
+
🤚
+
+
+ {[["1","Index"],["2","Middle"],["3","Ring"],["4","Pinky"]].map(([num,name])=>( +
+
{name}
+
+ ))} +
When a chord diagram shows a 1 on a string, press that string with your index finger. 2 = middle, 3 = ring, 4 = pinky.