Add sync clock entity for synchronized animation timing
Introduces Synchronization Clocks — shared, controllable time bases that CSS sources can optionally reference for synchronized animation. Backend: - New SyncClock dataclass, JSON store, Pydantic schemas, REST API - Runtime clock with thread-safe pause/resume/reset and speed control - Ref-counted runtime pool with eager creation for API control - clock_id field on all ColorStripSource types - Stream integration: clock time/speed replaces source-local values - Paused clock skips rendering (saves CPU + stops frame pushes) - Included in backup/restore via STORE_MAP Frontend: - Sync Clocks tab in Streams section with cards and controls - Clock dropdown in CSS editor (hidden speed slider when clock set) - Clock crosslink badge on CSS source cards (replaces speed badge) - Targets tab uses DataCache for picture/audio sources and sync clocks Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -146,7 +146,7 @@
|
||||
<div id="color-cycle-colors-list"></div>
|
||||
<button type="button" class="btn btn-secondary" onclick="colorCycleAddColor()" data-i18n="color_strip.color_cycle.add_color">+ Add Color</button>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div id="css-editor-cycle-speed-group" class="form-group">
|
||||
<div class="label-row">
|
||||
<label for="css-editor-cycle-speed">
|
||||
<span data-i18n="color_strip.color_cycle.speed">Speed:</span>
|
||||
@@ -226,7 +226,7 @@
|
||||
<div id="css-editor-effect-preview" class="effect-palette-preview"></div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div id="css-editor-effect-speed-group" class="form-group">
|
||||
<div class="label-row">
|
||||
<label for="css-editor-effect-speed">
|
||||
<span data-i18n="color_strip.effect.speed">Speed:</span>
|
||||
@@ -492,7 +492,7 @@
|
||||
</select>
|
||||
<small id="css-editor-animation-type-desc" class="field-desc"></small>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div id="css-editor-animation-speed-group" class="form-group">
|
||||
<div class="label-row">
|
||||
<label for="css-editor-animation-speed">
|
||||
<span data-i18n="color_strip.animation.speed">Speed:</span>
|
||||
@@ -508,6 +508,18 @@
|
||||
</details>
|
||||
</div>
|
||||
|
||||
<!-- Sync Clock (shown for animated types: static, gradient, color_cycle, effect) -->
|
||||
<div id="css-editor-clock-group" class="form-group" style="display:none">
|
||||
<div class="label-row">
|
||||
<label for="css-editor-clock" data-i18n="color_strip.clock">Sync Clock:</label>
|
||||
<button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?" data-i18n-aria-label="aria.hint">?</button>
|
||||
</div>
|
||||
<small class="input-hint" style="display:none" data-i18n="color_strip.clock.hint">Optionally link to a sync clock to synchronize animation timing and speed with other sources</small>
|
||||
<select id="css-editor-clock" onchange="onCSSClockChange()">
|
||||
<option value="" data-i18n="common.none">None</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div id="css-editor-error" class="error-message" style="display: none;"></div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
<!-- Sync Clock Editor Modal -->
|
||||
<div id="sync-clock-modal" class="modal" role="dialog" aria-modal="true" aria-labelledby="sync-clock-modal-title">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h2 id="sync-clock-modal-title" data-i18n="sync_clock.add">Add Sync Clock</h2>
|
||||
<button class="modal-close-btn" onclick="closeSyncClockModal()" data-i18n-aria-label="aria.close">✕</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="sync-clock-form" onsubmit="return false;">
|
||||
<input type="hidden" id="sync-clock-id">
|
||||
|
||||
<div id="sync-clock-error" class="error-message" style="display: none;"></div>
|
||||
|
||||
<!-- Name -->
|
||||
<div class="form-group">
|
||||
<div class="label-row">
|
||||
<label for="sync-clock-name" data-i18n="sync_clock.name">Name:</label>
|
||||
<button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?" data-i18n-aria-label="aria.hint">?</button>
|
||||
</div>
|
||||
<small class="input-hint" style="display:none" data-i18n="sync_clock.name.hint">A descriptive name for this synchronization clock</small>
|
||||
<input type="text" id="sync-clock-name" data-i18n-placeholder="sync_clock.name.placeholder" placeholder="Main Clock" required>
|
||||
</div>
|
||||
|
||||
<!-- Speed -->
|
||||
<div class="form-group">
|
||||
<div class="label-row">
|
||||
<label for="sync-clock-speed"><span data-i18n="sync_clock.speed">Speed:</span> <span id="sync-clock-speed-display">1.0</span>x</label>
|
||||
<button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?" data-i18n-aria-label="aria.hint">?</button>
|
||||
</div>
|
||||
<small class="input-hint" style="display:none" data-i18n="sync_clock.speed.hint">Animation speed multiplier for all linked sources (0.1x slow - 10x fast)</small>
|
||||
<input type="range" id="sync-clock-speed" min="0.1" max="10" step="0.1" value="1.0"
|
||||
oninput="document.getElementById('sync-clock-speed-display').textContent = this.value">
|
||||
</div>
|
||||
|
||||
<!-- Description -->
|
||||
<div class="form-group">
|
||||
<div class="label-row">
|
||||
<label for="sync-clock-description" data-i18n="sync_clock.description">Description (optional):</label>
|
||||
<button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?" data-i18n-aria-label="aria.hint">?</button>
|
||||
</div>
|
||||
<small class="input-hint" style="display:none" data-i18n="sync_clock.description.hint">Optional notes about this clock's purpose</small>
|
||||
<textarea id="sync-clock-description" rows="2" data-i18n-placeholder="sync_clock.description.placeholder" placeholder=""></textarea>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-icon btn-secondary" onclick="closeSyncClockModal()" title="Cancel" data-i18n-title="settings.button.cancel" data-i18n-aria-label="aria.cancel">✕</button>
|
||||
<button class="btn btn-icon btn-primary" onclick="saveSyncClock()" title="Save" data-i18n-title="settings.button.save" data-i18n-aria-label="aria.save">✓</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user