Keyframe-anchored motion on LTX-2.3 22B distilled: approved stills pin the first frame, the last frame, and optionally a middle anchor (chained LTXVAddGuide at exact frame indices), and the model generates the motion between them with optional synchronized audio - the motion engine of the keyframe-first pipeline (plan in stills, spend in motion)
Tags: flagshipltx-2videokeyframesinterpolationkeyframe-first2026-sota
Inputs (10)#
The typed parameter surface callers bind when they request this workflow. Enum options and numeric bounds are the values the workflow document declares.
promptstringrequiredfirst_frameimagerequiredlast_frameimagerequiredmiddle_frameimageuse_middle_framebooleandefault falseguide_strengthfloatdefault 0.7min 0.1max 1.0generate_audiobooleandefault trueresolutionenumdefault landscape_1280landscape_1280portrait_1280base_768duration_secondsintegerdefault 6min 1max 20seedintegerdefault -1ComfyUI node graph (29)#
The executable ComfyUI prompt graph: 29 nodes across 22 distinct node classes, wired by 44 data dependencies. Nodes tinted green come from a custom node pack this workflow declares; the rest are ComfyUI core / baked-community classes.
Nodes (29)#
1CheckpointLoaderSimplecoreckpt_name = ltx-2.3-22b-distilled-fp8.safetensorsMODELCLIPVAE2LTXAVTextEncoderLoadercoretext_encoder = gemma_3_12B_it_fp4_mixed.safetensorsckpt_name = ltx-2.3-22b-distilled-fp8.safetensorsdevice = defaultCLIP3CLIPTextEncodecoretext = {{prompt}} tmplclip = ◂ node 2 · out[0]CONDITIONING4CLIPTextEncodecoretext = static image, jump cut, morphing artifacts, watermark, subtitles, distorted faces, harsh noiseclip = ◂ node 2 · out[0]CONDITIONING5LTXVConditioningcorepositive = ◂ node 3 · out[0]negative = ◂ node 4 · out[0]frame_rate = 24.0CONDITIONINGCONDITIONING6EmptyLTXVLatentVideocorewidth = {{resolution_map[resolution].width}} tmplheight = {{resolution_map[resolution].height}} tmpllength = {{24 * duration_seconds + 1}} tmplbatch_size = 1LATENTfirst_loadLoadImagecoreimage = {{first_frame}} tmplIMAGEMASKfirst_prepLTXVPreprocesscoreimage = ◂ node first_load · out[0]img_compression = 35IMAGEguide_firstLTXVAddGuidecorepositive = ◂ node 5 · out[0]negative = ◂ node 5 · out[1]vae = ◂ node 1 · out[2]latent = ◂ node 6 · out[0]image = ◂ node first_prep · out[0]frame_idx = 0strength = {{guide_strength}} tmplCONDITIONINGCONDITIONINGLATENTmid_loadLoadImagecoreimage = {{middle_frame}} tmplIMAGEMASKmid_prepLTXVPreprocesscoreimage = ◂ node mid_load · out[0]img_compression = 35IMAGEguide_midLTXVAddGuidecorepositive = ◂ node guide_first · out[0]negative = ◂ node guide_first · out[1]vae = ◂ node 1 · out[2]latent = ◂ node guide_first · out[2]image = ◂ node mid_prep · out[0]frame_idx = {{(24 * duration_seconds // 2) // 8 * 8}} tmplstrength = {{guide_strength}} tmplCONDITIONINGCONDITIONINGLATENTguide_lastLTXVAddGuidecorepositive = ◂ node guide_mid · out[0]negative = ◂ node guide_mid · out[1]vae = ◂ node 1 · out[2]latent = ◂ node guide_mid · out[2]image = ◂ node last_prep · out[0]frame_idx = -1strength = {{guide_strength}} tmplCONDITIONINGCONDITIONINGLATENTlast_loadLoadImagecoreimage = {{last_frame}} tmplIMAGEMASKlast_prepLTXVPreprocesscoreimage = ◂ node last_load · out[0]img_compression = 35IMAGEaudio_vaeLTXVAudioVAELoadercoreckpt_name = ltx-2.3-22b-distilled-fp8.safetensorsVAEaudio_latentLTXVEmptyLatentAudiocoreframes_number = {{24 * duration_seconds + 1}} tmplframe_rate = 24batch_size = 1audio_vae = ◂ node audio_vae · out[0]LATENTav_concatLTXVConcatAVLatentcorevideo_latent = ◂ node guide_last · out[2]audio_latent = ◂ node audio_latent · out[0]LATENT7RandomNoisecorenoise_seed = {{seed}} tmplNOISE8CFGGuidercoremodel = ◂ node 1 · out[0]positive = ◂ node guide_last · out[0]negative = ◂ node guide_last · out[1]cfg = 1.0GUIDER9KSamplerSelectcoresampler_name = euler_cfg_ppSAMPLER10ManualSigmascoresigmas = 1.0, 0.99375, 0.9875, 0.98125, 0.975, 0.909375, 0.725, 0.421875, 0.0SIGMAS11SamplerCustomAdvancedcorenoise = ◂ node 7 · out[0]guider = ◂ node 8 · out[0]sampler = ◂ node 9 · out[0]sigmas = ◂ node 10 · out[0]latent_image = ◂ node av_concat · out[0]LATENTLATENTav_splitLTXVSeparateAVLatentcoreav_latent = ◂ node 11 · out[0]LATENTLATENTcrop_guidesLTXVCropGuidescorepositive = ◂ node guide_last · out[0]negative = ◂ node guide_last · out[1]latent = ◂ node av_split · out[0]CONDITIONINGCONDITIONINGLATENT12VAEDecodecoresamples = ◂ node crop_guides · out[2]vae = ◂ node 1 · out[2]IMAGEaudio_decodeLTXVAudioVAEDecodecoresamples = ◂ node av_split · out[1]audio_vae = ◂ node audio_vae · out[0]AUDIO13CreateVideocoreimages = ◂ node 12 · out[0]fps = 24audio = ◂ node audio_decode · out[0]VIDEO14SaveVideocorevideo = ◂ node 13 · out[0]filename_prefix = ltx2_keyframe_interpformat = autocodec = autoParameter banks (1)#
The prompt / configuration lookup tables this workflow keys into from its inputs — the vocabulary that turns a style / palette / preset selection into graph parameters.
resolution_map (3)#
landscape_1280{"width": 1280, "height": 704}portrait_1280{"width": 704, "height": 1280}base_768{"width": 768, "height": 512}Models & dependencies#
Models required (2)#
gemma_3_12B_it_fp4_mixed.safetensorsltx-2.3-22b-distilled-fp8.safetensorsOutput contract#
What a successful run of this workflow returns.
typevideoformatmp4audiotrueTaxonomy & routing#
How the control plane classifies this workflow — from the committed workflow-taxonomy-registry.json. It drives the consistency / control surface the agentic director can exercise over the workflow.
assetFamilykeyframe-anchored-motionoutputPackageProfilevideo-master-profilecontrolModalitieskeyframe-anchor-lockreference-ensembleseed-lockmodel-locksampler-scheduler-locktemporal-lockconsistencyDimensionsmotioncolor-scriptidentitynotesThe keyframe-first motion engine (L2): approved stills pinned at frame 0 / -1 / optional 8-snapped midpoint via chained LTXVAddGuide (strength 0.7 per FLF blueprint), guides cropped before decode.