Fix gamma correction, frame interpolation flicker, and target card redraws
- Fix inverted gamma formula: use (i/255)^gamma instead of (i/255)^(1/gamma) so gamma>1 correctly darkens midtones (standard LED gamma correction) - Fix frame interpolation flicker: move interp buffer update after temporal smoothing so idle-tick output is consistent with new-frame output - Fix target card hover/animation reset: use stable placeholder values in card HTML for volatile metrics (data-tm attributes), patch real values in-place after reconcile instead of replacing entire card DOM element Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -39,9 +39,55 @@ class KCEditorModal extends Modal {
|
||||
|
||||
const kcEditorModal = new KCEditorModal();
|
||||
|
||||
export function createKCTargetCard(target, sourceMap, patternTemplateMap, valueSourceMap) {
|
||||
export function patchKCTargetMetrics(target) {
|
||||
const card = document.querySelector(`[data-kc-target-id="${target.id}"]`);
|
||||
if (!card) return;
|
||||
const state = target.state || {};
|
||||
const metrics = target.metrics || {};
|
||||
|
||||
const fpsActual = card.querySelector('[data-tm="fps-actual"]');
|
||||
if (fpsActual) fpsActual.textContent = state.fps_actual?.toFixed(1) || '0.0';
|
||||
|
||||
const fpsCurrent = card.querySelector('[data-tm="fps-current"]');
|
||||
if (fpsCurrent) fpsCurrent.textContent = state.fps_current ?? '-';
|
||||
|
||||
const fpsTarget = card.querySelector('[data-tm="fps-target"]');
|
||||
if (fpsTarget) fpsTarget.textContent = state.fps_target || 0;
|
||||
|
||||
const frames = card.querySelector('[data-tm="frames"]');
|
||||
if (frames) frames.textContent = metrics.frames_processed || 0;
|
||||
|
||||
const keepalive = card.querySelector('[data-tm="keepalive"]');
|
||||
if (keepalive) keepalive.textContent = state.frames_keepalive ?? '-';
|
||||
|
||||
const errors = card.querySelector('[data-tm="errors"]');
|
||||
if (errors) errors.textContent = metrics.errors_count || 0;
|
||||
|
||||
const uptime = card.querySelector('[data-tm="uptime"]');
|
||||
if (uptime) uptime.textContent = formatUptime(metrics.uptime_seconds);
|
||||
|
||||
const timing = card.querySelector('[data-tm="timing"]');
|
||||
if (timing && state.timing_total_ms != null) {
|
||||
timing.innerHTML = `
|
||||
<div class="timing-header">
|
||||
<div class="metric-label">${t('device.metrics.timing')}</div>
|
||||
<div class="timing-total"><strong>${state.timing_total_ms}ms</strong></div>
|
||||
</div>
|
||||
<div class="timing-bar">
|
||||
<span class="timing-seg timing-extract" style="flex:${state.timing_calc_colors_ms}" title="calc ${state.timing_calc_colors_ms}ms"></span>
|
||||
<span class="timing-seg timing-smooth" style="flex:${state.timing_smooth_ms || 0.1}" title="smooth ${state.timing_smooth_ms}ms"></span>
|
||||
<span class="timing-seg timing-send" style="flex:${state.timing_broadcast_ms}" title="broadcast ${state.timing_broadcast_ms}ms"></span>
|
||||
</div>
|
||||
<div class="timing-legend">
|
||||
<span class="timing-legend-item"><span class="timing-dot timing-extract"></span>calc ${state.timing_calc_colors_ms}ms</span>
|
||||
<span class="timing-legend-item"><span class="timing-dot timing-smooth"></span>smooth ${state.timing_smooth_ms}ms</span>
|
||||
<span class="timing-legend-item"><span class="timing-dot timing-send"></span>broadcast ${state.timing_broadcast_ms}ms</span>
|
||||
</div>`;
|
||||
}
|
||||
}
|
||||
|
||||
export function createKCTargetCard(target, sourceMap, patternTemplateMap, valueSourceMap) {
|
||||
const state = target.state || {};
|
||||
const kcSettings = target.key_colors_settings || {};
|
||||
|
||||
const isProcessing = state.processing || false;
|
||||
@@ -105,50 +151,35 @@ export function createKCTargetCard(target, sourceMap, patternTemplateMap, valueS
|
||||
<div class="metrics-grid">
|
||||
<div class="metric">
|
||||
<div class="metric-label">${t('device.metrics.actual_fps')}</div>
|
||||
<div class="metric-value">${state.fps_actual?.toFixed(1) || '0.0'}</div>
|
||||
<div class="metric-value" data-tm="fps-actual">---</div>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<div class="metric-label">${t('device.metrics.current_fps')}</div>
|
||||
<div class="metric-value">${state.fps_current ?? '-'}</div>
|
||||
<div class="metric-value" data-tm="fps-current">---</div>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<div class="metric-label">${t('device.metrics.target_fps')}</div>
|
||||
<div class="metric-value">${state.fps_target || 0}</div>
|
||||
<div class="metric-value" data-tm="fps-target">---</div>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<div class="metric-label">${t('device.metrics.frames')}</div>
|
||||
<div class="metric-value">${metrics.frames_processed || 0}</div>
|
||||
<div class="metric-value" data-tm="frames">---</div>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<div class="metric-label">${t('device.metrics.keepalive')}</div>
|
||||
<div class="metric-value">${state.frames_keepalive ?? '-'}</div>
|
||||
<div class="metric-value" data-tm="keepalive">---</div>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<div class="metric-label">${t('device.metrics.errors')}</div>
|
||||
<div class="metric-value">${metrics.errors_count || 0}</div>
|
||||
<div class="metric-value" data-tm="errors">---</div>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<div class="metric-label">${t('device.metrics.uptime')}</div>
|
||||
<div class="metric-value">${formatUptime(metrics.uptime_seconds)}</div>
|
||||
<div class="metric-value" data-tm="uptime">---</div>
|
||||
</div>
|
||||
</div>
|
||||
${state.timing_total_ms != null ? `
|
||||
<div class="timing-breakdown">
|
||||
<div class="timing-header">
|
||||
<div class="metric-label">${t('device.metrics.timing')}</div>
|
||||
<div class="timing-total"><strong>${state.timing_total_ms}ms</strong></div>
|
||||
</div>
|
||||
<div class="timing-bar">
|
||||
<span class="timing-seg timing-extract" style="flex:${state.timing_calc_colors_ms}" title="calc ${state.timing_calc_colors_ms}ms"></span>
|
||||
<span class="timing-seg timing-smooth" style="flex:${state.timing_smooth_ms || 0.1}" title="smooth ${state.timing_smooth_ms}ms"></span>
|
||||
<span class="timing-seg timing-send" style="flex:${state.timing_broadcast_ms}" title="broadcast ${state.timing_broadcast_ms}ms"></span>
|
||||
</div>
|
||||
<div class="timing-legend">
|
||||
<span class="timing-legend-item"><span class="timing-dot timing-extract"></span>calc ${state.timing_calc_colors_ms}ms</span>
|
||||
<span class="timing-legend-item"><span class="timing-dot timing-smooth"></span>smooth ${state.timing_smooth_ms}ms</span>
|
||||
<span class="timing-legend-item"><span class="timing-dot timing-send"></span>broadcast ${state.timing_broadcast_ms}ms</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="timing-breakdown" data-tm="timing"></div>
|
||||
` : ''}
|
||||
</div>
|
||||
` : ''}
|
||||
|
||||
Reference in New Issue
Block a user