Spaces:
Running
Running
Download index.html from Ezequield/anycoder-2f0b2c45: direct link, hf CLI and curl.
- Browser
- Download file 24.6 kB
-
https://huggingface.co/spaces/Ezequield/anycoder-2f0b2c45/resolve/main/index.html
- Command line
-
hf download hf://spaces/Ezequield/anycoder-2f0b2c45/index.html
-
curl -L -o index.html https://huggingface.co/spaces/Ezequield/anycoder-2f0b2c45/resolve/main/index.html
24.6 kB
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>VCR-2001 Video Deck</title> | |
| <!-- Import Google Fonts for that Retro Digital look --> | |
| <link rel="preconnect" href="https://fonts.googleapis.com"> | |
| <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> | |
| <link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700&family=VT323&display=swap" rel="stylesheet"> | |
| <!-- FontAwesome for Icons --> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <style> | |
| :root { | |
| --vcr-body: #2b2b2b; | |
| --vcr-faceplate: #1a1a1a; | |
| --vcr-accent: #4a90e2; /* 2001 Tech Blue */ | |
| --vcr-led-red: #ff3333; | |
| --vcr-led-green: #33ff33; | |
| --crt-bg: #050505; | |
| --crt-scanline: rgba(18, 16, 16, 0.5); | |
| --metal-gradient: linear-gradient(135deg, #444 0%, #222 50%, #111 100%); | |
| } | |
| * { | |
| box-sizing: border-box; | |
| user-select: none; | |
| } | |
| body { | |
| margin: 0; | |
| padding: 0; | |
| background-color: #121212; | |
| background-image: radial-gradient(#222 1px, transparent 1px); | |
| background-size: 20px 20px; | |
| font-family: 'Orbitron', sans-serif; | |
| color: #eee; | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| justify-content: center; | |
| min-height: 100vh; | |
| overflow-x: hidden; | |
| } | |
| /* --- Header / Branding --- */ | |
| header { | |
| width: 100%; | |
| padding: 1rem; | |
| text-align: center; | |
| background: rgba(0, 0, 0, 0.8); | |
| border-bottom: 2px solid var(--vcr-accent); | |
| margin-bottom: 2rem; | |
| position: relative; | |
| z-index: 10; | |
| } | |
| .brand-title { | |
| font-size: 1.5rem; | |
| text-transform: uppercase; | |
| letter-spacing: 4px; | |
| color: var(--vcr-accent); | |
| text-shadow: 0 0 10px var(--vcr-accent); | |
| } | |
| .anycoder-link { | |
| font-family: 'VT323', monospace; | |
| font-size: 1.2rem; | |
| color: #888; | |
| text-decoration: none; | |
| margin-top: 5px; | |
| display: inline-block; | |
| transition: color 0.3s; | |
| } | |
| .anycoder-link:hover { | |
| color: #fff; | |
| text-shadow: 0 0 5px #fff; | |
| } | |
| /* --- Main VCR Unit --- */ | |
| .vcr-unit { | |
| width: 90%; | |
| max-width: 800px; | |
| background: var(--metal-gradient); | |
| border-radius: 10px; | |
| padding: 20px; | |
| box-shadow: | |
| 0 20px 50px rgba(0,0,0,0.8), | |
| inset 0 1px 1px rgba(255,255,255,0.2), | |
| 0 0 0 2px #000; | |
| display: flex; | |
| flex-direction: column; | |
| gap: 20px; | |
| position: relative; | |
| } | |
| /* Screws in corners */ | |
| .screw { | |
| width: 12px; | |
| height: 12px; | |
| background: #555; | |
| border-radius: 50%; | |
| position: absolute; | |
| box-shadow: inset 1px 1px 2px #000, 1px 1px 1px rgba(255,255,255,0.2); | |
| } | |
| .screw::after { | |
| content: ''; | |
| position: absolute; | |
| top: 50%; | |
| left: 50%; | |
| width: 80%; | |
| height: 2px; | |
| background: #222; | |
| transform: translate(-50%, -50%) rotate(45deg); | |
| } | |
| .screw.tl { top: 10px; left: 10px; } | |
| .screw.tr { top: 10px; right: 10px; } | |
| .screw.bl { bottom: 10px; left: 10px; } | |
| .screw.br { bottom: 10px; right: 10px; } | |
| /* --- The CRT Screen --- */ | |
| .crt-container { | |
| width: 100%; | |
| background: #000; | |
| border-radius: 20px / 10px; /* Slight curvature */ | |
| padding: 20px 20px 40px 20px; /* More padding bottom for bezel */ | |
| border: 4px solid #111; | |
| box-shadow: inset 0 0 20px rgba(0,0,0,1); | |
| position: relative; | |
| overflow: hidden; | |
| aspect-ratio: 4/3; | |
| } | |
| .screen-glass { | |
| width: 100%; | |
| height: 100%; | |
| background: var(--crt-bg); | |
| position: relative; | |
| overflow: hidden; | |
| border-radius: 4px; /* Inner screen radius */ | |
| box-shadow: 0 0 10px rgba(0,0,0,0.5); | |
| } | |
| video { | |
| width: 100%; | |
| height: 100%; | |
| object-fit: contain; | |
| display: block; | |
| filter: contrast(1.1) saturation(1.1); | |
| } | |
| /* CRT Effects Overlay */ | |
| .crt-overlay { | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| pointer-events: none; | |
| z-index: 5; | |
| background: | |
| /* Scanlines */ | |
| linear-gradient( | |
| rgba(18, 16, 16, 0) 50%, | |
| rgba(0, 0, 0, 0.25) 50% | |
| ), | |
| /* Subtle RGB shift */ | |
| linear-gradient( | |
| 90deg, | |
| rgba(255, 0, 0, 0.06), | |
| rgba(0, 255, 0, 0.02), | |
| rgba(0, 0, 255, 0.06) | |
| ); | |
| background-size: 100% 4px, 6px 100%; | |
| animation: flicker 0.15s infinite; | |
| } | |
| .screen-text { | |
| position: absolute; | |
| color: var(--vcr-led-green); | |
| font-family: 'VT323', monospace; | |
| font-size: 2rem; | |
| z-index: 6; | |
| text-shadow: 0 0 5px var(--vcr-led-green); | |
| pointer-events: none; | |
| display: flex; | |
| flex-direction: column; | |
| justify-content: center; | |
| align-items: center; | |
| width: 100%; | |
| height: 100%; | |
| background: rgba(0,0,0,0.7); | |
| text-align: center; | |
| } | |
| .screen-text.hidden { | |
| display: none; | |
| } | |
| .no-signal-anim { | |
| animation: blink 1s step-end infinite; | |
| } | |
| /* --- VCR Faceplate & Controls --- */ | |
| .faceplate { | |
| background: var(--vcr-faceplate); | |
| width: 100%; | |
| border-radius: 4px; | |
| padding: 20px; | |
| display: grid; | |
| grid-template-columns: 1fr 2fr; | |
| gap: 20px; | |
| border: 1px solid #333; | |
| box-shadow: inset 0 0 10px #000; | |
| } | |
| /* Left Side: Info & Brand */ | |
| .info-panel { | |
| display: flex; | |
| flex-direction: column; | |
| justify-content: space-between; | |
| border-right: 1px solid #333; | |
| padding-right: 20px; | |
| } | |
| .vcr-logo { | |
| font-size: 2rem; | |
| font-weight: bold; | |
| font-style: italic; | |
| background: linear-gradient(180deg, #ddd, #888); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| margin-bottom: 10px; | |
| } | |
| .lcd-display { | |
| background: #0a2a0a; /* Dark green LCD background */ | |
| color: var(--vcr-led-green); | |
| font-family: 'VT323', monospace; | |
| padding: 10px; | |
| border-radius: 4px; | |
| border: 2px inset #333; | |
| font-size: 1.2rem; | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| box-shadow: inset 0 0 5px rgba(0,0,0,0.8); | |
| } | |
| .counter { | |
| letter-spacing: 2px; | |
| } | |
| .status-led { | |
| width: 10px; | |
| height: 10px; | |
| background: #333; | |
| border-radius: 50%; | |
| box-shadow: inset 0 1px 2px rgba(0,0,0,0.5); | |
| transition: background 0.2s, box-shadow 0.2s; | |
| } | |
| .status-led.on { | |
| background: var(--vcr-led-red); | |
| box-shadow: 0 0 8px var(--vcr-led-red); | |
| } | |
| /* Right Side: Controls */ | |
| .controls-panel { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 15px; | |
| } | |
| /* Tape Slot Area */ | |
| .tape-slot { | |
| height: 50px; | |
| background: #000; | |
| border-radius: 4px; | |
| border: 1px solid #333; | |
| position: relative; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| overflow: hidden; | |
| } | |
| .tape-label { | |
| font-size: 0.8rem; | |
| color: #555; | |
| text-transform: uppercase; | |
| letter-spacing: 2px; | |
| } | |
| /* Main Buttons */ | |
| .button-row { | |
| display: flex; | |
| justify-content: space-between; | |
| gap: 10px; | |
| background: #222; | |
| padding: 10px; | |
| border-radius: 6px; | |
| border: 1px solid #444; | |
| } | |
| .vcr-btn { | |
| background: linear-gradient(180deg, #555, #333); | |
| border: none; | |
| border-radius: 4px; | |
| color: #ccc; | |
| padding: 10px 15px; | |
| font-family: 'Orbitron', sans-serif; | |
| font-size: 0.8rem; | |
| cursor: pointer; | |
| box-shadow: | |
| 0 4px 0 #111, | |
| 0 5px 5px rgba(0,0,0,0.5); | |
| transition: transform 0.1s, box-shadow 0.1s; | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| gap: 5px; | |
| flex: 1; | |
| } | |
| .vcr-btn i { | |
| font-size: 1.2rem; | |
| margin-bottom: 2px; | |
| } | |
| .vcr-btn:active { | |
| transform: translateY(4px); | |
| box-shadow: | |
| 0 0 0 #111, | |
| inset 0 2px 5px rgba(0,0,0,0.5); | |
| } | |
| .vcr-btn.play-btn { color: var(--vcr-led-green); } | |
| .vcr-btn.stop-btn { color: var(--vcr-led-red); } | |
| .vcr-btn.upload-btn { | |
| background: linear-gradient(180deg, var(--vcr-accent), #2a5a8c); | |
| color: #fff; | |
| } | |
| /* Tracking Slider */ | |
| .tracking-control { | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| } | |
| .tracking-label { | |
| font-size: 0.7rem; | |
| color: #888; | |
| text-transform: uppercase; | |
| width: 60px; | |
| } | |
| input[type=range] { | |
| -webkit-appearance: none; | |
| width: 100%; | |
| background: transparent; | |
| } | |
| input[type=range]::-webkit-slider-thumb { | |
| -webkit-appearance: none; | |
| height: 20px; | |
| width: 10px; | |
| border-radius: 2px; | |
| background: #ccc; | |
| cursor: pointer; | |
| margin-top: -8px; | |
| box-shadow: 1px 1px 3px #000; | |
| } | |
| input[type=range]::-webkit-slider-runnable-track { | |
| width: 100%; | |
| height: 4px; | |
| cursor: pointer; | |
| background: #111; | |
| border-radius: 2px; | |
| border: 1px solid #333; | |
| } | |
| /* --- Animations --- */ | |
| @keyframes flicker { | |
| 0% { opacity: 0.95; } | |
| 5% { opacity: 0.85; } | |
| 10% { opacity: 0.95; } | |
| 100% { opacity: 0.95; } | |
| } | |
| @keyframes blink { | |
| 0%, 100% { opacity: 1; } | |
| 50% { opacity: 0; } | |
| } | |
| @keyframes scanline-scroll { | |
| 0% { transform: translateY(-100%); } | |
| 100% { transform: translateY(100%); } | |
| } | |
| /* Noise overlay for static */ | |
| .static-noise { | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| background: url('data:image/svg+xml;utf8,%3Csvg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg"%3E%3Cfilter id="noiseFilter"%3E%3CfeTurbulence type="fractalNoise" baseFrequency="0.8" numOctaves="3" stitchTiles="stitch"/%3E%3C/filter%3E%3Crect width="100%25" height="100%25" filter="url(%23noiseFilter)" opacity="0.4"/%3E%3C/svg%3E'); | |
| opacity: 0; | |
| pointer-events: none; | |
| z-index: 4; | |
| mix-blend-mode: overlay; | |
| } | |
| .static-noise.active { | |
| opacity: 1; | |
| animation: noiseAnim 0.2s steps(4) infinite; | |
| } | |
| @keyframes noiseAnim { | |
| 0% { transform: translate(0, 0); } | |
| 10% { transform: translate(-5%, -5%); } | |
| 20% { transform: translate(-10%, 5%); } | |
| 30% { transform: translate(5%, -10%); } | |
| 40% { transform: translate(-5%, 15%); } | |
| 50% { transform: translate(-10%, 5%); } | |
| 60% { transform: translate(15%, 0); } | |
| 70% { transform: translate(0, 10%); } | |
| 80% { transform: translate(-15%, 0); } | |
| 90% { transform: translate(10%, 5%); } | |
| 100% { transform: translate(5%, 0); } | |
| } | |
| /* --- Responsive --- */ | |
| @media (max-width: 600px) { | |
| .faceplate { | |
| grid-template-columns: 1fr; | |
| } | |
| .info-panel { | |
| border-right: none; | |
| border-bottom: 1px solid #333; | |
| padding-right: 0; | |
| padding-bottom: 15px; | |
| } | |
| .vcr-btn span { | |
| display: none; /* Hide text labels on small screens */ | |
| } | |
| .vcr-btn { | |
| justify-content: center; | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <header> | |
| <div class="brand-title">VCR-2001</div> | |
| <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="anycoder-link"> | |
| Built with anycoder | |
| </a> | |
| </header> | |
| <main class="vcr-unit"> | |
| <!-- Decorative Screws --> | |
| <div class="screw tl"></div> | |
| <div class="screw tr"></div> | |
| <div class="screw bl"></div> | |
| <div class="screw br"></div> | |
| <!-- CRT Screen Section --> | |
| <div class="crt-container"> | |
| <div class="screen-glass"> | |
| <video id="videoPlayer" playsinline loop></video> | |
| <!-- Static Noise Layer --> | |
| <div class="static-noise" id="noiseLayer"></div> | |
| <!-- CRT Scanline Overlay --> | |
| <div class="crt-overlay"></div> | |
| <!-- On-screen Display / No Signal --> | |
| <div class="screen-text" id="screenText"> | |
| <div class="no-signal-anim">NO SIGNAL</div> | |
| <div style="font-size: 1rem; margin-top: 10px; color: #888;">[INSERT TAPE]</div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Controls Section --> | |
| <div class="faceplate"> | |
| <!-- Left: Info & LCD --> | |
| <div class="info-panel"> | |
| <div> | |
| <div class="vcr-logo">CYBERDECK</div> | |
| <div style="font-size: 0.7rem; color: #666; letter-spacing: 1px;">HI-FI STEREO VHS</div> | |
| </div> | |
| <div class="lcd-display"> | |
| <span id="clockDisplay">12:00 AM</span> | |
| <div class="status-led" id="statusLed"></div> | |
| </div> | |
| <div style="font-size: 0.7rem; color: #555;"> | |
| REC: <span id="recStatus">OFF</span> | |
| </div> | |
| </div> | |
| <!-- Right: Buttons & Inputs --> | |
| <div class="controls-panel"> | |
| <!-- Hidden File Input --> | |
| <input type="file" id="fileInput" accept="video/*" style="display: none;"> | |
| <div class="tape-slot"> | |
| <span class="tape-label" id="tapeLabel">NO TAPE</span> | |
| </div> | |
| <div class="button-row"> | |
| <button class="vcr-btn" id="ejectBtn" title="Eject"> | |
| <i class="fa-solid fa-eject"></i> | |
| <span>EJECT</span> | |
| </button> | |
| <button class="vcr-btn upload-btn" id="uploadBtn" title="Load Tape"> | |
| <i class="fa-solid fa-floppy-disk"></i> | |
| <span>LOAD</span> | |
| </button> | |
| </div> | |
| <div class="button-row"> | |
| <button class="vcr-btn" id="rewindBtn" title="Rewind"> | |
| <i class="fa-solid fa-backward"></i> | |
| <span>REW</span> | |
| </button> | |
| <button class="vcr-btn play-btn" id="playBtn" title="Play"> | |
| <i class="fa-solid fa-play"></i> | |
| <span>PLAY</span> | |
| </button> | |
| <button class="vcr-btn stop-btn" id="stopBtn" title="Stop"> | |
| <i class="fa-solid fa-stop"></i> | |
| <span>STOP</span> | |
| </button> | |
| <button class="vcr-btn" id="ffBtn" title="Fast Forward"> | |
| <i class="fa-solid fa-forward"></i> | |
| <span>FF</span> | |
| </button> | |
| </div> | |
| <div class="tracking-control"> | |
| <div class="tracking-label">TRACKING</div> | |
| <input type="range" id="trackingSlider" min="-20" max="20" value="0"> | |
| </div> | |
| </div> | |
| </div> | |
| </main> | |
| <script> | |
| document.addEventListener('DOMContentLoaded', () => { | |
| // Elements | |
| const video = document.getElementById('videoPlayer'); | |
| const fileInput = document.getElementById('fileInput'); | |
| const uploadBtn = document.getElementById('uploadBtn'); | |
| const playBtn = document.getElementById('playBtn'); | |
| const stopBtn = document.getElementById('stopBtn'); | |
| const ejectBtn = document.getElementById('ejectBtn'); | |
| const rewindBtn = document.getElementById('rewindBtn'); | |
| const ffBtn = document.getElementById('ffBtn'); | |
| const trackingSlider = document.getElementById('trackingSlider'); | |
| const screenText = document.getElementById('screenText'); | |
| const tapeLabel = document.getElementById('tapeLabel'); | |
| const statusLed = document.getElementById('statusLed'); | |
| const noiseLayer = document.getElementById('noiseLayer'); | |
| const clockDisplay = document.getElementById('clockDisplay'); | |
| const recStatus = document.getElementById('recStatus'); | |
| let isPlaying = false; | |
| let playbackSpeed = 1.0; | |
| let videoLoaded = false; | |
| // --- Clock Functionality --- | |
| function updateClock() { | |
| const now = new Date(); | |
| let hours = now.getHours(); | |
| const minutes = String(now.getMinutes()).padStart(2, '0'); | |
| const ampm = hours >= 12 ? 'PM' : 'AM'; | |
| hours = hours % 12; | |
| hours = hours ? hours : 12; | |
| clockDisplay.textContent = `${hours}:${minutes} ${ampm}`; | |
| } | |
| setInterval(updateClock, 1000); | |
| updateClock(); | |
| // --- File Upload Logic --- | |
| uploadBtn.addEventListener('click', () => { | |
| fileInput.click(); | |
| }); | |
| fileInput.addEventListener('change', (e) => { | |
| const file = e.target.files[0]; | |
| if (file) { | |
| const fileURL = URL.createObjectURL(file); | |
| video.src = fileURL; | |
| tapeLabel.textContent = file.name.substring(0, 20) + (file.name.length > 20 ? '...' : ''); | |
| // UI Updates | |
| screenText.classList.add('hidden'); | |
| noiseLayer.classList.remove('active'); | |
| // Simulate loading delay | |
| statusLed.classList.add('on'); // Red light for "Loading/Processing" | |
| recStatus.textContent = "LOADING"; | |
| video.onloadeddata = () => { | |
| videoLoaded = true; | |
| statusLed.classList.remove('on'); // Turn off loading light | |
| recStatus.textContent = "READY"; | |
| playVideo(); | |
| }; | |
| } | |
| }); | |
| // --- Playback Controls --- | |
| function playVideo() { | |
| if (!videoLoaded) return; | |
| video.play() | |
| .then(() => { | |
| isPlaying = true; | |
| statusLed.classList.add('on'); // Red light for "Play/Rec" | |
| playBtn.innerHTML = '<i class="fa-solid fa-pause"></i><span>PAUSE</span>'; | |
| noiseLayer.classList.remove('active'); | |
| recStatus.textContent = "PLAY"; | |
| }) | |
| .catch(err => console.error("Play error:", err)); | |
| } | |
| function pauseVideo() { | |
| video.pause(); | |
| isPlaying = false; | |
| statusLed.classList.remove('on'); | |
| playBtn.innerHTML = '<i class="fa-solid fa-play"></i><span>PLAY</span>'; | |
| recStatus.textContent = "PAUSE"; | |
| } | |
| function stopVideo() { | |
| video.pause(); | |
| video.currentTime = 0; | |
| isPlaying = false; | |
| statusLed.classList.remove('on'); | |
| playBtn.innerHTML = '<i class="fa-solid fa-play"></i><span>PLAY</span>'; | |
| recStatus.textContent = "STOP"; | |
| // Show static briefly | |
| noiseLayer.classList.add('active'); | |
| setTimeout(() => { | |
| if(!isPlaying) noiseLayer.classList.remove('active'); | |
| }, 500); | |
| } | |
| function ejectTape() { | |
| stopVideo(); | |
| video.src = ""; | |
| videoLoaded = false; | |
| tapeLabel.textContent = "NO TAPE"; | |
| screenText.classList.remove('hidden'); | |
| recStatus.textContent = "NO TAPE"; | |
| fileInput.value = ""; // Reset input | |
| } | |
| // --- Event Listeners --- | |
| playBtn.addEventListener('click', () => { | |
| if (isPlaying) { | |
| pauseVideo(); | |
| } else { | |
| playVideo(); | |
| } | |
| }); | |
| stopBtn.addEventListener('click', stopVideo); | |
| ejectBtn.addEventListener('click', ejectTape); | |
| rewindBtn.addEventListener('click', () => { | |
| if(!videoLoaded) return; | |
| video.playbackRate = 2.0; | |
| video.currentTime -= 5; // Jump back slightly | |
| recStatus.textContent = "<<<"; | |
| setTimeout(() => { video.playbackRate = 1.0; }, 500); | |
| }); | |
| ffBtn.addEventListener('click', () => { | |
| if(!videoLoaded) return; | |
| video.playbackRate = 2.0; | |
| video.currentTime += 5; // Jump forward slightly | |
| recStatus.textContent = ">>>"; | |
| setTimeout(() => { video.playbackRate = 1.0; }, 500); | |
| }); | |
| // --- Tracking Effect (Visual Only) --- | |
| trackingSlider.addEventListener('input', (e) => { | |
| const val = e.target.value; | |
| // Apply vertical shift and blur to simulate tracking error | |
| video.style.transform = `translateY(${val}px)`; | |
| video.style.filter = `blur(${Math.abs(val) / 5}px) contrast(1.1)`; | |
| }); | |
| // Reset tracking on mouse up | |
| trackingSlider.addEventListener('mouseup', () => { | |
| trackingSlider.value = 0; | |
| video.style.transform = `translateY(0px)`; | |
| video.style.filter = `blur(0px) contrast(1.1)`; | |
| }); | |
| // Video Ended Event | |
| video.addEventListener('ended', () => { | |
| isPlaying = false; | |
| statusLed.classList.remove('on'); | |
| playBtn.innerHTML = '<i class="fa-solid fa-play"></i><span>PLAY</span>'; | |
| recStatus.textContent = "END"; | |
| }); | |
| }); | |
| </script> | |
| </body> | |
| </html> |