anycoder-40b8531a / index.html
Abhi1907's picture
Upload folder using huggingface_hub
a9f28e6 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>NeuroFrame | Pro Text-to-Video AI</title>
<!-- Importing FontAwesome for Icons -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
/* --- CSS VARIABLES & RESET --- */
:root {
--bg-dark: #0f1115;
--bg-panel: #161b22;
--bg-input: #0d1117;
--primary: #6366f1; /* Indigo */
--primary-hover: #4f46e5;
--accent: #ec4899; /* Pink */
--text-main: #f0f6fc;
--text-muted: #8b949e;
--border: #30363d;
--radius-sm: 6px;
--radius-md: 12px;
--radius-lg: 20px;
--shadow: 0 4px 20px rgba(0, 0, 0, 0.5);
--font-family: 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
--transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
outline: none;
}
body {
font-family: var(--font-family);
background-color: var(--bg-dark);
color: var(--text-main);
height: 100vh;
display: flex;
flex-direction: column;
overflow: hidden;
}
/* --- SCROLLBAR --- */
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-track {
background: var(--bg-dark);
}
::-webkit-scrollbar-thumb {
background: var(--border);
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: var(--text-muted);
}
/* --- HEADER --- */
header {
height: 60px;
background-color: var(--bg-panel);
border-bottom: 1px solid var(--border);
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 20px;
z-index: 10;
}
.brand {
display: flex;
align-items: center;
gap: 12px;
font-size: 1.25rem;
font-weight: 700;
background: linear-gradient(135deg, var(--text-main), var(--primary));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.brand i {
font-size: 1.4rem;
color: var(--primary);
-webkit-text-fill-color: initial;
}
.header-actions {
display: flex;
align-items: center;
gap: 15px;
}
.api-status {
font-size: 0.85rem;
display: flex;
align-items: center;
gap: 6px;
padding: 6px 12px;
background: rgba(99, 102, 241, 0.1);
border: 1px solid rgba(99, 102, 241, 0.3);
border-radius: var(--radius-sm);
color: var(--primary);
}
.status-dot {
width: 8px;
height: 8px;
background-color: var(--primary);
border-radius: 50%;
box-shadow: 0 0 8px var(--primary);
animation: pulse 2s infinite;
}
@keyframes pulse {
0% { opacity: 1; transform: scale(1); }
50% { opacity: 0.5; transform: scale(0.8); }
100% { opacity: 1; transform: scale(1); }
}
.built-with {
font-size: 0.85rem;
color: var(--text-muted);
text-decoration: none;
transition: var(--transition);
}
.built-with:hover {
color: var(--text-main);
}
/* --- MAIN LAYOUT --- */
.app-container {
display: flex;
flex: 1;
overflow: hidden;
}
/* --- SIDEBAR (History) --- */
aside {
width: 280px;
background-color: var(--bg-panel);
border-right: 1px solid var(--border);
display: flex;
flex-direction: column;
transition: transform 0.3s ease;
}
.sidebar-header {
padding: 20px;
font-size: 0.9rem;
font-weight: 600;
color: var(--text-muted);
text-transform: uppercase;
letter-spacing: 1px;
border-bottom: 1px solid var(--border);
}
.history-list {
flex: 1;
overflow-y: auto;
padding: 10px;
}
.history-item {
display: flex;
flex-direction: column;
gap: 8px;
padding: 12px;
border-radius: var(--radius-sm);
cursor: pointer;
transition: var(--transition);
border: 1px solid transparent;
margin-bottom: 8px;
}
.history-item:hover {
background-color: rgba(255, 255, 255, 0.05);
border-color: rgba(255, 255, 255, 0.1);
}
.history-item.active {
background-color: rgba(99, 102, 241, 0.15);
border-color: var(--primary);
}
.history-prompt {
font-size: 0.85rem;
color: var(--text-main);
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.history-meta {
font-size: 0.75rem;
color: var(--text-muted);
display: flex;
justify-content: space-between;
}
/* --- CONTENT AREA --- */
main {
flex: 1;
display: flex;
flex-direction: column;
overflow-y: auto;
position: relative;
}
/* --- VIDEO PLAYER AREA --- */
.preview-stage {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
padding: 40px;
background-image: radial-gradient(circle at center, #1c2128 0%, #0f1115 100%);
min-height: 400px;
position: relative;
}
.video-container {
width: 100%;
max-width: 900px;
aspect-ratio: 16/9;
background-color: #000;
border-radius: var(--radius-md);
box-shadow: 0 20px 50px rgba(0,0,0,0.6);
border: 1px solid var(--border);
overflow: hidden;
position: relative;
display: flex;
justify-content: center;
align-items: center;
}
video {
width: 100%;
height: 100%;
object-fit: cover;
display: none;
}
.placeholder-state {
text-align: center;
color: var(--text-muted);
}
.placeholder-icon {
font-size: 4rem;
margin-bottom: 20px;
opacity: 0.3;
}
/* --- CONTROLS AREA --- */
.controls-panel {
background-color: var(--bg-panel);
border-top: 1px solid var(--border);
padding: 30px;
display: grid;
grid-template-columns: 1fr 350px;
gap: 40px;
}
.input-group {
display: flex;
flex-direction: column;
gap: 20px;
}
.text-area-wrapper {
position: relative;
}
textarea {
width: 100%;
height: 120px;
background-color: var(--bg-input);
border: 1px solid var(--border);
border-radius: var(--radius-md);
padding: 15px;
color: var(--text-main);
font-family: var(--font-family);
font-size: 1rem;
resize: none;
transition: var(--transition);
line-height: 1.5;
}
textarea:focus {
border-color: var(--primary);
box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.2);
}
.settings-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 20px;
}
.control-item {
display: flex;
flex-direction: column;
gap: 8px;
}
label {
font-size: 0.85rem;
font-weight: 600;
color: var(--text-muted);
}
select, input[type="text"], input[type="number"] {
background-color: var(--bg-input);
border: 1px solid var(--border);
color: var(--text-main);
padding: 10px 12px;
border-radius: var(--radius-sm);
font-size: 0.9rem;
transition: var(--transition);
}
select:focus, input:focus {
border-color: var(--primary);
}
/* Range Slider */
input[type=range] {
-webkit-appearance: none;
width: 100%;
background: transparent;
}
input[type=range]::-webkit-slider-thumb {
-webkit-appearance: none;
height: 16px;
width: 16px;
border-radius: 50%;
background: var(--primary);
cursor: pointer;
margin-top: -6px;
box-shadow: 0 0 10px rgba(99, 102, 241, 0.5);
}
input[type=range]::-webkit-slider-runnable-track {
width: 100%;
height: 4px;
cursor: pointer;
background: var(--border);
border-radius: 2px;
}
/* Generate Button */
.btn-generate {
background: linear-gradient(135deg, var(--primary), var(--accent));
color: white;
border: none;
border-radius: var(--radius-sm);
padding: 16px 32px;
font-size: 1rem;
font-weight: 700;
cursor: pointer;
transition: var(--transition);
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
box-shadow: 0 4px 15px rgba(99, 102, 241, 0.4);
margin-top: 10px;
}
.btn-generate:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(236, 72, 153, 0.4);
}
.btn-generate:disabled {
opacity: 0.7;
cursor: not-allowed;
transform: none;
}
/* Progress Section */
.progress-section {
background: rgba(0,0,0,0.2);
padding: 20px;
border-radius: var(--radius-md);
display: none; /* Hidden by default */
flex-direction: column;
gap: 15px;
}
.progress-section.active {
display: flex;
}
.progress-bar-container {
height: 6px;
background-color: var(--border);
border-radius: 3px;
overflow: hidden;
}
.progress-bar {
height: 100%;
width: 0%;
background: linear-gradient(90deg, var(--primary), var(--accent));
transition: width 0.3s ease;
}
.progress-text {
font-size: 0.85rem;
color: var(--text-muted);
display: flex;
justify-content: space-between;
}
/* Toast Notification */
.toast {
position: fixed;
bottom: 30px;
right: 30px;
background-color: var(--bg-panel);
border: 1px solid var(--border);
border-left: 4px solid var(--primary);
padding: 15px 25px;
border-radius: var(--radius-sm);
box-shadow: var(--shadow);
transform: translateY(100px);
opacity: 0;
transition: var(--transition);
z-index: 100;
display: flex;
align-items: center;
gap: 12px;
}
.toast.show {
transform: translateY(0);
opacity: 1;
}
/* --- RESPONSIVE DESIGN --- */
@media (max-width: 900px) {
.controls-panel {
grid-template-columns: 1fr;
gap: 20px;
}
aside {
position: absolute;
left: -280px;
height: calc(100vh - 60px);
z-index: 20;
}
aside.open {
transform: translateX(280px);
}
.mobile-menu-btn {
display: block !important;
}
}
.mobile-menu-btn {
display: none;
background: none;
border: none;
color: var(--text-main);
font-size: 1.2rem;
cursor: pointer;
}
</style>
</head>
<body>
<!-- Header -->
<header>
<div class="brand">
<button class="mobile-menu-btn" id="menuToggle"><i class="fas fa-bars"></i></button>
<i class="fas fa-film"></i>
NeuroFrame
</div>
<div class="header-actions">
<div class="api-status">
<div class="status-dot"></div>
API Connected
</div>
<a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="built-with">
Built with anycoder
</a>
<div class="user-avatar">
<i class="fas fa-user-circle fa-lg"></i>
</div>
</div>
</header>
<div class="app-container">
<!-- Sidebar: History -->
<aside id="sidebar">
<div class="sidebar-header">
Recent Generations
</div>
<div class="history-list" id="historyList">
<!-- History items will be injected here via JS -->
<div class="history-item active">
<div class="history-prompt">Cyberpunk city street at night, neon rain...</div>
<div class="history-meta">
<span>16:9</span>
<span>2m ago</span>
</div>
</div>
</div>
</aside>
<!-- Main Content -->
<main>
<!-- Preview Stage -->
<div class="preview-stage">
<div class="video-container" id="videoContainer">
<div class="placeholder-state" id="placeholderState">
<i class="fas fa-play-circle placeholder-icon"></i>
<h3>Ready to Create</h3>
<p>Enter a prompt and configure settings to generate video.</p>
</div>
<!-- Video Element -->
<video id="mainVideo" controls loop playsinline>
<source src="" type="video/mp4">
Your browser does not support the video tag.
</video>
<!-- Loading Overlay -->
<div id="loadingOverlay" style="display: none; position: absolute; inset: 0; background: rgba(0,0,0,0.8); flex-direction: column; justify-content: center; align-items: center; z-index: 5;">
<i class="fas fa-circle-notch fa-spin fa-3x" style="color: var(--primary); margin-bottom: 15px;"></i>
<h3 style="margin-bottom: 5px;">Generating Frames...</h3>
<p id="loadingText" style="color: var(--text-muted); font-size: 0.9rem;">Initializing diffusion model</p>
</div>
</div>
</div>
<!-- Controls Panel -->
<div class="controls-panel">
<!-- Left Column: Inputs -->
<div class="input-group">
<div class="text-area-wrapper">
<textarea id="promptInput" placeholder="Describe your video in detail (e.g., A cinematic drone shot of a futuristic mountain fortress during golden hour, 8k resolution)..."></textarea>
</div>
<div class="settings-grid">
<div class="control-item">
<label>Aspect Ratio</label>
<select id="aspectRatio">
<option value="16:9">16:9 (Landscape)</option>
<option value="9:16">9:16 (Portrait)</option>
<option value="1:1">1:1 (Square)</option>
<option value="2.35:1">2.35:1 (Cinematic)</option>
</select>
</div>
<div class="control-item">
<label>Motion Strength</label>
<input type="range" min="1" max="10" value="5" id="motionStrength">
</div>
<div class="control-item">
<label>Duration (Seconds)</label>
<select id="duration">
<option value="4">4s</option>
<option value="8" selected>8s</option>
<option value="16">16s</option>
</select>
</div>
<div class="control-item">
<label>Style Preset</label>
<select id="stylePreset">
<option value="realistic">Photorealistic</option>
<option value="anime">Anime / 2D</option>
<option value="3d-render">3D Render</option>
<option value="oil-painting">Oil Painting</option>
</select>
</div>
</div>
</div>
<!-- Right Column: Action & Status -->
<div class="action-group">
<div class="control-item" style="margin-bottom: 20px;">
<label>Negative Prompt (Optional)</label>
<input type="text" id="negativePrompt" placeholder="blur, distortion, low quality">
</div>
<div class="progress-section" id="progressSection">
<div class="progress-text">
<span id="progressStatus">Processing</span>
<span id="progressPercent">0%</span>
</div>
<div class="progress-bar-container">
<div class="progress-bar" id="progressBar"></div>
</div>
</div>
<button class="btn-generate" id="generateBtn">
<i class="fas fa-wand-magic-sparkles"></i>
Generate Video
</button>
<div style="margin-top: 15px; font-size: 0.8rem; color: var(--text-muted); text-align: center;">
Est. cost: ~0.05 credits
</div>
</div>
</div>
</main>
</div>
<!-- Toast Notification -->
<div class="toast" id="toast">
<i class="fas fa-check-circle" style="color: var(--primary);"></i>
<span id="toastMessage">Video generated successfully!</span>
</div>
<script>
// --- DOM Elements ---
const generateBtn = document.getElementById('generateBtn');
const promptInput = document.getElementById('promptInput');
const videoContainer = document.getElementById('videoContainer');
const mainVideo = document.getElementById('mainVideo');
const placeholderState = document.getElementById('placeholderState');
const loadingOverlay = document.getElementById('loadingOverlay');
const loadingText = document.getElementById('loadingText');
const progressSection = document.getElementById('progressSection');
const progressBar = document.getElementById('progressBar');
const progressPercent = document.getElementById('progressPercent');
const progressStatus = document.getElementById('progressStatus');
const historyList = document.getElementById('historyList');
const toast = document.getElementById('toast');
const menuToggle = document.getElementById('menuToggle');
const sidebar = document.getElementById('sidebar');
// --- State ---
let isGenerating = false;
// --- Sample Videos for Simulation ---
// Using reliable, copyright-free stock video URLs for demonstration
const sampleVideos = [
"https://videos.pexels.com/video-files/3129671/3129671-uhd_2560_1440_30fps.mp4", // Cyberpunk/Neon
"https://videos.pexels.com/video-files/856973/856973-hd_1920_1080_30fps.mp4", // Nature/Timelapse
"https://videos.pexels.com/video-files/2759484/2759484-hd_1920_1080_25fps.mp4", // Abstract/Tech
"https://videos.pexels.com/video-files/3121459/3121459-hd_1920_1080_25fps.mp4" // City/Night
];
// --- Event Listeners ---
menuToggle.addEventListener('click', () => {
sidebar.classList.toggle('open');
});
generateBtn.addEventListener('click', startGeneration);
// --- Functions ---
function startGeneration() {
const prompt = promptInput.value.trim();
if (!prompt) {
showToast("Please enter a text prompt first.", "error");
promptInput.focus();
return;
}
if (isGenerating) return;
// Start UI State
isGenerating = true;
generateBtn.disabled = true;
generateBtn.innerHTML = '<i class="fas fa-circle-notch fa-spin"></i> Generating...';
// Hide video, show loading
mainVideo.style.display = 'none';
mainVideo.pause();
placeholderState.style.display = 'none';
loadingOverlay.style.display = 'flex';
progressSection.classList.add('active');
// Reset Progress
progressBar.style.width = '0%';
progressPercent.innerText = '0%';
// Simulation Logic
let progress = 0;
const statusMessages = [
"Initializing diffusion model...",
"Analyzing text prompt semantics...",
"Generating initial noise latents...",
"Denoising frames (Step 10/50)...",
"Denoising frames (Step 30/50)...",
"Upscaling resolution...",
"Rendering final video stream..."
];
const interval = setInterval(() => {
progress += Math.random() * 15; // Random increment
if (progress > 100) progress = 100;
// Update UI
progressBar.style.width = `${progress}%`;
progressPercent.innerText = `${Math.floor(progress)}%`;
// Update text based on progress
const msgIndex = Math.min(Math.floor((progress / 100) * statusMessages.length), statusMessages.length - 1);
loadingText.innerText = statusMessages[msgIndex];
progressStatus.innerText = statusMessages[msgIndex];
if (progress >= 100) {
clearInterval(interval);
finishGeneration(prompt);
}
}, 800);
}
function finishGeneration(prompt) {
// Simulate a brief delay at 100%
setTimeout(() => {
// Select a random video from samples
const randomVideo = sampleVideos[Math.floor(Math.random() * sampleVideos.length)];
// Update Video Player
mainVideo.src = randomVideo;
mainVideo.style.display = 'block';
loadingOverlay.style.display = 'none';
// Auto play
mainVideo.play().catch(e => console.log("Auto-play prevented by browser policy"));
// Reset Button
isGenerating = false;
generateBtn.disabled = false;
generateBtn.innerHTML = '<i class="fas fa-wand-magic-sparkles"></i> Generate Video';
progressSection.classList.remove('active');
// Add to History
addToHistory(prompt);
// Show Success Message
showToast("Video generated successfully!");
}, 1000);
}
function addToHistory(prompt) {
const item = document.createElement('div');
item.className = 'history-item';
// Truncate prompt if too long
const displayPrompt = prompt.length > 60 ? prompt.substring(0, 60) + "..." : prompt;
item.innerHTML = `
<div class="history-prompt">${displayPrompt}</div>
<div class="history-meta">
<span>${document.getElementById('aspectRatio').value}</span>
<span>Just now</span>
</div>
`;
// Add click event to load this "history" (simulation)
item.addEventListener('click', () => {
document.querySelectorAll('.history-item').forEach(i => i.classList.remove('active'));
item.classList.add('active');
promptInput.value = prompt;
// In a real app, this would reload the specific video blob
mainVideo.currentTime = 0;
mainVideo.play();
});
// Insert at top
historyList.insertBefore(item, historyList.firstChild);
// Remove 'active' from others
document.querySelectorAll('.history-item').forEach(i => i.classList.remove('active'));
item.classList.add('active');
}
function showToast(message, type = "success") {
const toastMsg = document.getElementById('toastMessage');
toastMsg.innerText = message;
// Simple styling change for error vs success
if(type === 'error') {
toast.style.borderLeftColor = '#ef4444';
toast.querySelector('i').className = 'fas fa-exclamation-circle';
toast.querySelector('i').style.color = '#ef4444';
} else {
toast.style.borderLeftColor = 'var(--primary)';
toast.querySelector('i').className = 'fas fa-check-circle';
toast.querySelector('i').style.color = 'var(--primary)';
}
toast.classList.add('show');
setTimeout(() => {
toast.classList.remove('show');
}, 3000);
}
// Initialize with a prompt placeholder animation logic
promptInput.addEventListener('focus', () => {
promptInput.parentElement.style.boxShadow = "0 0 0 3px rgba(99, 102, 241, 0.1)";
});
promptInput.addEventListener('blur', () => {
promptInput.parentElement.style.boxShadow = "none";
});
</script>
</body>
</html>