flux2-quantization / index.html
multimodalart's picture
Upload 640 files
ba939f0 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Quantization Comparison</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Monaco', 'Courier New', monospace;
background: #0a0a0a;
color: #e0e0e0;
padding: 20px;
line-height: 1.6;
}
.container {
max-width: 800px;
margin: 0 auto;
}
h1 {
text-align: center;
font-size: 24px;
font-weight: 300;
margin-bottom: 10px;
letter-spacing: 2px;
color: #ffffff;
}
.subtitle {
text-align: center;
font-size: 12px;
color: #888;
margin-bottom: 20px;
}
.controls {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 15px;
margin-bottom: 15px;
}
.control-group {
background: #151515;
padding: 20px;
border: 1px solid #333;
}
.control-label {
font-size: 11px;
text-transform: uppercase;
letter-spacing: 1px;
color: #999;
margin-bottom: 15px;
}
input[type="range"] {
width: 100%;
height: 2px;
background: #333;
outline: none;
-webkit-appearance: none;
}
input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 16px;
height: 16px;
background: #fff;
cursor: pointer;
border-radius: 50%;
}
input[type="range"]::-moz-range-thumb {
width: 16px;
height: 16px;
background: #fff;
cursor: pointer;
border-radius: 50%;
border: none;
}
.slider-value {
text-align: center;
font-size: 14px;
margin-top: 10px;
color: #fff;
font-weight: bold;
}
.main-display {
display: grid;
grid-template-columns: 300px 1fr;
gap: 20px;
margin-bottom: 15px;
}
.input-images-panel {
background: #151515;
border: 1px solid #333;
padding: 20px;
}
.panel-header {
font-size: 11px;
text-transform: uppercase;
letter-spacing: 1px;
color: #999;
margin-bottom: 15px;
text-align: center;
}
.input-image-grid {
display: flex;
flex-direction: column;
gap: 10px;
}
.input-image-item {
background: #0a0a0a;
padding: 10px;
border: 1px solid #222;
}
.input-image-item img {
width: 100%;
display: block;
margin-bottom: 5px;
}
.input-image-label {
font-size: 10px;
color: #666;
text-align: center;
}
.no-input-images {
color: #444;
font-size: 12px;
text-align: center;
padding: 40px 20px;
}
.output-display {
background: #151515;
border: 1px solid #333;
padding: 20px;
}
.image-container {
width: 100%;
aspect-ratio: 1 / 1;
display: flex;
align-items: center;
justify-content: center;
background: #0a0a0a;
margin-bottom: 15px;
position: relative;
}
.image-container img {
max-width: 100%;
max-height: 100%;
object-fit: contain;
}
.image-info {
padding: 15px;
background: #0a0a0a;
border-left: 2px solid #444;
font-size: 12px;
color: #aaa;
display: none;
}
.info-row {
margin-bottom: 5px;
}
.info-label {
color: #666;
display: inline-block;
width: 150px;
}
.info-value {
color: #fff;
}
.prompt-display {
background: #151515;
border: 1px solid #333;
padding: 20px;
margin-bottom: 15px;
}
.prompt-nav-inline {
display: flex;
align-items: center;
gap: 15px;
}
.nav-button-inline {
background: #222;
border: 1px solid #444;
color: #fff;
padding: 12px 20px;
cursor: pointer;
font-family: inherit;
font-size: 18px;
transition: all 0.2s;
flex-shrink: 0;
min-width: 50px;
}
.nav-button-inline:hover:not(:disabled) {
background: #333;
border-color: #666;
}
.nav-button-inline:disabled {
opacity: 0.3;
cursor: not-allowed;
}
.prompt-text-inline {
flex: 1;
}
.prompt-text {
font-size: 14px;
line-height: 1.8;
color: #fff;
margin-bottom: 8px;
}
.prompt-counter {
font-size: 11px;
color: #666;
}
.error-message {
color: #ff6666;
text-align: center;
padding: 20px;
}
.keyboard-hint {
text-align: center;
font-size: 10px;
color: #acacac;
margin-bottom: 15px;
}
/* Gallery mode styles */
.gallery-overlay {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background: rgba(0, 0, 0, 0.95);
z-index: 1000;
overflow: auto;
}
.gallery-overlay.active {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 40px 20px;
}
.gallery-content-wrapper {
display: flex;
flex-direction: row;
align-items: flex-start;
justify-content: center;
gap: 15px;
max-width: 90vw;
}
.gallery-input-images {
display: none;
flex-direction: column;
gap: 10px;
max-width: 180px;
max-height: 70vh;
overflow-y: auto;
padding-right: 5px;
}
.gallery-input-images.visible {
display: flex;
}
.gallery-input-images::-webkit-scrollbar {
width: 6px;
}
.gallery-input-images::-webkit-scrollbar-track {
background: #1a1a1a;
}
.gallery-input-images::-webkit-scrollbar-thumb {
background: #444;
border-radius: 3px;
}
.gallery-input-images::-webkit-scrollbar-thumb:hover {
background: #666;
}
.gallery-input-header {
font-size: 9px;
text-transform: uppercase;
letter-spacing: 0.5px;
color: #666;
text-align: center;
margin-bottom: 5px;
padding-bottom: 10px;
border-bottom: 1px solid #333;
}
.gallery-input-item {
background: #151515;
border: 1px solid #333;
padding: 10px;
}
.gallery-input-item img {
width: 100%;
display: block;
margin-bottom: 5px;
}
.gallery-input-label {
font-size: 9px;
color: #666;
text-align: center;
text-transform: uppercase;
}
.gallery-main-content {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
gap: 20px;
position: relative;
}
.gallery-image-container {
max-width: 100%;
max-height: 70vh;
position: relative;
}
.gallery-image-container img {
max-width: 100%;
max-height: 70vh;
object-fit: contain;
display: block;
}
.gallery-info {
max-width: 800px;
width: 100%;
background: #151515;
border: 1px solid #333;
padding: 20px;
color: #e0e0e0;
margin-top: 20px;
}
.gallery-prompt {
font-size: 14px;
line-height: 1.8;
margin-bottom: 15px;
color: #fff;
height: 50px;
position: relative;
cursor: help;
transition: color 0.2s;
}
.gallery-prompt-text {
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
height: 50px;
}
.gallery-prompt:hover {
color: #aaa;
}
.gallery-prompt::before {
content: '';
position: absolute;
right: 0;
bottom: 0;
font-size: 12px;
opacity: 0.5;
}
.gallery-prompt-tooltip {
display: none;
position: absolute;
top: 0;
left: 0;
width: 100%;
background: #0a0a0a;
border: 2px solid #888;
padding: 20px;
color: #fff;
font-size: 14px;
line-height: 1.8;
z-index: 10001;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.8);
}
/* Desktop: hover */
@media (hover: hover) and (pointer: fine) {
.gallery-prompt:hover .gallery-prompt-tooltip {
display: block;
}
}
/* Mobile: click/tap */
@media (hover: none) or (pointer: coarse) {
.gallery-prompt.active .gallery-prompt-tooltip {
display: block;
}
.gallery-prompt-tooltip-close {
display: flex;
}
}
.gallery-prompt-tooltip-close {
display: none;
position: absolute;
top: 10px;
right: 10px;
background: #222;
border: 1px solid #444;
color: #fff;
width: 24px;
height: 24px;
cursor: pointer;
align-items: center;
justify-content: center;
font-size: 16px;
z-index: 10002;
}
.gallery-prompt-tooltip-close:hover {
background: #333;
}
.gallery-settings {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 15px;
font-size: 12px;
}
.gallery-setting-item {
background: #0a0a0a;
padding: 10px;
border: 1px solid #222;
}
.gallery-setting-label {
color: #666;
font-size: 10px;
margin-bottom: 5px;
}
.gallery-setting-value {
color: #fff;
font-weight: bold;
}
.gallery-close {
position: fixed;
top: 20px;
right: 20px;
background: #222;
border: 1px solid #444;
color: #fff;
font-size: 24px;
width: 40px;
height: 40px;
cursor: pointer;
z-index: 1001;
display: flex;
align-items: center;
justify-content: center;
}
.gallery-close:hover {
background: #333;
border-color: #666;
}
.gallery-nav {
background: rgba(34, 34, 34, 0.9);
border: 1px solid #444;
color: #fff;
font-size: 24px;
width: 50px;
height: 50px;
cursor: pointer;
z-index: 1002;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s;
flex-shrink: 0;
}
.gallery-nav:hover:not(:disabled) {
background: rgba(51, 51, 51, 0.95);
border-color: #666;
}
.gallery-nav:disabled {
opacity: 0.3;
cursor: not-allowed;
}
.expand-icon {
position: absolute;
top: 10px;
right: 10px;
background: rgba(34, 34, 34, 0.8);
border: 1px solid #444;
color: #fff;
font-size: 20px;
width: 36px;
height: 36px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
opacity: 0.6;
transition: all 0.2s;
}
.image-container:hover .expand-icon {
opacity: 1;
background: rgba(34, 34, 34, 0.95);
}
.expand-icon:hover {
background: rgba(51, 51, 51, 0.95);
border-color: #666;
transform: scale(1.1);
}
/* Mobile responsive styles */
@media (max-width: 768px) {
body {
padding: 10px;
}
.container {
max-width: 100%;
}
h1 {
font-size: 18px;
letter-spacing: 1px;
}
.subtitle {
font-size: 10px;
}
.controls {
grid-template-columns: 1fr;
gap: 10px;
}
.control-group {
padding: 15px;
}
.main-display {
grid-template-columns: 1fr;
gap: 15px;
}
.input-images-panel {
order: 2;
}
.output-display {
order: 1;
}
.prompt-text {
font-size: 12px;
}
.nav-button-inline {
padding: 10px 15px;
font-size: 16px;
min-width: 40px;
}
.keyboard-hint {
font-size: 9px;
}
/* Hide gallery input images on mobile */
.gallery-input-images.visible {
display: none !important;
}
.gallery-overlay.active {
padding: 20px 10px;
}
.gallery-content-wrapper {
max-width: 100vw;
}
.gallery-main-content {
max-width: 100% !important;
}
.gallery-image-container {
max-height: 50vh;
}
.gallery-nav {
width: 40px;
height: 40px;
font-size: 20px;
}
.gallery-info {
max-width: 100vw;
}
}
</style>
</head>
<body>
<div class="container">
<h1>QUANTIZATION COMPARISON</h1>
<div class="keyboard-hint">
Keyboard: arrow left/right (prompts) | arrow up/down (text encoder) | A D (transformer) | F (fullscreen)
</div>
<!-- Prompt display with inline navigation -->
<div class="prompt-display">
<div class="panel-header">Current Prompt</div>
<div class="prompt-nav-inline">
<button class="nav-button-inline" id="prevBtn" onclick="changePrompt(-1)">&#8592;</button>
<div class="prompt-text-inline">
<div class="prompt-text" id="promptText">Loading prompts...</div>
<div class="prompt-counter" id="promptCounter">- / -</div>
</div>
<button class="nav-button-inline" id="nextBtn" onclick="changePrompt(1)">&#8594;</button>
</div>
</div>
<!-- Controls -->
<div class="controls">
<div class="control-group">
<div class="control-label">Transformer Quantization</div>
<input type="range" id="transformerSlider" min="0" max="2" step="1" value="0" oninput="updateDisplay()">
<div class="slider-value" id="transformerValue">BF16</div>
</div>
<div class="control-group">
<div class="control-label">Text Encoder Quantization</div>
<input type="range" id="textEncoderSlider" min="0" max="2" step="1" value="0" oninput="updateDisplay()">
<div class="slider-value" id="textEncoderValue">BF16</div>
</div>
</div>
<!-- Main display area -->
<div class="main-display">
<!-- Input images panel -->
<div class="input-images-panel">
<div class="panel-header">Input Images</div>
<div id="inputImagesContainer">
<div class="no-input-images">No input images<br>for this prompt</div>
</div>
</div>
<!-- Output display -->
<div class="output-display">
<div class="panel-header">Generated Output</div>
<div class="image-container" id="imageContainer">
<div class="loading">Loading...</div>
<button class="expand-icon" onclick="openGallery()" title="View fullscreen">&#x26F6;</button>
</div>
<div class="image-info">
<div class="info-row">
<span class="info-label">Configuration:</span>
<span class="info-value" id="configInfo">-</span>
</div>
</div>
<!-- Steps toggle -->
<div style="margin-top: 15px; padding: 15px; background: #0a0a0a; border: 1px solid #222; text-align: center;">
<div style="font-size: 10px; color: #666; margin-bottom: 10px; text-transform: uppercase;">Sampling Steps</div>
<div style="display: flex; gap: 10px; justify-content: center;">
<button class="step-toggle" onclick="setSteps(50)" id="steps50Btn" style="background: #333; border: 1px solid #555; color: #fff; padding: 8px 20px; cursor: pointer; font-family: inherit; font-size: 12px;">50 Steps</button>
<button class="step-toggle" onclick="setSteps(28)" id="steps28Btn" style="background: #222; border: 1px solid #444; color: #fff; padding: 8px 20px; cursor: pointer; font-family: inherit; font-size: 12px;">28 Steps</button>
</div>
</div>
</div>
</div>
<!-- Sampling settings info -->
<div style="margin-top: 15px; padding: 20px; background: #151515; border: 1px solid #333; text-align: center;">
<div style="font-size: 11px; text-transform: uppercase; letter-spacing: 1px; color: #999; margin-bottom: 15px;">Generation Settings (All Images)</div>
<div style="display: grid; grid-template-columns: repeat(4, 1fr); gap: 15px; max-width: 600px; margin: 0 auto;">
<div>
<div style="font-size: 10px; color: #666; margin-bottom: 5px;">IMAGE SIZE</div>
<div style="font-size: 14px; color: #fff;">1024 x 1024</div>
</div>
<div>
<div style="font-size: 10px; color: #666; margin-bottom: 5px;">STEPS</div>
<div style="font-size: 14px; color: #fff;" id="currentStepsDisplay">50</div>
</div>
<div>
<div style="font-size: 10px; color: #666; margin-bottom: 5px;">GUIDANCE</div>
<div style="font-size: 14px; color: #fff;">2.5</div>
</div>
<div>
<div style="font-size: 10px; color: #666; margin-bottom: 5px;">SEED</div>
<div style="font-size: 14px; color: #fff;">42</div>
</div>
</div>
</div>
</div>
<!-- Gallery overlay -->
<div class="gallery-overlay" id="galleryOverlay" onclick="closeGallery(event)">
<button class="gallery-close" onclick="closeGallery(event); event.stopPropagation();">x</button>
<!-- Main content wrapper -->
<div class="gallery-content-wrapper" onclick="event.stopPropagation()">
<!-- Input images panel (left side) -->
<div class="gallery-input-images" id="galleryInputImages" onclick="event.stopPropagation()">
<!-- Will be populated dynamically -->
</div>
<div class="gallery-main-content">
<button class="gallery-nav gallery-nav-left" id="galleryPrevBtn" onclick="changePromptInGallery(-1); event.stopPropagation();">&#8592;</button>
<div class="gallery-image-container" id="galleryImageContainer">
<img id="galleryImage" src="" alt="Fullscreen image">
</div>
<button class="gallery-nav gallery-nav-right" id="galleryNextBtn" onclick="changePromptInGallery(1); event.stopPropagation();">&#8594;</button>
</div>
</div>
<!-- Info panel below -->
<div class="gallery-info" onclick="event.stopPropagation()">
<div class="gallery-prompt" id="galleryPrompt" ontouchstart="togglePromptTooltip(event)">
<div class="gallery-prompt-text" id="galleryPromptText"></div>
<div class="gallery-prompt-tooltip" id="galleryPromptTooltip">
<button class="gallery-prompt-tooltip-close" onclick="closePromptTooltip(event)">x</button>
<div id="galleryPromptFull"></div>
</div>
</div>
<!-- Compact inline controls -->
<div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 15px; margin-top: 15px; padding: 15px; background: #0a0a0a; border: 1px solid #222;">
<!-- Text Encoder -->
<div>
<div style="font-size: 9px; color: #666; margin-bottom: 8px; text-transform: uppercase; letter-spacing: 0.5px;">Text Encoder</div>
<div style="display: flex; gap: 5px;">
<button onclick="setTextEncoderFromGallery(0)" id="galleryTextBF16" style="flex: 1; background: #1a1a1a; border: 1px solid #333; color: #888; padding: 6px 8px; cursor: pointer; font-family: inherit; font-size: 11px; transition: all 0.15s;">BF16</button>
<button onclick="setTextEncoderFromGallery(1)" id="galleryText8bit" style="flex: 1; background: #1a1a1a; border: 1px solid #333; color: #888; padding: 6px 8px; cursor: pointer; font-family: inherit; font-size: 11px; transition: all 0.15s;">8-bit</button>
<button onclick="setTextEncoderFromGallery(2)" id="galleryText4bit" style="flex: 1; background: #1a1a1a; border: 1px solid #333; color: #888; padding: 6px 8px; cursor: pointer; font-family: inherit; font-size: 11px; transition: all 0.15s;">4-bit</button>
</div>
</div>
<!-- Transformer -->
<div>
<div style="font-size: 9px; color: #666; margin-bottom: 8px; text-transform: uppercase; letter-spacing: 0.5px;">Transformer</div>
<div style="display: flex; gap: 5px;">
<button onclick="setTransformerFromGallery(0)" id="galleryTransBF16" style="flex: 1; background: #1a1a1a; border: 1px solid #333; color: #888; padding: 6px 8px; cursor: pointer; font-family: inherit; font-size: 11px; transition: all 0.15s;">BF16</button>
<button onclick="setTransformerFromGallery(1)" id="galleryTrans8bit" style="flex: 1; background: #1a1a1a; border: 1px solid #333; color: #888; padding: 6px 8px; cursor: pointer; font-family: inherit; font-size: 11px; transition: all 0.15s;">8-bit</button>
<button onclick="setTransformerFromGallery(2)" id="galleryTrans4bit" style="flex: 1; background: #1a1a1a; border: 1px solid #333; color: #888; padding: 6px 8px; cursor: pointer; font-family: inherit; font-size: 11px; transition: all 0.15s;">4-bit</button>
</div>
</div>
<!-- Steps -->
<div>
<div style="font-size: 9px; color: #666; margin-bottom: 8px; text-transform: uppercase; letter-spacing: 0.5px;">Steps</div>
<div style="display: flex; gap: 5px;">
<button onclick="setStepsFromGallery(50)" id="gallerySteps50" style="flex: 1; background: #1a1a1a; border: 1px solid #333; color: #888; padding: 6px 8px; cursor: pointer; font-family: inherit; font-size: 11px; transition: all 0.15s;">50</button>
<button onclick="setStepsFromGallery(28)" id="gallerySteps28" style="flex: 1; background: #1a1a1a; border: 1px solid #333; color: #888; padding: 6px 8px; cursor: pointer; font-family: inherit; font-size: 11px; transition: all 0.15s;">28</button>
</div>
</div>
</div>
<!-- Other settings -->
<div style="display: flex; gap: 15px; margin-top: 10px; padding: 10px 15px; background: #0a0a0a; border: 1px solid #222; font-size: 11px;">
<div style="flex: 1;">
<span style="color: #666;">GUIDANCE:</span>
<span style="color: #fff; margin-left: 5px;">2.5</span>
</div>
<div style="flex: 1;">
<span style="color: #666;">SEED:</span>
<span style="color: #fff; margin-left: 5px;">42</span>
</div>
</div>
</div>
</div>
</div>
<script>
// All 35 prompts from 1_generate_embeddings.py
// PROMPTS_FROM_HTML (29 prompts) + PROMPTS_FROM_FILE (6 prompts)
const allPrompts = [
// === PROMPTS_FROM_HTML (29 prompts) ===
// quantization_comparison (8 prompts) - indices 0-7
{ text: "a cat sitting on a windowsill", idx: 0, images: null },
{ text: "a professional photograph of a steaming cup of coffee on a wooden table, morning sunlight streaming through a window, soft shadows, warm tones, shallow depth of field, 50mm lens, f/1.8", idx: 1, images: null },
{ text: "abstract watercolor sunset", idx: 2, images: null },
{ text: "an intricate digital painting in the style of Studio Ghibli, featuring a young girl walking through a magical forest filled with glowing mushrooms, fireflies, and ancient trees with twisted roots, soft lighting, highly detailed, beautiful composition", idx: 3, images: null },
{ text: "a dragon in the clouds", idx: 4, images: null },
{ text: "a majestic crystal palace floating among the clouds at sunset, with waterfalls cascading into the sky, ethereal light rays piercing through, fantasy architecture with intricate spires and bridges, painted in the style of romantic landscape art", idx: 5, images: null },
{ text: "cyberpunk city street at night", idx: 6, images: null },
{ text: "a highly detailed technical illustration of a futuristic spacecraft interior, with holographic displays, sleek metallic surfaces, blue accent lighting, control panels with glowing buttons, science fiction concept art, 4K render, octane render", idx: 7, images: null },
// unified_comparison (14 prompts) - indices 8-21
{ text: "a mecha robot in a favela", idx: 8, images: null },
{ text: "a highly detailed giant mecha robot standing in a Brazilian favela, colorful houses stacked on hillside, dramatic lighting with sunset rays, people looking up in awe, power lines and graffiti, photorealistic, cinematic composition, vibrant colors, urban sci-fi aesthetic", idx: 9, images: null },
{ text: "the spirit of a tamagotchi wandering in the city of Vienna", idx: 10, images: null },
{ text: "a ghostly translucent spirit of a vintage tamagotchi pet floating through the historic streets of Vienna, classical baroque architecture in background, St. Stephen's Cathedral visible, ethereal glow, digital particles trailing, whimsical yet melancholic atmosphere, soft evening light, magical realism", idx: 11, images: null },
{ text: "A wide angle photo of an androgynous model wearing brain computer interface in a fashion show, catwalk, futuristic photo from 1990, analog color", idx: 12, images: null },
{ text: "a wide angle photograph of an androgynous fashion model walking down a futuristic runway wearing an elaborate brain-computer interface headpiece with LED lights and neural sensors, 1990s retrofuturistic aesthetic, audience in background, dramatic catwalk lighting, slightly grainy analog film quality, warm color grading, Kodak Portra 400 film look, avant-garde haute couture", idx: 13, images: null },
{ text: "Woman eats her feijoada with chopsticks in the first feijoada restaurant in Tokyo, Reuters", idx: 14, images: null },
{ text: "a Reuters press photograph of a Japanese woman skillfully eating Brazilian feijoada with chopsticks in the newly opened first feijoada restaurant in Tokyo, traditional black bean stew in bowl, interior with blend of Japanese and Brazilian decor, warm lighting, documentary photography style, cultural fusion moment, candid expression", idx: 15, images: null },
{ text: "The inauguration of the first wormhole portal between New York and Shanghai", idx: 16, images: null },
{ text: "the grand inauguration ceremony of humanity's first stable wormhole portal connecting New York City and Shanghai, massive glowing circular portal structure with swirling energy, dignitaries on stage, crowds of people, Times Square on one side transitioning to Shanghai skyline visible through the portal, news cameras, spectacular lighting effects, historic moment, photojournalism style", idx: 17, images: null },
{ text: "The inauguration of the first tram line on the moon", idx: 18, images: null },
{ text: "the ceremonial opening of the first lunar tram line on the moon's surface, sleek futuristic tram with large windows on rails, lunar colony dome structures in background, astronauts in modern spacesuits attending ceremony, Earth visible in black sky, lunar dust, solar panels, flags from multiple nations, wide landscape shot, NASA-style documentary photography", idx: 19, images: null },
{ text: "this man eating pizza", idx: 20, images: ["IMG_6552.webp"] },
{ text: "turn this person into a 90s anime villain, but keep their look, clothing and facial features", idx: 21, images: ["speaker-robin-bfl-headshot-1.webp"] },
// custom_prompts_comparison (4 prompts) - indices 22-25
{ text: "a man and woman are standing together against a backdrop, the backdrop is divided equally in half down the middle, left side is red, right side is gold, the woman is wearing a t-shirt with a yoda motif, she has a long skirt with birds on it, the man is wearing a three piece purple suit, he has spiky blue hair", idx: 22, images: null },
{ text: "A man in a business suit standing in front of a large screen, shot from behind-the-scenes perspective of a game show set. The suit is split vertically down the middle: left half bright green, right half bright orange. The screen behind him is also split vertically: left half pink, right half blue. Realistic photography style, professional lighting, behind-the-scenes candid shot, game show studio environment, detailed fabric textures on the suit, crisp color separation", idx: 23, images: null },
{ text: "A man in a dramatic chrome-bioluminescent sci-fi costume and headdress is bracing for battle with epic two-handed giant scimitar, on a snowy city street in London, a giant totoro is behind him lying on the floor, further behind is a man in a high vis jacket clinging high up on a lamppost, distant police sirens", idx: 24, images: null },
{ text: "The man in image 1 is lying on the sofa in image 3, and the puppy in image 2 is lying on the floor, sleeping", idx: 25, images: ["man.webp", "puppy.webp", "sofa.webp"] },
// text_rendering_comparison (3 prompts) - indices 26-28
{ text: "a clean white office whiteboard with a handwritten inspirational message in neat black marker that reads 'Success is not final, failure is not fatal: it is the courage to continue that counts. Believe in yourself and all that you are. - Winston Churchill', professional conference room setting, natural daylight from window, clear legible handwriting, modern office environment", idx: 26, images: null },
{ text: "urban brick wall with bold colorful street art graffiti, main text in large letters says 'CLIMATE ACTION NOW' in vibrant red and yellow spray paint, below it a smaller subtitle reads 'the planet can't wait! start acting NOW' in blue and green, activist street art style, realistic urban photography, weathered brick texture, sharp focus on the text, dramatic lighting", idx: 27, images: null },
{ text: "a modern corporate office or international airport terminal wall displaying 8 identical round analog clocks arranged in a 2x4 grid pattern, each clock has a sleek black frame with white face and black hands, below each clock is a metal nameplate with city name in bold capital letters, top row left to right: 'NEW YORK', 'LONDON', 'TOKYO', 'SYDNEY', bottom row left to right: 'DUBAI', 'SAO PAULO', 'BEIJING', 'LOS ANGELES', each clock showing different times corresponding to their time zones, mounted on a clean white wall with subtle shadows, professional architectural photography, symmetrical composition, good lighting, sharp focus on clock faces and text", idx: 28, images: null },
// === PROMPTS_FROM_FILE (6 prompts) ===
// indices 29-34
{ text: "Create a vase on a table in living room, the color of the vase is a gradient of color, starting with #02eb3c color and finishing with #edfa3c. The flowers inside the vase have the color #ff0088", idx: 29, images: null },
{ text: "Educational weather infographic titled 'WHY FREIBURG IS SO SUNNY' in bold navy letters at top on cream background, illustrated geographic cross-section showing sunny valley between two mountain ranges, left side blue-grey mountains labeled 'VOSGES', right side dark green mountains labeled 'BLACK FOREST', central golden sunshine rays creating 'SUNSHINE POCKET' text over valley, blue arrow from left showing 'MOIST AIR FROM WEST', orange sun icon with '1,800 HOURS' text in top right corner, Freiburg city with church spire and colorful houses with blue solar panels in valley center, green and yellow vineyard terraces on hillsides, bottom beige panel with three facts in clean sans-serif text: First fact: 'Protected by two mountain ranges', Second fact: 'Creates Germany's sunniest microclimate', Third fact: 'Perfect for wine and solar energy', facts separated by vertical divider lines, flat illustration style with soft gradients, educational geography poster aesthetic", idx: 30, images: null },
{ text: "Sloth out drinking in Bangkok at night in a street full of party folks , 2000s digicam style, people in the background fading", idx: 31, images: null },
{ text: "stock photo of two people, a man and a woman, wearing lab coats writing on a white board with markers, the white board has text that reads 'Black Forest Labs revolutionized the open weights generative media space with FLUX.1. And since day one, BFL and Hugging Face have worked together to bring this amazing models to the community. The HF, diffusers library and the Spaces demos allowed millions of developers and enthusiasts to get started with generative media synthesis. FLUX.2 will bring this process to a completely new level'", idx: 32, images: null },
{ text: "{\"scene\": \"Professional studio product photography setup with polished concrete surface\", \"subjects\": [{\"description\": \"Minimalist ceramic coffee mug with steam rising from hot coffee inside\", \"pose\": \"Stationary on surface\", \"position\": \"Center foreground on polished concrete surface\", \"color_palette\": [\"matte black ceramic\"]}, {\"description\": \"Minimalist ceramic coffee mug, matching design to the black mug\", \"pose\": \"Stationary on surface\", \"position\": \"Right side of the black mug on polished concrete surface\", \"color_palette\": [\"matte yellow ceramic\"]}], \"style\": \"Ultra-realistic product photography with commercial quality\", \"color_palette\": [\"matte black\", \"matte yellow\", \"concrete gray\", \"soft white highlights\"], \"lighting\": \"Three-point softbox setup creating soft, diffused highlights with no harsh shadows\", \"mood\": \"Clean, professional, minimalist\", \"background\": \"Polished concrete surface with studio backdrop\", \"composition\": \"rule of thirds\", \"camera\": {\"angle\": \"high angle\", \"distance\": \"medium shot\", \"focus\": \"Sharp focus on steam rising from coffee and both mugs in frame\", \"lens-mm\": 85, \"f-number\": \"f/5.6\", \"ISO\": 200}}", idx: 33, images: null },
{ text: "The person from image 1 is petting the cat from image 2, the bird from image 3 is next to them", idx: 34, images: ["woman.webp", "cat.webp", "bird.webp"] },
];
let currentPromptIndex = 0;
let currentSteps = 50; // Default to 50 steps
const quantModes = ['bf16', '8bit', '4bit'];
function setSteps(steps) {
currentSteps = steps;
// Update button styles
const btn50 = document.getElementById('steps50Btn');
const btn28 = document.getElementById('steps28Btn');
if (steps === 50) {
btn50.style.background = '#333';
btn50.style.borderColor = '#555';
btn28.style.background = '#222';
btn28.style.borderColor = '#444';
} else {
btn50.style.background = '#222';
btn50.style.borderColor = '#444';
btn28.style.background = '#333';
btn28.style.borderColor = '#555';
}
// Update current steps display
document.getElementById('currentStepsDisplay').textContent = steps;
updateDisplay();
}
function updateDisplay() {
const transformerIdx = parseInt(document.getElementById('transformerSlider').value);
const textEncoderIdx = parseInt(document.getElementById('textEncoderSlider').value);
const transformerMode = quantModes[transformerIdx];
const textEncoderMode = quantModes[textEncoderIdx];
// Update slider displays
document.getElementById('transformerValue').textContent = transformerMode.toUpperCase();
document.getElementById('textEncoderValue').textContent = textEncoderMode.toUpperCase();
// Get current prompt
const prompt = allPrompts[currentPromptIndex];
// Build image path - switch between 50 and 28 steps folders
const folderName = currentSteps === 50 ? 'diffusers_comparison' : 'diffusers_comparison_28steps';
const imagePath = `${folderName}/images/textenc_${textEncoderMode}_trans_${transformerMode}_p${String(currentPromptIndex).padStart(2, '0')}.webp`;
// Update image
const container = document.getElementById('imageContainer');
container.innerHTML = `<img src="${imagePath}" alt="Generated image" onerror="handleImageError(this)"><button class="expand-icon" onclick="openGallery()" title="View fullscreen (F)">&#x26F6;</button>`;
// Update info
document.getElementById('configInfo').textContent =
`Text Encoder: ${textEncoderMode.toUpperCase()} | Transformer: ${transformerMode.toUpperCase()}`;
// Update input images
updateInputImages(prompt.images);
// Update prompt display
updatePromptDisplay();
}
function updateInputImages(imagesList) {
const container = document.getElementById('inputImagesContainer');
if (!imagesList || imagesList.length === 0) {
container.innerHTML = '<div class="no-input-images">No input images<br>for this prompt</div>';
return;
}
const labels = ['Image 1', 'Image 2', 'Image 3'];
container.innerHTML = '<div class="input-image-grid">' +
imagesList.map((imgPath, idx) => `
<div class="input-image-item">
<img src="${imgPath}" alt="Input ${idx + 1}" onerror="this.parentElement.innerHTML='<div class=\\'error-message\\'>Missing: ${imgPath}</div>'">
<div class="input-image-label">${labels[idx] || 'Image ' + (idx + 1)}</div>
</div>
`).join('') +
'</div>';
}
function updatePromptDisplay() {
const prompt = allPrompts[currentPromptIndex];
document.getElementById('promptText').textContent = prompt.text;
document.getElementById('promptCounter').textContent =
`${currentPromptIndex + 1} / ${allPrompts.length}`;
// Update navigation buttons
document.getElementById('prevBtn').disabled = currentPromptIndex === 0;
document.getElementById('nextBtn').disabled = currentPromptIndex === allPrompts.length - 1;
}
function changePrompt(delta) {
currentPromptIndex += delta;
currentPromptIndex = Math.max(0, Math.min(allPrompts.length - 1, currentPromptIndex));
updateDisplay();
}
function handleImageError(img) {
img.parentElement.innerHTML = `
<div class="error-message">
Image not found<br>
<small>${img.src}</small><br><br>
<small>Run comparison scripts to generate this image</small>
</div>
`;
}
// Gallery functions
function openGallery() {
const transformerIdx = parseInt(document.getElementById('transformerSlider').value);
const textEncoderIdx = parseInt(document.getElementById('textEncoderSlider').value);
const transformerMode = quantModes[transformerIdx];
const textEncoderMode = quantModes[textEncoderIdx];
const prompt = allPrompts[currentPromptIndex];
const folderName = currentSteps === 50 ? 'diffusers_comparison' : 'diffusers_comparison_28steps';
const imagePath = `${folderName}/images/textenc_${textEncoderMode}_trans_${transformerMode}_p${String(currentPromptIndex).padStart(2, '0')}.webp`;
document.getElementById('galleryImage').src = imagePath;
// Set truncated text in the text div
document.getElementById('galleryPromptText').textContent = prompt.text;
// Set full text in tooltip
document.getElementById('galleryPromptFull').textContent = prompt.text;
// Update text encoder button states
['BF16', '8bit', '4bit'].forEach((mode, idx) => {
const btn = document.getElementById('galleryText' + mode);
if (idx === textEncoderIdx) {
btn.style.background = '#fff';
btn.style.borderColor = '#fff';
btn.style.color = '#000';
} else {
btn.style.background = '#1a1a1a';
btn.style.borderColor = '#333';
btn.style.color = '#888';
}
});
// Update transformer button states
['BF16', '8bit', '4bit'].forEach((mode, idx) => {
const btn = document.getElementById('galleryTrans' + mode);
if (idx === transformerIdx) {
btn.style.background = '#fff';
btn.style.borderColor = '#fff';
btn.style.color = '#000';
} else {
btn.style.background = '#1a1a1a';
btn.style.borderColor = '#333';
btn.style.color = '#888';
}
});
// Update steps button states
if (currentSteps === 50) {
document.getElementById('gallerySteps50').style.background = '#fff';
document.getElementById('gallerySteps50').style.borderColor = '#fff';
document.getElementById('gallerySteps50').style.color = '#000';
document.getElementById('gallerySteps28').style.background = '#1a1a1a';
document.getElementById('gallerySteps28').style.borderColor = '#333';
document.getElementById('gallerySteps28').style.color = '#888';
} else {
document.getElementById('gallerySteps50').style.background = '#1a1a1a';
document.getElementById('gallerySteps50').style.borderColor = '#333';
document.getElementById('gallerySteps50').style.color = '#888';
document.getElementById('gallerySteps28').style.background = '#fff';
document.getElementById('gallerySteps28').style.borderColor = '#fff';
document.getElementById('gallerySteps28').style.color = '#000';
}
// Handle input images
const galleryInputPanel = document.getElementById('galleryInputImages');
const galleryOverlay = document.getElementById('galleryOverlay');
if (prompt.images && prompt.images.length > 0) {
// Show input images
const labels = ['Image 1', 'Image 2', 'Image 3'];
galleryInputPanel.innerHTML = `
<div class="gallery-input-header">Input Images</div>
${prompt.images.map((imgPath, idx) => `
<div class="gallery-input-item">
<img src="${imgPath}" alt="Input ${idx + 1}">
<div class="gallery-input-label">${labels[idx] || 'Image ' + (idx + 1)}</div>
</div>
`).join('')}
`;
galleryInputPanel.classList.add('visible');
galleryOverlay.classList.remove('no-input-images');
} else {
// Hide input images
galleryInputPanel.classList.remove('visible');
galleryOverlay.classList.add('no-input-images');
}
// Update navigation button states
document.getElementById('galleryPrevBtn').disabled = currentPromptIndex === 0;
document.getElementById('galleryNextBtn').disabled = currentPromptIndex === allPrompts.length - 1;
document.getElementById('galleryOverlay').classList.add('active');
}
function setTextEncoderFromGallery(value) {
document.getElementById('textEncoderSlider').value = value;
updateDisplay();
openGallery();
}
function setTransformerFromGallery(value) {
document.getElementById('transformerSlider').value = value;
updateDisplay();
openGallery();
}
function setStepsFromGallery(steps) {
setSteps(steps);
openGallery();
}
function changePromptInGallery(delta) {
changePrompt(delta);
openGallery(); // Refresh gallery with new prompt
}
function togglePromptTooltip(event) {
event.stopPropagation();
const promptEl = document.getElementById('galleryPrompt');
promptEl.classList.toggle('active');
}
function closePromptTooltip(event) {
event.stopPropagation();
document.getElementById('galleryPrompt').classList.remove('active');
}
function closeGallery(event) {
if (event) event.stopPropagation();
document.getElementById('galleryOverlay').classList.remove('active');
}
// Keyboard shortcuts for gallery
document.addEventListener('keydown', (e) => {
const galleryOpen = document.getElementById('galleryOverlay').classList.contains('active');
if (e.key === 'Escape' && galleryOpen) {
closeGallery();
return;
}
if (e.key === 'f' || e.key === 'F') {
if (!galleryOpen) {
openGallery();
} else {
closeGallery();
}
return;
}
// Prompt navigation (works in both modes)
if (e.key === 'ArrowLeft') {
changePrompt(-1);
if (galleryOpen) openGallery(); // Update gallery if open
}
if (e.key === 'ArrowRight') {
changePrompt(1);
if (galleryOpen) openGallery(); // Update gallery if open
}
// Text encoder navigation (works in both modes)
if (e.key === 'ArrowUp' || e.key === 'w' || e.key === 'W') {
const slider = document.getElementById('textEncoderSlider');
const newValue = Math.max(0, parseInt(slider.value) - 1);
slider.value = newValue;
updateDisplay();
if (galleryOpen) {
// Small delay to ensure updateDisplay completes
setTimeout(() => openGallery(), 10);
}
e.preventDefault();
}
if (e.key === 'ArrowDown' || e.key === 's' || e.key === 'S') {
const slider = document.getElementById('textEncoderSlider');
const newValue = Math.min(2, parseInt(slider.value) + 1);
slider.value = newValue;
updateDisplay();
if (galleryOpen) {
setTimeout(() => openGallery(), 10);
}
e.preventDefault();
}
// Transformer navigation (works in both modes)
if (e.key === 'a' || e.key === 'A') {
const slider = document.getElementById('transformerSlider');
const newValue = Math.max(0, parseInt(slider.value) - 1);
slider.value = newValue;
updateDisplay();
if (galleryOpen) {
setTimeout(() => openGallery(), 10);
}
e.preventDefault();
}
if (e.key === 'd' || e.key === 'D') {
const slider = document.getElementById('transformerSlider');
const newValue = Math.min(2, parseInt(slider.value) + 1);
slider.value = newValue;
updateDisplay();
if (galleryOpen) {
setTimeout(() => openGallery(), 10);
}
e.preventDefault();
}
});
// Initialize
window.onload = () => {
updateDisplay();
// Auto-open gallery on wide screens
if (window.innerWidth > 800) {
openGallery();
}
};
</script>
</body>
</html>