Improve CSS test preview: HD resolution, screen-only border, and refactor frontend docs

- Bump capture preview resolution from 480×360 to 960×540 (HD)
- Increase preview FPS from 2 to ~12 FPS (AUX_INTERVAL 0.5→0.08)
- Add accent-color border on screen rect only (not LED edges) via ::after
- Use dynamic aspect-ratio from decoded JPEG frames instead of fixed height
- Widen modal to 900px for picture sources
- Move frontend conventions from CLAUDE.md to contexts/frontend.md

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-13 01:50:23 +03:00
parent 568a992a4e
commit e912019873
5 changed files with 182 additions and 116 deletions

View File

@@ -775,7 +775,7 @@ async def test_color_strip_ws(
if is_picture and hasattr(stream, '_live_stream'):
_frame_live = stream._live_stream
_last_aux_time = 0.0
_AUX_INTERVAL = 0.5 # send JPEG preview / brightness updates every 0.5s
_AUX_INTERVAL = 0.08 # send JPEG preview / brightness updates ~12 FPS
# Stream binary RGB frames at ~20 Hz
while True:
@@ -832,7 +832,7 @@ async def test_color_strip_ws(
img = img[:, :, :3]
# Downscale for bandwidth
h, w = img.shape[:2]
scale = min(480 / w, 360 / h, 1.0)
scale = min(960 / w, 540 / h, 1.0)
if scale < 1.0:
new_w = max(1, int(w * scale))
new_h = max(1, int(h * scale))

View File

@@ -175,8 +175,10 @@
grid-template-columns: 14px 1fr 14px;
grid-template-rows: 14px 1fr 14px;
width: 100%;
height: 320px;
aspect-ratio: 16 / 9;
max-height: 70vh;
overflow: hidden;
border-radius: 4px;
}
.css-test-rect-corner {
@@ -184,12 +186,11 @@
}
.css-test-rect-screen {
position: relative;
background-image: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
background-size: cover;
background-position: center;
border-radius: 2px;
outline: 1px solid rgba(255, 255, 255, 0.15);
outline-offset: -1px;
display: flex;
flex-direction: column;
align-items: center;
@@ -198,6 +199,16 @@
overflow: hidden;
}
.css-test-rect-screen::after {
content: '';
position: absolute;
inset: 0;
border: 2px solid var(--primary-color);
border-radius: 2px;
pointer-events: none;
z-index: 10;
}
.css-test-rect-label {
color: rgba(255, 255, 255, 0.85);
font-size: 0.8rem;

View File

@@ -1973,6 +1973,10 @@ function _cssTestConnect(sourceId, ledCount) {
document.getElementById('css-test-layers-view').style.display = _cssTestIsComposite ? '' : 'none';
document.getElementById('css-test-status').style.display = 'none';
// Widen modal for picture sources to show the screen rectangle larger
const modalContent = document.querySelector('#test-css-source-modal .modal-content');
if (modalContent) modalContent.style.maxWidth = isPicture ? '900px' : '';
// Hide LED count control for picture sources (LED count is fixed by calibration)
document.getElementById('css-test-led-control').style.display = isPicture ? 'none' : '';
@@ -2016,6 +2020,14 @@ function _cssTestConnect(sourceId, ledCount) {
screen.style.backgroundSize = 'cover';
screen.style.backgroundPosition = 'center';
if (oldUrl) URL.revokeObjectURL(oldUrl);
// Set aspect ratio from first decoded frame
const rect = document.getElementById('css-test-rect');
if (rect && !rect._aspectSet && img.naturalWidth && img.naturalHeight) {
rect.style.aspectRatio = `${img.naturalWidth} / ${img.naturalHeight}`;
rect.style.height = 'auto';
rect._aspectSet = true;
requestAnimationFrame(() => _cssTestRenderTicks(_cssTestMeta?.edges));
}
};
img.onerror = () => URL.revokeObjectURL(url);
img.src = url;
@@ -2356,6 +2368,12 @@ export function closeTestCssSourceModal() {
// Revoke blob URL for frame preview
const screen = document.getElementById('css-test-rect-screen');
if (screen && screen._blobUrl) { URL.revokeObjectURL(screen._blobUrl); screen._blobUrl = null; screen.style.backgroundImage = ''; }
// Reset aspect ratio for next open
const rect = document.getElementById('css-test-rect');
if (rect) { rect.style.aspectRatio = ''; rect.style.height = ''; rect._aspectSet = false; }
// Reset modal width
const modalContent = document.querySelector('#test-css-source-modal .modal-content');
if (modalContent) modalContent.style.maxWidth = '';
const modal = document.getElementById('test-css-source-modal');
if (modal) { modal.style.display = 'none'; }
}