Created
December 30, 2025 01:31
-
-
Save wwtv127/e6ba0da95d1d60afa17ab9982af46998 to your computer and use it in GitHub Desktop.
R1 Artifact: R1 Tube
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> | |
| <title>R1 Tube</title> | |
| <style> | |
| :root { | |
| --r1-orange: #ff4e00; | |
| --bg-black: #0f0f0f; | |
| --text-white: #ffffff; | |
| --card-bg: #1a1a1a; | |
| --nav-height: 35px; | |
| } | |
| * { | |
| box-sizing: border-box; | |
| -webkit-tap-highlight-color: transparent; | |
| } | |
| body { | |
| margin: 0; | |
| padding: 0; | |
| width: 240px; | |
| height: 287px; | |
| background: var(--bg-black); | |
| color: var(--text-white); | |
| font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; | |
| overflow: hidden; | |
| display: flex; | |
| flex-direction: column; | |
| } | |
| /* Startup Screen */ | |
| #startup-screen { | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| width: 240px; | |
| height: 287px; | |
| background: #0f0f0f; | |
| z-index: 1000; | |
| display: flex; | |
| flex-direction: column; | |
| justify-content: center; | |
| align-items: center; | |
| transition: opacity 0.5s ease; | |
| } | |
| #yt-loader-wrapper { | |
| width: 160px; | |
| height: 40px; | |
| position: relative; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| } | |
| #yt-track { | |
| width: 140px; | |
| height: 2px; | |
| background: #2a2a2a; | |
| border-radius: 1px; | |
| position: relative; | |
| transition: opacity 0.3s ease; | |
| } | |
| #yt-progress { | |
| position: absolute; | |
| left: 0; | |
| top: 0; | |
| height: 100%; | |
| width: 0%; | |
| background: var(--r1-orange); | |
| border-radius: 1px; | |
| transition: width 1.8s cubic-bezier(0.1, 0.5, 0.1, 1); | |
| } | |
| #yt-progress::after { | |
| content: ''; | |
| position: absolute; | |
| right: -4px; | |
| top: -3px; | |
| width: 8px; | |
| height: 8px; | |
| background: white; | |
| border-radius: 50%; | |
| box-shadow: 0 0 8px var(--r1-orange); | |
| } | |
| #yt-logo-final { | |
| position: absolute; | |
| opacity: 0; | |
| transform: scale(0.9); | |
| transition: all 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.2); | |
| display: flex; | |
| align-items: center; | |
| gap: 6px; | |
| font-weight: 800; | |
| font-size: 20px; | |
| letter-spacing: -1px; | |
| color: white; | |
| pointer-events: none; | |
| } | |
| .r1-play-icon { | |
| width: 28px; | |
| height: 20px; | |
| background: var(--r1-orange); | |
| border-radius: 5px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| position: relative; | |
| flex-shrink: 0; | |
| } | |
| .r1-play-icon::after { | |
| content: ''; | |
| width: 0; | |
| height: 0; | |
| border-style: solid; | |
| border-width: 4px 0 4px 7px; | |
| border-color: transparent transparent transparent white; | |
| } | |
| #yt-logo-final span { color: var(--r1-orange); } | |
| /* Header */ | |
| #header { | |
| height: 40px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: space-between; | |
| padding: 0 10px; | |
| background: #0f0f0f; | |
| border-bottom: 1px solid #222; | |
| flex-shrink: 0; | |
| z-index: 10; | |
| } | |
| #logo { | |
| display: flex; | |
| align-items: center; | |
| gap: 4px; | |
| font-weight: 800; | |
| font-size: 14px; | |
| color: white; | |
| letter-spacing: -0.5px; | |
| } | |
| #logo .r1-play-icon { width: 20px; height: 14px; border-radius: 3px; } | |
| #logo .r1-play-icon::after { border-width: 3px 0 3px 5px; } | |
| #logo span { color: var(--r1-orange); } | |
| #search-btn { | |
| background: #222; | |
| border: 1px solid #444; | |
| color: white; | |
| padding: 4px 8px; | |
| border-radius: 4px; | |
| font-size: 10px; | |
| cursor: pointer; | |
| } | |
| /* Content Areas */ | |
| #content-area { | |
| flex-grow: 1; | |
| overflow-y: auto; | |
| scrollbar-width: none; | |
| position: relative; | |
| padding-bottom: var(--nav-height); | |
| } | |
| #content-area::-webkit-scrollbar { display: none; } | |
| /* Video Item Styling */ | |
| .video-item { | |
| display: flex; | |
| padding: 8px; | |
| border-bottom: 1px solid #1a1a1a; | |
| height: 70px; | |
| align-items: center; | |
| transition: all 0.2s ease; | |
| opacity: 0; | |
| transform: translateY(10px); | |
| } | |
| .video-item.in-view { opacity: 1; transform: translateY(0); } | |
| .video-item.selected { background: #1a1a1a; border-left: 4px solid var(--r1-orange); } | |
| .thumbnail { width: 80px; height: 45px; background: #333; margin-right: 8px; border-radius: 4px; object-fit: cover; } | |
| .video-title { font-size: 11px; line-height: 1.2; height: 2.4em; overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; } | |
| /* Shorts Feed Styling - Optimized for Single Video */ | |
| #shorts-feed { | |
| display: none; | |
| height: 100%; | |
| overflow-y: scroll; | |
| scroll-snap-type: y mandatory; | |
| scrollbar-width: none; | |
| } | |
| #shorts-feed::-webkit-scrollbar { display: none; } | |
| .short-container { | |
| height: calc(287px - 40px - var(--nav-height)); | |
| width: 240px; | |
| scroll-snap-align: start; | |
| position: relative; | |
| background: #000; | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| } | |
| .short-placeholder { | |
| width: 100%; | |
| height: 100%; | |
| background: #000; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| color: #333; | |
| font-size: 10px; | |
| } | |
| .short-video-active { | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| object-fit: cover; | |
| z-index: 2; | |
| } | |
| .short-info { | |
| position: absolute; | |
| bottom: 10px; | |
| left: 10px; | |
| right: 10px; | |
| text-shadow: 0 1px 4px rgba(0,0,0,0.8); | |
| pointer-events: none; | |
| z-index: 5; | |
| background: linear-gradient(transparent, rgba(0,0,0,0.7)); | |
| padding: 5px; | |
| border-radius: 0 0 5px 5px; | |
| } | |
| .short-title { font-size: 11px; font-weight: bold; margin-bottom: 2px; color: white; } | |
| .short-channel { font-size: 9px; color: var(--r1-orange); } | |
| /* Navigation Bar */ | |
| #nav-bar { | |
| position: fixed; | |
| bottom: 0; | |
| left: 0; | |
| width: 240px; | |
| height: var(--nav-height); | |
| background: #000; | |
| display: flex; | |
| border-top: 1px solid #222; | |
| z-index: 50; | |
| } | |
| .nav-item { | |
| flex: 1; | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| justify-content: center; | |
| font-size: 9px; | |
| color: #666; | |
| cursor: pointer; | |
| } | |
| .nav-item.active { color: var(--r1-orange); } | |
| .nav-icon { font-size: 14px; margin-bottom: 1px; } | |
| /* Overlays */ | |
| #player-overlay, #search-overlay { | |
| position: fixed; top: 0; left: 0; width: 240px; height: 287px; | |
| background: #000; display: none; z-index: 100; | |
| flex-direction: column; transform: translateY(100%); | |
| transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1); | |
| } | |
| #player-overlay.active, #search-overlay.active { display: flex; transform: translateY(0); } | |
| #video-container { width: 240px; height: 135px; background: #000; position: relative; } | |
| #back-btn { | |
| position: absolute; top: 8px; left: 8px; background: var(--r1-orange); | |
| color: white; border: none; padding: 4px 8px; border-radius: 4px; | |
| font-size: 10px; z-index: 110; cursor: pointer; | |
| } | |
| #video-details { padding: 8px 10px; flex-grow: 1; overflow-y: auto; font-size: 11px; background: #080808; } | |
| </style> | |
| </head> | |
| <body> | |
| <div id="startup-screen"> | |
| <div id="yt-loader-wrapper"> | |
| <div id="yt-track"><div id="yt-progress"></div></div> | |
| <div id="yt-logo-final"> | |
| <div class="r1-play-icon"></div> | |
| R1<span>TUBE</span> | |
| </div> | |
| </div> | |
| </div> | |
| <div id="header"> | |
| <div id="logo"> | |
| <div class="r1-play-icon"></div> | |
| R1<span>TUBE</span> | |
| </div> | |
| <button id="search-btn" onclick="openSearch()">🔍</button> | |
| </div> | |
| <div id="content-area"> | |
| <div id="video-list"></div> | |
| <div id="shorts-feed"></div> | |
| </div> | |
| <div id="nav-bar"> | |
| <div class="nav-item active" onclick="switchTab('home')"> | |
| <div class="nav-icon">🏠</div> | |
| Home | |
| </div> | |
| <div class="nav-item" onclick="switchTab('shorts')"> | |
| <div class="nav-icon">📱</div> | |
| Shorts | |
| </div> | |
| </div> | |
| <!-- Search Overlay --> | |
| <div id="search-overlay"> | |
| <div style="padding: 20px;"> | |
| <div style="margin-bottom: 10px; font-weight: bold; color: var(--r1-orange);">SEARCH</div> | |
| <input type="text" id="search-input" style="width:100%; background:#222; border:1px solid var(--r1-orange); color:white; padding:10px; border-radius:6px;" placeholder="Search YouTube..."> | |
| <div style="font-size: 10px; color: #666; margin-top: 10px;">Side Button to close.</div> | |
| </div> | |
| </div> | |
| <!-- Player Overlay --> | |
| <div id="player-overlay"> | |
| <div id="video-container"> | |
| <button id="back-btn" onclick="closePlayer()">BACK</button> | |
| </div> | |
| <div id="video-details"> | |
| <div id="det-title" style="font-weight:bold; color:white; margin-bottom:4px;"></div> | |
| <div id="det-likes" style="color:var(--r1-orange); font-size:10px; margin-bottom:8px;"></div> | |
| <div id="det-desc" style="color:#aaa; line-height:1.4;"></div> | |
| </div> | |
| </div> | |
| <script> | |
| const API_KEY = "AIzaSyBzB8j2OwAR6-PaIqWIijmZEdkw8gmFznQ"; | |
| let videos = []; | |
| let shorts = []; | |
| let currentIndex = 0; | |
| let currentShortIndex = -1; | |
| let currentTab = 'home'; | |
| let isPlayerOpen = false; | |
| let isSearchOpen = false; | |
| let nextShortsToken = ""; | |
| function initStartup() { | |
| const progress = document.getElementById('yt-progress'); | |
| const track = document.getElementById('yt-track'); | |
| const logo = document.getElementById('yt-logo-final'); | |
| const screen = document.getElementById('startup-screen'); | |
| setTimeout(() => { progress.style.width = '100%'; }, 100); | |
| setTimeout(() => { | |
| track.style.opacity = '0'; | |
| logo.style.opacity = '1'; | |
| logo.style.transform = 'scale(1)'; | |
| setTimeout(() => { | |
| screen.style.opacity = '0'; | |
| loadContent(); | |
| setTimeout(() => { screen.style.display = 'none'; }, 500); | |
| }, 1000); | |
| }, 1900); | |
| } | |
| async function loadContent() { | |
| searchVideos(); | |
| loadShorts(); | |
| } | |
| async function searchVideos(query = "popular now") { | |
| try { | |
| const ytResponse = await fetch(`https://www.googleapis.com/youtube/v3/search?part=snippet&maxResults=15&q=${encodeURIComponent(query)}&type=video&key=${API_KEY}`); | |
| const data = await ytResponse.json(); | |
| if (data.items) { | |
| videos = data.items.filter(v => v.id.videoId); | |
| renderHome(); | |
| } | |
| } catch (e) { console.error(e); } | |
| } | |
| async function loadShorts() { | |
| try { | |
| const response = await fetch(`https://www.googleapis.com/youtube/v3/search?part=snippet&maxResults=10&q=shorts&type=video&videoDuration=short&pageToken=${nextShortsToken}&key=${API_KEY}`); | |
| const data = await response.json(); | |
| if (data.items) { | |
| nextShortsToken = data.nextPageToken || ""; | |
| const newShorts = data.items.filter(v => v.id.videoId); | |
| shorts = [...shorts, ...newShorts]; | |
| renderShorts(); | |
| // Auto-load the first short if we are in the tab and nothing is playing | |
| if (currentTab === 'shorts' && currentShortIndex === -1) { | |
| updateActiveShort(0); | |
| } | |
| } | |
| } catch (e) { console.error(e); } | |
| } | |
| function renderHome() { | |
| const list = document.getElementById('video-list'); | |
| list.innerHTML = ''; | |
| videos.forEach((vid, index) => { | |
| const item = document.createElement('div'); | |
| item.className = `video-item ${index === currentIndex && currentTab === 'home' ? 'selected' : ''}`; | |
| item.id = `video-item-${index}`; | |
| item.innerHTML = ` | |
| <img class="thumbnail" src="${vid.snippet.thumbnails.default.url}"> | |
| <div class="video-info"><div class="video-title">${vid.snippet.title}</div></div> | |
| `; | |
| item.onclick = () => { currentIndex = index; openPlayer(vid); }; | |
| list.appendChild(item); | |
| setTimeout(() => item.classList.add('in-view'), 50); | |
| }); | |
| } | |
| function renderShorts() { | |
| const feed = document.getElementById('shorts-feed'); | |
| const currentContainers = feed.querySelectorAll('.short-container').length; | |
| shorts.slice(currentContainers).forEach((short, index) => { | |
| const globalIndex = currentContainers + index; | |
| const container = document.createElement('div'); | |
| container.className = 'short-container'; | |
| container.id = `short-container-${globalIndex}`; | |
| container.innerHTML = ` | |
| <div class="short-placeholder">Loading...</div> | |
| <div class="short-info"> | |
| <div class="short-title">${short.snippet.title}</div> | |
| <div class="short-channel">@${short.snippet.channelTitle}</div> | |
| </div> | |
| `; | |
| feed.appendChild(container); | |
| }); | |
| } | |
| function updateActiveShort(index) { | |
| if (index === currentShortIndex || index < 0 || index >= shorts.length) return; | |
| // Remove previous iframe | |
| const oldIframe = document.querySelector('.short-video-active'); | |
| if (oldIframe) oldIframe.remove(); | |
| currentShortIndex = index; | |
| const container = document.getElementById(`short-container-${index}`); | |
| if (!container) return; | |
| const videoId = shorts[index].id.videoId; | |
| const iframe = document.createElement('iframe'); | |
| iframe.className = 'short-video-active'; | |
| iframe.src = `https://www.youtube.com/embed/${videoId}?loop=1&playlist=${videoId}&autoplay=1&controls=0&modestbranding=1&rel=0`; | |
| iframe.frameBorder = "0"; | |
| iframe.allow = "autoplay; encrypted-media"; | |
| container.appendChild(iframe); | |
| } | |
| function switchTab(tab) { | |
| currentTab = tab; | |
| document.querySelectorAll('.nav-item').forEach(el => el.classList.remove('active')); | |
| document.getElementById('video-list').style.display = tab === 'home' ? 'block' : 'none'; | |
| document.getElementById('shorts-feed').style.display = tab === 'shorts' ? 'block' : 'none'; | |
| if (tab === 'home') { | |
| document.querySelectorAll('.nav-item')[0].classList.add('active'); | |
| // Stop any playing shorts when leaving tab | |
| const oldIframe = document.querySelector('.short-video-active'); | |
| if (oldIframe) oldIframe.remove(); | |
| currentShortIndex = -1; | |
| renderHome(); | |
| } else { | |
| document.querySelectorAll('.nav-item')[1].classList.add('active'); | |
| updateActiveShort(0); | |
| } | |
| } | |
| // Detect current short via scroll position | |
| document.getElementById('shorts-feed').addEventListener('scroll', (e) => { | |
| const el = e.target; | |
| const height = el.clientHeight; | |
| const newIndex = Math.round(el.scrollTop / height); | |
| if (newIndex !== currentShortIndex) { | |
| updateActiveShort(newIndex); | |
| } | |
| if (el.scrollHeight - el.scrollTop <= el.clientHeight + 100) { | |
| loadShorts(); | |
| } | |
| }); | |
| function openSearch() { | |
| isSearchOpen = true; | |
| const overlay = document.getElementById('search-overlay'); | |
| overlay.style.display = 'flex'; | |
| setTimeout(() => overlay.classList.add('active'), 10); | |
| document.getElementById('search-input').focus(); | |
| } | |
| function closeSearch() { | |
| document.getElementById('search-overlay').classList.remove('active'); | |
| setTimeout(() => { document.getElementById('search-overlay').style.display = 'none'; isSearchOpen = false; }, 300); | |
| } | |
| document.getElementById('search-input').addEventListener('keydown', (e) => { | |
| if (e.key === 'Enter') { | |
| searchVideos(e.target.value); | |
| closeSearch(); | |
| switchTab('home'); | |
| } | |
| }); | |
| function openPlayer(video) { | |
| isPlayerOpen = true; | |
| const overlay = document.getElementById('player-overlay'); | |
| overlay.style.display = 'flex'; | |
| setTimeout(() => overlay.classList.add('active'), 10); | |
| document.getElementById('det-title').innerText = video.snippet.title; | |
| const container = document.getElementById('video-container'); | |
| const old = container.querySelector('iframe'); if (old) old.remove(); | |
| const iframe = document.createElement('iframe'); | |
| iframe.width = "240"; iframe.height = "135"; | |
| iframe.src = `https://www.youtube.com/embed/${video.id.videoId}?autoplay=1`; | |
| iframe.frameBorder = "0"; iframe.allow = "autoplay; encrypted-media"; | |
| container.appendChild(iframe); | |
| } | |
| function closePlayer() { | |
| document.getElementById('player-overlay').classList.remove('active'); | |
| setTimeout(() => { | |
| document.getElementById('player-overlay').style.display = 'none'; | |
| const f = document.getElementById('video-container').querySelector('iframe'); | |
| if (f) f.remove(); | |
| isPlayerOpen = false; | |
| }, 300); | |
| } | |
| // Hardware Controls | |
| window.addEventListener("scrollUp", () => { | |
| if (currentTab === 'home' && !isPlayerOpen && !isSearchOpen) { | |
| if (currentIndex > 0) { currentIndex--; renderHome(); } | |
| } else if (currentTab === 'shorts') { | |
| document.getElementById('shorts-feed').scrollBy({ top: -212, behavior: 'smooth' }); | |
| } | |
| }); | |
| window.addEventListener("scrollDown", () => { | |
| if (currentTab === 'home' && !isPlayerOpen && !isSearchOpen) { | |
| if (currentIndex < videos.length - 1) { currentIndex++; renderHome(); } | |
| } else if (currentTab === 'shorts') { | |
| document.getElementById('shorts-feed').scrollBy({ top: 212, behavior: 'smooth' }); | |
| } | |
| }); | |
| window.addEventListener("sideClick", () => { | |
| if (isSearchOpen) closeSearch(); | |
| else if (isPlayerOpen) closePlayer(); | |
| else if (currentTab === 'home') openPlayer(videos[currentIndex]); | |
| }); | |
| window.onload = initStartup; | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment