Skip to content

[players] Fix sub-preview playback, add task player trim handles#2134

Merged
frankrousseau merged 16 commits into
cgwire:mainfrom
frankrousseau:main
Jul 14, 2026
Merged

[players] Fix sub-preview playback, add task player trim handles#2134
frankrousseau merged 16 commits into
cgwire:mainfrom
frankrousseau:main

Conversation

@frankrousseau

@frankrousseau frankrousseau commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Problem

  • A compared video could not play when the main preview is an image, and sub-preview navigation dropped the comparison mode.
  • Playlists stopped on video sub-previews following an image, applied shot trim handles to sub-previews, showed holes in the progress strip and left the playhead stuck on picture entities.
  • Switching playlist sub-previews mid-playback resumed the old video instead of loading the sub.
  • Continuous playlist playback stalled on entities without preview, shown as an invisible hole in the strip.
  • The task preview player ignored shot trim handles entirely.
  • Raw seeks on a playing video flashed stale frames and the loading spinner.
  • Inline frame in/out editing crashed on the shots page (stale memoized map caches) and the edit shot modal never recomputed nb_frames.
  • Undoing a full erase lost the erased annotation objects.
  • The "use current frame" checkbox was misaligned in the task view.

Solution

  • Native controls for the compared video, comparison kept across sub-preview navigation, compared index following the main one in both players.
  • Playlists play video sub-previews untrimmed from frame 0 and reload the decoder on every sub switch; the strip renders from frame counts frozen at reset time so it tiles without holes, and the playhead jumps on picture entities.
  • Preview-less entities hold their edit length like a slug, advance automatically and show a neutral grey slot.
  • PreviewPlayer shows draggable, persisted handle markers and playback respects the trim (start on handle-in, pause or loop on handle-out).
  • VideoViewer arms a raw-seek target: stale presentations are skipped and the loading spinner stays off until the target frame lands.
  • Entity map caches are cleared in place (their getters memoize the reference) and the format sanitizers accept numbers, restoring both frame editing paths.
  • Fully erased objects come back as additions on undo.
  • The checkbox is realigned with its row.

frankrousseau and others added 16 commits July 13, 2026 17:16
The audio player no longer renders a paperclip download link on error but an informational chip, so assert on .attachment-error (and the absence of a link). Add an AttachmentImage spec covering its render and error fallback.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
When the main preview is an image, the frame-synced comparison viewer has no transport, so a compared video couldn't be played. Render the compared clip as a plain, vertically-centered <video controls loop muted> (like the playlist) when the main isn't a movie and the comparison is.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…red index

The currentPreview watcher tore comparison mode down on every sub-preview step; gate that (and the default-target reset) on a real revision change so navigating sub-previews of the same revision keeps comparing. Also make the compared sub-preview track the main sub-preview index, staying on the compared revision's last one when it has fewer.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… index

A video sub-preview after an image was frozen by the still-image loop and then skipped; play it from its start instead. The entity handle-in/out (the main preview's trim) no longer applies to sub-previews, which was stopping them at an arbitrary frame. Also make the compared sub-preview track the main sub-preview index, clamping to the compared revision's last one.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The strip computed segment positions from frame counts frozen at reset
time but recomputed widths reactively from live preview fields. Any
divergence (per-entity fps of the current entity, durations refreshed
after the reset, a picture revision carrying a video sub-preview's
duration) opened holes between segments. Freeze per-entity start frame
and frame count in resetPlaylistFrameData and render the strip from
those two fields only, so segments tile by construction. Sub-preview
durations no longer stretch a picture entity's slot either.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…tity

playEntity only moved the playlist playhead in its movie branch, and
pictures have no time-update channel driving it, so selecting or
auto-advancing to a picture entity left the strip indicator stuck at
its previous position. Jump it to the entity's slot in the non-movie
branch too; strip clicks/drags pass updateFullPlaylist=false and keep
their exact clicked position.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Loading a video sub-preview reapplied the entity's trim handles to the
sub-preview timeline: the handle-out marker landed at an arbitrary spot
and pressing play seeked to the entity handle-in instead of frame 0.
Sub-previews are not the entity's trimmed main preview: resetHandles now
sets neutral handles when a sub-preview is displayed and the progress
bar hides the handle markers there. Preloading the next entity's handles
(slate skip on entity change) keeps the real values.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The task player ignored shot trim handles entirely. Show the handle
markers on the progress bar for shot movie previews (main preview only,
hidden on sub-previews), let them be dragged to edit the trim
(persisted through editShot like in PlaylistPlayer, inert in read-only
mode), and make playback respect them: play jumps to the handle-in
frame start, reaching handle-out pauses on the marker (or loops from
handle-in when repeating), with the bar fill aligned on the marker.
The shot is read at call time and refreshed on an isShotsLoading
watcher because the shotMap getter exposes a non-reactive cache.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A raw seek issued while playing (trim loop, play jump to handle-in,
room sync) flashed the viewer: frames still queued behind the seek
point kept painting for a tick or two, and the video element's waiting
event flipped isLoading, hiding the canvas behind the loading spinner.
Arm a seek target in setCurrentTimeRaw: the render loop skips
presentations far from it and the waiting handler leaves the canvas
alone until the target frame lands.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The shotMap/assetMap/editMap/episodeMap/sequenceMap getters expose
non-reactive cache maps, so Vuex memoizes the reference captured at
their first read. Reset and rebuild mutations reassigned those caches
to new Map() instances, leaving every consumer on a stale, empty map:
on the shots page, inline frame in/out editing crashed on an undefined
shot lookup and nb_frames stopped being computed. Clear the maps in
place instead of reassigning them.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Number-typed TextFields emit valueAsNumber, but sanitizeInteger
returned 0 for any non-string value, so EditShotModal never recomputed
nb_frames when frame in or frame out changed. Accept numbers in the
format composable sanitizers and cover them with a spec.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Switching sub-previews mid-playback kept the decoder on the old
source: the "sub-preview" resumed the previous video at its position
and stopped at that video's end. Reload the current entity on every
sub-preview index change and resume playback on the new source.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Continuous playback stalled on an entity without preview: the
sub-preview branch of continuePlayingPlaylist incremented the preview
index forever (no previews list to exhaust) and playEntity never armed
the advance timer for extension-less entities. Advance to the next
entity when there is no previews list, arm the picture timer for
preview-less entities so their edit length is held like a slug, and
paint their strip slot in neutral grey instead of an invisible segment.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Undoing a full erase re-added the object locally but synced it as an
update. Zou drops updates whose id is no longer in the stored drawing
and remote viewers ignore them, so the restored object was lost on the
next reload once the deletion had been saved. Record an addition first:
zou applies additions before updates, so the same-batch undo (where the
object still exists server-side) keeps working through the update.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@frankrousseau frankrousseau merged commit 23a261b into cgwire:main Jul 14, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant