Hide the extend last-frame preview by default on xAIGen.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Towsty
2026-08-31 18:50:29 -05:00
co-authored by Cursor
parent d4bcf8482e
commit 6926538589
+56 -16
View File
@@ -1311,8 +1311,22 @@
</div> </div>
<button type="button" class="text-xs text-zinc-400 hover:text-white" @click="closeExtend">Close</button> <button type="button" class="text-xs text-zinc-400 hover:text-white" @click="closeExtend">Close</button>
</div> </div>
<div class="overflow-hidden rounded-xl bg-black/40"> <div class="relative overflow-hidden rounded-xl bg-black/40" style="min-height: 8rem">
<img v-if="lastFrameUrl" :src="lastFrameUrl" alt="Last frame" class="max-h-48 w-full object-contain"> <img
v-if="lastFrameUrl && !hideExtendLastFrame"
:src="lastFrameUrl"
alt="Last frame"
class="max-h-48 w-full object-contain"
>
<button
v-else-if="hideExtendLastFrame"
type="button"
class="sensitive-glow flex min-h-[8rem] w-full flex-col items-center justify-center gap-1 px-3 py-8 text-amber-100"
@click="revealExtendLastFrame"
>
<span class="text-sm font-medium">Last frame ready</span>
<span class="text-xs text-amber-100/80">Click to reveal · preview hidden</span>
</button>
<p v-else class="px-3 py-8 text-center text-xs text-zinc-500"> <p v-else class="px-3 py-8 text-center text-xs text-zinc-500">
{{ lastFrameLoading ? 'Reading last frame…' : 'Last frame preview unavailable' }} {{ lastFrameLoading ? 'Reading last frame…' : 'Last frame preview unavailable' }}
</p> </p>
@@ -2448,6 +2462,7 @@ const extendPrompt = ref('')
const extendDuration = ref(5) const extendDuration = ref(5)
const lastFrameUrl = ref('') const lastFrameUrl = ref('')
const lastFrameLoading = ref(false) const lastFrameLoading = ref(false)
const lastFrameRevealed = ref(false)
const watchingLibrary = ref(false) const watchingLibrary = ref(false)
let lastFrameObjectUrl = '' let lastFrameObjectUrl = ''
let lastFrameGen = 0 let lastFrameGen = 0
@@ -2801,6 +2816,11 @@ const videoModelHint = computed(() => {
const frameCount = computed(() => Math.max(5, Math.floor(duration.value * fps.value))) const frameCount = computed(() => Math.max(5, Math.floor(duration.value * fps.value)))
const cfgPct = computed(() => ((cfg.value - CFG_MIN) / (CFG_MAX - CFG_MIN)) * 100) const cfgPct = computed(() => ((cfg.value - CFG_MIN) / (CFG_MAX - CFG_MIN)) * 100)
const currentClip = computed(() => clips.value.find(clip => clip.id === currentClipId.value)) const currentClip = computed(() => clips.value.find(clip => clip.id === currentClipId.value))
const hideExtendLastFrame = computed(() => (
showPrivacyToggles.value
&& !lastFrameRevealed.value
&& (hideInputPreview.value || hideThumbnail.value || currentClip.value?.hideThumbnail === true)
))
const canExtend = computed(() => Boolean( const canExtend = computed(() => Boolean(
videoUrl.value videoUrl.value
&& !lockedSave.value && !lockedSave.value
@@ -3731,6 +3751,12 @@ watch(hideThumbnail, (value) => {
} catch { /* ignore */ } } catch { /* ignore */ }
}) })
watch(hideExtendLastFrame, (hidden) => {
if (hidden || !extendOpen.value) return
const id = currentClipId.value || clipIdFromPlayer()
if (id && !lastFrameUrl.value && !lastFrameLoading.value) void loadLastFrame(id)
})
watch(withSound, (value) => { watch(withSound, (value) => {
try { try {
localStorage.setItem('aigen-generate-sound', String(value)) localStorage.setItem('aigen-generate-sound', String(value))
@@ -5153,6 +5179,7 @@ function concealFromOutsideTap(event: Event) {
if (concealEditOutput.value && !editAwaitingReveal.value && !editLockedSave.value && editResultUrl.value) { if (concealEditOutput.value && !editAwaitingReveal.value && !editLockedSave.value && editResultUrl.value) {
editAwaitingReveal.value = true editAwaitingReveal.value = true
} }
if (showPrivacyToggles.value) lastFrameRevealed.value = false
} }
function concealAndPause() { function concealAndPause() {
@@ -5399,6 +5426,7 @@ function closeExtend() {
lastFrameGen += 1 lastFrameGen += 1
extendOpen.value = false extendOpen.value = false
lastFrameLoading.value = false lastFrameLoading.value = false
lastFrameRevealed.value = false
if (lastFrameObjectUrl) { if (lastFrameObjectUrl) {
URL.revokeObjectURL(lastFrameObjectUrl) URL.revokeObjectURL(lastFrameObjectUrl)
lastFrameObjectUrl = '' lastFrameObjectUrl = ''
@@ -5406,6 +5434,29 @@ function closeExtend() {
lastFrameUrl.value = '' lastFrameUrl.value = ''
} }
async function loadLastFrame(id: string) {
lastFrameLoading.value = true
const gen = ++lastFrameGen
try {
const blob = await $fetch<Blob>(`/api/library/clips/${id}/last-frame`, { responseType: 'blob' })
if (gen !== lastFrameGen) return
if (lastFrameObjectUrl) URL.revokeObjectURL(lastFrameObjectUrl)
lastFrameObjectUrl = URL.createObjectURL(blob)
lastFrameUrl.value = lastFrameObjectUrl
} catch (error: any) {
if (gen !== lastFrameGen) return
toast(error?.data?.statusMessage || 'Could not extract the last frame')
} finally {
if (gen === lastFrameGen) lastFrameLoading.value = false
}
}
function revealExtendLastFrame() {
lastFrameRevealed.value = true
const id = currentClipId.value || clipIdFromPlayer()
if (id && !lastFrameUrl.value && !lastFrameLoading.value) void loadLastFrame(id)
}
async function openExtend(item?: LibraryClip) { async function openExtend(item?: LibraryClip) {
if (item) openClip(item) if (item) openClip(item)
const id = item?.id || clipIdFromPlayer() const id = item?.id || clipIdFromPlayer()
@@ -5418,23 +5469,12 @@ async function openExtend(item?: LibraryClip) {
extendPrompt.value = clip?.prompt || prompt.value extendPrompt.value = clip?.prompt || prompt.value
extendDuration.value = clampDuration(duration.value) extendDuration.value = clampDuration(duration.value)
extendLoraStack.value = readLoraStack(clip) extendLoraStack.value = readLoraStack(clip)
lastFrameRevealed.value = false
extendOpen.value = true extendOpen.value = true
lastFrameLoading.value = true
lastFrameUrl.value = '' lastFrameUrl.value = ''
lastFrameLoading.value = false
player.value?.pause() player.value?.pause()
const gen = ++lastFrameGen if (!hideExtendLastFrame.value) await loadLastFrame(id)
try {
const blob = await $fetch<Blob>(`/api/library/clips/${id}/last-frame`, { responseType: 'blob' })
if (gen !== lastFrameGen) return
if (lastFrameObjectUrl) URL.revokeObjectURL(lastFrameObjectUrl)
lastFrameObjectUrl = URL.createObjectURL(blob)
lastFrameUrl.value = lastFrameObjectUrl
} catch (error: any) {
if (gen !== lastFrameGen) return
toast(error?.data?.statusMessage || 'Could not extract the last frame')
} finally {
if (gen === lastFrameGen) lastFrameLoading.value = false
}
} }
async function generateExtension() { async function generateExtension() {