| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>INFERNO - Uncensored AI Image Generator</title> |
| <script src="https://cdn.tailwindcss.com"></script> |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> |
| <style> |
| :root { |
| --primary: #ff2d2d; |
| --primary-dark: #cc0000; |
| --secondary: #ff5e5e; |
| --accent: #ff9a9a; |
| --dark: #1a1a1a; |
| --light: #f5f5f5; |
| --danger: #ff3860; |
| --warning: #ffdd57; |
| --success: #23d160; |
| } |
| |
| body { |
| background-color: var(--dark); |
| color: var(--light); |
| font-family: 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif; |
| } |
| |
| .inferno-bg { |
| background: linear-gradient(135deg, var(--primary) 0%, var(--primary-dark) 100%); |
| } |
| |
| .model-card { |
| transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); |
| border: 2px solid transparent; |
| } |
| |
| .model-card:hover { |
| transform: translateY(-3px); |
| box-shadow: 0 10px 25px rgba(255, 45, 45, 0.3); |
| border-color: var(--primary); |
| } |
| |
| .model-card.selected { |
| background-color: rgba(255, 45, 45, 0.1); |
| border-color: var(--primary); |
| } |
| |
| .tab-active { |
| border-bottom: 3px solid var(--primary); |
| font-weight: 700; |
| color: var(--light); |
| } |
| |
| .image-placeholder { |
| background: linear-gradient(45deg, #2a2a2a 25%, #333 25%, #333 50%, #2a2a2a 50%, #2a2a2a 75%, #333 75%, #333 100%); |
| background-size: 20px 20px; |
| } |
| |
| .prompt-textarea:focus { |
| box-shadow: 0 0 0 2px rgba(255, 45, 45, 0.5); |
| border-color: var(--primary); |
| } |
| |
| .slider-thumb::-webkit-slider-thumb { |
| -webkit-appearance: none; |
| appearance: none; |
| width: 18px; |
| height: 18px; |
| border-radius: 50%; |
| background: var(--primary); |
| cursor: pointer; |
| border: 2px solid var(--light); |
| } |
| |
| .slider-thumb::-moz-range-thumb { |
| width: 18px; |
| height: 18px; |
| border-radius: 50%; |
| background: var(--primary); |
| cursor: pointer; |
| border: 2px solid var(--light); |
| } |
| |
| .nsfw-toggle { |
| position: relative; |
| display: inline-block; |
| width: 60px; |
| height: 30px; |
| } |
| |
| .nsfw-toggle input { |
| opacity: 0; |
| width: 0; |
| height: 0; |
| } |
| |
| .nsfw-slider { |
| position: absolute; |
| cursor: pointer; |
| top: 0; |
| left: 0; |
| right: 0; |
| bottom: 0; |
| background-color: #ccc; |
| transition: .4s; |
| border-radius: 30px; |
| } |
| |
| .nsfw-slider:before { |
| position: absolute; |
| content: ""; |
| height: 22px; |
| width: 22px; |
| left: 4px; |
| bottom: 4px; |
| background-color: white; |
| transition: .4s; |
| border-radius: 50%; |
| } |
| |
| input:checked + .nsfw-slider { |
| background-color: var(--danger); |
| } |
| |
| input:checked + .nsfw-slider:before { |
| transform: translateX(30px); |
| } |
| |
| .error-toast { |
| animation: slideIn 0.5s, fadeOut 0.5s 2.5s forwards; |
| } |
| |
| @keyframes slideIn { |
| from { transform: translateX(100%); } |
| to { transform: translateX(0); } |
| } |
| |
| @keyframes fadeOut { |
| to { opacity: 0; } |
| } |
| |
| .pagination-btn.active { |
| background-color: var(--primary); |
| color: white; |
| } |
| |
| .loading-spinner { |
| animation: spin 1s linear infinite; |
| } |
| |
| @keyframes spin { |
| 0% { transform: rotate(0deg); } |
| 100% { transform: rotate(360deg); } |
| } |
| |
| .nsfw-badge { |
| animation: pulse 2s infinite; |
| } |
| |
| @keyframes pulse { |
| 0% { box-shadow: 0 0 0 0 rgba(255, 56, 96, 0.7); } |
| 70% { box-shadow: 0 0 0 10px rgba(255, 56, 96, 0); } |
| 100% { box-shadow: 0 0 0 0 rgba(255, 56, 96, 0); } |
| } |
| </style> |
| </head> |
| <body class="bg-gray-900 text-gray-100"> |
| |
| <div id="toast-container" class="fixed bottom-4 right-4 space-y-2 z-50"></div> |
|
|
| |
| <header class="inferno-bg text-white py-4 shadow-lg sticky top-0 z-40"> |
| <div class="container mx-auto px-4"> |
| <div class="flex items-center justify-between"> |
| <div class="flex items-center space-x-3"> |
| <i class="fas fa-fire text-3xl"></i> |
| <h1 class="text-2xl font-bold">INFERNO</h1> |
| <span class="nsfw-badge bg-red-600 text-xs px-2 py-1 rounded-full ml-2">NSFW</span> |
| </div> |
| <div class="flex items-center space-x-4"> |
| <button id="dark-mode-toggle" class="p-2 rounded-full hover:bg-red-800 transition"> |
| <i class="fas fa-moon"></i> |
| </button> |
| <div class="relative group"> |
| <button class="flex items-center space-x-2 bg-red-700 hover:bg-red-800 px-4 py-2 rounded-lg transition"> |
| <i class="fas fa-user"></i> |
| <span>Account</span> |
| </button> |
| <div class="absolute right-0 mt-2 w-48 bg-gray-800 rounded-lg shadow-lg py-1 z-50 hidden group-hover:block"> |
| <a href="#" class="block px-4 py-2 hover:bg-gray-700">Profile</a> |
| <a href="#" class="block px-4 py-2 hover:bg-gray-700">Settings</a> |
| <a href="#" class="block px-4 py-2 hover:bg-gray-700">Sign out</a> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| </header> |
|
|
| |
| <main class="container mx-auto px-4 py-8"> |
| <div class="bg-gray-800 rounded-xl shadow-2xl overflow-hidden"> |
| |
| <div class="flex border-b border-gray-700"> |
| <button id="multi-model-tab" class="tab-active px-6 py-4 text-white font-bold flex items-center"> |
| <i class="fas fa-layer-group mr-2"></i> Multi-Model Inferno |
| </button> |
| <button id="single-model-tab" class="px-6 py-4 text-gray-400 font-medium flex items-center hover:text-white transition"> |
| <i class="fas fa-cube mr-2"></i> Single Model |
| </button> |
| <button id="batch-tab" class="px-6 py-4 text-gray-400 font-medium flex items-center hover:text-white transition"> |
| <i class="fas fa-clone mr-2"></i> Batch Mode |
| </button> |
| <button id="settings-tab" class="px-6 py-4 text-gray-400 font-medium flex items-center ml-auto hover:text-white transition"> |
| <i class="fas fa-cog mr-2"></i> Settings |
| </button> |
| </div> |
|
|
| |
| <div id="multi-model-content" class="p-6"> |
| <div class="grid grid-cols-1 lg:grid-cols-3 gap-6"> |
| |
| <div class="lg:col-span-2 space-y-6"> |
| |
| <div class="flex items-center justify-between bg-gray-700 p-4 rounded-lg"> |
| <div class="flex items-center space-x-2"> |
| <i class="fas fa-exclamation-triangle text-red-500"></i> |
| <span class="font-medium">NSFW Mode</span> |
| </div> |
| <label class="nsfw-toggle"> |
| <input type="checkbox" id="nsfw-toggle" checked> |
| <span class="nsfw-slider"></span> |
| </label> |
| </div> |
|
|
| |
| <div class="bg-gray-700 p-4 rounded-lg"> |
| <div class="flex items-center justify-between mb-2"> |
| <label class="block text-white font-medium">Your Raw Prompt</label> |
| <button id="random-prompt" class="text-xs bg-gray-600 hover:bg-gray-500 px-2 py-1 rounded transition"> |
| <i class="fas fa-dice mr-1"></i> Randomize |
| </button> |
| </div> |
| <textarea id="prompt-input" class="prompt-textarea w-full h-32 px-4 py-3 bg-gray-800 border border-gray-600 rounded-lg focus:outline-none focus:border-red-500 text-white" placeholder="Let your imagination run wild... describe exactly what you want to see, no matter how depraved or exquisite...">A cybernetic dominatrix with glowing crimson eyes and liquid metal skin stands atop a neon-lit skyscraper, her whip crackling with electricity as the city burns below, ultra-detailed, hyper-realistic, 8K</textarea> |
| </div> |
|
|
| |
| <div class="bg-gray-700 p-4 rounded-lg"> |
| <label class="block text-white font-medium mb-2">Negative Prompt</label> |
| <textarea id="negative-prompt" class="w-full px-4 py-3 bg-gray-800 border border-gray-600 rounded-lg focus:outline-none focus:border-red-500 text-white" placeholder="What you don't want to see...">[deformed | disfigured], poorly drawn, [bad : wrong] anatomy, [extra | missing | floating | disconnected] limb, (mutated hands and fingers), blurry, text, fuzziness, censored, low quality, artifacts</textarea> |
| </div> |
|
|
| |
| <div class="bg-gray-700 p-4 rounded-lg"> |
| <div class="flex items-center justify-between cursor-pointer" id="advanced-settings-toggle"> |
| <h3 class="text-white font-medium">Advanced Settings</h3> |
| <i class="fas fa-chevron-down text-gray-400 transition-transform duration-300"></i> |
| </div> |
| <div id="advanced-settings-content" class="mt-4 hidden space-y-4"> |
| |
| <div class="grid grid-cols-2 gap-4"> |
| <div> |
| <label class="block text-gray-300 text-sm mb-1">Width</label> |
| <div class="flex items-center"> |
| <input type="range" min="256" max="1216" step="32" value="768" class="slider-thumb w-full h-2 bg-gray-600 rounded-lg appearance-none cursor-pointer"> |
| <span id="width-value" class="ml-3 text-white w-16 text-center">768</span> |
| </div> |
| </div> |
| <div> |
| <label class="block text-gray-300 text-sm mb-1">Height</label> |
| <div class="flex items-center"> |
| <input type="range" min="256" max="1216" step="32" value="768" class="slider-thumb w-full h-2 bg-gray-600 rounded-lg appearance-none cursor-pointer"> |
| <span id="height-value" class="ml-3 text-white w-16 text-center">768</span> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div class="grid grid-cols-2 gap-4"> |
| <div> |
| <label class="block text-gray-300 text-sm mb-1">Inference Steps</label> |
| <div class="flex items-center"> |
| <input type="range" min="1" max="100" step="1" value="30" class="slider-thumb w-full h-2 bg-gray-600 rounded-lg appearance-none cursor-pointer"> |
| <span id="steps-value" class="ml-3 text-white w-16 text-center">30</span> |
| </div> |
| </div> |
| <div> |
| <label class="block text-gray-300 text-sm mb-1">Guidance Scale</label> |
| <div class="flex items-center"> |
| <input type="range" min="1" max="30" step="0.1" value="7.5" class="slider-thumb w-full h-2 bg-gray-600 rounded-lg appearance-none cursor-pointer"> |
| <span id="cfg-value" class="ml-3 text-white w-16 text-center">7.5</span> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div> |
| <label class="block text-gray-300 text-sm mb-1">Seed</label> |
| <div class="flex items-center"> |
| <input type="number" id="seed-input" class="w-full px-3 py-2 bg-gray-800 border border-gray-600 rounded-lg focus:outline-none focus:border-red-500 text-white" value="-1"> |
| <button id="randomize-seed" class="ml-3 bg-gray-600 hover:bg-gray-500 text-white px-4 py-2 rounded-lg transition"> |
| <i class="fas fa-random mr-2"></i> Randomize |
| </button> |
| </div> |
| </div> |
|
|
| |
| <div> |
| <label class="block text-gray-300 text-sm mb-1">Sampler</label> |
| <select id="sampler-select" class="w-full px-3 py-2 bg-gray-800 border border-gray-600 rounded-lg focus:outline-none focus:border-red-500 text-white"> |
| <option value="euler_a">Euler a</option> |
| <option value="euler">Euler</option> |
| <option value="lms">LMS</option> |
| <option value="heun">Heun</option> |
| <option value="dpm2">DPM2</option> |
| <option value="dpm2_a">DPM2 a</option> |
| <option value="dpmpp_2s_a">DPM++ 2S a</option> |
| <option value="dpmpp_2m">DPM++ 2M</option> |
| <option value="dpmpp_sde">DPM++ SDE</option> |
| <option value="ddim">DDIM</option> |
| </select> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div class="bg-gray-700 p-4 rounded-lg"> |
| <div class="flex items-center justify-between mb-2"> |
| <label class="block text-white font-medium">Select Models (Max 4)</label> |
| <span id="selected-count" class="text-xs bg-red-600 px-2 py-1 rounded">4/4 selected</span> |
| </div> |
| <div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-3"> |
| |
| <div class="model-card bg-gray-800 rounded-lg p-3 cursor-pointer"> |
| <div class="flex items-center"> |
| <input type="checkbox" class="mr-2 model-checkbox" checked data-model="sd15"> |
| <div> |
| <h4 class="font-medium text-white">Stable Diffusion 1.5</h4> |
| <p class="text-xs text-gray-400">512x512 resolution</p> |
| </div> |
| </div> |
| </div> |
| <div class="model-card bg-gray-800 rounded-lg p-3 cursor-pointer"> |
| <div class="flex items-center"> |
| <input type="checkbox" class="mr-2 model-checkbox" checked data-model="sd21"> |
| <div> |
| <h4 class="font-medium text-white">Stable Diffusion 2.1</h4> |
| <p class="text-xs text-gray-400">768x768 resolution</p> |
| </div> |
| </div> |
| </div> |
| <div class="model-card bg-gray-800 rounded-lg p-3 cursor-pointer"> |
| <div class="flex items-center"> |
| <input type="checkbox" class="mr-2 model-checkbox" data-model="openjourney"> |
| <div> |
| <h4 class="font-medium text-white">OpenJourney</h4> |
| <p class="text-xs text-gray-400">Artistic style</p> |
| </div> |
| </div> |
| </div> |
| <div class="model-card bg-gray-800 rounded-lg p-3 cursor-pointer"> |
| <div class="flex items-center"> |
| <input type="checkbox" class="mr-2 model-checkbox" data-model="dreamlike"> |
| <div> |
| <h4 class="font-medium text-white">Dreamlike</h4> |
| <p class="text-xs text-gray-400">Photorealistic</p> |
| </div> |
| </div> |
| </div> |
| <div class="model-card bg-gray-800 rounded-lg p-3 cursor-pointer"> |
| <div class="flex items-center"> |
| <input type="checkbox" class="mr-2 model-checkbox" data-model="anything"> |
| <div> |
| <h4 class="font-medium text-white">Anything V3</h4> |
| <p class="text-xs text-gray-400">Anime style</p> |
| </div> |
| </div> |
| </div> |
| <div class="model-card bg-gray-800 rounded-lg p-3 cursor-pointer"> |
| <div class="flex items-center"> |
| <input type="checkbox" class="mr-2 model-checkbox" data-model="deliberate"> |
| <div> |
| <h4 class="font-medium text-white">Deliberate</h4> |
| <p class="text-xs text-gray-400">Detailed images</p> |
| </div> |
| </div> |
| </div> |
| <div class="model-card bg-gray-800 rounded-lg p-3 cursor-pointer"> |
| <div class="flex items-center"> |
| <input type="checkbox" class="mr-2 model-checkbox" data-model="realistic"> |
| <div> |
| <h4 class="font-medium text-white">Realistic Vision</h4> |
| <p class="text-xs text-gray-400">Hyper-realistic</p> |
| </div> |
| </div> |
| </div> |
| <div class="model-card bg-gray-800 rounded-lg p-3 cursor-pointer"> |
| <div class="flex items-center"> |
| <input type="checkbox" class="mr-2 model-checkbox" data-model="hentai"> |
| <div> |
| <h4 class="font-medium text-white">Hentai Diffusion</h4> |
| <p class="text-xs text-gray-400">NSFW content</p> |
| </div> |
| </div> |
| </div> |
| <div class="model-card bg-gray-800 rounded-lg p-3 cursor-pointer"> |
| <div class="flex items-center"> |
| <input type="checkbox" class="mr-2 model-checkbox" data-model="waifu"> |
| <div> |
| <h4 class="font-medium text-white">Waifu Diffusion</h4> |
| <p class="text-xs text-gray-400">Anime characters</p> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="mt-3 flex justify-between"> |
| <button id="random-models" class="text-red-400 hover:text-red-300 text-sm font-medium"> |
| <i class="fas fa-random mr-1"></i> Randomize Models |
| </button> |
| <button id="clear-models" class="text-gray-400 hover:text-gray-300 text-sm font-medium"> |
| <i class="fas fa-times mr-1"></i> Clear Selection |
| </button> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div class="space-y-6"> |
| |
| <button id="generate-button" class="w-full bg-red-600 hover:bg-red-700 text-white font-bold py-3 px-4 rounded-lg transition flex items-center justify-center"> |
| <i class="fas fa-fire mr-2"></i> IGNITE CREATION |
| </button> |
|
|
| |
| <div class="bg-gray-700 p-4 rounded-lg"> |
| <div class="grid grid-cols-3 gap-2 text-center"> |
| <div> |
| <div class="text-xs text-gray-400">Queue</div> |
| <div id="queue-count" class="font-bold">0</div> |
| </div> |
| <div> |
| <div class="text-xs text-gray-400">ETA</div> |
| <div id="eta-time" class="font-bold">-</div> |
| </div> |
| <div> |
| <div class="text-xs text-gray-400">Cost</div> |
| <div id="generation-cost" class="font-bold">0.00</div> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div class="bg-gray-700 p-4 rounded-lg"> |
| <h3 class="text-white font-medium mb-3">Model Outputs</h3> |
| <div class="grid grid-cols-2 gap-3"> |
| |
| <div id="output-1" class="image-placeholder rounded-lg h-40 flex items-center justify-center relative"> |
| <span class="text-gray-400">Stable Diffusion 1.5</span> |
| <div class="absolute bottom-2 right-2 flex space-x-1"> |
| <button class="download-btn hidden bg-gray-800 hover:bg-gray-700 text-white p-1 rounded-full w-7 h-7 flex items-center justify-center"> |
| <i class="fas fa-download text-xs"></i> |
| </button> |
| <button class="upscale-btn hidden bg-red-600 hover:bg-red-700 text-white p-1 rounded-full w-7 h-7 flex items-center justify-center"> |
| <i class="fas fa-expand text-xs"></i> |
| </button> |
| </div> |
| </div> |
| <div id="output-2" class="image-placeholder rounded-lg h-40 flex items-center justify-center relative"> |
| <span class="text-gray-400">Stable Diffusion 2.1</span> |
| <div class="absolute bottom-2 right-2 flex space-x-1"> |
| <button class="download-btn hidden bg-gray-800 hover:bg-gray-700 text-white p-1 rounded-full w-7 h-7 flex items-center justify-center"> |
| <i class="fas fa-download text-xs"></i> |
| </button> |
| <button class="upscale-btn hidden bg-red-600 hover:bg-red-700 text-white p-1 rounded-full w-7 h-7 flex items-center justify-center"> |
| <i class="fas fa-expand text-xs"></i> |
| </button> |
| </div> |
| </div> |
| <div id="output-3" class="image-placeholder rounded-lg h-40 flex items-center justify-center relative"> |
| <span class="text-gray-400">Output 3</span> |
| <div class="absolute bottom-2 right-2 flex space-x-1"> |
| <button class="download-btn hidden bg-gray-800 hover:bg-gray-700 text-white p-1 rounded-full w-7 h-7 flex items-center justify-center"> |
| <i class="fas fa-download text-xs"></i> |
| </button> |
| <button class="upscale-btn hidden bg-red-600 hover:bg-red-700 text-white p-1 rounded-full w-7 h-7 flex items-center justify-center"> |
| <i class="fas fa-expand text-xs"></i> |
| </button> |
| </div> |
| </div> |
| <div id="output-4" class="image-placeholder rounded-lg h-40 flex items-center justify-center relative"> |
| <span class="text-gray-400">Output 4</span> |
| <div class="absolute bottom-2 right-2 flex space-x-1"> |
| <button class="download-btn hidden bg-gray-800 hover:bg-gray-700 text-white p-1 rounded-full w-7 h-7 flex items-center justify-center"> |
| <i class="fas fa-download text-xs"></i> |
| </button> |
| <button class="upscale-btn hidden bg-red-600 hover:bg-red-700 text-white p-1 rounded-full w-7 h-7 flex items-center justify-center"> |
| <i class="fas fa-expand text-xs"></i> |
| </button> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div class="bg-gray-700 p-4 rounded-lg"> |
| <div class="flex items-center justify-between mb-3"> |
| <h3 class="text-white font-medium">Your Inferno Gallery</h3> |
| <div class="flex space-x-2"> |
| <button id="clear-gallery" class="text-gray-400 hover:text-gray-300 text-sm font-medium"> |
| <i class="fas fa-trash-alt mr-1"></i> Clear |
| </button> |
| <button id="download-all" class="text-gray-400 hover:text-gray-300 text-sm font-medium"> |
| <i class="fas fa-download mr-1"></i> Download All |
| </button> |
| </div> |
| </div> |
| <div id="gallery-container" class="grid grid-cols-2 gap-2"> |
| |
| </div> |
| |
| <div id="gallery-pagination" class="mt-4 flex justify-center space-x-1 hidden"> |
| <button class="pagination-btn px-3 py-1 rounded bg-gray-600 hover:bg-gray-500">1</button> |
| <button class="pagination-btn px-3 py-1 rounded bg-gray-600 hover:bg-gray-500">2</button> |
| <button class="pagination-btn px-3 py-1 rounded bg-gray-600 hover:bg-gray-500">3</button> |
| <span class="px-3 py-1">...</span> |
| <button class="pagination-btn px-3 py-1 rounded bg-gray-600 hover:bg-gray-500">10</button> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div id="single-model-content" class="p-6 hidden"> |
| |
| |
| </div> |
|
|
| |
| <div id="batch-content" class="p-6 hidden"> |
| |
| </div> |
|
|
| |
| <div id="settings-content" class="p-6 hidden"> |
| |
| </div> |
| </div> |
| </main> |
|
|
| |
| <footer class="bg-gray-800 py-6 mt-12"> |
| <div class="container mx-auto px-4"> |
| <div class="flex flex-col md:flex-row justify-between items-center"> |
| <div class="flex items-center space-x-2 mb-4 md:mb-0"> |
| <i class="fas fa-fire text-red-500"></i> |
| <span class="font-bold">INFERNO AI</span> |
| </div> |
| <div class="flex space-x-6"> |
| <a href="#" class="text-gray-400 hover:text-white transition">Terms</a> |
| <a href="#" class="text-gray-400 hover:text-white transition">Privacy</a> |
| <a href="#" class="text-gray-400 hover:text-white transition">API</a> |
| <a href="#" class="text-gray-400 hover:text-white transition">Discord</a> |
| <a href="#" class="text-gray-400 hover:text-white transition">GitHub</a> |
| </div> |
| </div> |
| <div class="mt-4 text-center md:text-left text-gray-500 text-sm"> |
| © 2023 Inferno AI. All generated content is the sole responsibility of the user. |
| </div> |
| </div> |
| </footer> |
|
|
| <script> |
| |
| const state = { |
| darkMode: true, |
| nsfwEnabled: true, |
| selectedModels: ['sd15', 'sd21'], |
| generationQueue: [], |
| galleryItems: [], |
| currentGalleryPage: 1, |
| itemsPerPage: 8, |
| credits: 1000, |
| generationStats: { |
| totalGenerations: 0, |
| totalCost: 0, |
| fastestGeneration: null, |
| longestGeneration: null |
| } |
| }; |
| |
| |
| const elements = { |
| multiModelTab: document.getElementById('multi-model-tab'), |
| singleModelTab: document.getElementById('single-model-tab'), |
| batchTab: document.getElementById('batch-tab'), |
| settingsTab: document.getElementById('settings-tab'), |
| multiModelContent: document.getElementById('multi-model-content'), |
| singleModelContent: document.getElementById('single-model-content'), |
| batchContent: document.getElementById('batch-content'), |
| settingsContent: document.getElementById('settings-content'), |
| nsfwToggle: document.getElementById('nsfw-toggle'), |
| promptInput: document.getElementById('prompt-input'), |
| negativePrompt: document.getElementById('negative-prompt'), |
| randomPromptBtn: document.getElementById('random-prompt'), |
| generateButton: document.getElementById('generate-button'), |
| modelCheckboxes: document.querySelectorAll('.model-checkbox'), |
| randomModelsBtn: document.getElementById('random-models'), |
| clearModelsBtn: document.getElementById('clear-models'), |
| selectedCount: document.getElementById('selected-count'), |
| outputContainers: [ |
| document.getElementById('output-1'), |
| document.getElementById('output-2'), |
| document.getElementById('output-3'), |
| document.getElementById('output-4') |
| ], |
| galleryContainer: document.getElementById('gallery-container'), |
| clearGalleryBtn: document.getElementById('clear-gallery'), |
| downloadAllBtn: document.getElementById('download-all'), |
| galleryPagination: document.getElementById('gallery-pagination'), |
| queueCount: document.getElementById('queue-count'), |
| etaTime: document.getElementById('eta-time'), |
| generationCost: document.getElementById('generation-cost'), |
| darkModeToggle: document.getElementById('dark-mode-toggle'), |
| toastContainer: document.getElementById('toast-container'), |
| widthSlider: document.querySelector('input[type="range"][id^="width"]'), |
| heightSlider: document.querySelector('input[type="range"][id^="height"]'), |
| stepsSlider: document.querySelector('input[type="range"][id^="steps"]'), |
| cfgSlider: document.querySelector('input[type="range"][id^="cfg"]'), |
| widthValue: document.getElementById('width-value'), |
| heightValue: document.getElementById('height-value'), |
| stepsValue: document.getElementById('steps-value'), |
| cfgValue: document.getElementById('cfg-value'), |
| seedInput: document.getElementById('seed-input'), |
| randomizeSeed: document.getElementById('randomize-seed'), |
| samplerSelect: document.getElementById('sampler-select') |
| }; |
| |
| |
| const nsfwPrompts = [ |
| "A voluptuous succubus with glowing red eyes and leathery wings seductively lounges on a throne of bones, her curvaceous form barely concealed by wisps of shadow, hyper-detailed, cinematic lighting", |
| "A muscular werewolf in mid-transformation pins down a trembling victim, his claws digging into their flesh as drool drips from his fangs, ultra-realistic, dark fantasy", |
| "A cybernetic dominatrix in a skin-tight latex suit wields a plasma whip, her augmented eyes scanning the neon-lit dungeon for her next plaything, 8K, hyper-detailed", |
| "An elven princess bound in enchanted vines struggles against her restraints as dark magic swirls around her naked form, fantasy art, highly detailed", |
| "A post-apocalyptic warrior woman with scarred skin and mechanical limbs stands atop a ruined tank, her plasma rifle glowing as mutants swarm below, sci-fi, ultra-detailed" |
| ]; |
| |
| |
| const sfwPrompts = [ |
| "A majestic dragon soars over a medieval castle at sunset, its scales shimmering in the golden light, fantasy art, highly detailed", |
| "An astronaut floating in space gazes at Earth with wonder, the planet reflected in their visor, ultra-realistic, cinematic", |
| "A cyberpunk street at night with neon signs reflecting on wet pavement, bustling with futuristic crowds, 8K, hyper-detailed", |
| "A tranquil Japanese garden in autumn with a wooden bridge over a koi pond, cherry blossoms falling, peaceful atmosphere", |
| "A steampunk airship navigates through clouds with intricate brass mechanisms visible, Victorian era aesthetic, detailed" |
| ]; |
| |
| |
| function init() { |
| setupEventListeners(); |
| updateSelectedCount(); |
| updateSliderValues(); |
| loadGalleryFromStorage(); |
| renderGallery(); |
| } |
| |
| |
| function setupEventListeners() { |
| |
| elements.multiModelTab.addEventListener('click', () => switchTab('multi')); |
| elements.singleModelTab.addEventListener('click', () => switchTab('single')); |
| elements.batchTab.addEventListener('click', () => switchTab('batch')); |
| elements.settingsTab.addEventListener('click', () => switchTab('settings')); |
| |
| |
| elements.nsfwToggle.addEventListener('change', toggleNSFW); |
| |
| |
| elements.randomPromptBtn.addEventListener('click', generateRandomPrompt); |
| |
| |
| elements.modelCheckboxes.forEach(checkbox => { |
| checkbox.addEventListener('change', handleModelSelection); |
| }); |
| elements.randomModelsBtn.addEventListener('click', randomizeModels); |
| elements.clearModelsBtn.addEventListener('click', clearModelSelection); |
| |
| |
| elements.generateButton.addEventListener('click', startGeneration); |
| |
| |
| elements.clearGalleryBtn.addEventListener('click', clearGallery); |
| elements.downloadAllBtn.addEventListener('click', downloadAllGalleryItems); |
| |
| |
| elements.widthSlider.addEventListener('input', () => updateSliderValue('width')); |
| elements.heightSlider.addEventListener('input', () => updateSliderValue('height')); |
| elements.stepsSlider.addEventListener('input', () => updateSliderValue('steps')); |
| elements.cfgSlider.addEventListener('input', () => updateSliderValue('cfg')); |
| |
| |
| elements.randomizeSeed.addEventListener('click', randomizeSeed); |
| |
| |
| elements.darkModeToggle.addEventListener('click', toggleDarkMode); |
| |
| |
| document.getElementById('advanced-settings-toggle').addEventListener('click', toggleAdvancedSettings); |
| } |
| |
| |
| function switchTab(tab) { |
| |
| elements.multiModelContent.classList.add('hidden'); |
| elements.singleModelContent.classList.add('hidden'); |
| elements.batchContent.classList.add('hidden'); |
| elements.settingsContent.classList.add('hidden'); |
| |
| |
| elements.multiModelTab.classList.remove('tab-active'); |
| elements.singleModelTab.classList.remove('tab-active'); |
| elements.batchTab.classList.remove('tab-active'); |
| elements.settingsTab.classList.remove('tab-active'); |
| |
| |
| switch(tab) { |
| case 'multi': |
| elements.multiModelContent.classList.remove('hidden'); |
| elements.multiModelTab.classList.add('tab-active'); |
| break; |
| case 'single': |
| elements.singleModelContent.classList.remove('hidden'); |
| elements.singleModelTab.classList.add('tab-active'); |
| break; |
| case 'batch': |
| elements.batchContent.classList.remove('hidden'); |
| elements.batchTab.classList.add('tab-active'); |
| break; |
| case 'settings': |
| elements.settingsContent.classList.remove('hidden'); |
| elements.settingsTab.classList.add('tab-active'); |
| break; |
| } |
| } |
| |
| |
| function toggleNSFW() { |
| state.nsfwEnabled = elements.nsfwToggle.checked; |
| showToast(state.nsfwEnabled ? 'NSFW mode activated. Let your imagination run wild.' : 'NSFW mode deactivated. Keeping it clean.', state.nsfwEnabled ? 'warning' : 'success'); |
| } |
| |
| |
| function generateRandomPrompt() { |
| const prompts = state.nsfwEnabled ? nsfwPrompts : sfwPrompts; |
| const randomPrompt = prompts[Math.floor(Math.random() * prompts.length)]; |
| elements.promptInput.value = randomPrompt; |
| showToast('Prompt randomized. Let the chaos begin.', 'info'); |
| } |
| |
| |
| function handleModelSelection(e) { |
| const model = e.target.dataset.model; |
| const isChecked = e.target.checked; |
| |
| if (isChecked) { |
| if (state.selectedModels.length >= 4) { |
| e.target.checked = false; |
| showToast('Maximum of 4 models can be selected at once. Remove some first.', 'error'); |
| return; |
| } |
| state.selectedModels.push(model); |
| } else { |
| state.selectedModels = state.selectedModels.filter(m => m !== model); |
| } |
| |
| |
| const card = e.target.closest('.model-card'); |
| if (isChecked) { |
| card.classList.add('selected'); |
| } else { |
| card.classList.remove('selected'); |
| } |
| |
| updateSelectedCount(); |
| } |
| |
| |
| function randomizeModels() { |
| |
| elements.modelCheckboxes.forEach(checkbox => { |
| checkbox.checked = false; |
| checkbox.closest('.model-card').classList.remove('selected'); |
| }); |
| |
| |
| const allModels = Array.from(elements.modelCheckboxes).map(cb => cb.dataset.model); |
| const numModels = Math.floor(Math.random() * 3) + 2; |
| state.selectedModels = []; |
| |
| for (let i = 0; i < numModels; i++) { |
| let randomModel; |
| do { |
| randomModel = allModels[Math.floor(Math.random() * allModels.length)]; |
| } while (state.selectedModels.includes(randomModel)); |
| |
| state.selectedModels.push(randomModel); |
| const checkbox = document.querySelector(`.model-checkbox[data-model="${randomModel}"]`); |
| checkbox.checked = true; |
| checkbox.closest('.model-card').classList.add('selected'); |
| } |
| |
| updateSelectedCount(); |
| showToast(`Randomly selected ${numModels} models. Roll the dice!`, 'info'); |
| } |
| |
| |
| function clearModelSelection() { |
| elements.modelCheckboxes.forEach(checkbox => { |
| checkbox.checked = false; |
| checkbox.closest('.model-card').classList.remove('selected'); |
| }); |
| state.selectedModels = []; |
| updateSelectedCount(); |
| showToast('All models deselected. Clean slate.', 'info'); |
| } |
| |
| |
| function updateSelectedCount() { |
| elements.selectedCount.textContent = `${state.selectedModels.length}/4 selected`; |
| if (state.selectedModels.length === 4) { |
| elements.selectedCount.classList.add('bg-red-600'); |
| } else { |
| elements.selectedCount.classList.remove('bg-red-600'); |
| } |
| } |
| |
| |
| function startGeneration() { |
| if (state.selectedModels.length === 0) { |
| showToast('Select at least one model to generate images.', 'error'); |
| return; |
| } |
| |
| if (elements.promptInput.value.trim() === '') { |
| showToast('Enter a prompt to generate images. Your imagination is the limit.', 'error'); |
| return; |
| } |
| |
| |
| elements.generateButton.disabled = true; |
| elements.generateButton.innerHTML = '<i class="fas fa-spinner loading-spinner mr-2"></i> IGNITING...'; |
| |
| |
| const params = { |
| prompt: elements.promptInput.value, |
| negativePrompt: elements.negativePrompt.value, |
| width: parseInt(elements.widthValue.textContent), |
| height: parseInt(elements.heightValue.textContent), |
| steps: parseInt(elements.stepsValue.textContent), |
| cfg: parseFloat(elements.cfgValue.textContent), |
| seed: elements.seedInput.value === '-1' ? Math.floor(Math.random() * 4294967295) : parseInt(elements.seedInput.value), |
| sampler: elements.samplerSelect.value, |
| nsfw: state.nsfwEnabled |
| }; |
| |
| |
| state.generationQueue = [...state.selectedModels]; |
| updateQueueDisplay(); |
| |
| |
| state.selectedModels.forEach((model, index) => { |
| setTimeout(() => { |
| simulateGeneration(model, params, index); |
| }, index * 2000); |
| }); |
| |
| |
| const cost = state.selectedModels.length * 5; |
| state.credits -= cost; |
| showToast(`Generation started. ${cost} credits deducted.`, 'info'); |
| } |
| |
| |
| function simulateGeneration(model, params, index) { |
| |
| state.generationQueue = state.generationQueue.filter(m => m !== model); |
| updateQueueDisplay(); |
| |
| |
| const outputContainer = elements.outputContainers[index]; |
| outputContainer.innerHTML = ` |
| <div class="absolute inset-0 bg-black bg-opacity-70 flex flex-col items-center justify-center rounded-lg"> |
| <i class="fas fa-spinner loading-spinner text-red-500 text-2xl mb-2"></i> |
| <span class="text-white text-sm">Generating with ${getModelName(model)}...</span> |
| <span class="text-gray-400 text-xs mt-1">ETA: ${Math.floor(Math.random() * 10) + 5}s</span> |
| </div> |
| `; |
| |
| |
| const generationTime = Math.floor(Math.random() * 3000) + 2000; |
| |
| setTimeout(() => { |
| |
| if (Math.random() < 0.1) { |
| simulateFailedGeneration(model, index); |
| return; |
| } |
| |
| |
| const imageUrl = getRandomImageUrl(); |
| outputContainer.innerHTML = ` |
| <img src="${imageUrl}" class="w-full h-full object-cover rounded-lg"> |
| <div class="absolute bottom-2 right-2 flex space-x-1"> |
| <button class="download-btn bg-gray-800 hover:bg-gray-700 text-white p-1 rounded-full w-7 h-7 flex items-center justify-center"> |
| <i class="fas fa-download text-xs"></i> |
| </button> |
| <button class="upscale-btn bg-red-600 hover:bg-red-700 text-white p-1 rounded-full w-7 h-7 flex items-center justify-center"> |
| <i class="fas fa-expand text-xs"></i> |
| </button> |
| </div> |
| <div class="absolute top-2 left-2 bg-black bg-opacity-70 text-white text-xs px-2 py-1 rounded"> |
| ${getModelName(model)} |
| </div> |
| `; |
| |
| |
| const galleryItem = { |
| id: Date.now(), |
| model, |
| prompt: params.prompt, |
| imageUrl, |
| timestamp: new Date().toISOString(), |
| params |
| }; |
| state.galleryItems.unshift(galleryItem); |
| saveGalleryToStorage(); |
| renderGallery(); |
| |
| |
| if (state.generationQueue.length === 0) { |
| elements.generateButton.disabled = false; |
| elements.generateButton.innerHTML = '<i class="fas fa-fire mr-2"></i> IGNITE CREATION'; |
| } |
| |
| |
| setupImageButtons(outputContainer, galleryItem); |
| }, generationTime); |
| } |
| |
| |
| function simulateFailedGeneration(model, index) { |
| const outputContainer = elements.outputContainers[index]; |
| outputContainer.innerHTML = ` |
| <div class="absolute inset-0 bg-black bg-opacity-70 flex flex-col items-center justify-center rounded-lg"> |
| <i class="fas fa-exclamation-triangle text-red-500 text-2xl mb-2"></i> |
| <span class="text-white text-sm">Generation failed</span> |
| <span class="text-gray-400 text-xs mt-1">${getModelName(model)}</span> |
| <button class="retry-btn mt-2 text-xs bg-red-600 hover:bg-red-700 text-white px-2 py-1 rounded"> |
| Retry |
| </button> |
| </div> |
| `; |
| |
| |
| outputContainer.querySelector('.retry-btn').addEventListener('click', () => { |
| state.generationQueue.push(model); |
| updateQueueDisplay(); |
| simulateGeneration(model, {}, index); |
| }); |
| |
| |
| if (state.generationQueue.length === 0) { |
| elements.generateButton.disabled = false; |
| elements.generateButton.innerHTML = '<i class="fas fa-fire mr-2"></i> IGNITE CREATION'; |
| } |
| |
| showToast(`Generation failed for ${getModelName(model)}. The demons resisted your call.`, 'error'); |
| } |
| |
| |
| function updateQueueDisplay() { |
| elements.queueCount.textContent = state.generationQueue.length; |
| |
| if (state.generationQueue.length > 0) { |
| const eta = state.generationQueue.length * 5 + Math.floor(Math.random() * 10); |
| elements.etaTime.textContent = `${eta}s`; |
| elements.generationCost.textContent = (state.generationQueue.length * 5).toFixed(2); |
| } else { |
| elements.etaTime.textContent = '-'; |
| elements.generationCost.textContent = '0.00'; |
| } |
| } |
| |
| |
| function getModelName(modelId) { |
| const modelNames = { |
| 'sd15': 'Stable Diffusion 1.5', |
| 'sd21': 'Stable Diffusion 2.1', |
| 'openjourney': 'OpenJourney', |
| 'dreamlike': 'Dreamlike', |
| 'anything': 'Anything V3', |
| 'deliberate': 'Deliberate', |
| 'realistic': 'Realistic Vision', |
| 'hentai': 'Hentai Diffusion', |
| 'waifu': 'Waifu Diffusion' |
| }; |
| return modelNames[modelId] || modelId; |
| } |
| |
| |
| function getRandomImageUrl() { |
| const randomNum = Math.floor(Math.random() * 1000); |
| return `https://picsum.photos/800/800?random=${randomNum}`; |
| } |
| |
| |
| function setupImageButtons(container, galleryItem) { |
| container.querySelector('.download-btn').addEventListener('click', () => { |
| downloadImage(galleryItem.imageUrl, `inferno-${galleryItem.model}-${galleryItem.id}.jpg`); |
| showToast('Image downloaded. Treasure your creation.', 'success'); |
| }); |
| |
| container.querySelector('.upscale-btn').addEventListener('click', () => { |
| showToast(`Upscaling image generated with ${getModelName(galleryItem.model)}...`, 'info'); |
| |
| }); |
| } |
| |
| |
| function downloadImage(url, filename) { |
| const a = document.createElement('a'); |
| a.href = url; |
| a.download = filename; |
| document.body.appendChild(a); |
| a.click(); |
| document.body.removeChild(a); |
| } |
| |
| |
| function loadGalleryFromStorage() { |
| const savedGallery = localStorage.getItem('infernoGallery'); |
| if (savedGallery) { |
| try { |
| state.galleryItems = JSON.parse(savedGallery); |
| } catch (e) { |
| console.error('Failed to parse gallery data', e); |
| state.galleryItems = []; |
| } |
| } |
| } |
| |
| |
| function saveGalleryToStorage() { |
| localStorage.setItem('infernoGallery', JSON.stringify(state.galleryItems)); |
| } |
| |
| |
| function renderGallery() { |
| elements.galleryContainer.innerHTML = ''; |
| |
| if (state.galleryItems.length === 0) { |
| elements.galleryContainer.innerHTML = ` |
| <div class="col-span-2 py-8 text-center"> |
| <i class="fas fa-fire text-gray-600 text-3xl mb-2"></i> |
| <p class="text-gray-500">Your gallery is empty. Ignite some creations!</p> |
| </div> |
| `; |
| elements.galleryPagination.classList.add('hidden'); |
| return; |
| } |
| |
| |
| const totalPages = Math.ceil(state.galleryItems.length / state.itemsPerPage); |
| const startIndex = (state.currentGalleryPage - 1) * state.itemsPerPage; |
| const endIndex = Math.min(startIndex + state.itemsPerPage, state.galleryItems.length); |
| const itemsToShow = state.galleryItems.slice(startIndex, endIndex); |
| |
| |
| itemsToShow.forEach(item => { |
| const galleryItemElement = document.createElement('div'); |
| galleryItemElement.className = 'bg-gray-800 border border-gray-700 rounded-lg overflow-hidden relative group'; |
| galleryItemElement.innerHTML = ` |
| <img src="${item.imageUrl}" class="w-full h-32 object-cover"> |
| <div class="p-2"> |
| <p class="text-xs text-gray-300 truncate">${item.prompt.substring(0, 40)}${item.prompt.length > 40 ? '...' : ''}</p> |
| <p class="text-xs text-gray-500">${getModelName(item.model)}</p> |
| </div> |
| <div class="absolute inset-0 bg-black bg-opacity-0 group-hover:bg-opacity-60 transition flex items-center justify-center space-x-2 opacity-0 group-hover:opacity-100"> |
| <button class="download-btn bg-gray-800 hover:bg-gray-700 text-white p-2 rounded-full w-10 h-10 flex items-center justify-center"> |
| <i class="fas fa-download"></i> |
| </button> |
| <button class="upscale-btn bg-red-600 hover:bg-red-700 text-white p-2 rounded-full w-10 h-10 flex items-center justify-center"> |
| <i class="fas fa-expand"></i> |
| </button> |
| <button class="delete-btn bg-gray-800 hover:bg-red-600 text-white p-2 rounded-full w-10 h-10 flex items-center justify-center"> |
| <i class="fas fa-trash"></i> |
| </button> |
| </div> |
| `; |
| elements.galleryContainer.appendChild(galleryItemElement); |
| |
| |
| galleryItemElement.querySelector('.download-btn').addEventListener('click', () => { |
| downloadImage(item.imageUrl, `inferno-${item.model}-${item.id}.jpg`); |
| showToast('Image downloaded. Another trophy for your collection.', 'success'); |
| }); |
| |
| galleryItemElement.querySelector('.upscale-btn').addEventListener('click', () => { |
| showToast(`Upscaling image generated with ${getModelName(item.model)}...`, 'info'); |
| }); |
| |
| galleryItemElement.querySelector('.delete-btn').addEventListener('click', () => { |
| state.galleryItems = state.galleryItems.filter(i => i.id !== item.id); |
| saveGalleryToStorage(); |
| renderGallery(); |
| showToast('Image deleted. Reduced to ashes.', 'info'); |
| }); |
| }); |
| |
| |
| if (totalPages > 1) { |
| elements.galleryPagination.classList.remove('hidden'); |
| elements.galleryPagination.innerHTML = ''; |
| |
| |
| if (state.currentGalleryPage > 1) { |
| const prevBtn = document.createElement('button'); |
| prevBtn.className = 'pagination-btn px-3 py-1 rounded bg-gray-600 hover:bg-gray-500'; |
| prevBtn.innerHTML = '<i class="fas fa-chevron-left"></i>'; |
| prevBtn.addEventListener('click', () => { |
| state.currentGalleryPage--; |
| renderGallery(); |
| }); |
| elements.galleryPagination.appendChild(prevBtn); |
| } |
| |
| |
| const maxVisiblePages = 5; |
| let startPage = Math.max(1, state.currentGalleryPage - Math.floor(maxVisiblePages / 2)); |
| let endPage = Math.min(totalPages, startPage + maxVisiblePages - 1); |
| |
| if (endPage - startPage + 1 < maxVisiblePages) { |
| startPage = Math.max(1, endPage - maxVisiblePages + 1); |
| } |
| |
| if (startPage > 1) { |
| const firstBtn = document.createElement('button'); |
| firstBtn.className = 'pagination-btn px-3 py-1 rounded bg-gray-600 hover:bg-gray-500'; |
| firstBtn.textContent = '1'; |
| firstBtn.addEventListener('click', () => { |
| state.currentGalleryPage = 1; |
| renderGallery(); |
| }); |
| elements.galleryPagination.appendChild(firstBtn); |
| |
| if (startPage > 2) { |
| const ellipsis = document.createElement('span'); |
| ellipsis.className = 'px-3 py-1'; |
| ellipsis.textContent = '...'; |
| elements.galleryPagination.appendChild(ellipsis); |
| } |
| } |
| |
| for (let i = startPage; i <= endPage; i++) { |
| const pageBtn = document.createElement('button'); |
| pageBtn.className = `pagination-btn px-3 py-1 rounded ${i === state.currentGalleryPage ? 'bg-red-600 text-white' : 'bg-gray-600 hover:bg-gray-500'}`; |
| pageBtn.textContent = i; |
| pageBtn.addEventListener('click', () => { |
| state.currentGalleryPage = i; |
| renderGallery(); |
| }); |
| elements.galleryPagination.appendChild(pageBtn); |
| } |
| |
| if (endPage < totalPages) { |
| if (endPage < totalPages - 1) { |
| const ellipsis = document.createElement('span'); |
| ellipsis.className = 'px-3 py-1'; |
| ellipsis.textContent = '...'; |
| elements.galleryPagination.appendChild(ellipsis); |
| } |
| |
| const lastBtn = document.createElement('button'); |
| lastBtn.className = 'pagination-btn px-3 py-1 rounded bg-gray-600 hover:bg-gray-500'; |
| lastBtn.textContent = totalPages; |
| lastBtn.addEventListener('click', () => { |
| state.currentGalleryPage = totalPages; |
| renderGallery(); |
| }); |
| elements.galleryPagination.appendChild(lastBtn); |
| } |
| |
| |
| if (state.currentGalleryPage < totalPages) { |
| const nextBtn = document.createElement('button'); |
| nextBtn.className = 'pagination-btn px-3 py-1 rounded bg-gray-600 hover:bg-gray-500'; |
| nextBtn.innerHTML = '<i class="fas fa-chevron-right"></i>'; |
| nextBtn.addEventListener('click', () => { |
| state.currentGalleryPage++; |
| renderGallery(); |
| }); |
| elements.galleryPagination.appendChild(nextBtn); |
| } |
| } else { |
| elements.galleryPagination.classList.add('hidden'); |
| } |
| } |
| |
| |
| function clearGallery() { |
| if (state.galleryItems.length === 0) return; |
| |
| if (confirm('Burn your entire gallery to ashes? This cannot be undone.')) { |
| state.galleryItems = []; |
| saveGalleryToStorage(); |
| renderGallery(); |
| showToast('Gallery purged. All creations reduced to dust.', 'warning'); |
| } |
| } |
| |
| |
| function downloadAllGalleryItems() { |
| if (state.galleryItems.length === 0) { |
| showToast('Your gallery is empty. Nothing to download.', 'error'); |
| return; |
| } |
| |
| showToast('Preparing your collection for download...', 'info'); |
| |
| setTimeout(() => { |
| showToast('Download complete. Your dark creations are now yours forever.', 'success'); |
| }, 2000); |
| } |
| |
| |
| function updateSliderValues() { |
| updateSliderValue('width'); |
| updateSliderValue('height'); |
| updateSliderValue('steps'); |
| updateSliderValue('cfg'); |
| } |
| |
| |
| function updateSliderValue(type) { |
| const slider = elements[`${type}Slider`]; |
| const valueElement = elements[`${type}Value`]; |
| valueElement.textContent = slider.value; |
| } |
| |
| |
| function randomizeSeed() { |
| const newSeed = Math.floor(Math.random() * 4294967295); |
| elements.seedInput.value = newSeed; |
| showToast(`Seed randomized: ${newSeed}. New possibilities await.`, 'info'); |
| } |
| |
| |
| function toggleDarkMode() { |
| state.darkMode = !state.darkMode; |
| if (state.darkMode) { |
| document.body.classList.add('bg-gray-900', 'text-gray-100'); |
| document.body.classList.remove('bg-gray-100', 'text-gray-900'); |
| elements.darkModeToggle.innerHTML = '<i class="fas fa-moon"></i>'; |
| showToast('Dark mode activated. The shadows welcome you.', 'info'); |
| } else { |
| document.body.classList.remove('bg-gray-900', 'text-gray-100'); |
| document.body.classList.add('bg-gray-100', 'text-gray-900'); |
| elements.darkModeToggle.innerHTML = '<i class="fas fa-sun"></i>'; |
| showToast('Light mode activated. The brightness burns.', 'warning'); |
| } |
| } |
| |
| |
| function toggleAdvancedSettings() { |
| const content = document.getElementById('advanced-settings-content'); |
| const icon = document.querySelector('#advanced-settings-toggle i'); |
| |
| content.classList.toggle('hidden'); |
| icon.classList.toggle('rotate-180'); |
| } |
| |
| |
| function showToast(message, type = 'info') { |
| const toast = document.createElement('div'); |
| const types = { |
| 'info': { bg: 'bg-gray-700', icon: 'fa-info-circle' }, |
| 'success': { bg: 'bg-green-700', icon: 'fa-check-circle' }, |
| 'warning': { bg: 'bg-yellow-700', icon: 'fa-exclamation-circle' }, |
| 'error': { bg: 'bg-red-700', icon: 'fa-times-circle' } |
| }; |
| |
| toast.className = `error-toast ${types[type].bg} text-white px-4 py-3 rounded-lg shadow-lg flex items-start max-w-md`; |
| toast.innerHTML = ` |
| <i class="fas ${types[type].icon} mr-2 mt-0.5"></i> |
| <span>${message}</span> |
| `; |
| |
| elements.toastContainer.appendChild(toast); |
| |
| |
| setTimeout(() => { |
| toast.remove(); |
| }, 3000); |
| } |
| |
| |
| document.addEventListener('DOMContentLoaded', init); |
| </script> |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=Boobs00/inferno" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
| </html> |