<div class="stick">
<div class="glow-1 hidden"></div>
<div class="glow-2 hidden"></div>
</div>
<div class="container">
<div class="top-row">
<div class="note-group group-of-two group-1">
<div class="note note-1" data-frequency="207.65"><div>G#</div></div>
<div class="note note-2" data-frequency="233.08"><div>A#</div></div>
</div>
<div class="note-group group-of-two group-2">
<div class="note note-3" data-frequency="277.18"><div>C#</div></div>
<div class="note note-4" data-frequency="311.13"><div>D#</div></div>
</div>
<div class="note-group group-of-three group-3">
<div class="note note-5" data-frequency="369.99"><div>F#</div></div>
<div class="note note-6" data-frequency="415.30"><div>G#</div></div>
<div class="note note-7" data-frequency="466.16"><div>A#</div></div>
</div>
<div class="note-group group-of-two group-4">
<div class="note note-8" data-frequency="554.37"><div>C#</div></div>
<div class="note note-9" data-frequency="622.25"><div>D#</div></div>
</div>
<div class="note-group group-of-three group-5">
<div class="note note-10" data-frequency="739.99"><div>F#</div></div>
<div class="note note-11" data-frequency="830.61"><div>G#</div></div>
<div class="note note-12" data-frequency="932.33"><div>A#</div></div>
</div>
</div>
<div class="bottom-row">
<div class="note note-13" data-frequency="196.00"><div>G</div></div>
<div class="note note-14" data-frequency="220.00"><div>A</div></div>
<div class="note note-15" data-frequency="246.94"><div>B</div></div>
<div class="note note-16" data-frequency="261.63"><div>C</div></div>
<div class="note note-17" data-frequency="293.66"><div>D</div></div>
<div class="note note-18" data-frequency="329.63"><div>E</div></div>
<div class="note note-19" data-frequency="349.23"><div>F</div></div>
<div class="note note-20" data-frequency="392.00"><div>G</div></div>
<div class="note note-21" data-frequency="440.00"><div>A</div></div>
<div class="note note-22" data-frequency="493.88"><div>B</div></div>
<div class="note note-23" data-frequency="523.25"><div>C</div></div>
<div class="note note-24" data-frequency="587.33"><div>D</div></div>
<div class="note note-25" data-frequency="659.25"><div>E</div></div>
<div class="note note-26" data-frequency="698.46"><div>F</div></div>
<div class="note note-27" data-frequency="783.99"><div>G</div></div>
<div class="note note-28" data-frequency="880.00"><div>A</div></div>
<div class="note note-29" data-frequency="987.77"><div>B</div></div>
<div class="note note-30" data-frequency="1046.50"><div>C</div></div>
</div>
</div>
.container {
margin: 0 auto;
height: 100%;
width: 588px;
min-width: 588px;
display: flex;
flex-direction: column;
justify-content: center;
.top-row {
display: flex;
position: relative;
z-index: 2;
.note-group {
display: flex;
justify-content: space-between;
position: relative;
top: 52px;
&.group-of-two { width: 60px; }
&.group-of-three { width: 93px; }
&.group-1 { margin-left: 17px; }
&.group-2 { margin-left: 36px; }
&.group-3 { margin-left: 42px; }
&.group-4 { margin-left: 39px; }
&.group-5 { margin-left: 38px; }
}
.note { margin-top: auto; }
}
.bottom-row {
width: 100%;
display: flex;
justify-content: space-between;
.note > div {
display: flex;
justify-content: center;
align-items: flex-end;
}
}
}
.note {
width: 27px;
font-family: 'Roboto', sans-serif;
font-weight: 900;
font-size: 14px;
line-height: 14px;
color: #333333;
text-align: center;
perspective: 200px;
user-select: none;
& > div {
background-image: linear-gradient(-180deg, #E9D5D0 0%, #E6E5F2 98%);
box-shadow: 0px 2px 2px 0px rgba(0,0,0,0.26);
border-radius: 3px;
width: 100%;
height: 100%;
padding: 8px 0;
box-sizing: border-box;
transform-origin: top center;
}
&:hover > div {
background-image: linear-gradient(-180deg, #E3C377 3%, #ADDC9D 98%);
transform: rotateX(-5deg);
}
&.note-1 { height: 183px; }
&.note-2 { height: 178px; }
&.note-3 { height: 168px; }
&.note-4 { height: 163px; }
&.note-5 { height: 153px; }
&.note-6 { height: 148px; }
&.note-7 { height: 143px; }
&.note-8 { height: 133px; }
&.note-9 { height: 128px; }
&.note-10 { height: 118px; }
&.note-11 { height: 113px; }
&.note-12 { height: 108px; }
&.note-13 { height: 183px; }
&.note-14 { height: 178px; }
&.note-15 { height: 173px; }
&.note-16 { height: 168px; }
&.note-17 { height: 163px; }
&.note-18 { height: 158px; }
&.note-19 { height: 153px; }
&.note-20 { height: 148px; }
&.note-21 { height: 143px; }
&.note-22 { height: 138px; }
&.note-23 { height: 133px; }
&.note-24 { height: 128px; }
&.note-25 { height: 123px; }
&.note-26 { height: 118px; }
&.note-27 { height: 113px; }
&.note-28 { height: 108px; }
&.note-29 { height: 103px; }
&.note-30 { height: 98px; }
}
.stick {
position: absolute;
height: 117px;
width: 22px;
left: 100px;
background-image: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/355309/stick.svg);
background-repeat: no-repeat;
background-size: cover;
z-index: 9999;
transform-origin: 4px 50%;
transform: rotate(-25deg);
pointer-events: none;
.glow-1, .glow-2 {
border-radius: 50%;
background-color: rgba(255, 243, 178, 0.25);
position: relative;
animation-name: bonyonyon;
animation-timing-function: linear;
animation-play-state: paused;
animation-iteration-count: infinite;
transition: opacity 0.3s ease;
opacity: 1;
&.hidden {
opacity: 0;
}
}
.glow-1 {
width: 34px;
height: 34px;
left: -6px;
top: -6px;
z-index: 9997;
animation-duration: 0.3s;
}
.glow-2 {
width: 28px;
height: 28px;
left: -3px;
top: -37px;
z-index: 9998;
animation-duration: 0.2s;
animation-delay: .1s;
}
}
body {
background-image: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/355309/background.svg);
background-color: #583864;
background-size: auto 100%;
display: flex;
align-items: center;
}
html {
height: 100%;
}
body {
min-height: 100%;
margin: 0;
cursor: none;
}
@keyframes bonyonyon {
from {
transform: scale(1);
}
to {
transform: scale(1.5);
}
}
class Sound {
constructor(context) {
this.context = context;
}
setup() {
this.oscillator = this.context.createOscillator();
this.gainNode = this.context.createGain();
this.oscillator.connect(this.gainNode);
this.gainNode.connect(this.context.destination);
this.oscillator.type = 'sine';
}
play(value) {
this.setup();
this.oscillator.frequency.value = value;
this.gainNode.gain.setValueAtTime(0, this.context.currentTime);
this.gainNode.gain.linearRampToValueAtTime(1, this.context.currentTime + 0.01);
this.oscillator.start(this.context.currentTime);
this.stop(this.context.currentTime);
}
stop() {
this.gainNode.gain.exponentialRampToValueAtTime(0.001, this.context.currentTime + 1);
this.oscillator.stop(this.context.currentTime + 1);
}
}
let context = new (window.AudioContext || window.webkitAudioContext)();
document.addEventListener('mousemove', cursor);
var stick = document.querySelector('.stick');
var glow1 = document.querySelector('.stick .glow-1');
var glow2 = document.querySelector('.stick .glow-2');
var notes = document.querySelectorAll('.note');
notes.forEach((note) => {
note.addEventListener('mouseenter', () => {
playSound(note);
showGlow();
setTimeout(hideGlow, 300);
})
note.addEventListener('mouseleave', hideGlow);
})
function playSound(note) {
let sound = new Sound(context);
let value = note.dataset.frequency;
sound.play(value);
sound.stop();
}
function showGlow() {
glow1.style.animationPlayState = "running";
glow2.style.animationPlayState = "running";
glow1.classList.remove('hidden');
glow2.classList.remove('hidden');
}
function hideGlow() {
glow1.style.animationPlayState = "paused";
glow2.style.animationPlayState = "paused";
glow1.classList.add('hidden');
glow2.classList.add('hidden');
}
function cursor(e) {
stick.style.top = e.clientY - 12 + "px";
stick.style.left = e.clientX + 12 + "px";
}
Also see: Tab Triggers