Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Z-Image Turbo | Transform Ideas into Visuals</title> | |
| <!-- Google Fonts --> | |
| <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=Outfit:wght@300;400;600;700&family=Space+Grotesk:wght@300;500;700&display=swap" rel="stylesheet"> | |
| <!-- FontAwesome Icons --> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <style> | |
| /* | |
| * Z-Image Turbo - Modern CSS Styling | |
| * Using CSS Variables for theming and Flexbox/Grid for layout | |
| */ | |
| :root { | |
| --bg-dark: #0b0c15; | |
| --bg-panel: rgba(255, 255, 255, 0.03); | |
| --bg-panel-hover: rgba(255, 255, 255, 0.07); | |
| --primary: #6c5ce7; | |
| --primary-glow: rgba(108, 92, 231, 0.5); | |
| --accent: #00cec9; | |
| --text-main: #ffffff; | |
| --text-muted: #a0a0b0; | |
| --border: rgba(255, 255, 255, 0.1); | |
| --radius-lg: 24px; | |
| --radius-md: 16px; | |
| --radius-sm: 8px; | |
| --font-main: 'Outfit', sans-serif; | |
| --font-display: 'Space Grotesk', sans-serif; | |
| } | |
| * { | |
| box-sizing: border-box; | |
| margin: 0; | |
| padding: 0; | |
| outline: none; | |
| } | |
| body { | |
| background-color: var(--bg-dark); | |
| background-image: | |
| radial-gradient(circle at 10% 20%, rgba(108, 92, 231, 0.15) 0%, transparent 40%), | |
| radial-gradient(circle at 90% 80%, rgba(0, 206, 201, 0.15) 0%, transparent 40%); | |
| color: var(--text-main); | |
| font-family: var(--font-main); | |
| min-height: 100vh; | |
| display: flex; | |
| flex-direction: column; | |
| overflow-x: hidden; | |
| } | |
| /* --- Header --- */ | |
| header { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| padding: 20px 5%; | |
| border-bottom: 1px solid var(--border); | |
| backdrop-filter: blur(10px); | |
| position: sticky; | |
| top: 0; | |
| z-index: 100; | |
| background: rgba(11, 12, 21, 0.8); | |
| } | |
| .logo { | |
| font-family: var(--font-display); | |
| font-size: 1.5rem; | |
| font-weight: 700; | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| text-transform: uppercase; | |
| letter-spacing: 1px; | |
| background: linear-gradient(90deg, #fff, var(--accent)); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| } | |
| .built-with { | |
| color: var(--text-muted); | |
| font-size: 0.85rem; | |
| text-decoration: none; | |
| display: flex; | |
| align-items: center; | |
| gap: 5px; | |
| transition: color 0.3s; | |
| } | |
| .built-with:hover { | |
| color: var(--accent); | |
| } | |
| /* --- Main Layout --- */ | |
| main { | |
| flex: 1; | |
| display: grid; | |
| grid-template-columns: 1fr 1.5fr; | |
| gap: 30px; | |
| padding: 40px 5%; | |
| max-width: 1600px; | |
| width: 100%; | |
| margin: 0 auto; | |
| } | |
| @media (max-width: 900px) { | |
| main { | |
| grid-template-columns: 1fr; | |
| } | |
| } | |
| /* --- Control Panel (Left) --- */ | |
| .controls-panel { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 24px; | |
| height: fit-content; | |
| } | |
| .input-group { | |
| background: var(--bg-panel); | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius-lg); | |
| padding: 20px; | |
| position: relative; | |
| transition: all 0.3s ease; | |
| } | |
| .input-group:focus-within { | |
| border-color: var(--primary); | |
| box-shadow: 0 0 20px rgba(108, 92, 231, 0.2); | |
| background: var(--bg-panel-hover); | |
| } | |
| label { | |
| display: block; | |
| font-size: 0.85rem; | |
| color: var(--accent); | |
| margin-bottom: 10px; | |
| font-weight: 600; | |
| text-transform: uppercase; | |
| letter-spacing: 0.5px; | |
| } | |
| textarea { | |
| width: 100%; | |
| background: transparent; | |
| border: none; | |
| color: var(--text-main); | |
| font-family: var(--font-main); | |
| font-size: 1.1rem; | |
| resize: none; | |
| height: 120px; | |
| line-height: 1.6; | |
| } | |
| textarea::placeholder { | |
| color: rgba(255, 255, 255, 0.3); | |
| } | |
| /* Aspect Ratio Selector */ | |
| .aspect-ratio { | |
| display: flex; | |
| gap: 10px; | |
| margin-top: 10px; | |
| } | |
| .ratio-btn { | |
| background: rgba(255, 255, 255, 0.05); | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius-sm); | |
| padding: 8px 12px; | |
| color: var(--text-muted); | |
| cursor: pointer; | |
| font-size: 0.8rem; | |
| transition: all 0.2s; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| } | |
| .ratio-btn:hover, .ratio-btn.active { | |
| background: var(--primary); | |
| color: white; | |
| border-color: var(--primary); | |
| } | |
| /* Style Selector */ | |
| .style-grid { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fill, minmax(80px, 1fr)); | |
| gap: 10px; | |
| } | |
| .style-chip { | |
| background: rgba(255, 255, 255, 0.05); | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius-sm); | |
| padding: 10px; | |
| text-align: center; | |
| cursor: pointer; | |
| transition: all 0.2s; | |
| font-size: 0.8rem; | |
| color: var(--text-muted); | |
| } | |
| .style-chip i { | |
| display: block; | |
| font-size: 1.2rem; | |
| margin-bottom: 5px; | |
| color: var(--text-main); | |
| } | |
| .style-chip:hover, .style-chip.active { | |
| background: linear-gradient(135deg, rgba(108, 92, 231, 0.3), rgba(0, 206, 201, 0.2)); | |
| border-color: var(--accent); | |
| color: white; | |
| transform: translateY(-2px); | |
| } | |
| /* Generate Button */ | |
| .generate-btn { | |
| background: linear-gradient(135deg, var(--primary), var(--accent)); | |
| color: white; | |
| border: none; | |
| padding: 18px; | |
| border-radius: var(--radius-lg); | |
| font-size: 1.1rem; | |
| font-weight: 700; | |
| cursor: pointer; | |
| transition: all 0.3s ease; | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| gap: 10px; | |
| box-shadow: 0 10px 30px -10px var(--primary-glow); | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| .generate-btn:hover { | |
| transform: translateY(-2px); | |
| box-shadow: 0 15px 40px -10px var(--primary-glow); | |
| } | |
| .generate-btn:active { | |
| transform: translateY(1px); | |
| } | |
| .generate-btn:disabled { | |
| opacity: 0.7; | |
| cursor: not-allowed; | |
| transform: none; | |
| } | |
| .btn-icon { | |
| font-size: 1.2rem; | |
| } | |
| /* --- Preview Panel (Right) --- */ | |
| .preview-panel { | |
| position: relative; | |
| background: var(--bg-panel); | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius-lg); | |
| overflow: hidden; | |
| min-height: 500px; | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| justify-content: center; | |
| } | |
| .image-container { | |
| width: 100%; | |
| height: 100%; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| position: relative; | |
| } | |
| .generated-image { | |
| max-width: 100%; | |
| max-height: 100%; | |
| border-radius: var(--radius-md); | |
| box-shadow: 0 20px 50px rgba(0,0,0,0.5); | |
| display: none; /* Hidden by default */ | |
| animation: fadeIn 0.8s ease; | |
| } | |
| /* Loading State */ | |
| .loader-overlay { | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| background: rgba(11, 12, 21, 0.9); | |
| backdrop-filter: blur(5px); | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| justify-content: center; | |
| z-index: 10; | |
| opacity: 0; | |
| pointer-events: none; | |
| transition: opacity 0.3s; | |
| } | |
| .loader-overlay.active { | |
| opacity: 1; | |
| pointer-events: all; | |
| } | |
| .spinner { | |
| width: 60px; | |
| height: 60px; | |
| border: 4px solid rgba(255, 255, 255, 0.1); | |
| border-left-color: var(--accent); | |
| border-radius: 50%; | |
| animation: spin 1s linear infinite; | |
| margin-bottom: 20px; | |
| } | |
| .loading-text { | |
| font-family: var(--font-display); | |
| font-size: 1.2rem; | |
| letter-spacing: 2px; | |
| color: var(--accent); | |
| margin-bottom: 10px; | |
| } | |
| .progress-bar { | |
| width: 200px; | |
| height: 4px; | |
| background: rgba(255, 255, 255, 0.1); | |
| border-radius: 2px; | |
| overflow: hidden; | |
| } | |
| .progress-fill { | |
| height: 100%; | |
| width: 0%; | |
| background: linear-gradient(90deg, var(--primary), var(--accent)); | |
| transition: width 0.2s linear; | |
| } | |
| /* Empty State */ | |
| .empty-state { | |
| text-align: center; | |
| color: var(--text-muted); | |
| } | |
| .empty-state i { | |
| font-size: 4rem; | |
| margin-bottom: 20px; | |
| opacity: 0.3; | |
| } | |
| .empty-state h3 { | |
| font-size: 1.5rem; | |
| margin-bottom: 10px; | |
| color: var(--text-main); | |
| } | |
| /* --- Footer --- */ | |
| footer { | |
| text-align: center; | |
| padding: 30px; | |
| color: var(--text-muted); | |
| font-size: 0.9rem; | |
| border-top: 1px solid var(--border); | |
| margin-top: auto; | |
| } | |
| /* --- Toast Notification --- */ | |
| .toast { | |
| position: fixed; | |
| bottom: 30px; | |
| left: 50%; | |
| transform: translateX(-50%) translateY(100px); | |
| background: #fff; | |
| color: #000; | |
| padding: 12px 24px; | |
| border-radius: 50px; | |
| font-weight: 600; | |
| box-shadow: 0 10px 30px rgba(0,0,0,0.3); | |
| opacity: 0; | |
| transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275); | |
| z-index: 1000; | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| } | |
| .toast.show { | |
| transform: translateX(-50%) translateY(0); | |
| opacity: 1; | |
| } | |
| /* --- Animations --- */ | |
| @keyframes spin { | |
| to { transform: rotate(360deg); } | |
| } | |
| @keyframes fadeIn { | |
| from { opacity: 0; transform: scale(0.98); } | |
| to { opacity: 1; transform: scale(1); } | |
| } | |
| @keyframes pulse { | |
| 0% { box-shadow: 0 0 0 0 rgba(108, 92, 231, 0.4); } | |
| 70% { box-shadow: 0 0 0 10px rgba(108, 92, 231, 0); } | |
| 100% { box-shadow: 0 0 0 0 rgba(108, 92, 231, 0); } | |
| } | |
| /* --- History Strip --- */ | |
| .history-strip { | |
| margin-top: 20px; | |
| display: flex; | |
| gap: 15px; | |
| overflow-x: auto; | |
| padding-bottom: 10px; | |
| scrollbar-width: thin; | |
| scrollbar-color: var(--primary) transparent; | |
| } | |
| .history-item { | |
| width: 80px; | |
| height: 80px; | |
| border-radius: var(--radius-md); | |
| overflow: hidden; | |
| border: 2px solid transparent; | |
| cursor: pointer; | |
| transition: all 0.2s; | |
| flex-shrink: 0; | |
| position: relative; | |
| } | |
| .history-item img { | |
| width: 100%; | |
| height: 100%; | |
| object-fit: cover; | |
| } | |
| .history-item:hover, .history-item.active { | |
| border-color: var(--accent); | |
| transform: scale(1.05); | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <!-- Header --> | |
| <header> | |
| <div class="logo"> | |
| <i class="fa-solid fa-bolt"></i> Z-Image Turbo | |
| </div> | |
| <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="built-with"> | |
| Built with anycoder <i class="fa-solid fa-arrow-up-right-from-square"></i> | |
| </a> | |
| </header> | |
| <!-- Main Content --> | |
| <main> | |
| <!-- Controls Section --> | |
| <section class="controls-panel"> | |
| <div class="input-group"> | |
| <label for="prompt"><i class="fa-solid fa-wand-magic-sparkles"></i> Describe your vision</label> | |
| <textarea id="prompt" placeholder="A futuristic city with neon lights, cyberpunk style, highly detailed..."></textarea> | |
| </div> | |
| <div class="input-group"> | |
| <label>Style</label> | |
| <div class="style-grid"> | |
| <div class="style-chip active" data-style="realistic"> | |
| <i class="fa-solid fa-camera"></i> Real | |
| </div> | |
| <div class="style-chip" data-style="anime"> | |
| <i class="fa-solid fa-star"></i> Anime | |
| </div> | |
| <div class="style-chip" data-style="cyberpunk"> | |
| <i class="fa-solid fa-robot"></i> Cyber | |
| </div> | |
| <div class="style-chip" data-style="oil"> | |
| <i class="fa-solid fa-palette"></i> Oil | |
| </div> | |
| <div class="style-chip" data-style="3d"> | |
| <i class="fa-solid fa-cube"></i> 3D Render | |
| </div> | |
| <div class="style-chip" data-style="sketch"> | |
| <i class="fa-solid fa-pencil"></i> Sketch | |
| </div> | |
| </div> | |
| </div> | |
| <div class="input-group"> | |
| <label>Aspect Ratio</label> | |
| <div class="aspect-ratio"> | |
| <div class="ratio-btn active" data-ratio="1:1"> | |
| <i class="fa-regular fa-square"></i> 1:1 | |
| </div> | |
| <div class="ratio-btn" data-ratio="16:9"> | |
| <i class="fa-solid fa-video"></i> 16:9 | |
| </div> | |
| <div class="ratio-btn" data-ratio="9:16"> | |
| <i class="fa-solid fa-mobile-screen"></i> 9:16 | |
| </div> | |
| <div class="ratio-btn" data-ratio="4:3"> | |
| <i class="fa-solid fa-image"></i> 4:3 | |
| </div> | |
| </div> | |
| </div> | |
| <button class="generate-btn" id="generateBtn"> | |
| <span class="btn-text">Generate Image</span> | |
| <i class="fa-solid fa-arrow-right btn-icon"></i> | |
| </button> | |
| </section> | |
| <!-- Preview Section --> | |
| <section class="preview-panel" id="previewPanel"> | |
| <!-- Empty State --> | |
| <div class="empty-state" id="emptyState"> | |
| <i class="fa-solid fa-image"></i> | |
| <h3>Ready to create?</h3> | |
| <p>Enter a prompt and let Z-Image Turbo work its magic.</p> | |
| </div> | |
| <!-- Loader --> | |
| <div class="loader-overlay" id="loader"> | |
| <div class="spinner"></div> | |
| <div class="loading-text" id="loadingText">Initializing...</div> | |
| <div class="progress-bar"> | |
| <div class="progress-fill" id="progressFill"></div> | |
| </div> | |
| </div> | |
| <!-- Result Image --> | |
| <div class="image-container"> | |
| <img src="" alt="Generated AI Art" class="generated-image" id="resultImage"> | |
| </div> | |
| <!-- History Strip --> | |
| <div class="history-strip" id="historyStrip"> | |
| <!-- History items will be injected here --> | |
| </div> | |
| </section> | |
| </main> | |
| <!-- Footer --> | |
| <footer> | |
| <p>© 2023 Z-Image Turbo. Powered by AI.</p> | |
| </footer> | |
| <!-- Toast Notification --> | |
| <div class="toast" id="toast"> | |
| <i class="fa-solid fa-circle-info"></i> | |
| <span id="toastMessage">Message here</span> | |
| </div> | |
| <!-- JavaScript Logic --> | |
| <script> | |
| document.addEventListener('DOMContentLoaded', () => { | |
| // Elements | |
| const promptInput = document.getElementById('prompt'); | |
| const generateBtn = document.getElementById('generateBtn'); | |
| const resultImage = document.getElementById('resultImage'); | |
| const emptyState = document.getElementById('emptyState'); | |
| const loader = document.getElementById('loader'); | |
| const progressFill = document.getElementById('progressFill'); | |
| const loadingText = document.getElementById('loadingText'); | |
| const toast = document.getElementById('toast'); | |
| const toastMessage = document.getElementById('toastMessage'); | |
| const styleChips = document.querySelectorAll('.style-chip'); | |
| const ratioBtns = document.querySelectorAll('.ratio-btn'); | |
| const historyStrip = document.getElementById('historyStrip'); | |
| // State | |
| let currentStyle = 'realistic'; | |
| let currentRatio = '1:1'; | |
| const history = []; | |
| // --- Event Listeners for UI Controls --- | |
| // Style Selection | |
| styleChips.forEach(chip => { | |
| chip.addEventListener('click', () => { | |
| styleChips.forEach(c => c.classList.remove('active')); | |
| chip.classList.add('active'); | |
| currentStyle = chip.dataset.style; | |
| }); | |
| }); | |
| // Ratio Selection | |
| ratioBtns.forEach(btn => { | |
| btn.addEventListener('click', () => { | |
| ratioBtns.forEach(b => b.classList.remove('active')); | |
| btn.classList.add('active'); | |
| currentRatio = btn.dataset.ratio; | |
| }); | |
| }); | |
| // Generate Action | |
| generateBtn.addEventListener('click', startGeneration); | |
| // --- Core Functions --- | |
| function startGeneration() { | |
| const prompt = promptInput.value.trim(); | |
| // Validation | |
| if (!prompt) { | |
| showToast('Please enter a description first!', true); | |
| promptInput.focus(); | |
| return; | |
| } | |
| // Lock UI | |
| setLoading(true); | |
| // Simulation Variables | |
| let progress = 0; | |
| const steps = [ | |
| "Analyzing prompt...", | |
| "Connecting to neural network...", | |
| "Diffusing pixels...", | |
| "Refining details...", | |
| "Finalizing output..." | |
| ]; | |
| let stepIndex = 0; | |
| // Simulate Progress Loop | |
| const interval = setInterval(() => { | |
| progress += Math.floor(Math.random() * 5) + 2; // Random increment | |
| if (progress > 100) progress = 100; | |
| progressFill.style.width = `${progress}%`; | |
| // Update text based on progress thresholds | |
| if (progress > 20 && stepIndex === 0) { loadingText.innerText = steps[1]; stepIndex++; } | |
| if (progress > 50 && stepIndex === 1) { loadingText.innerText = steps[2]; stepIndex++; } | |
| if (progress > 80 && stepIndex === 2) { loadingText.innerText = steps[3]; stepIndex++; } | |
| if (progress > 95 && stepIndex === 3) { loadingText.innerText = steps[4]; stepIndex++; } | |
| if (progress === 100) { | |
| clearInterval(interval); | |
| finishGeneration(prompt); | |
| } | |
| }, 100); // Speed of simulation | |
| } | |
| function finishGeneration(prompt) { | |
| // Generate a consistent image based on prompt + style | |
| // Using picsum.photos with a seed creates a deterministic "random" image | |
| const seed = encodeURIComponent(prompt + currentStyle + Date.now()); | |
| let width = 1024; | |
| let height = 1024; | |
| // Adjust ratio for image dimensions | |
| if (currentRatio === '16:9') { width = 1280; height = 720; } | |
| if (currentRatio === '9:16') { width = 720; height = 1280; } | |
| if (currentRatio === '4:3') { width = 1024; height = 768; } | |
| // Construct URL (Unsplash Source API for variety, seeded) | |
| // Note: In a real app, this would be your API endpoint. | |
| const imageUrl = `https://picsum.photos/seed/${seed}/${width}/${height}.jpg`; | |
| // Preload image to ensure smooth display | |
| const tempImg = new Image(); | |
| tempImg.onload = () => { | |
| resultImage.src = imageUrl; | |
| emptyState.style.display = 'none'; | |
| resultImage.style.display = 'block'; | |
| setLoading(false); | |
| // Add to history | |
| addToHistory(imageUrl); | |
| showToast('Image generated successfully!'); | |
| }; | |
| tempImg.src = imageUrl; | |
| } | |
| function setLoading(isLoading) { | |
| if (isLoading) { | |
| loader.classList.add('active'); | |
| generateBtn.disabled = true; | |
| generateBtn.querySelector('.btn-text').innerText = 'Generating...'; | |
| resultImage.style.display = 'none'; | |
| historyStrip.innerHTML = ''; // Clear history while generating | |
| } else { | |
| loader.classList.remove('active'); | |
| generateBtn.disabled = false; | |
| generateBtn.querySelector('.btn-text').innerText = 'Generate Image'; | |
| progressFill.style.width = '0%'; | |
| } | |
| } | |
| function addToHistory(url) { | |
| const item = document.createElement('div'); | |
| item.className = 'history-item'; | |
| item.innerHTML = `<img src="${url}" alt="History">`; | |
| item.addEventListener('click', () => { | |
| // Remove active class from others | |
| document.querySelectorAll('.history-item').forEach(i => i.classList.remove('active')); | |
| item.classList.add('active'); | |
| // Show image in main view | |
| emptyState.style.display = 'none'; | |
| resultImage.style.display = 'block'; | |
| resultImage.src = url; | |
| }); | |
| history.prepend(item); | |
| // Limit history to 5 items | |
| if (history.length > 5) { | |
| historyStrip.lastElementChild.remove(); | |
| } | |
| } | |
| function showToast(msg, isError = false) { | |
| toastMessage.innerText = msg; | |
| toast.style.background = isError ? '#ff4757' : '#fff'; | |
| toast.style.color = isError ? '#fff' : '#000'; | |
| toast.classList.add('show'); | |
| setTimeout(() => { | |
| toast.classList.remove('show'); | |
| }, 3000); | |
| } | |
| }); | |
| </script> | |
| </body> | |
| </html> |