Spaces:
Running
Running
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>LOKI.AI IMAGE PLAYGROUND</title> | |
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:ital,wght@0,400;0,500;0,700;1,400&display=swap" rel="stylesheet"> | |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css"> | |
<style> | |
:root { | |
--primary-bg: #ffffff; | |
--secondary-bg: #f8f8f8; | |
--text-color: #000000; | |
--border-color: #e0e0e0; | |
--accent-color: #000000; | |
--card-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); | |
} | |
.dark { | |
--primary-bg: #121212; | |
--secondary-bg: #1e1e1e; | |
--text-color: #ffffff; | |
--border-color: #333333; | |
--accent-color: #ffffff; | |
--card-shadow: 0 4px 6px rgba(0, 0, 0, 0.3); | |
} | |
* { | |
margin: 0; | |
padding: 0; | |
box-sizing: border-box; | |
font-family: 'DM Sans', sans-serif; | |
} | |
body { | |
background-color: var(--secondary-bg); | |
color: var(--text-color); | |
transition: all 0.3s ease; | |
padding: 20px; | |
} | |
.container { | |
max-width: 1000px; | |
margin: 0 auto; | |
} | |
.card { | |
background-color: var(--primary-bg); | |
border-radius: 12px; | |
padding: 24px; | |
box-shadow: var(--card-shadow); | |
transition: all 0.3s ease; | |
} | |
.header { | |
display: flex; | |
justify-content: space-between; | |
align-items: center; | |
margin-bottom: 24px; | |
flex-wrap: wrap; | |
gap: 12px; | |
} | |
.title { | |
font-size: 28px; | |
font-weight: 700; | |
color: var(--text-color); | |
} | |
.theme-toggle { | |
display: flex; | |
align-items: center; | |
gap: 8px; | |
} | |
.toggle-label { | |
font-size: 14px; | |
color: var(--text-color); | |
opacity: 0.7; | |
} | |
.toggle-switch { | |
position: relative; | |
width: 48px; | |
height: 24px; | |
background-color: #e5e5e5; | |
border-radius: 12px; | |
cursor: pointer; | |
transition: background-color 0.3s; | |
} | |
.dark .toggle-switch { | |
background-color: #555; | |
} | |
.toggle-thumb { | |
position: absolute; | |
top: 2px; | |
left: 2px; | |
width: 20px; | |
height: 20px; | |
border-radius: 50%; | |
background-color: white; | |
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); | |
transition: transform 0.3s; | |
} | |
.dark .toggle-thumb { | |
transform: translateX(24px); | |
} | |
.form-row { | |
display: grid; | |
grid-template-columns: 1fr; | |
gap: 16px; | |
margin-bottom: 16px; | |
} | |
@media (min-width: 768px) { | |
.form-row { | |
grid-template-columns: 1fr 1fr; | |
} | |
.form-row.three-cols { | |
grid-template-columns: 1fr 1fr 1fr; | |
} | |
} | |
.form-group { | |
display: flex; | |
flex-direction: column; | |
gap: 6px; | |
} | |
.form-label { | |
font-size: 14px; | |
font-weight: 500; | |
color: var(--text-color); | |
opacity: 0.8; | |
} | |
.form-control { | |
padding: 10px 12px; | |
border-radius: 8px; | |
border: 1px solid var(--border-color); | |
background-color: var(--secondary-bg); | |
color: var(--text-color); | |
font-size: 14px; | |
transition: all 0.2s; | |
appearance: none; | |
} | |
.form-control:focus { | |
outline: none; | |
border-color: var(--accent-color); | |
box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.1); | |
} | |
.dark .form-control:focus { | |
box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.1); | |
} | |
.select-wrapper { | |
position: relative; | |
} | |
.select-wrapper:after { | |
content: ''; | |
position: absolute; | |
top: 50%; | |
right: 12px; | |
transform: translateY(-50%); | |
width: 0; | |
height: 0; | |
border-left: 5px solid transparent; | |
border-right: 5px solid transparent; | |
border-top: 5px solid var(--text-color); | |
pointer-events: none; | |
} | |
.btn { | |
padding: 10px 18px; | |
border-radius: 8px; | |
font-weight: 500; | |
cursor: pointer; | |
transition: all 0.2s; | |
border: none; | |
text-align: center; | |
} | |
.btn-primary { | |
background-color: var(--accent-color); | |
color: var(--primary-bg); | |
} | |
.btn-primary:hover { | |
opacity: 0.9; | |
transform: translateY(-2px); | |
} | |
.btn-primary:active { | |
transform: translateY(0); | |
} | |
.btn-download { | |
background-color: rgba(255, 255, 255, 0.2); | |
backdrop-filter: blur(4px); | |
padding: 8px; | |
border-radius: 50%; | |
position: absolute; | |
bottom: 10px; | |
right: 10px; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); | |
} | |
.dark .btn-download { | |
background-color: rgba(0, 0, 0, 0.3); | |
} | |
.btn-download svg { | |
width: 20px; | |
height: 20px; | |
stroke: var(--accent-color); | |
} | |
.btn-full { | |
width: 100%; | |
} | |
.text-center { | |
text-align: center; | |
} | |
.result { | |
margin-top: 24px; | |
display: none; | |
} | |
.result-title { | |
font-size: 18px; | |
font-weight: 500; | |
margin-bottom: 4px; | |
} | |
.result-subtitle { | |
font-size: 14px; | |
opacity: 0.7; | |
margin-bottom: 16px; | |
} | |
.images-grid { | |
display: grid; | |
grid-template-columns: 1fr; | |
gap: 16px; | |
} | |
.images-grid.multi-column { | |
grid-template-columns: repeat(2, 1fr); | |
} | |
.image-wrapper { | |
position: relative; | |
border-radius: 8px; | |
overflow: hidden; | |
box-shadow: 0 3px 10px rgba(0, 0, 0, 0.1); | |
transform-origin: center; | |
} | |
.dark .image-wrapper { | |
box-shadow: 0 3px 10px rgba(0, 0, 0, 0.3); | |
} | |
.image-wrapper img { | |
width: 100%; | |
height: auto; | |
display: block; | |
transition: transform 0.3s ease; | |
} | |
.image-wrapper:hover img { | |
transform: scale(1.03); | |
} | |
.loading { | |
display: none; | |
flex-direction: column; | |
align-items: center; | |
justify-content: center; | |
padding: 32px 0; | |
} | |
.loading-spinner { | |
width: 40px; | |
height: 40px; | |
border: 4px solid rgba(0, 0, 0, 0.1); | |
border-left-color: var(--accent-color); | |
border-radius: 50%; | |
animation: spinner 1s linear infinite; | |
margin-bottom: 16px; | |
} | |
.dark .loading-spinner { | |
border-color: rgba(255, 255, 255, 0.1); | |
border-left-color: var(--accent-color); | |
} | |
@keyframes spinner { | |
to { | |
transform: rotate(360deg); | |
} | |
} | |
.loading-text { | |
font-size: 14px; | |
opacity: 0.7; | |
} | |
.error { | |
background-color: rgba(255, 0, 0, 0.1); | |
color: #e53e3e; | |
padding: 16px; | |
border-radius: 8px; | |
margin-top: 24px; | |
display: none; | |
} | |
.dark .error { | |
background-color: rgba(255, 0, 0, 0.05); | |
} | |
.error-title { | |
font-size: 16px; | |
font-weight: 500; | |
margin-bottom: 4px; | |
} | |
.error-message { | |
font-size: 14px; | |
opacity: 0.8; | |
} | |
.footer { | |
margin-top: 16px; | |
text-align: center; | |
font-size: 12px; | |
opacity: 0.5; | |
} | |
.confetti { | |
position: fixed; | |
width: 10px; | |
height: 10px; | |
background-color: #f00; | |
opacity: 0; | |
top: 0; | |
left: 0; | |
} | |
</style> | |
</head> | |
<body> | |
<div class="container"> | |
<div class="card animate__animated animate__fadeIn"> | |
<div class="header"> | |
<h1 class="title animate__animated animate__slideInLeft">LOKI.AI IMAGE PLAYGROUND</h1> | |
<div class="theme-toggle animate__animated animate__slideInRight"> | |
<span class="toggle-label">Theme</span> | |
<div id="theme-toggle" class="toggle-switch"> | |
<div class="toggle-thumb"></div> | |
</div> | |
</div> | |
</div> | |
<div class="form-row animate__animated animate__fadeInUp" style="animation-delay: 0.1s;"> | |
<div class="form-group"> | |
<label for="model" class="form-label">Select Model</label> | |
<div class="select-wrapper"> | |
<select id="model" class="form-control"> | |
<option value="Flux Realism">Flux Realism</option> | |
<option value="Flux Pro Ultra">Flux Pro Ultra</option> | |
<option value="grok-2-aurora">grok-2-aurora</option> | |
<option value="Flux Pro">Flux Pro</option> | |
<option value="Flux Pro Ultra Raw">Flux Pro Ultra Raw</option> | |
<option value="Flux Dev">Flux Dev</option> | |
<option value="Flux Schnell">Flux Schnell</option> | |
<option value="stable-diffusion-3-large-turbo">stable-diffusion-3-large-turbo</option> | |
<option value="sdxl-lightning-4step">sdxl-lightning-4step</option> | |
<option value="dall-e-3">dall-e-3</option> | |
</select> | |
</div> | |
</div> | |
<div class="form-group"> | |
<label for="prompt" class="form-label">Enter Prompt</label> | |
<input type="text" id="prompt" class="form-control" placeholder="Describe what you want to see..." value="sky"> | |
</div> | |
</div> | |
<div class="form-row three-cols animate__animated animate__fadeInUp" style="animation-delay: 0.2s;"> | |
<div class="form-group"> | |
<label for="image-size" class="form-label">Image Size</label> | |
<div class="select-wrapper"> | |
<select id="image-size" class="form-control"> | |
<option value="512">512 x 512</option> | |
<option value="768">768 x 768</option> | |
<option value="1024" selected>1024 x 1024</option> | |
<option value="1536">1536 x 1536</option> | |
</select> | |
</div> | |
</div> | |
<div class="form-group"> | |
<label for="image-count" class="form-label">Number of Images</label> | |
<div class="select-wrapper"> | |
<select id="image-count" class="form-control"> | |
<option value="1" selected>1</option> | |
<option value="2">2</option> | |
<option value="4">4</option> | |
</select> | |
</div> | |
</div> | |
<div class="form-group"> | |
<label class="form-label"> </label> | |
<button id="generate" class="btn btn-primary btn-full animate__animated animate__pulse animate__infinite"> | |
Generate Image | |
</button> | |
</div> | |
</div> | |
<div id="result" class="result"> | |
<div class="text-center animate__animated animate__fadeIn"> | |
<h2 class="result-title">Your Creation</h2> | |
<p class="result-subtitle">Created with <span id="model-used"></span></p> | |
</div> | |
<div id="images-container" class="images-grid"></div> | |
</div> | |
<div id="loading" class="loading"> | |
<div class="loading-spinner"></div> | |
<p class="loading-text">Creating your masterpiece...</p> | |
</div> | |
<div id="error" class="error"> | |
<h3 class="error-title">Oops! Something went wrong.</h3> | |
<p class="error-message">Please try again or check your connection.</p> | |
</div> | |
</div> | |
<div class="footer"> | |
© 2025 LOKI.AI IMAGE PLAYGROUND | All rights reserved | |
</div> | |
</div> | |
<script> | |
document.addEventListener('DOMContentLoaded', () => { | |
// Elements | |
const themeToggle = document.getElementById('theme-toggle'); | |
const generateBtn = document.getElementById('generate'); | |
const promptInput = document.getElementById('prompt'); | |
const modelSelect = document.getElementById('model'); | |
const imageSizeSelect = document.getElementById('image-size'); | |
const imageCountSelect = document.getElementById('image-count'); | |
const resultDiv = document.getElementById('result'); | |
const loadingDiv = document.getElementById('loading'); | |
const errorDiv = document.getElementById('error'); | |
const imagesContainer = document.getElementById('images-container'); | |
const modelUsed = document.getElementById('model-used'); | |
// Theme Toggle | |
themeToggle.addEventListener('click', () => { | |
document.body.classList.toggle('dark'); | |
localStorage.setItem('theme', document.body.classList.contains('dark') ? 'dark' : 'light'); | |
}); | |
// Check for saved theme preference | |
if (localStorage.getItem('theme') === 'dark' || | |
(!localStorage.getItem('theme') && window.matchMedia('(prefers-color-scheme: dark)').matches)) { | |
document.body.classList.add('dark'); | |
} | |
// Create confetti | |
function createConfetti() { | |
const colors = ['#ff0000', '#00ff00', '#0000ff', '#ffff00', '#ff00ff', '#00ffff']; | |
const confettiCount = 100; | |
for (let i = 0; i < confettiCount; i++) { | |
const confetti = document.createElement('div'); | |
confetti.className = 'confetti'; | |
confetti.style.backgroundColor = colors[Math.floor(Math.random() * colors.length)]; | |
confetti.style.left = Math.random() * 100 + 'vw'; | |
confetti.style.opacity = Math.random() + 0.5; | |
confetti.style.width = Math.random() * 10 + 5 + 'px'; | |
confetti.style.height = Math.random() * 10 + 5 + 'px'; | |
document.body.appendChild(confetti); | |
const animation = confetti.animate([ | |
{ transform: 'translateY(0) rotate(0)', opacity: 1 }, | |
{ transform: `translateY(${window.innerHeight}px) rotate(${Math.random() * 360}deg)`, opacity: 0 } | |
], { | |
duration: Math.random() * 2000 + 2000, | |
easing: 'cubic-bezier(0, 0.55, 0.45, 1)' | |
}); | |
animation.onfinish = () => confetti.remove(); | |
} | |
} | |
// Generate image | |
generateBtn.addEventListener('click', async () => { | |
const prompt = promptInput.value.trim(); | |
const model = modelSelect.value; | |
const size = parseInt(imageSizeSelect.value); | |
const number = parseInt(imageCountSelect.value); | |
if (!prompt) { | |
promptInput.style.borderColor = 'red'; | |
promptInput.classList.add('animate__animated', 'animate__shakeX'); | |
setTimeout(() => { | |
promptInput.style.borderColor = ''; | |
promptInput.classList.remove('animate__animated', 'animate__shakeX'); | |
}, 1000); | |
return; | |
} | |
// Show loading state | |
resultDiv.style.display = 'none'; | |
errorDiv.style.display = 'none'; | |
loadingDiv.style.display = 'flex'; | |
generateBtn.disabled = true; | |
try { | |
const response = await fetch('https://parthsadaria-lokiai.hf.space/images/generations', { | |
method: 'POST', | |
headers: { | |
'Content-Type': 'application/json', | |
}, | |
body: JSON.stringify({ | |
model: model, | |
prompt: prompt, | |
size: size, | |
number: number | |
}) | |
}); | |
if (!response.ok) { | |
throw new Error('API request failed'); | |
} | |
const data = await response.json(); | |
// Display result | |
loadingDiv.style.display = 'none'; | |
resultDiv.style.display = 'block'; | |
modelUsed.textContent = model; | |
// Clear previous images | |
imagesContainer.innerHTML = ''; | |
// Trigger confetti animation | |
createConfetti(); | |
// Set grid columns based on number of images | |
if (number > 1) { | |
imagesContainer.className = 'images-grid multi-column'; | |
} else { | |
imagesContainer.className = 'images-grid'; | |
} | |
// Add generated images | |
if (data.data && data.data.length > 0) { | |
data.data.forEach((item, index) => { | |
const imgWrapper = document.createElement('div'); | |
imgWrapper.className = 'image-wrapper animate__animated animate__zoomIn'; | |
imgWrapper.style.animationDelay = `${index * 0.2}s`; | |
const img = document.createElement('img'); | |
img.src = item.url; | |
img.alt = `Generated image ${index + 1}`; | |
const downloadBtn = document.createElement('button'); | |
downloadBtn.className = 'btn-download'; | |
downloadBtn.innerHTML = ` | |
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> | |
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path> | |
<polyline points="7 10 12 15 17 10"></polyline> | |
<line x1="12" y1="15" x2="12" y2="3"></line> | |
</svg> | |
`; | |
downloadBtn.addEventListener('click', () => { | |
const a = document.createElement('a'); | |
a.href = item.url; | |
a.download = `loki-ai-${model}-${index + 1}.jpg`; | |
document.body.appendChild(a); | |
a.click(); | |
document.body.removeChild(a); | |
}); | |
imgWrapper.appendChild(img); | |
imgWrapper.appendChild(downloadBtn); | |
imagesContainer.appendChild(imgWrapper); | |
}); | |
} | |
} catch (error) { | |
console.error('Error:', error); | |
loadingDiv.style.display = 'none'; | |
errorDiv.style.display = 'block'; | |
errorDiv.classList.add('animate__animated', 'animate__fadeIn'); | |
} finally { | |
generateBtn.disabled = false; | |
} | |
}); | |
// Enter key to generate | |
promptInput.addEventListener('keypress', (e) => { | |
if (e.key === 'Enter') { | |
generateBtn.click(); | |
} | |
}); | |
}); | |
</script> | |
</body> | |
</html> |