Skip to content

Instantly share code, notes, and snippets.

@wwtv127
Created December 30, 2025 01:45
Show Gist options
  • Select an option

  • Save wwtv127/cca402f04e382cdd4099d4b3bac2f8bc to your computer and use it in GitHub Desktop.

Select an option

Save wwtv127/cca402f04e382cdd4099d4b3bac2f8bc to your computer and use it in GitHub Desktop.
R1 Artifact: My Project
<!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; /* Fixed height for consistent calculation */
align-items: center;
transition: opacity 0.2s ease, background 0.1s 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 */
#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;
flex-direction: column;
justify-content: center;
align-items: center;
overflow: hidden;
}
.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: 0;
left: 0;
right: 0;
text-shadow: 0 1px 4px rgba(0,0,0,1);
pointer-events: none;
z-index: 5;
background: linear-gradient(transparent, rgba(0,0,0,0.95));
padding: 12px 10px 8px 10px;
display: flex;
flex-direction: column;
justify-content: flex-end;
}
.short-title {
font-size: 11px;
font-weight: bold;
margin-bottom: 2px;
color: white;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.short-channel { font-size: 9px; color: var(--r1-orange); font-weight: 600; }
/* 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 = "";
let shortsScrollTimeout = null;
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();
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 ? '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 = () => { selectVideo(index); openPlayer(vid); };
list.appendChild(item);
setTimeout(() => item.classList.add('in-view'), 50);
});
}
function selectVideo(index) {
const listItems = document.querySelectorAll('.video-item');
listItems.forEach(item => item.classList.remove('selected'));
currentIndex = index;
const current = document.getElementById(`video-item-${index}`);
if (current) {
current.classList.add('selected');
// Manual Scroll Logic for Perfect Smoothness
const container = document.getElementById('content-area');
const itemHeight = 70; // Matching CSS
const targetScroll = index * itemHeight;
container.scrollTo({
top: targetScroll,
behavior: 'smooth'
});
}
}
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;
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&iv_load_policy=3`;
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');
const oldIframe = document.querySelector('.short-video-active');
if (oldIframe) oldIframe.remove();
currentShortIndex = -1;
selectVideo(currentIndex);
} else {
document.querySelectorAll('.nav-item')[1].classList.add('active');
updateActiveShort(0);
}
}
// Fixed Shorts Scroll Logic
document.getElementById('shorts-feed').addEventListener('scroll', (e) => {
if (shortsScrollTimeout) clearTimeout(shortsScrollTimeout);
// Only update when scrolling stops to prevent jitter
shortsScrollTimeout = setTimeout(() => {
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();
}
}, 150); // Small debounce window
});
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');
}
});
async 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;
document.getElementById('det-likes').innerText = "Loading stats...";
document.getElementById('det-desc').innerText = video.snippet.description || "No description available.";
try {
const statsResponse = await fetch(`https://www.googleapis.com/youtube/v3/videos?part=statistics&id=${video.id.videoId}&key=${API_KEY}`);
const statsData = await statsResponse.json();
if (statsData.items && statsData.items[0]) {
const likes = parseInt(statsData.items[0].statistics.likeCount).toLocaleString();
const views = parseInt(statsData.items[0].statistics.viewCount).toLocaleString();
document.getElementById('det-likes').innerText = `👍 ${likes} Likes • 👁️ ${views} Views`;
}
} catch (e) {
document.getElementById('det-likes').innerText = "Stats unavailable";
}
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) selectVideo(currentIndex - 1);
} 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) selectVideo(currentIndex + 1);
} 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' && videos[currentIndex]) 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