Allow Studio 2 MiniMax text-to-video with empty start when locks are off.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Towsty
2026-09-16 14:56:16 -05:00
co-authored by Cursor
parent 5694104226
commit 36d24feb9c
4 changed files with 27 additions and 5 deletions
-1
View File
@@ -52,7 +52,6 @@ export function validateRequest(raw, xaigen = false) {
if (video) {
if (promptSections.cameraBeats.slice(0,-1).some(b=>b.durationSec == null)) fail('Only the last camera beat can run to the end.')
if (promptSections.cameraBeats.reduce((sum,b)=>sum+(b.durationSec || 0),0)>duration) fail('Camera beats exceed the clip duration.')
if (raw.lockFace === false && raw.lockOutfit === false && !raw.imageAId && !raw.startClipId) fail('Choose a start still or previous clip when both identity locks are off.')
}
const frames=Math.ceil((duration*number('fps',24,1,60)-5)/17)*17+5
const shotSeeds=queueSeeds(raw.settings,1+(Array.isArray(raw.batch)?raw.batch.length:0))
+11
View File
@@ -2,9 +2,20 @@ export function nativeVideoGraph(template, request, files, prefix) {
const appearance = request.lockFace !== false || request.lockOutfit !== false
if (appearance && !files.hero) throw new Error('Identity still is required; never substitute the start frame.')
const g=structuredClone(template), s=request.settings
const textToVideo = request.mode === 'video' && !appearance && !files.start
if (appearance) { g.hero.inputs.image=files.hero; g['155'].inputs['ref_images.ref_image_0']=['hero',0] }
else { delete g.hero; delete g['155'].inputs['ref_images.ref_image_0'] }
Object.assign(g['155'].inputs,{prompt:request.compiledPrompt,width:s.width,height:s.height,length:Math.ceil((s.duration*(s.fps || 24)-5)/17)*17+5,ref_image_size:'max'})
if (textToVideo) {
// Studio 1 T2V: MiniMaxH3ImageToVideo with first_frame disconnected (no empty placeholder still).
g['155'].class_type = 'MiniMaxH3ImageToVideo'
g['155']._meta = { title: 'MiniMax H3 Text to Video' }
delete g['155'].inputs['ref_images.ref_image_0']
delete g['155'].inputs.ref_image_size
delete g['155'].inputs.audio_vae
delete g['155'].inputs.first_frame
delete g['155'].inputs.last_frame
}
let conditioning=['155',0]
for (const [name,image,frame] of [['start',files.start,0],['end',files.end,-1],...(files.guides||[]).map((f,i)=>[`guide${i}`,f.image,f.frame])]) {
if (!image) continue