Custom Code Experiment •
Hypotrochoid MP4
Source Code View HTML / CSS / JavaScript
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hypotrochoid Video Player</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background-color: #000;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
overflow: hidden;
color: #fff;
}
#video-container {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background-color: #000;
}
#video-player {
width: 100%;
height: 100%;
object-fit: contain;
cursor: pointer;
}
.controls {
position: absolute;
bottom: 0;
left: 0;
right: 0;
background: linear-gradient(transparent, rgba(0, 0, 0, 0.8));
padding: 20px;
display: flex;
justify-content: center;
align-items: center;
gap: 15px;
opacity: 0;
transition: opacity 0.3s ease;
}
#video-container:hover .controls {
opacity: 1;
}
.control-btn {
background: rgba(30, 30, 30, 0.8);
border: none;
color: white;
width: 50px;
height: 50px;
border-radius: 50%;
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
font-size: 20px;
transition: all 0.2s ease;
}
.control-btn:hover {
background: rgba(50, 50, 50, 0.9);
transform: scale(1.1);
}
.progress-container {
flex-grow: 1;
height: 6px;
background: rgba(255, 255, 255, 0.2);
border-radius: 3px;
cursor: pointer;
margin: 0 15px;
}
.progress-bar {
height: 100%;
background: #4a9eff;
border-radius: 3px;
width: 0%;
transition: width 0.1s;
}
.time-display {
font-size: 14px;
min-width: 100px;
text-align: center;
font-variant-numeric: tabular-nums;
}
#fullscreen-btn {
margin-left: auto;
}
.title {
position: absolute;
top: 20px;
left: 20px;
font-size: 18px;
font-weight: 500;
opacity: 0.9;
}
.loading {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 18px;
color: #aaa;
}
.error {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
text-align: center;
padding: 30px;
background: rgba(30, 30, 30, 0.9);
border-radius: 10px;
max-width: 80%;
}
.error h3 {
margin-bottom: 15px;
color: #ff6b6b;
}
.error-btn {
background: #4a9eff;
color: white;
border: none;
padding: 10px 20px;
border-radius: 5px;
margin-top: 15px;
cursor: pointer;
font-weight: 500;
}
@media (max-width: 768px) {
.controls {
padding: 10px;
gap: 10px;
}
.control-btn {
width: 44px;
height: 44px;
font-size: 18px;
}
.time-display {
min-width: 80px;
font-size: 13px;
}
}
</style>
</head>
<body>
<div id="video-container">
<div class="loading" id="loading">Loading video...</div>
<video id="video-player" preload="auto">
<source src="https://raw.githubusercontent.com/alaric-visi/hypotrochoid-mp4/main/hypotrochoid.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>
<div class="controls">
<button class="control-btn" id="play-pause-btn">⏸</button>
<div class="time-display"><span id="current-time">0:00</span> / <span id="duration">0:00</span></div>
<div class="progress-container" id="progress-container">
<div class="progress-bar" id="progress-bar"></div>
</div>
<button class="control-btn" id="mute-btn">🔊</button>
<button class="control-btn" id="fullscreen-btn">⛶</button>
</div>
<div class="error" id="error-message" style="display: none;">
<h3>Error Loading Video</h3>
<p id="error-text">Unable to load the video from GitHub. Please check your connection.</p>
<button class="error-btn" id="retry-btn">Try Again</button>
</div>
</div>
<script>
const videoPlayer = document.getElementById('video-player');
const playPauseBtn = document.getElementById('play-pause-btn');
const muteBtn = document.getElementById('mute-btn');
const fullscreenBtn = document.getElementById('fullscreen-btn');
const currentTimeEl = document.getElementById('current-time');
const durationEl = document.getElementById('duration');
const progressBar = document.getElementById('progress-bar');
const progressContainer = document.getElementById('progress-container');
const loadingEl = document.getElementById('loading');
const errorMessage = document.getElementById('error-message');
const errorText = document.getElementById('error-text');
const retryBtn = document.getElementById('retry-btn');
const videoUrl = 'https://raw.githubusercontent.com/alaric-visi/hypotrochoid-mp4/main/hypotrochoid.mp4';
function formatTime(seconds) {
const mins = Math.floor(seconds / 60);
const secs = Math.floor(seconds % 60);
return `${mins}:${secs < 10 ? '0' : ''}${secs}`;
}
function updateTime() {
const currentTime = videoPlayer.currentTime;
const duration = videoPlayer.duration;
currentTimeEl.textContent = formatTime(currentTime);
if (duration) {
durationEl.textContent = formatTime(duration);
const progressPercent = (currentTime / duration) * 100;
progressBar.style.width = `${progressPercent}%`;
}
}
function togglePlayPause() {
if (videoPlayer.paused || videoPlayer.ended) {
videoPlayer.play();
playPauseBtn.textContent = '⏸';
} else {
videoPlayer.pause();
playPauseBtn.textContent = '▶';
}
}
function toggleMute() {
videoPlayer.muted = !videoPlayer.muted;
muteBtn.textContent = videoPlayer.muted ? '🔇' : '🔊';
}
function toggleFullscreen() {
if (!document.fullscreenElement) {
if (document.documentElement.requestFullscreen) {
document.documentElement.requestFullscreen();
} else if (document.documentElement.webkitRequestFullscreen) {
document.documentElement.webkitRequestFullscreen();
} else if (document.documentElement.msRequestFullscreen) {
document.documentElement.msRequestFullscreen();
}
} else {
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.webkitExitFullscreen) {
document.webkitExitFullscreen();
} else if (document.msExitFullscreen) {
document.msExitFullscreen();
}
}
}
function setProgress(e) {
const width = this.clientWidth;
const clickX = e.offsetX;
const duration = videoPlayer.duration;
videoPlayer.currentTime = (clickX / width) * duration;
}
function handleVideoLoad() {
loadingEl.style.display = 'none';
errorMessage.style.display = 'none';
videoPlayer.style.display = 'block';
videoPlayer.play().catch(e => {
console.log("Auto-play prevented, waiting for user interaction");
playPauseBtn.textContent = '▶';
});
}
function handleVideoError() {
loadingEl.style.display = 'none';
videoPlayer.style.display = 'none';
errorMessage.style.display = 'block';
if (videoPlayer.error) {
switch(videoPlayer.error.code) {
case 1:
errorText.textContent = "Video loading was aborted.";
break;
case 2:
errorText.textContent = "Network error while loading video.";
break;
case 3:
errorText.textContent = "Video decoding error.";
break;
case 4:
errorText.textContent = "Video not supported or file format invalid.";
break;
default:
errorText.textContent = "An error occurred while loading the video.";
}
}
}
function initPlayer() {
videoPlayer.src = videoUrl;
videoPlayer.addEventListener('loadeddata', handleVideoLoad);
videoPlayer.addEventListener('error', handleVideoError);
videoPlayer.addEventListener('timeupdate', updateTime);
videoPlayer.addEventListener('ended', () => {
playPauseBtn.textContent = '↺';
});
playPauseBtn.addEventListener('click', togglePlayPause);
muteBtn.addEventListener('click', toggleMute);
fullscreenBtn.addEventListener('click', toggleFullscreen);
progressContainer.addEventListener('click', setProgress);
retryBtn.addEventListener('click', () => {
loadingEl.style.display = 'block';
errorMessage.style.display = 'none';
videoPlayer.src = videoUrl;
videoPlayer.load();
});
videoPlayer.addEventListener('click', togglePlayPause);
document.addEventListener('keydown', (e) => {
// Space bar toggles play/pause
if (e.code === 'Space' && e.target === document.body) {
e.preventDefault();
togglePlayPause();
}
if (e.code === 'KeyM' && e.target === document.body) {
e.preventDefault();
toggleMute();
}
if (e.code === 'KeyF' && e.target === document.body) {
e.preventDefault();
toggleFullscreen();
}
if (e.code === 'ArrowLeft' && e.target === document.body) {
e.preventDefault();
videoPlayer.currentTime = Math.max(0, videoPlayer.currentTime - 5);
}
if (e.code === 'ArrowRight' && e.target === document.body) {
e.preventDefault();
videoPlayer.currentTime = Math.min(videoPlayer.duration, videoPlayer.currentTime + 5);
}
});
videoPlayer.addEventListener('play', () => {
playPauseBtn.textContent = '⏸';
});
videoPlayer.addEventListener('pause', () => {
playPauseBtn.textContent = '▶';
});
document.addEventListener('fullscreenchange', updateFullscreenButton);
document.addEventListener('webkitfullscreenchange', updateFullscreenButton);
document.addEventListener('msfullscreenchange', updateFullscreenButton);
function updateFullscreenButton() {
if (document.fullscreenElement || document.webkitFullscreenElement || document.msFullscreenElement) {
fullscreenBtn.textContent = '⛶';
} else {
fullscreenBtn.textContent = '⛶';
}
}
}
document.addEventListener('DOMContentLoaded', initPlayer);
</script>
</body>
</html>