better responsiveness

This commit is contained in:
2025-07-05 18:42:17 +02:00
parent bacc6f0325
commit 7df2b49c26
5 changed files with 476 additions and 52 deletions

View File

@ -13,6 +13,9 @@
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Bitfielder - Bitfield Shader App">
<meta name="twitter:description" content="Interactive bitfield shader editor for creating visual patterns using bitwise operations">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600;700&display=swap" rel="stylesheet">
<style>
:root {
--ui-opacity: 0.3;
@ -27,7 +30,7 @@
body {
background: #000;
color: #fff;
font-family: monospace;
font-family: 'IBM Plex Mono', monospace;
overflow: hidden;
}
@ -67,6 +70,137 @@
display: flex;
gap: 10px;
margin-left: auto;
align-items: center;
}
#topbar .controls-desktop {
display: flex;
gap: 10px;
align-items: center;
}
#topbar .controls-mobile {
display: none;
gap: 8px;
align-items: center;
margin-left: auto;
}
#hamburger-menu {
display: none;
background: rgba(255, 255, 255, 0.1);
border: 1px solid #555;
color: #fff;
width: 36px;
height: 36px;
padding: 0;
border-radius: 4px;
cursor: pointer;
align-items: center;
justify-content: center;
}
#hamburger-menu:hover {
background: rgba(255, 255, 255, 0.2);
}
#hamburger-menu svg {
width: 18px;
height: 18px;
}
#mobile-menu {
position: fixed;
top: 40px;
right: -320px;
width: 320px;
max-width: 80vw;
height: calc(100vh - 40px);
background: rgba(0, 0, 0, var(--ui-opacity));
backdrop-filter: blur(3px);
border-left: 1px solid rgba(255, 255, 255, 0.1);
z-index: 150;
transition: right 0.3s ease;
overflow-y: auto;
padding: 20px;
}
#mobile-menu.open {
right: 0;
}
#mobile-menu h3 {
color: #fff;
font-size: 16px;
margin-bottom: 20px;
padding-bottom: 10px;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.mobile-menu-section {
margin-bottom: 20px;
}
.mobile-menu-item {
margin-bottom: 15px;
}
.mobile-menu-item label {
display: block;
color: #ccc;
font-size: 12px;
margin-bottom: 5px;
}
.mobile-menu-item select,
.mobile-menu-item input[type="range"] {
width: 100%;
background: rgba(255, 255, 255, 0.1);
border: 1px solid #555;
color: #fff;
padding: 8px;
border-radius: 4px;
font-size: 14px;
}
.mobile-menu-buttons {
display: flex;
flex-direction: column;
gap: 10px;
}
.mobile-menu-buttons button {
background: rgba(255, 255, 255, 0.1);
border: 1px solid #555;
color: #fff;
padding: 12px;
border-radius: 4px;
cursor: pointer;
font-family: 'IBM Plex Mono', monospace;
font-size: 14px;
text-align: left;
display: flex;
align-items: center;
gap: 10px;
}
.mobile-menu-buttons button:hover {
background: rgba(255, 255, 255, 0.2);
}
#mobile-menu-overlay {
display: none;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 149;
}
#mobile-menu-overlay.open {
display: block;
}
#topbar button {
@ -76,7 +210,7 @@
padding: 6px 12px;
border-radius: 4px;
cursor: pointer;
font-family: monospace;
font-family: 'IBM Plex Mono', monospace;
font-size: 12px;
}
@ -84,6 +218,30 @@
background: rgba(255, 255, 255, 0.2);
}
.icon-button {
width: 36px;
height: 36px;
padding: 0;
display: flex;
align-items: center;
justify-content: center;
}
.icon-button svg {
width: 18px;
height: 18px;
}
/* Lucide icon styles */
[data-lucide] {
display: inline-block;
vertical-align: middle;
}
button svg {
pointer-events: none;
}
#editor-panel {
position: fixed;
bottom: 0;
@ -113,7 +271,7 @@
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 4px;
color: #fff;
font-family: monospace;
font-family: 'IBM Plex Mono', monospace;
font-size: 16px;
padding: 15px;
resize: none;
@ -127,7 +285,7 @@
border: 1px solid rgba(255, 255, 255, 0.2);
color: #fff;
padding: 20px 30px;
font-family: monospace;
font-family: 'IBM Plex Mono', monospace;
font-size: 16px;
font-weight: bold;
cursor: pointer;
@ -230,7 +388,7 @@
padding: 8px 12px;
border-radius: 4px;
cursor: pointer;
font-family: monospace;
font-family: 'IBM Plex Mono', monospace;
font-size: 12px;
z-index: 1000;
display: none;
@ -242,14 +400,14 @@
#shader-library {
position: fixed;
top: 0;
right: -300px;
top: 40px;
left: -300px;
width: 300px;
height: 100vh;
height: calc(100vh - 40px);
background: rgba(0, 0, 0, calc(var(--ui-opacity) + 0.1));
border-left: 1px solid rgba(255, 255, 255, 0.1);
border-right: 1px solid rgba(255, 255, 255, 0.1);
z-index: 90;
transition: right 0.3s ease;
transition: left 0.3s ease;
backdrop-filter: blur(3px);
overflow-y: auto;
}
@ -257,21 +415,21 @@
#shader-library-trigger {
position: fixed;
top: 0;
right: 0;
top: 40px;
left: 0;
width: 20px;
height: 100vh;
height: calc(100vh - 40px);
z-index: 91;
cursor: pointer;
}
#shader-library-trigger:hover + #shader-library,
#shader-library:hover {
right: 0;
left: 0;
}
#shader-library.open {
right: 0;
left: 0;
}
.library-header {
@ -302,7 +460,7 @@
color: #fff;
padding: 6px 8px;
border-radius: 4px;
font-family: monospace;
font-family: 'IBM Plex Mono', monospace;
font-size: 12px;
}
@ -317,7 +475,7 @@
color: #fff;
padding: 6px 8px;
border-radius: 4px;
font-family: monospace;
font-family: 'IBM Plex Mono', monospace;
font-size: 12px;
}
@ -328,7 +486,7 @@
padding: 6px 12px;
border-radius: 4px;
cursor: pointer;
font-family: monospace;
font-family: 'IBM Plex Mono', monospace;
font-size: 12px;
}
@ -380,7 +538,7 @@
padding: 4px 6px;
border-radius: 3px;
transition: all 0.2s ease;
font-family: monospace;
font-family: 'IBM Plex Mono', monospace;
}
.shader-action:hover {
@ -411,7 +569,7 @@
padding: 8px 10px;
background: rgba(0, 0, 0, var(--ui-opacity));
color: #ccc;
font-family: monospace;
font-family: 'IBM Plex Mono', monospace;
font-size: 11px;
border-top: 1px solid rgba(255, 255, 255, 0.1);
word-break: break-all;
@ -432,15 +590,29 @@
/* Responsive Design */
@media (max-width: 768px) {
#topbar .controls {
margin-left: auto;
}
#topbar .controls-desktop {
display: none;
}
#topbar .controls-mobile {
display: flex;
}
#hamburger-menu {
display: flex;
}
#topbar {
flex-wrap: wrap;
height: auto;
padding: 10px;
height: 40px;
padding: 0 10px;
}
#topbar .title {
margin-right: 10px;
margin-bottom: 5px;
margin-right: auto;
}
#topbar .controls {
@ -487,11 +659,13 @@
#shader-library {
width: 100%;
right: -100%;
left: -100%;
top: 40px;
height: calc(100vh - 40px);
}
#shader-library-trigger {
width: 30px;
display: none;
}
}
@ -558,26 +732,82 @@
<div id="topbar">
<div class="title">Bitfielder</div>
<div class="controls">
<label style="color: #ccc; font-size: 12px; margin-right: 10px;">
Resolution:
<select id="resolution-select" style="background: rgba(255,255,255,0.1); border: 1px solid #555; color: #fff; padding: 4px; border-radius: 4px;">
<div class="controls-desktop">
<label style="color: #ccc; font-size: 12px; margin-right: 10px;">
Resolution:
<select id="resolution-select" style="background: rgba(255,255,255,0.1); border: 1px solid #555; color: #fff; padding: 4px; border-radius: 4px;">
<option value="1">Full (1x)</option>
<option value="2">Half (2x)</option>
<option value="4">Quarter (4x)</option>
<option value="8">Eighth (8x)</option>
</select>
</label>
<label style="color: #ccc; font-size: 12px; margin-right: 10px;">
FPS:
<select id="fps-select" style="background: rgba(255,255,255,0.1); border: 1px solid #555; color: #fff; padding: 4px; border-radius: 4px;">
<option value="15">15 FPS</option>
<option value="30" selected>30 FPS</option>
<option value="60">60 FPS</option>
</select>
</label>
<label style="color: #ccc; font-size: 12px; margin-right: 10px;">
Render Mode:
<select id="render-mode-select" style="background: rgba(255,255,255,0.1); border: 1px solid #555; color: #fff; padding: 4px; border-radius: 4px;">
<option value="classic" selected>Classic</option>
<option value="grayscale">Grayscale</option>
<option value="red">Red Channel</option>
<option value="green">Green Channel</option>
<option value="blue">Blue Channel</option>
<option value="rgb">RGB Split</option>
<option value="hsv">HSV</option>
<option value="rainbow">Rainbow</option>
</select>
</label>
<label style="color: #ccc; font-size: 12px; margin-right: 10px;">
UI Opacity:
<input type="range" id="opacity-slider" min="10" max="100" value="30" style="width: 80px; vertical-align: middle;">
<span id="opacity-value" style="font-size: 11px;">30%</span>
</label>
<button id="help-btn">?</button>
<button id="fullscreen-btn">Fullscreen</button>
<button id="hide-ui-btn">Hide UI</button>
<button id="random-btn">Random</button>
<button id="share-btn">Share</button>
<button id="export-png-btn">Export PNG</button>
</div>
<div class="controls-mobile">
<button id="library-btn-mobile" class="icon-button" aria-label="Shader Library"></button>
<button id="random-btn-mobile" class="icon-button" aria-label="Random"></button>
<button id="hide-ui-btn-mobile" class="icon-button" aria-label="Hide UI"></button>
<button id="hamburger-menu" class="icon-button" aria-label="Menu"></button>
</div>
</div>
</div>
<div id="mobile-menu-overlay"></div>
<div id="mobile-menu">
<h3>Settings</h3>
<div class="mobile-menu-section">
<div class="mobile-menu-item">
<label>Resolution</label>
<select id="resolution-select-mobile">
<option value="1">Full (1x)</option>
<option value="2">Half (2x)</option>
<option value="4">Quarter (4x)</option>
<option value="8">Eighth (8x)</option>
</select>
</label>
<label style="color: #ccc; font-size: 12px; margin-right: 10px;">
FPS:
<select id="fps-select" style="background: rgba(255,255,255,0.1); border: 1px solid #555; color: #fff; padding: 4px; border-radius: 4px;">
</div>
<div class="mobile-menu-item">
<label>FPS</label>
<select id="fps-select-mobile">
<option value="15">15 FPS</option>
<option value="30" selected>30 FPS</option>
<option value="60">60 FPS</option>
</select>
</label>
<label style="color: #ccc; font-size: 12px; margin-right: 10px;">
Render Mode:
<select id="render-mode-select" style="background: rgba(255,255,255,0.1); border: 1px solid #555; color: #fff; padding: 4px; border-radius: 4px;">
</div>
<div class="mobile-menu-item">
<label>Render Mode</label>
<select id="render-mode-select-mobile">
<option value="classic" selected>Classic</option>
<option value="grayscale">Grayscale</option>
<option value="red">Red Channel</option>
@ -587,18 +817,19 @@
<option value="hsv">HSV</option>
<option value="rainbow">Rainbow</option>
</select>
</label>
<label style="color: #ccc; font-size: 12px; margin-right: 10px;">
UI Opacity:
<input type="range" id="opacity-slider" min="10" max="100" value="30" style="width: 80px; vertical-align: middle;">
<span id="opacity-value" style="font-size: 11px;">30%</span>
</label>
<button id="help-btn">?</button>
<button id="fullscreen-btn">Fullscreen</button>
<button id="hide-ui-btn">Hide UI</button>
<button id="random-btn">Random</button>
<button id="share-btn">Share</button>
<button id="export-png-btn">Export PNG</button>
</div>
<div class="mobile-menu-item">
<label>UI Opacity: <span id="opacity-value-mobile">30%</span></label>
<input type="range" id="opacity-slider-mobile" min="10" max="100" value="30">
</div>
</div>
<div class="mobile-menu-section">
<div class="mobile-menu-buttons">
<button id="help-btn-mobile"><span class="icon"></span> Help</button>
<button id="fullscreen-btn-mobile"><span class="icon"></span> Fullscreen</button>
<button id="share-btn-mobile"><span class="icon"></span> Share</button>
<button id="export-png-btn-mobile"><span class="icon"></span> Export PNG</button>
</div>
</div>
</div>