diff --git a/js/ltx_director.js b/js/ltx_director.js index f0cb07f..e4c2426 100644 --- a/js/ltx_director.js +++ b/js/ltx_director.js @@ -11550,6 +11550,10 @@ app.registerExtension({ self.removeInput(idx); } } + const timelineIdx = self.inputs.findIndex(i => i?.name === "timeline"); + if (timelineIdx !== -1 && self.inputs[timelineIdx]?.link == null) { + self.removeInput(timelineIdx); + } }; this._resolveNodeLinkedValue = function (targetNode, inputName, options = {}) { const originNode = self._findLinkedOriginNode(targetNode, inputName); @@ -11583,14 +11587,18 @@ app.registerExtension({ return { imageFile, imageB64: imageUrl }; }; this._buildExternalTimelinePayload = function () { - const timelineNode = self._findLinkedOriginNode(self, "timeline"); - const comfyClass = timelineNode?.comfyClass || timelineNode?.type || ""; - if (!timelineNode || comfyClass !== "TimelineCS") { - return null; + let sectionSetNode = self._findLinkedOriginNode(self, "section_set"); + let setClass = sectionSetNode?.comfyClass || sectionSetNode?.type || ""; + if (!sectionSetNode || setClass !== "TimelineSectionSetCS") { + const timelineNode = self._findLinkedOriginNode(self, "timeline"); + const comfyClass = timelineNode?.comfyClass || timelineNode?.type || ""; + if (!timelineNode || comfyClass !== "TimelineCS") { + return null; + } + sectionSetNode = self._findLinkedOriginNode(timelineNode, "section_set"); + setClass = sectionSetNode?.comfyClass || sectionSetNode?.type || ""; } - const sectionSetNode = self._findLinkedOriginNode(timelineNode, "section_set"); - const setClass = sectionSetNode?.comfyClass || sectionSetNode?.type || ""; const sections = []; let duration = 0; if (sectionSetNode && setClass === "TimelineSectionSetCS") { diff --git a/ltx_director.py b/ltx_director.py index 32b7cfb..62f70e7 100644 --- a/ltx_director.py +++ b/ltx_director.py @@ -33,7 +33,7 @@ from .prompt_relay import ( from .patches import detect_model_type, apply_patches from .msr_character import MSRCharacterSetData -from .timeline_nodes import TimelineData +from .timeline_nodes import TimelineData, TimelineSectionSetData log = logging.getLogger(__name__) @@ -2044,10 +2044,15 @@ class LTXDirector(io.ComfyNode): optional=True, tooltip="Optional external MSR Character Set. Replaces the legacy inline character panel in the director UI.", ), + TimelineSectionSetData.Input( + "section_set", + optional=True, + tooltip="Optional external Timeline Section Set DUMAS payload. When connected, it populates the main timeline track and derives the duration from the sections.", + ), TimelineData.Input( "timeline", optional=True, - tooltip="Optional external Timeline DUMAS payload. When connected, it populates the main timeline track and duration.", + tooltip="Legacy external Timeline DUMAS payload kept for backward compatibility with older workflows.", ), io.Float.Input( "start", force_input=True, optional=True, default=0.0, @@ -2084,7 +2089,7 @@ class LTXDirector(io.ComfyNode): custom_width=768, custom_height=512, resize_method="maintain aspect ratio", divisible_by=32, img_compression=0, audio_vae=None, optional_latent=None, use_custom_audio=False, inpaint_audio=True, use_custom_motion=True, override_audio=False, - vae=None, reference_strength=1.0, character_set=None, timeline=None, + vae=None, reference_strength=1.0, character_set=None, section_set=None, timeline=None, start=None, end=None, duration=None) -> io.NodeOutput: input_dir = folder_paths.get_input_directory() image_cache = {} @@ -2101,9 +2106,15 @@ class LTXDirector(io.ComfyNode): processed_image_cache[cache_key] = processed return processed - if timeline is not None: + external_timeline_source = None + if section_set is not None: + external_timeline_source = {"sections": list((section_set or {}).get("sections") or [])} + elif timeline is not None: + external_timeline_source = timeline + + if external_timeline_source is not None: external_tdata, external_local_prompts, external_segment_lengths, external_duration_seconds, external_duration_frames = _build_runtime_timeline_payload( - timeline, + external_timeline_source, float(frame_rate) if frame_rate else 24.0, ) try: