From f9447b3deb3ed64bac42774b99e97f2d06e460e7 Mon Sep 17 00:00:00 2001 From: Mathias Wagner Date: Sat, 1 Mar 2025 17:34:24 +0100 Subject: [PATCH] Fix MusicSlider.jsx --- .../components/MusicSlider/MusicSlider.jsx | 68 +++++++++++++++---- .../Game/components/MusicSlider/styles.sass | 34 ++++++++-- 2 files changed, 85 insertions(+), 17 deletions(-) diff --git a/client/src/pages/Game/components/MusicSlider/MusicSlider.jsx b/client/src/pages/Game/components/MusicSlider/MusicSlider.jsx index 63045de..f74082a 100644 --- a/client/src/pages/Game/components/MusicSlider/MusicSlider.jsx +++ b/client/src/pages/Game/components/MusicSlider/MusicSlider.jsx @@ -1,6 +1,21 @@ import { useState, useEffect, useRef, useCallback } from 'react'; import "./styles.sass"; +const frequencyToNote = (frequency) => { + const A4 = 440; + const notes = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']; + + const halfSteps = Math.round(12 * Math.log2(frequency / A4)); + + const A4Index = notes.indexOf('A'); + let noteIndex = (A4Index + halfSteps) % 12; + if (noteIndex < 0) noteIndex += 12; + + const octave = 4 + Math.floor((halfSteps + A4Index) / 12); + + return `${notes[noteIndex]}${octave}`; +}; + export const MusicSlider = ({ isReadOnly, onFrequencyChange, frequency: externalFrequency, composerIsPlaying }) => { const [audioContext, setAudioContext] = useState(null); const [oscillator, setOscillator] = useState(null); @@ -187,6 +202,25 @@ export const MusicSlider = ({ isReadOnly, onFrequencyChange, frequency: external return `${Math.max(0, Math.min(pos, 100))}%`; }; + const getMouthSize = () => { + const minSize = 30; + const maxSize = 60; + const freqRange = 880; + const sizeRange = maxSize - minSize; + const relativeFreq = frequency.current - 220; + const size = minSize + (relativeFreq / freqRange) * sizeRange; + return Math.max(minSize, Math.min(maxSize, size)); + }; + + const shouldShowNoteMarker = () => { + if (!isReadOnly) return isDragging.current; + return composerIsPlaying; + }; + + if (isReadOnly && !composerIsPlaying) { + return null; + } + return (
@@ -195,22 +229,32 @@ export const MusicSlider = ({ isReadOnly, onFrequencyChange, frequency: external
-
+
-
-
-
- {(!isReadOnly && isDragging.current) && Math.round(frequency.current)} +
+ {shouldShowNoteMarker() && ( +
+ {frequencyToNote(frequency.current)} +
+ )}
-
+ )}
); diff --git a/client/src/pages/Game/components/MusicSlider/styles.sass b/client/src/pages/Game/components/MusicSlider/styles.sass index 12b1ca4..40a9e34 100644 --- a/client/src/pages/Game/components/MusicSlider/styles.sass +++ b/client/src/pages/Game/components/MusicSlider/styles.sass @@ -104,10 +104,23 @@ .note-marker position: absolute top: -50px - font-size: 32pt + font-size: 24pt color: $white text-shadow: 0 0 15px rgba(255, 255, 255, 0.7) font-weight: bold + font-family: 'Arial', sans-serif + background: rgba(0, 0, 0, 0.6) + padding: 2px 8px + border-radius: 8px + backdrop-filter: blur(5px) + min-width: 60px + text-align: center + animation: note-pop 0.2s ease-out + opacity: 1 + + .read-only & + background: rgba(0, 0, 0, 0.8) + box-shadow: 0 0 20px rgba(0, 0, 0, 0.4) .otamatone-face width: 140px @@ -169,10 +182,11 @@ border-radius: 50% position: absolute bottom: 30px - width: 30px - height: 30px - transition: all 0.3s ease - animation: mouth-pulse 5s infinite alternate ease-in-out + transition: all 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275) + transform-origin: center center + + &.active + animation: mouth-pulse 0.5s infinite alternate ease-in-out @keyframes blink 0%, 90%, 100% @@ -200,4 +214,14 @@ opacity: 0 100% transform: translateY(0) + opacity: 1 + +@keyframes note-pop + 0% + transform: scale(0.8) + opacity: 0.5 + 50% + transform: scale(1.1) + 100% + transform: scale(1) opacity: 1 \ No newline at end of file