Movie Editor: keyboard split/remove for the selected clip

S splits the selected clip at the playhead (midpoint if the playhead is outside
it); Delete/Backspace removes it. Ignored while typing in a field. Replaces the
hard-to-reach corner action buttons; toolbar shows a 'S split · remove' hint.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
digital-garbage
2026-06-07 09:12:15 +03:00
co-authored by Claude Opus 4.8
parent cd9f4dfb81
commit af8d84e29e
2 changed files with 28 additions and 0 deletions
+1
View File
@@ -322,6 +322,7 @@ input[type=number] { font-family: var(--font-mono); }
.tl-toolbar .tl-spacer { flex: 1; }
.tl-tc { font-family: var(--font-mono); font-size: 11px; color: var(--muted); }
.tl-zlabel { font-family: var(--font-mono); font-size: 10px; letter-spacing: 1px; text-transform: uppercase; color: var(--faint); }
.tl-keys { font-family: var(--font-mono); font-size: 10px; letter-spacing: .5px; color: var(--faint); margin-right: 10px; opacity: .8; }
.tl-scroll { flex: 1; overflow-x: auto; overflow-y: hidden; position: relative; }
.tl-content { position: relative; height: 100%; min-height: 100%; }
+27
View File
@@ -183,6 +183,8 @@
tlTcEl = tc; // keep ref for Player's onPlayheadChanged updates
bar.append(tc);
const spacer = el("div", "tl-spacer"); bar.append(spacer);
const keys = el("span", "tl-keys", "S split · ⌫ remove"); keys.title = "Select a clip, then: S splits it at the playhead · Delete/Backspace removes it";
bar.append(keys);
const zlabel = el("span", "tl-zlabel", "zoom"); bar.append(zlabel);
const zout = el("button", "btn ghost tiny", "−"); zout.onclick = () => setZoom(pxPerSec / 1.4);
const zin = el("button", "btn ghost tiny", "+"); zin.onclick = () => setZoom(pxPerSec * 1.4);
@@ -265,6 +267,31 @@
S.subscribe(render);
// ── keyboard: S = split selected clip at playhead, Del/Backspace = remove it ──
function splitSelectedAtPlayhead() {
const st = S.get();
if (!st.project || !st.selectedSceneId) return;
const p = st.project;
let off = 0, target = null;
for (const sc of (p.scenes || [])) { if (sc.id === st.selectedSceneId) { target = sc; break; } off += sDur(sc, p); }
if (!target) return;
const ph = window.Player?.getPlayhead() ?? 0;
const fps = sFps(target, p), dur = sDur(target, p);
// Split at the playhead when it's inside the clip; otherwise at the midpoint.
const at = (ph > off + 0.05 && ph < off + dur - 0.05) ? Math.round((ph - off) * fps) : null;
S.splitScene(target.id, at);
}
window.addEventListener("keydown", (e) => {
const a = document.activeElement;
if (a && (a.tagName === "INPUT" || a.tagName === "TEXTAREA" || a.isContentEditable)) return;
if (e.metaKey || e.ctrlKey || e.altKey) return;
const st = S.get();
if (!st.project || !st.selectedSceneId) return;
if (e.key === "s" || e.key === "S") { e.preventDefault(); splitSelectedAtPlayhead(); }
else if (e.key === "Delete" || e.key === "Backspace") { e.preventDefault(); S.removeScene(st.selectedSceneId); }
});
// Update only the playhead needle + timecode during video playback.
// Runs at video's timeupdate rate (~4–25Hz) — no full re-render needed.
if (window.Player) {