Bass Fretboard Trainer - Learn Notes and Scales

Clique sur : C

minigame

Learn Guitar Bass Notes

Jsuis vraiment nul à la basse, je reprends tout juste mon apprentissage et je trouvais pas de minijeu comme ça dc j'en ai codé un avec ChatGPT. Autant vous le partager si jamais vous êtes aussi guez que moi ça peut aider. Plus tard dans mon apprentissage je ferais ptet une entraineur de gamme ptet avec le micro pour pouvoir jouer avec sa basse ça purrait être sympa. Je vous partage le code ci-dessous si vous avez envie de l'améliorer où d'y joueur offline.
				
					<style>
  .bass-container {
    display: flex;
    flex-direction: column;
    align-items: center;
    font-family: sans-serif;
  }

  .fretboard {
    display: grid;
    grid-template-columns: repeat(12, 40px);
    grid-gap: 4px;
    margin: 10px 0;
    position: relative;
  }

  .fret {
    width: 40px;
    height: 40px;
    background-color: #ddd;
    border: 1px solid #999;
    border-radius: 50pc;
    text-align: center;
    line-height: 40px;
    cursor: pointer;
    transition: background-color 0.2s;
    z-index: 1;
    font-size: 14px;
    font-weight: bold;
  }

  .fret:hover {
    background-color: #bbb;
  }

  .string-lines {
    position: absolute;
    top: 50%;
    left: 0;
    width: 100%;
    display: grid;
    grid-template-rows: repeat(4, 1fr);
    height: 160px;
    transform: translateY(-50%);
    z-index: 0;
  }

  .string-line {
    border-bottom: 3px solid black;
    width: 100%;
    background color: #494949;
  }

  .string-line:nth-child(1) { border-width: 2px; } /* G */
  .string-line:nth-child(2) { border-width: 3px; } /* D */
  .string-line:nth-child(3) { border-width: 4px; } /* A */
  .string-line:nth-child(4) { border-width: 5px; } /* E */

  .dots {
    display: flex;
    justify-content: space-between;
    width: calc(12 * 40px + 11 * 4px);
    margin-top: 10px;
    padding-left: 2px;
    position: relative;
  }

  .dot {
    width: 10px;
    height: 10px;
    background: black;
    border-radius: 50%;
    position: absolute;
    bottom: 0;
    transform: translateX(-50%);
  }

  .note-display {
    font-size: 20px;
    margin: 10px 0;
  }

  .feedback {
    font-weight: bold;
    margin-top: 10px;
  }
</style>

<div class="bass-container">
  <h1>Bass Fretboard Trainer - Learn Notes and Scales</h1>

  <label for="mode">Mode : </label>
  <select id="mode" onchange="onModeChange()">
    <option value="quiz">Quiz</option>
    <option value="free">Apprentissage libre</option>
    <option value="scale">Apprentissage des gammes</option>
  </select>

  <div id="difficulty-container">
    <label for="difficulty">Niveau de difficulté : </label>
    <select id="difficulty" onchange="buildFretboard()">
      <option value="1">Niveau 1 - Notes sur cordes à vide et repères</option>
      <option value="2">Niveau 2 - Notes sur cordes à vide uniquement</option>
      <option value="3">Niveau 3 - Aucune note visible</option>
    </select>
  </div>

  <div id="scale-selector" style="display: none;">
    <label for="scale">Gamme : </label>
    <select id="scale" onchange="buildFretboard()">
      <option value="C_major">C Major</option>
      <option value="G_major">G Major</option>
      <option value="D_major">D Major</option>
      <option value="A_minor">A Minor</option>
    </select>
  </div>

  <div class="note-display" id="quizPrompt">Clique sur : <span id="targetNote">C</span></div>

  <div class="fretboard-wrapper" style="position: relative;">
    <div class="fretboard" id="fretboard"></div>
    <div class="string-lines">
      <div class="string-line"></div>
      <div class="string-line"></div>
      <div class="string-line"></div>
      <div class="string-line"></div>
    </div>
  </div>

  <div class="dots">
    <div class="dot" style="left: calc(4 * 44px - 22px);"></div>
    <div class="dot" style="left: calc(6 * 44px - 22px);"></div>
    <div class="dot" style="left: calc(8 * 44px - 22px);"></div>
    <div class="dot" style="left: calc(10 * 44px - 22px);"></div>
    <div class="dot" style="left: calc(13 * 44px - 22px);"></div>
    <div class="dot" style="left: calc(13 * 45px - 22px);"></div>
  </div>

  <div class="feedback" id="feedback"></div>
