@bycrux/editor 0.6.3 → 0.6.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -577,7 +577,7 @@ function ReviewSurface<P extends Project>({
|
|
|
577
577
|
right below, one column — not a separate assets column. */}
|
|
578
578
|
{(adapter.listVersionHistory || slots?.runHistory ||
|
|
579
579
|
(assetsPlacement === 'sidebar' && slots?.assetsPanel)) && (
|
|
580
|
-
<div className={`${assetsPlacement === 'sidebar' ? 'w-
|
|
580
|
+
<div className={`${assetsPlacement === 'sidebar' ? 'w-56' : 'w-48'} shrink-0 border-l border-[var(--editor-border)] bg-[var(--editor-surface)] flex flex-col overflow-hidden`}>
|
|
581
581
|
{adapter.listVersionHistory && (
|
|
582
582
|
<VersionPanel versions={versions} restoring={restoring} onRestore={handleRestoreVersion} />
|
|
583
583
|
)}
|
|
@@ -63,7 +63,13 @@ export default function CaptionPreview({ track, currentTime, fps, compileOverlay
|
|
|
63
63
|
: null
|
|
64
64
|
|
|
65
65
|
return (
|
|
66
|
-
<
|
|
66
|
+
// zIndex 45 keeps captions above the active <video> (z 1) and overlay items
|
|
67
|
+
// (z `trackIdx + 12`, ≈12–20) — mirroring the final render, where the caption
|
|
68
|
+
// track composites on top — while staying below the editing affordances
|
|
69
|
+
// (selection handles z 50, play button z 100). Without an explicit z-index the
|
|
70
|
+
// root sits at `auto`, so the opaque active video paints over it and captions
|
|
71
|
+
// never appear in the preview.
|
|
72
|
+
<div ref={wrapRef} className="absolute inset-0 pointer-events-none overflow-hidden" style={{ zIndex: 45 }}>
|
|
67
73
|
<OverlayErrorBoundary label={`caption: ${track.style}`} resetKey={track.style}>
|
|
68
74
|
{element && scale !== null && (
|
|
69
75
|
<div style={{
|
|
@@ -214,6 +214,18 @@ export function useVideoPlayback(
|
|
|
214
214
|
}
|
|
215
215
|
}
|
|
216
216
|
|
|
217
|
+
// Start playback on a slot during an automated clip-boundary switch (context
|
|
218
|
+
// already running — no gesture needed). If the slot isn't buffered yet (a slow
|
|
219
|
+
// non-faststart HEVC tail-moov fetch can still be in flight), play() may reject
|
|
220
|
+
// with AbortError; retry on `canplay` so the switch never dead-stops at the cut.
|
|
221
|
+
function playSoon(video: HTMLVideoElement) {
|
|
222
|
+
const p = video.play()
|
|
223
|
+
if (p) p.catch(() => {
|
|
224
|
+
const onCanPlay = () => { video.removeEventListener('canplay', onCanPlay); video.play().catch(() => {}) }
|
|
225
|
+
video.addEventListener('canplay', onCanPlay)
|
|
226
|
+
})
|
|
227
|
+
}
|
|
228
|
+
|
|
217
229
|
function ensureVideoGain(slot: 0 | 1): GainNode | null {
|
|
218
230
|
if (videoGainRef.current[slot]) return videoGainRef.current[slot]
|
|
219
231
|
const video = slot === 0 ? video0Ref.current : video1Ref.current
|
|
@@ -569,7 +581,7 @@ export function useVideoPlayback(
|
|
|
569
581
|
if (preloadSrcRef.current !== src) { nv.src = src; nv.currentTime = effectiveInPoint(nc) }
|
|
570
582
|
const gain = ensureVideoGain(ns)
|
|
571
583
|
if (gain) gain.gain.value = nc.muted ? 0 : (nc.volume ?? 1)
|
|
572
|
-
nv
|
|
584
|
+
playSoon(nv)
|
|
573
585
|
}
|
|
574
586
|
void (activeSlotRef.current === 0 ? video0Ref.current : video1Ref.current)?.pause()
|
|
575
587
|
activeSlotRef.current = ns
|
|
@@ -659,21 +671,26 @@ export function useVideoPlayback(
|
|
|
659
671
|
const clipInPoint = effectiveInPoint(clip)
|
|
660
672
|
const outPoint = effectiveOutPoint(clip) ?? clip.end - clip.start + clipInPoint
|
|
661
673
|
|
|
662
|
-
// Preload next clip into inactive slot
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
674
|
+
// Preload the next clip into the inactive slot as early as possible. The
|
|
675
|
+
// source files are large 4K 10-bit HEVC with the moov atom at the END of the
|
|
676
|
+
// file (not web-faststart), so the browser needs a slow tail range-fetch to
|
|
677
|
+
// index and seek before it can decode. The old "~1s before end" lead was far
|
|
678
|
+
// too short: at a cross-source cut the next slot wasn't ready and play()
|
|
679
|
+
// stalled, freezing playback at the boundary. (Same-source cuts hid the bug —
|
|
680
|
+
// the moov was already cached from the active slot.) Give the load the whole
|
|
681
|
+
// current clip as runway instead; the preloadSrcRef guard keeps it idempotent
|
|
682
|
+
// and a scrub clears it.
|
|
683
|
+
const nextIdx = activeIdxRef.current + 1
|
|
684
|
+
if (nextIdx < clips.length && clips[nextIdx].src) {
|
|
685
|
+
const inactiveVideo = slot === 0 ? video1Ref.current : video0Ref.current
|
|
686
|
+
const nextSrc = fileUrlRef.current(playbackSrcFor(clips[nextIdx]))
|
|
687
|
+
if (inactiveVideo && preloadSrcRef.current !== nextSrc) {
|
|
688
|
+
preloadSrcRef.current = nextSrc
|
|
689
|
+
inactiveVideo.src = nextSrc
|
|
690
|
+
inactiveVideo.currentTime = effectiveInPoint(clips[nextIdx])
|
|
691
|
+
const inactiveSlot = (1 - slot) as 0 | 1
|
|
692
|
+
const nextGain = ensureVideoGain(inactiveSlot)
|
|
693
|
+
if (nextGain) nextGain.gain.value = clips[nextIdx].muted ? 0 : (clips[nextIdx].volume ?? 1)
|
|
677
694
|
}
|
|
678
695
|
}
|
|
679
696
|
|
|
@@ -723,7 +740,7 @@ export function useVideoPlayback(
|
|
|
723
740
|
}
|
|
724
741
|
const nextGain = ensureVideoGain(nextSlot)
|
|
725
742
|
if (nextGain) nextGain.gain.value = next.muted ? 0 : (next.volume ?? 1)
|
|
726
|
-
nextVideo
|
|
743
|
+
playSoon(nextVideo)
|
|
727
744
|
}
|
|
728
745
|
|
|
729
746
|
activeSlotRef.current = nextSlot
|