Fix stale frame in API CSS preview when source is inactive

Server: send initial frame immediately after metadata for api_input
sources so the client gets the current buffer (fallback color if
inactive) instead of never receiving a frame when push_generation
stays at 0.

Frontend: clear all test modal canvases on open to prevent stale
pixels from previous sessions. Reset FPS timestamps after metadata
so the initial bootstrap frame isn't counted in the FPS chart.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-20 14:29:51 +03:00
parent 47c696bae3
commit 81b275979b
2 changed files with 18 additions and 1 deletions

View File

@@ -890,6 +890,14 @@ async def test_color_strip_ws(
meta["layer_infos"] = layer_infos meta["layer_infos"] = layer_infos
await websocket.send_text(_json.dumps(meta)) await websocket.send_text(_json.dumps(meta))
# For api_input: send the current buffer immediately so the client
# gets a frame right away (fallback color if inactive) rather than
# leaving the canvas blank/stale until external data arrives.
if is_api_input:
initial_colors = stream.get_latest_colors()
if initial_colors is not None:
await websocket.send_bytes(initial_colors.tobytes())
# For picture sources, grab the live stream for frame preview # For picture sources, grab the live stream for frame preview
_frame_live = None _frame_live = None
if is_picture and hasattr(stream, 'live_stream'): if is_picture and hasattr(stream, 'live_stream'):

View File

@@ -2563,10 +2563,15 @@ function _openTestModal(sourceId: string) {
modal.onclick = (e) => { if (e.target === modal) closeTestCssSourceModal(); }; modal.onclick = (e) => { if (e.target === modal) closeTestCssSourceModal(); };
_cssTestSourceId = sourceId; _cssTestSourceId = sourceId;
// Reset views // Reset views and clear stale canvas content
(document.getElementById('css-test-strip-view') as HTMLElement).style.display = 'none'; (document.getElementById('css-test-strip-view') as HTMLElement).style.display = 'none';
(document.getElementById('css-test-rect-view') as HTMLElement).style.display = 'none'; (document.getElementById('css-test-rect-view') as HTMLElement).style.display = 'none';
(document.getElementById('css-test-layers-view') as HTMLElement).style.display = 'none'; (document.getElementById('css-test-layers-view') as HTMLElement).style.display = 'none';
// Clear all test canvases to prevent stale frames from previous sessions
modal.querySelectorAll('canvas').forEach(c => {
const ctx = c.getContext('2d');
if (ctx) ctx.clearRect(0, 0, c.width, c.height);
});
(document.getElementById('css-test-led-group') as HTMLElement).style.display = ''; (document.getElementById('css-test-led-group') as HTMLElement).style.display = '';
// Input source selector: shown for both CSS test and CSPT test, hidden for api_input // Input source selector: shown for both CSS test and CSPT test, hidden for api_input
const csptGroup = document.getElementById('css-test-cspt-input-group') as HTMLElement | null; const csptGroup = document.getElementById('css-test-cspt-input-group') as HTMLElement | null;
@@ -2660,6 +2665,10 @@ function _cssTestConnect(sourceId: string, ledCount: number, fps?: number) {
const isPicture = _cssTestMeta.edges && _cssTestMeta.edges.length > 0; const isPicture = _cssTestMeta.edges && _cssTestMeta.edges.length > 0;
_cssTestIsComposite = _cssTestMeta.layers && _cssTestMeta.layers.length > 0; _cssTestIsComposite = _cssTestMeta.layers && _cssTestMeta.layers.length > 0;
// Reset FPS timestamps so the initial bootstrap frame
// (sent right after metadata for api_input) isn't counted
if (_cssTestIsApiInput) _cssTestFpsTimestamps = [];
// Show correct view // Show correct view
(document.getElementById('css-test-strip-view') as HTMLElement).style.display = (isPicture || _cssTestIsComposite) ? 'none' : ''; (document.getElementById('css-test-strip-view') as HTMLElement).style.display = (isPicture || _cssTestIsComposite) ? 'none' : '';
(document.getElementById('css-test-rect-view') as HTMLElement).style.display = isPicture ? '' : 'none'; (document.getElementById('css-test-rect-view') as HTMLElement).style.display = isPicture ? '' : 'none';