</div>

<script>
  const notes = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'];
  const scales = {
    C_major: ['C', 'D', 'E', 'F', 'G', 'A', 'B'],
    G_major: ['G', 'A', 'B', 'C', 'D', 'E', 'F#'],
    D_major: ['D', 'E', 'F#', 'G', 'A', 'B', 'C#'],
    A_minor: ['A', 'B', 'C', 'D', 'E', 'F', 'G'],
  };

  const strings = [
    { name: 'G', start: 7 },
    { name: 'D', start: 2 },
    { name: 'A', start: 9 },
    { name: 'E', start: 4 }
  ];

  const fretboard = document.getElementById('fretboard');
  const targetNoteEl = document.getElementById('targetNote');
  const feedbackEl = document.getElementById('feedback');
  const difficultySelect = document.getElementById('difficulty');
  const quizPrompt = document.getElementById('quizPrompt');
  const modeSelect = document.getElementById('mode');
  const difficultyContainer = document.getElementById('difficulty-container');
  const scaleSelector = document.getElementById('scale-selector');
  const scaleSelect = document.getElementById('scale');

  let targetNote = randomNote();

  function randomNote() {
    return notes[Math.floor(Math.random() * notes.length)];
  }

  function updateTargetNote() {
    targetNote = randomNote();
    targetNoteEl.textContent = targetNote;
    feedbackEl.textContent = '';
  }

  function onModeChange() {
    const mode = modeSelect.value;
    quizPrompt.style.display = mode === 'quiz' ? 'block' : 'none';
    difficultyContainer.style.display = mode === 'quiz' ? 'block' : 'none';
    scaleSelector.style.display = mode === 'scale' ? 'block' : 'none';
    feedbackEl.textContent = '';
    buildFretboard();
    if (mode === 'quiz') updateTargetNote();
  }

  function buildFretboard() {
    const mode = modeSelect.value;
    const difficulty = parseInt(difficultySelect.value);
    const selectedScale = scaleSelect.value;
    const scaleNotes = scales[selectedScale] || [];
    fretboard.innerHTML = '';

    strings.forEach((string, stringIndex) => {
      for (let fret = 0; fret < 12; fret++) {
        const noteIndex = (string.start + fret) % 12;
        const note = notes[noteIndex];

        const div = document.createElement('div');
        div.className = 'fret';
        div.dataset.note = note;
        div.dataset.string = string.name;
        div.dataset.fret = fret;
        div.title = `${string.name} corde, frette ${fret} = ${note}`;

        if (mode === 'free') {
          div.textContent = note;
        } else if (mode === 'quiz') {
          if (
            (difficulty === 1 && (fret === 0 || [3,5,7,9,12].includes(fret))) ||
            (difficulty === 2 && fret === 0)
          ) {
            div.textContent = note;
          }
        } else if (mode === 'scale') {
          if (scaleNotes.includes(note)) {
            div.textContent = note;
            div.style.backgroundColor = '#b0d4ff';
          }
        }

        div.addEventListener('click', () => {
          if (mode === 'quiz') {
            if (note === targetNote) {
              feedbackEl.textContent = '✅ Bonne réponse !';
              feedbackEl.style.color = 'green';
              updateTargetNote();
            } else {
              feedbackEl.textContent = '❌ Mauvaise réponse';
              feedbackEl.style.color = 'red';
            }
          }
        });

        fretboard.appendChild(div);
      }
    });
  }

  onModeChange();
</script>