<div class="video-block">
<svg class="video-block__svg">
<defs>
<clipPath id="video-block__clip">
<circle class="video-block__clip-circle" cx="60%" cy="30%" r="45%"/>
</clipPath>
<linearGradient id="video-block__grad" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="red"/>
<stop offset="100%" stop-color="blue"/>
</linearGradient>
</defs>
<circle class="video-block__circle" cx="60%" cy="30%" r="48%" fill="none" stroke="url(#video-block__grad)"/>
</svg>
<video class="video-block__video" autoplay playsinline muted loop preload poster="https://thenewcode.com/assets/images/vid-glacier.jpg" playsinline>
<source src="https://thenewcode.com/assets/videos/glacier.mp4" type="video/mp4">
<source src="https://thenewcode.com/assets/videos/glacier.webm" type="video/webm">
</video>
</div>
body {
display: flex;
flex-direction: column;
margin: 0;
background:
linear-gradient(to right, #0001 1px, transparent 1px) 0 0 / 8px 8px,
linear-gradient(to bottom, #0001 1px, transparent 1px) 0 0 / 8px 8px;
font-family: sans-serif;
min-height: 100vh;
height: 1px;
}
.video-block {
position: relative;
outline: 1px solid red;
width: 90%;
margin: 20px auto 0;
}
.video-block__svg {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
}
.video-block__circle {
stroke-width: 2px;
stroke-dasharray: 10px;
}
.video-block__video {
display: block;
width: 100%;
clip-path: url('#video-block__clip');
}
import { value, spring } from "https://cdn.skypack.dev/popmotion@8";
const section = document.querySelector('.video-block');
const clip = section.querySelector('.video-block__clip-circle');
const circle = section.querySelector('.video-block__circle');
const clipXY = value(
{ x: 60, y: 30 },
({ x, y }) => {
clip.setAttribute('cx', x + '%');
clip.setAttribute('cy', y + '%');
}
);
const circleXY = value(
{ x: 60, y: 30 },
({ x, y }) => {
circle.setAttribute('cx', x + '%');
circle.setAttribute('cy', y + '%');
}
);
section.addEventListener('mousemove', ({ clientX, clientY }) => {
const rect = section.getBoundingClientRect();
const x = 100 * (event.clientX - rect.left) / rect.width;
const y = 100 * (event.clientY - rect.top) / rect.height;
spring({
from: clipXY.get(),
to: { x, y },
velocity: clipXY.getVelocity(),
stiffness: 200,
damping: 50,
mass: 3,
}).start(clipXY);
spring({
from: circleXY.get(),
to: { x, y },
velocity: circleXY.getVelocity(),
stiffness: 200,
damping: 50,
mass: 2.5,
}).start(circleXY);
});
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.