144 lines
4.2 KiB
HTML
144 lines
4.2 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
<title>Proximity Music</title>
|
|
<style>
|
|
html {
|
|
height: 100%;
|
|
}
|
|
|
|
body {
|
|
min-height: 100%;
|
|
position: relative;
|
|
margin: 0;
|
|
}
|
|
|
|
folk-shape:has(record-player) {
|
|
box-shadow: 10px 0px 150px 0px rgba(0, 0, 0, 0.61);
|
|
|
|
&::part(resize-top-left),
|
|
&::part(resize-top-right),
|
|
&::part(resize-bottom-right),
|
|
&::part(resize-bottom-left) {
|
|
display: none;
|
|
}
|
|
}
|
|
|
|
folk-shape > video {
|
|
height: 100%;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<folk-shape x="100" y="75" width="330" height="198">
|
|
<record-player>
|
|
<audio src="/Feather.mov"></audio>
|
|
</record-player>
|
|
</folk-shape>
|
|
|
|
<folk-shape 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>
|
|
</folk-shape>
|
|
|
|
<folk-shape 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>
|
|
</folk-shape>
|
|
|
|
<folk-shape 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>
|
|
</folk-shape>
|
|
|
|
<script type="module">
|
|
import './src/record-player.ts';
|
|
import '@labs/standalone/folk-shape.ts';
|
|
import { aabbIntersection } from '@lib/common/collision.ts';
|
|
|
|
let proximityDistance = 150;
|
|
const proximitySet = new Set();
|
|
const recordPlayerGeometry = document.querySelector('folk-shape:has(record-player)');
|
|
const recordPlayer = recordPlayerGeometry.firstElementChild;
|
|
const flowers = document.querySelectorAll('folk-shape: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 updateFlowerProximity(flower) {
|
|
const alreadyIntersection = proximitySet.has(flower);
|
|
// TODO: refactor this hack once resizing and the vertices API are figured out
|
|
const isNowIntersecting = aabbIntersection(
|
|
recordPlayerGeometry.getTransformDOMRect(),
|
|
flower.getTransformDOMRect(),
|
|
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('transform', 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>
|