A starter template for React + styled-components.
A Pen by landolabrum on CodePen.
<div id="app"></div> |
A starter template for React + styled-components.
A Pen by landolabrum on CodePen.
const { createRoot } = ReactDOM; | |
const { useState, useEffect } = React; | |
const { createGlobalStyle } = styled; | |
const GlobalStyle = createGlobalStyle` | |
html, body, #app { | |
height: 100%; | |
min-height: 100%; | |
background-color:#1818f8; | |
} | |
#app { | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
} | |
`; | |
const App = styled.div` | |
display: flex; | |
flex-direction: column; | |
justify-content: center; | |
align-items: center; | |
`; | |
const StyledLabel = styled.p` | |
font-family: "Roboto Mono", monospace; | |
font-size: 20px; | |
`; | |
const Container = () => ( | |
<App> | |
<GlobalStyle /> | |
<StyledLabel> | |
</StyledLabel> | |
<KeyboardComponent/> | |
</App> | |
); | |
const root = createRoot(document.getElementById("app")); | |
root.render(<Container />); | |
const backgroundColor = '#181818'; | |
const colorOne = '#0f0'; | |
const colorTwo = '#e0e0e0'; | |
const KeyboardComponent = () => { | |
const [pitch, setPitch] = useState(0); | |
const [audioContext, setAudioContext] = useState(null); | |
const [oscillator, setOscillator] = useState(null); | |
useEffect(() => { | |
const newAudioContext = new (window.AudioContext || window.webkitAudioContext)(); | |
setAudioContext(newAudioContext); | |
const newOscillator = newAudioContext.createOscillator(); | |
setOscillator(newOscillator); | |
return () => { | |
if (newOscillator.state === 'started') { | |
newOscillator.stop(); | |
} | |
newOscillator.disconnect(); | |
newAudioContext.close(); | |
}; | |
}, []); | |
const handlePitchChange = (event) => { | |
setPitch(event.target.value); | |
}; | |
const handleKeyPress = (key) => { | |
console.log(`Key ${key} pressed, pitch: ${pitch}`); | |
// Play the tone based on the pitch using the Web Audio API | |
playTone(pitch); | |
}; | |
const playTone = (frequency) => { | |
if (!oscillator) return; | |
oscillator.type = 'sine'; | |
oscillator.frequency.setValueAtTime(frequency, audioContext.currentTime); | |
oscillator.connect(audioContext.destination); | |
oscillator.start(); | |
oscillator.stop(audioContext.currentTime + 0.1); | |
}; | |
const keyboardKeys = ['A', 'S', 'D', 'F', 'G']; | |
return ( | |
<div | |
style={{ | |
backgroundColor, | |
color: colorTwo, | |
width: '100%', | |
display: 'flex', | |
flexDirection: 'column', | |
alignItems: 'center', | |
}} | |
> | |
<div style={{ display: 'flex', justifyContent: 'center', width: '100%' }}> | |
{keyboardKeys.map((key) => ( | |
<button | |
key={key} | |
onMouseDown={() => handleKeyPress(key)} | |
onMouseUp={() => oscillator?.stop()} // Stop the tone when mouse is released | |
style={{ margin: '5px', padding: '10px 20px', backgroundColor, color: colorTwo, border: `2px solid ${colorOne}` }} | |
> | |
{key} | |
</button> | |
))} | |
</div> | |
<input | |
type="range" | |
min="0" | |
max="100" | |
value={pitch} | |
onChange={handlePitchChange} | |
style={{ width: '80%', backgroundColor, color: colorTwo }} | |
/> | |
<input | |
type="number" | |
min="0" | |
max="100" | |
value={pitch} | |
onChange={handlePitchChange} | |
style={{ width: '80%', backgroundColor, color: colorTwo }} | |
/> | |
</div> | |
); | |
}; |
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.0.0/umd/react.production.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.0.0/umd/react-dom.production.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-is/18.0.0/umd/react-is.production.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/styled-components/5.3.5/styled-components.min.js"></script> |
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/css/all.min.css" rel="stylesheet" /> |