Skip to content

Feature: per-gap pause length editing in the timeline #501

Description

@RobinDev

Context

document.json already models inter-word pauses as non_text content items with a length field (and implicit gaps via sourceStart/length arithmetic between adjacent word items in the same source). The data is editable, but there is currently no UI affordance: non_text items render as plain whitespace in app/src/pages/Editor/Document.tsx, so users can't see or adjust individual pause durations.

Per-gap editing inline in the transcript is a high-leverage pacing feature — it lets editors tighten or stretch individual pauses without leaving the text view or re-recording.

Proposal

Make each meaningful non_text item (e.g. length > 0.15s, threshold configurable) render as a small interactive chip inline between words. Clicking it opens a popover with:

  • numeric input in seconds (step 0.05),
  • − / + nudge buttons,
  • a "delete gap" action,
  • optional horizontal drag handle (drag right = longer).

Keyboard parity: Alt+→ / Alt+← to nudge the selected/hovered gap by 50ms.

Visual polish (optional, high impact): render the chip's width proportional to length so pacing issues are visible at a glance without playback.

Implementation sketch

Redux action in app/src/state/editor/edit.ts:

export const setItemLength = createAsyncActionWithReducer<
  { index: number; length: number }
>('editor/setItemLength', async ({ index, length }, { getState }) => {
  // clamp; if expanding past available source runway, handle per source type
}, (state, payload) => {
  state.document.content[payload.index].length = Math.max(0, payload.length);
});

Integrates with existing redux-undo so it's undoable for free.

Expansion handling. Two cases:

  1. Underlying source has unused runway after sourceStart + length → just extend length. Video continues naturally.

  2. No runway → behavior depends on source type:

    • Audio-only source: retarget to a synthetic silence source (ffmpeg -f lavfi -i anullsrc), added once with a reserved key.
    • Video source: generate a hold clip on first expansion of that source and reuse it for subsequent expansions. Two flavors worth supporting (user-selectable per gap, default = freeze):
      • Freeze frame — ffmpeg -loop 1 -i frame.png -f lavfi -i anullsrc -t <len> -c:v libx264 -tune stillimage -pix_fmt yuv420p hold.mp4 from the last frame at sourceStart + originalLength. Standard "held pause" look.
      • Slow motion — slow the trailing N frames of the source: ffmpeg -i source.mp4 -ss <t-Δ> -t Δ -filter:v "setpts=<factor>*PTS" -filter:a "atempo=1/<factor>" slow.mp4. Useful for emphasis pauses where complete freeze feels too static.

    One hold/slow clip per source, reused for later expansions on the same source to bound zip growth.

Renderer. New GapChip component rendered from the document item renderer when item.type === 'non_text' && item.length > threshold. Default styling subtle (low opacity, brightens on hover) to avoid visual noise.

Scope

Offer

Happy to implement as a PR if maintainers are interested. Open questions:

  • Default visibility threshold for the chip (0.15s? show all? toggle in view menu?).
  • Should chip width be proportional to length by default, or behind a setting?
  • For video expansion: default to freeze-frame, slow-motion, or expose a per-gap toggle in the popover?
  • Would a renderer-level "freeze last frame on length overrun" be preferable to generating hold clips? Avoids zip growth but requires player changes.

Activity

  1. pajowu commented on May 19, 2026

    @pajowu
    Member

    First a few thoughts and corrections:

    • Pauses longer than 0.4s already render a quater_rest icon.
    • The document format contains the V3ArtificialSilence item, which renders as silence / black video.
    • Freeze Frames / Slow Motion do not seem like a good idea and would require changes to the document format.
      • especially reusing the same clip again and again seems like a horrible idea. why would you want to see a freeze frame from much earlier in the source at a random later pause?
    • I'm not sure about the UX of this and whether this will be needed much, but I'm open to trying an implementation and seeing how it feels (but first see the general comments below)
      • Alt+→ / Alt+← don't fit our existing keyboard shortcut scheme
      • deleting a gap is already possible via selecting the item + pressing delete, not sure we need another ui item for that
      • if there is a same-source item after the non_text-item, there should be an intuitive way to extend the non_text item only until the start of the next item in the source (i.e. that the non_texts sourceStart+length is equal to the following items sourceStart).
      • rendering pauses with a different size depending on the length of it is something we decided against, i don't think this feature would change that
      • a low opacity element probably won't work a11y-wise (plus we already have a break icon)

    General Comments:

    This is you second issue within less than an hour. Both issues feel strongly AI-generated and contain wrong factual statements (in this example that silences render as plain whitespace, for which you also linked the wrong file). While I cannot say for sure that they were, I'm assuming so until proven otherwise.

    The Vegan Bug Bakery has a strict policy on AI use (tl;dr: just don't). Since we only adopted it recently, it wasn't already added to the audapolis repo, but will soon (#502).

    Please respect this policy when filing any more issues or opening a PR. Violations will not be tolerated.

  2. pajowu commented on May 19, 2026

    @pajowu
    Member

    The core idea of adding ui for pause editing (especially for creating/modifying artificial_silence-items) is good and something we wanted to add to audapolis for a long time (thats one reason why artificial_silence-items even exist). However it has to be implemented in a way that matches the existing software and the expectation of its users.

    As this issue probably violates our ai-policy, I'll close it for now. Feel free to open a new issue which conforms to this policy (i.e. one you completely wrote yourself) or correct me if this assumption is wrong.

  3. RobinDev commented on May 19, 2026

    @RobinDev
    Author

    We do not accept any contributions that were generated partly or in whole using generative AI (e.g. LLMs).
    This includes but is not limited to issues, pull requests, code, documentation and artwork.

    Really ?

    The previous issues submitted was read end edited by myself before to be posted. I am not familiar with this policy, for me it sound like : "we only accept keyboard issues, if you use your mouse, you are not a real dev"

  4. pajowu commented on May 19, 2026

    @pajowu
    Member

    Thanks for confirming my suspicion. I understand that you were not familiar with the policy, that's why I added it to this repo and pointed you to it. This is not something we will discuss at this point.

  5. locked as resolved and limited conversation to collaborators on May 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions