|
|
<!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-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); |
|
|
} |
|
|
|
|
|
|
|
|
@media (hover: hover) and (pointer: fine) { |
|
|
.gallery-prompt:hover .gallery-prompt-tooltip { |
|
|
display: block; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@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); |
|
|
} |
|
|
|
|
|
|
|
|
@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; |
|
|
} |
|
|
|
|
|
|
|
|
.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> |
|
|
|
|
|
<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)">←</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)">→</button> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<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> |
|
|
|
|
|
|
|
|
<div class="main-display"> |
|
|
|
|
|
<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> |
|
|
|
|
|
|
|
|
<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">⛶</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> |
|
|
|
|
|
<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> |
|
|
|
|
|
|
|
|
<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> |
|
|
|
|
|
|
|
|
<div class="gallery-overlay" id="galleryOverlay" onclick="closeGallery(event)"> |
|
|
<button class="gallery-close" onclick="closeGallery(event); event.stopPropagation();">x</button> |
|
|
|
|
|
|
|
|
<div class="gallery-content-wrapper" onclick="event.stopPropagation()"> |
|
|
|
|
|
<div class="gallery-input-images" id="galleryInputImages" onclick="event.stopPropagation()"> |
|
|
|
|
|
</div> |
|
|
|
|
|
<div class="gallery-main-content"> |
|
|
<button class="gallery-nav gallery-nav-left" id="galleryPrevBtn" onclick="changePromptInGallery(-1); event.stopPropagation();">←</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();">→</button> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<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> |
|
|
|
|
|
|
|
|
<div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 15px; margin-top: 15px; padding: 15px; background: #0a0a0a; border: 1px solid #222;"> |
|
|
|
|
|
<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> |
|
|
|
|
|
|
|
|
<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> |
|
|
|
|
|
|
|
|
<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> |
|
|
|
|
|
|
|
|
<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> |
|
|
|
|
|
|
|
|
const allPrompts = [ |
|
|
|
|
|
|
|
|
|
|
|
{ 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 }, |
|
|
|
|
|
|
|
|
{ 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"] }, |
|
|
|
|
|
|
|
|
{ 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: "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 }, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{ 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; |
|
|
const quantModes = ['bf16', '8bit', '4bit']; |
|
|
|
|
|
function setSteps(steps) { |
|
|
currentSteps = steps; |
|
|
|
|
|
|
|
|
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'; |
|
|
} |
|
|
|
|
|
|
|
|
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]; |
|
|
|
|
|
|
|
|
document.getElementById('transformerValue').textContent = transformerMode.toUpperCase(); |
|
|
document.getElementById('textEncoderValue').textContent = textEncoderMode.toUpperCase(); |
|
|
|
|
|
|
|
|
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`; |
|
|
|
|
|
|
|
|
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)">⛶</button>`; |
|
|
|
|
|
|
|
|
document.getElementById('configInfo').textContent = |
|
|
`Text Encoder: ${textEncoderMode.toUpperCase()} | Transformer: ${transformerMode.toUpperCase()}`; |
|
|
|
|
|
|
|
|
updateInputImages(prompt.images); |
|
|
|
|
|
|
|
|
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}`; |
|
|
|
|
|
|
|
|
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> |
|
|
`; |
|
|
} |
|
|
|
|
|
|
|
|
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; |
|
|
|
|
|
|
|
|
document.getElementById('galleryPromptText').textContent = prompt.text; |
|
|
|
|
|
|
|
|
document.getElementById('galleryPromptFull').textContent = prompt.text; |
|
|
|
|
|
|
|
|
['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'; |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
['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'; |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
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'; |
|
|
} |
|
|
|
|
|
|
|
|
const galleryInputPanel = document.getElementById('galleryInputImages'); |
|
|
const galleryOverlay = document.getElementById('galleryOverlay'); |
|
|
|
|
|
if (prompt.images && prompt.images.length > 0) { |
|
|
|
|
|
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 { |
|
|
|
|
|
galleryInputPanel.classList.remove('visible'); |
|
|
galleryOverlay.classList.add('no-input-images'); |
|
|
} |
|
|
|
|
|
|
|
|
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(); |
|
|
} |
|
|
|
|
|
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'); |
|
|
} |
|
|
|
|
|
|
|
|
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; |
|
|
} |
|
|
|
|
|
|
|
|
if (e.key === 'ArrowLeft') { |
|
|
changePrompt(-1); |
|
|
if (galleryOpen) openGallery(); |
|
|
} |
|
|
if (e.key === 'ArrowRight') { |
|
|
changePrompt(1); |
|
|
if (galleryOpen) openGallery(); |
|
|
} |
|
|
|
|
|
|
|
|
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) { |
|
|
|
|
|
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(); |
|
|
} |
|
|
|
|
|
|
|
|
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(); |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
window.onload = () => { |
|
|
updateDisplay(); |
|
|
|
|
|
|
|
|
if (window.innerWidth > 800) { |
|
|
openGallery(); |
|
|
} |
|
|
}; |
|
|
</script> |
|
|
</body> |
|
|
</html> |
|
|
|