Let text-to-video generate without a still: Still/Text lives on the Video card, and Text mode skips the required input image.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+34
-37
@@ -12,9 +12,11 @@
|
||||
:current="imageStudio ? 'image' : 'video'"
|
||||
:ltx-enabled="ltxEnabled"
|
||||
:video-engine="videoEngine"
|
||||
:video-start="videoStart"
|
||||
:image-engine="v2Engine"
|
||||
@select="selectStudioKind"
|
||||
@video-engine="selectVideoEngine"
|
||||
@video-start="selectVideoStart"
|
||||
@image-engine="setV2Engine"
|
||||
/>
|
||||
<div class="grid min-w-0 gap-6 lg:grid-cols-[minmax(0,1fr)_minmax(0,1fr)] lg:items-stretch">
|
||||
@@ -37,11 +39,13 @@
|
||||
: 'Edit: one still plus text. Compose is a separate graph if you need a second still.')
|
||||
: studioMode === 'edit'
|
||||
? 'Drop the still to edit. An optional second still applies image 2 onto image 1. Files leave the desktop after save.'
|
||||
: 'Drop a still, describe the motion, then send the job. Generate stays available — a long shot list takes one queue slot, and you can line up more while it runs.' }}</p>
|
||||
: (textToVideo
|
||||
? 'Text-to-video: write a prompt and generate. No start still required. Shot 2+ still continues from the last frame.'
|
||||
: 'Drop a still, describe the motion, then send the job. Switch the Video card to Text for text-to-video.') }}</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="!(studioMode === 'editv2' && (v2Mode === 'generate' || (v2Mode === 'iterate' && !file && !inputStillId)))"
|
||||
v-if="!(studioMode === 'editv2' && (v2Mode === 'generate' || (v2Mode === 'iterate' && !file && !inputStillId))) && !(studioMode === 'video' && textToVideo && !file && !inputStillId)"
|
||||
class="relative cursor-pointer rounded-2xl border border-dashed border-white/15 bg-zinc-950/50 p-4 transition hover:border-amber-300/50"
|
||||
:class="{ 'border-amber-300/70 bg-amber-400/5': dragging }"
|
||||
@dragover.prevent="dragging = true"
|
||||
@@ -73,6 +77,13 @@
|
||||
<p class="mt-1 text-sm text-zinc-500">{{ textToVideo ? 'Text-to-video does not need a still. Shot 2+ will still extend from the last frame.' : 'Browse the library or upload a new PNG, JPG, or WEBP' }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-else-if="studioMode === 'video' && textToVideo"
|
||||
class="rounded-2xl border border-dashed border-white/15 bg-zinc-950/40 px-4 py-3 text-sm text-zinc-400"
|
||||
>
|
||||
<button type="button" class="font-medium text-amber-100 hover:underline" @click="openPicker('main')">Optional · add a start still</button>
|
||||
<span class="mt-1 block text-zinc-500">Text-to-video does not need one. Shot 2+ still extends from the last frame.</span>
|
||||
</div>
|
||||
<div
|
||||
v-else-if="studioMode === 'editv2' && v2Mode === 'generate' && (file || inputStillId)"
|
||||
class="rounded-2xl border border-white/10 bg-zinc-950/40 px-4 py-3 text-sm text-zinc-400"
|
||||
@@ -649,30 +660,7 @@
|
||||
</div>
|
||||
|
||||
<div v-if="studioMode === 'video'" class="space-y-3">
|
||||
<div>
|
||||
<p class="mb-2 text-xs uppercase tracking-wider text-zinc-500">Start from</p>
|
||||
<div class="grid grid-cols-2 gap-2">
|
||||
<button
|
||||
type="button"
|
||||
class="rounded-xl border px-3 py-2 text-left text-sm"
|
||||
:class="videoStart === 'still' ? 'border-amber-300 bg-amber-400/10 text-amber-100' : 'border-white/10 hover:border-white/20'"
|
||||
@click="videoStart = 'still'"
|
||||
>
|
||||
<span class="block font-semibold">A still</span>
|
||||
<span class="text-xs text-zinc-400">Image to video. Extensions use the last frame.</span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="rounded-xl border px-3 py-2 text-left text-sm"
|
||||
:class="videoStart === 'text' ? 'border-amber-300 bg-amber-400/10 text-amber-100' : 'border-white/10 hover:border-white/20'"
|
||||
@click="videoStart = 'text'"
|
||||
>
|
||||
<span class="block font-semibold">Text only</span>
|
||||
<span class="text-xs text-zinc-400">No start still. Shot 2+ still continues from last frame.</span>
|
||||
</button>
|
||||
</div>
|
||||
<p class="mt-2 text-xs text-zinc-500">{{ videoModelHint }}</p>
|
||||
</div>
|
||||
<p class="text-xs text-zinc-500">{{ videoModelHint }}</p>
|
||||
<div v-if="showLegacyMinimaxV1 && videoEngine === 'minimax' && videoStart === 'still'">
|
||||
<p class="mb-2 text-xs uppercase tracking-wider text-zinc-500">MiniMax graph</p>
|
||||
<div class="grid grid-cols-2 gap-2">
|
||||
@@ -7468,6 +7456,11 @@ function selectVideoEngine(engine: VideoEngineId) {
|
||||
applyEngineDefaults(engine)
|
||||
}
|
||||
|
||||
function selectVideoStart(start: VideoStartId) {
|
||||
videoStart.value = start
|
||||
if (studioMode.value !== 'video') selectStudioKind('video')
|
||||
}
|
||||
|
||||
function applyVideoWorkflow(raw?: string) {
|
||||
const parsed = coerceVideoWorkflow(raw, ltxEnabled.value)
|
||||
videoEngine.value = videoEngineOf(parsed)
|
||||
@@ -7522,15 +7515,17 @@ async function generate() {
|
||||
toast('Choose a library folder before generating.')
|
||||
return
|
||||
}
|
||||
try {
|
||||
await ensureVideoInputStill()
|
||||
} catch {
|
||||
toast('Could not load the selected still for image-to-video.')
|
||||
return
|
||||
}
|
||||
if (!textToVideo.value && !file.value && !inputStillId.value) {
|
||||
toast('Load a still first. Image-to-video needs an input still.')
|
||||
return
|
||||
if (!textToVideo.value) {
|
||||
try {
|
||||
await ensureVideoInputStill()
|
||||
} catch {
|
||||
toast('Could not load the selected still for image-to-video.')
|
||||
return
|
||||
}
|
||||
if (!file.value && !inputStillId.value) {
|
||||
toast('Load a still first. Image-to-video needs an input still.')
|
||||
return
|
||||
}
|
||||
}
|
||||
const shots = shotScriptMode.value ? parsedShots.value : null
|
||||
const initialPrompt = (shots?.[0]?.prompt || prompt.value).trim()
|
||||
@@ -7549,8 +7544,10 @@ async function generate() {
|
||||
try {
|
||||
await ensureGenerationNotifyPermission()
|
||||
const body = new FormData()
|
||||
if (file.value) body.append('image', file.value)
|
||||
if (inputStillId.value) body.append('stillId', inputStillId.value)
|
||||
if (!textToVideo.value) {
|
||||
if (file.value) body.append('image', file.value)
|
||||
if (inputStillId.value) body.append('stillId', inputStillId.value)
|
||||
}
|
||||
body.append('prompt', composePromptParts(promptPre.value, initialPrompt, promptPost.value) || initialPrompt)
|
||||
body.append('promptMid', initialPrompt)
|
||||
body.append('promptPre', promptPre.value.trim())
|
||||
|
||||
Reference in New Issue
Block a user