folk-canvas/demo/music.html

183 lines
5.4 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Music</title>
<style>
html {
height: 100%;
}
body {
min-height: 100%;
position: relative;
margin: 0;
}
fc-geometry:has(record-player) {
&::part(resize-nw),
&::part(resize-ne),
&::part(resize-se),
&::part(resize-sw) {
display: none;
}
}
fc-geometry > video {
height: 100%;
}
</style>
</head>
<body>
<!--
sips -c 326 276 --cropOffset 1 1 *.png --out pngs/
ffmpeg -framerate 25 -pattern_type glob -i '*.png' -c:v prores -pix_fmt yuva444p10le dancing-flower.mov
ffmpeg -framerate 25 -f image2 -pattern_type glob -i '*.png' -c:v libvpx-vp9 -pix_fmt yuva420p dancing-flowers.webm
-->
<fc-geometry x="100" y="75" width="330" height="198">
<record-player>
<audio src="/Feather.mp3"></audio>
</record-player>
</fc-geometry>
<fc-geometry x="25" y="300" width="166" height="200">
<video loop>
<source src="/dancing-flower.mov" type="video/quicktime" />
<source src="/dancing-flower.webm" type="video/webm" />
</video>
</fc-geometry>
<fc-geometry x="155" y="315" width="166" height="200">
<video loop>
<source src="/dancing-flower.mov" type="video/quicktime" />
<source src="/dancing-flower.webm" type="video/webm" />
</video>
</fc-geometry>
<fc-geometry x="280" y="305" width="166" height="200">
<video loop>
<source src="/dancing-flower.mov" type="video/quicktime" />
<source src="/dancing-flower.webm" type="video/webm" />
</video>
</fc-geometry>
<script type="module">
import { FolkGeometry } from '../src/canvas/fc-geometry.ts';
import { RecordPlayer } from '../src/music/record-player.ts';
FolkGeometry.register();
RecordPlayer.register();
let proximityDistance = 200;
const proximitySet = new Set();
const recordPlayerGeometry = document.querySelector(
'fc-geometry:has(record-player)'
);
const recordPlayer = recordPlayerGeometry.firstElementChild;
const flowers = document.querySelectorAll('fc-geometry:has(video)');
// set playback rate when video is ready
function setPlayback(e) {
e.target.playbackRate = (91 / 60) * e.target.duration;
e.target.removeEventListener('canplay', setPlayback);
}
flowers.forEach((el) => {
el.firstElementChild.addEventListener('canplay', setPlayback);
});
function collisionDetection(rect1, rect2) {
return (
rect1.left < rect2.right &&
rect1.right > rect2.left &&
rect1.top < rect2.bottom &&
rect1.bottom > rect2.top
);
}
function proximityDetection(rect1, rect2, distance = 30) {
return collisionDetection(
DOMRectReadOnly.fromRect({
x: rect1.x - distance,
y: rect1.y - distance,
height: rect1.height + distance * 2,
width: rect1.width + distance * 2,
}),
rect2
);
}
function updateFlowerProximity(flower) {
const alreadyIntersection = proximitySet.has(flower);
// TODO: refactor this hack once resizing and the vertices API are figured out
const isNowIntersecting = proximityDetection(
DOMRectReadOnly.fromRect({
x: recordPlayerGeometry.x,
y: recordPlayerGeometry.y,
height: recordPlayerGeometry.height,
width: recordPlayerGeometry.width,
}),
DOMRectReadOnly.fromRect({
x: flower.x,
y: flower.y,
height: flower.height,
width: flower.width,
}),
proximityDistance
);
const video = flower.firstElementChild;
if (isNowIntersecting && !alreadyIntersection) {
proximitySet.add(flower);
if (!recordPlayer.paused) {
video.play();
}
} else if (alreadyIntersection && !isNowIntersecting) {
proximitySet.delete(flower);
video.pause();
}
}
function updateRecordPlayerProximity() {
proximitySet.forEach((el) => el.firstElementChild.pause?.());
proximitySet.clear();
for (const flower of flowers) {
updateFlowerProximity(flower);
}
}
function handleProximity(e) {
if (e.target === recordPlayerGeometry) {
updateRecordPlayerProximity();
} else {
updateFlowerProximity(e.target);
}
}
document.addEventListener('move', handleProximity);
document.addEventListener('resize', handleProximity);
document.addEventListener('playing', (e) => {
proximitySet.forEach((el) => el.firstElementChild.play?.());
});
document.addEventListener('stopped', (e) => {
proximitySet.forEach((el) => {
el.firstElementChild.pause?.();
el.firstElementChild.currentTime = 0;
});
});
function updateVolume() {
proximityDistance = recordPlayer.volume * 500;
updateRecordPlayerProximity();
}
updateVolume();
document.addEventListener('volume', updateVolume);
</script>
</body>
</html>