mirror of
https://github.com/9x/sheetmusictrainer.git
synced 2026-11-03 22:03:54 +01:00
Add Assist mode: primitive note display for practicing from paper
New game mode 'assist' — no trainer, no scoring: - Large display of the currently mic-detected note - Live notation staff (same pipeline as the pitch monitor) - Live fretboard showing alternative positions for the played note (respects the fret-window practice filter) - Tuner and Metronome remain the shared footer tools, identical in all modes; user can practice own-pace from paper with a free metronome Header mode toggle gains 'Assist'; 'm' shortcut cycles back to sight reading from assist/phrase. Export PitchData type.
This commit is contained in:
39
src/App.tsx
39
src/App.tsx
@@ -8,6 +8,7 @@ import { SingleNoteTrainer, type SingleNoteHandle } from './components/SingleNot
|
||||
import { LiveNoteStaff } from './components/LiveNoteStaff';
|
||||
import { resolveClefTranspose } from './music/InstrumentConfigs';
|
||||
import { PhraseTrainer, type PhraseHandle } from './components/PhraseTrainer';
|
||||
import { AssistMode } from './components/AssistMode';
|
||||
import { usePitchDetector } from './hooks/usePitchDetector';
|
||||
import { useSettings } from './context/useSettings';
|
||||
import { audioEngine } from './audio/AudioEngine';
|
||||
@@ -26,6 +27,7 @@ function App() {
|
||||
const setSettings = updateSettings;
|
||||
|
||||
const isPhrase = settings.gameMode === 'phrase';
|
||||
const isAssist = settings.gameMode === 'assist';
|
||||
|
||||
const currentTuning = TUNINGS[settings.tuningId];
|
||||
const currentInstrumentDef = INSTRUMENT_DEFINITIONS[settings.instrument];
|
||||
@@ -175,6 +177,25 @@ function App() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isAssist) {
|
||||
// Assist mode: only display shortcuts — no trainer actions.
|
||||
switch (e.key.toLowerCase()) {
|
||||
case 'h':
|
||||
setSettings(s => ({ ...s, showHint: !s.showHint }));
|
||||
break;
|
||||
case 'z':
|
||||
setSettings(s => ({ ...s, zenMode: !s.zenMode }));
|
||||
break;
|
||||
case 'v':
|
||||
setSettings(s => ({ ...s, showFretboard: !s.showFretboard }));
|
||||
break;
|
||||
case 'l':
|
||||
setListening(l => !l);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
switch (e.key.toLowerCase()) {
|
||||
case 'h':
|
||||
setSettings(s => ({ ...s, showHint: !s.showHint }));
|
||||
@@ -207,16 +228,16 @@ function App() {
|
||||
|
||||
window.addEventListener('keydown', handleKeyDown);
|
||||
return () => window.removeEventListener('keydown', handleKeyDown);
|
||||
}, [settings, showHelp, isPhrase, setSettings]);
|
||||
}, [settings, showHelp, isPhrase, isAssist, setSettings]);
|
||||
|
||||
// 'm' cycles all three modes from phrase mode too.
|
||||
// 'm' cycles back to sight reading from phrase/assist modes.
|
||||
useEffect(() => {
|
||||
const handler = (e: KeyboardEvent) => {
|
||||
if (e.key.toLowerCase() !== 'm') return;
|
||||
const target = e.target as HTMLElement | null;
|
||||
if (target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement ||
|
||||
target instanceof HTMLButtonElement || target instanceof HTMLSelectElement || target?.isContentEditable) return;
|
||||
if (settings.gameMode === 'phrase') {
|
||||
if (settings.gameMode === 'phrase' || settings.gameMode === 'assist') {
|
||||
setSettings(s => ({ ...s, gameMode: 'sight_reading' }));
|
||||
}
|
||||
};
|
||||
@@ -263,6 +284,13 @@ function App() {
|
||||
>
|
||||
Phrases
|
||||
</button>
|
||||
<button
|
||||
className={`toggle-option ${settings.gameMode === 'assist' ? 'active' : ''}`}
|
||||
onClick={() => setSettings(s => ({ ...s, gameMode: 'assist' }))}
|
||||
title="Practice companion: shows played notes while you work from paper"
|
||||
>
|
||||
Assist
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<button
|
||||
@@ -305,6 +333,11 @@ function App() {
|
||||
micError={error}
|
||||
windowWidth={windowWidth}
|
||||
/>
|
||||
) : isAssist ? (
|
||||
<AssistMode
|
||||
pitchData={displayedPitch}
|
||||
windowWidth={windowWidth}
|
||||
/>
|
||||
) : (
|
||||
<SingleNoteTrainer
|
||||
ref={singleNoteRef}
|
||||
|
||||
Reference in New Issue
Block a user