Summary
In Studio, pressing Backspace while the caret is inside a text property field deletes the selected design element instead of a character. The first press is consumed correctly by the input; the second one falls through to what appears to be a global delete-element shortcut and removes the entire selected clip from index.html.
This is silent data loss during ordinary typing. It happened twice in a single 10-minute editing session and destroyed two complete scene cards.
Severity
High — normal text editing destroys unrelated markup, and the recovery path (below) additionally rolls back edits the user had already made. There is no visible warning and no obvious undo affordance at the moment it happens.
Steps to reproduce
- Open a composition in Studio (
npm run dev / hyperframes preview).
- Select a design element that contains a text child.
- Click into the text property field in the inspector and place the caret at the end.
- Press Backspace twice.
Expected: two characters are removed from the text field.
Actual: the first press removes one character; the second deletes the selected design element and all of its children from the document.
Evidence
Studio's own .hyperframes/backup/ trail captures both occurrences. Diffs below are data-hf-id stripped for readability.
Occurrence 1 — 00-48-27 → 00-49-05 (36,691 → 35,349 bytes). Caret was in the #t-repl-kicker text field, mid-word ("This video was made with a "). One backspace removed the whole #t-repl clip:
- <div id="t-repl" class="clip type" data-start="40.752" data-duration="6.792" data-track-index="2">
- <div id="t-repl-label" class="label">Replaced by</div>
- <div id="t-repl-r1" class="repl-row">
- <div class="repl-name">HeyGen</div>
- <div class="repl-note">Avatars, voice, video</div>
- </div>
- ... (three more rows)
- <div id="t-repl-kicker">This video was made with a </div>
- </div>
+
Occurrence 2 — 00-57-40-971 → 00-57-48 (36,711 → 36,293 bytes). Caret was in the #t-end-credit field. The preceding backup shows "...Claude Code an Codex" — the first backspace had correctly deleted the d from and. The next backspace removed the whole #t-end clip:
- <div id="t-end" class="clip type" data-start="52.072" data-duration="4.528" data-track-index="2">
- <div id="t-end-1" class="hero">Adobe</div>
- <div id="t-end-2" class="hero">Cancelled</div>
- <div id="t-end-credit">Made with HeyGen, HyperFrames, Claude Code an Codex</div>
- </div>
+
The second case is the clearest: the same key, pressed twice in a row in the same field, is routed to two different handlers.
Secondary effect: recovery discards unrelated edits
After the deletion, the element is restored from a backup — but the restore lands on a state from before the user's recent typing. In occurrence 2, the write at 00-58-10 brought #t-end back while simultaneously reverting #t-end-credit to its original wording, discarding the in-progress edit.
The user-visible symptom is "I made several changes and they all reverted at once," which reads as a separate persistence bug but is downstream of this one. Worth fixing together: a single stray keypress rewinds an entire batch of unrelated edits.
Suggested direction
The global delete/backspace shortcut should bail out when the event target is an <input>, <textarea>, or contenteditable element — or more robustly, when document.activeElement is a text-entry field. A closest('input, textarea, [contenteditable]') guard on the keydown handler would cover the inspector fields.
Environment
- hyperframes 0.7.90 (latest at time of report)
- Node v22.17.0, linux x64 (WSL2)
- Studio via
hyperframes preview
- Composition: single-file
index.html, 46 timed elements across 8 tracks, ~36 KB
hyperframes check passes with 0 errors before and after; the deletion is not something lint can catch after the fact
Summary
In Studio, pressing Backspace while the caret is inside a text property field deletes the selected design element instead of a character. The first press is consumed correctly by the input; the second one falls through to what appears to be a global delete-element shortcut and removes the entire selected clip from
index.html.This is silent data loss during ordinary typing. It happened twice in a single 10-minute editing session and destroyed two complete scene cards.
Severity
High — normal text editing destroys unrelated markup, and the recovery path (below) additionally rolls back edits the user had already made. There is no visible warning and no obvious undo affordance at the moment it happens.
Steps to reproduce
npm run dev/hyperframes preview).Expected: two characters are removed from the text field.
Actual: the first press removes one character; the second deletes the selected design element and all of its children from the document.
Evidence
Studio's own
.hyperframes/backup/trail captures both occurrences. Diffs below aredata-hf-idstripped for readability.Occurrence 1 —
00-48-27→00-49-05(36,691 → 35,349 bytes). Caret was in the#t-repl-kickertext field, mid-word ("This video was made with a "). One backspace removed the whole#t-replclip:Occurrence 2 —
00-57-40-971→00-57-48(36,711 → 36,293 bytes). Caret was in the#t-end-creditfield. The preceding backup shows"...Claude Code an Codex"— the first backspace had correctly deleted thedfromand. The next backspace removed the whole#t-endclip:The second case is the clearest: the same key, pressed twice in a row in the same field, is routed to two different handlers.
Secondary effect: recovery discards unrelated edits
After the deletion, the element is restored from a backup — but the restore lands on a state from before the user's recent typing. In occurrence 2, the write at
00-58-10brought#t-endback while simultaneously reverting#t-end-creditto its original wording, discarding the in-progress edit.The user-visible symptom is "I made several changes and they all reverted at once," which reads as a separate persistence bug but is downstream of this one. Worth fixing together: a single stray keypress rewinds an entire batch of unrelated edits.
Suggested direction
The global delete/backspace shortcut should bail out when the event target is an
<input>,<textarea>, orcontenteditableelement — or more robustly, whendocument.activeElementis a text-entry field. Aclosest('input, textarea, [contenteditable]')guard on the keydown handler would cover the inspector fields.Environment
hyperframes previewindex.html, 46 timed elements across 8 tracks, ~36 KBhyperframes checkpasses with 0 errors before and after; the deletion is not somethinglintcan catch after the fact