Skip to content

Preserve placeholder connections when resolving to multiple clips - #277

Open
jakubjezek001 wants to merge 9 commits into
developfrom
enhancement/template-builder-multiple-resolved-connected-nodes
Open

Preserve placeholder connections when resolving to multiple clips#277
jakubjezek001 wants to merge 9 commits into
developfrom
enhancement/template-builder-multiple-resolved-connected-nodes

Conversation

@jakubjezek001

@jakubjezek001 jakubjezek001 commented Jun 26, 2026

Copy link
Copy Markdown
Member

Changelog Description

When a Loader Placeholder resolves to multiple clips without explicit "Input"/"Output" nodes, the system now preserves the original upstream and downstream connections by falling back to the last connectable node. Previously, placeholders resolving to multiple items would disconnect from the node graph, leaving all loaded clips floating. This fix ensures the first resolved item maintains the placeholder's original connections while additional items remain unconnected as intended.

The change addresses the root cause where get_group_io_nodes() returns None for both input/output when multiple clips lack specifically named IO nodes. The fallback logic identifies connectable nodes (those with available inputs or outputs) and uses the last one to maintain graph connectivity.

Additional info

The fix modifies the _set_loaded_connections method in the placeholder loader to include fallback logic when IO nodes are unavailable:

  • Filters loaded nodes for those with maxInputs() > 0 or maxOutputs() > 0
  • Uses the last connectable node as fallback for both input and output connections
  • Preserves existing behavior when proper IO nodes exist
  • Also improves docstring formatting for better code clarity

Testing notes:

  1. Create a Loader Placeholder in Nuke that resolves to multiple clips (e.g., multiple versions of a render)
  2. Connect nodes upstream and downstream of the placeholder
  3. Resolve the placeholder to load all matching clips
  4. Verify that the first loaded clip maintains the upstream/downstream connections
  5. Verify that additional loaded clips appear unconnected in the node graph

Dependency

Close #109
AY-7741

When multiple clips are loaded without explicit "Input"/"Output" nodes,
fall back to the last connectable node to preserve upstream/downstream
connections. Also improve docstring formatting.
@jakubjezek001 jakubjezek001 added the type: bug Something isn't working label Jun 26, 2026
@jakubjezek001 jakubjezek001 changed the title Fix placeholder node connections when IO nodes unavailable Enhancement: Preserve placeholder connections when resolving to multiple clips Jun 26, 2026
@jakubjezek001 jakubjezek001 self-assigned this Jun 26, 2026
@jakubjezek001 jakubjezek001 added the sponsored This is directly sponsored by a client or community member label Jun 26, 2026
@jakubjezek001 jakubjezek001 reopened this Jun 26, 2026
@jakubjezek001

Copy link
Copy Markdown
Member Author

closed by accindent

@jakubjezek001
jakubjezek001 marked this pull request as ready for review June 26, 2026 11:03
@jakubjezek001 jakubjezek001 changed the title Enhancement: Preserve placeholder connections when resolving to multiple clips Preserve placeholder connections when resolving to multiple clips Jun 26, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Improves Nuke Loader Placeholder behavior when it resolves to multiple clips by attempting to preserve the original node-graph connections (upstream/downstream) instead of leaving all loaded nodes disconnected.

Changes:

  • Updates _set_loaded_connections to add fallback logic when get_group_io_nodes() can’t find explicitly named “Input”/“Output” nodes for multi-clip loads.
  • Adjusts the method docstring/comment formatting for clarity.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread client/ayon_nuke/plugins/workfile_build/load_placeholder.py Outdated

@moonyuet moonyuet left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Works well for the load placeholder with clip loader
https://github.com/user-attachments/assets/aa609a5c-7613-4eb4-bce5-e86ef6556be6

It also works with load geo(input and output nodes).

Recording.2026-06-26.200953.mp4

Comment thread client/ayon_nuke/plugins/workfile_build/load_placeholder.py Outdated
@BigRoy

BigRoy commented Jul 13, 2026

Copy link
Copy Markdown
Member

What's the status here? @jakubjezek001

@jakubjezek001
jakubjezek001 requested a review from BigRoy July 15, 2026 14:26
Comment on lines +371 to +381
if input_node is None:
input_candidates = [
n for n in connectable if n.maxInputs() > 0]
input_node = (
input_candidates[0] if input_candidates else None)

if output_node is None:
output_candidates = [
n for n in connectable if n.maxOutputs() > 0]
output_node = (
output_candidates[0] if output_candidates else None)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you load a group that has say 5 nodes, and they are connected in one stream, like A-B-C-D-E. The input would be A, the output would be E. Right?

In this logic here, the input and output would be A - because it allows more inputs and outputs than zero and has the first name (sorted). I'm still confused by this logic.

It should really be that we prefer nodes that are at the start of the graph, e.g. have no inputs but do have outputs. (so they must be somewhere at the start of it) The same goes for outputs, it must be a node that preferably has no output connections (within the loaded nodes), allows to have outputs and if there are two nodes for which this is true prefer the one that does have input connections. So that if for whatever reason you load a group that has a separate floating node C, we'd still take the one at the end of a stream of nodes:

A-B
C

☝️ pick B?

Or what's the reasoning you're after @jakubjezek001 ?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

before it was not connecting any node by mistake. So if placeholder was connected and was resolving in multiple loadable containers - before it would not connect anything at all. But now after the fix it will connect at least single loaded node.

Try it and will see.

@BigRoy BigRoy Jul 16, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It may work consistently for a single node, but not for a graph of nodes as I'm trying to explain. If we're solving just the single node case - then the logic should consider it's only a single node. Then no need for the sorting and iterating. Then just:

if len(nodes) == 1:
    node = nodes[0]
    if node.maxInputs() > 0:
        input_node = node
    if node.maxOutputs() > 0:
        output_node = node

Right?

@moonyuet moonyuet Jul 20, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean this?

Suggested change
if input_node is None:
input_candidates = [
n for n in connectable if n.maxInputs() > 0]
input_node = (
input_candidates[0] if input_candidates else None)
if output_node is None:
output_candidates = [
n for n in connectable if n.maxOutputs() > 0]
output_node = (
output_candidates[0] if output_candidates else None)
if len(connectable) == 1:
node = connectable[0]
if node.maxInputs() > 0:
input_node = node
if node.maxOutputs() > 0:
output_node = node

@BigRoy BigRoy Jul 20, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The way I understand this can load and handle a group of nodes. These nodes, can have their own connections between themselves already.

Like:

A-B-C.

The logic we're defining here is to describe which of these nodes can act as input or output to the rest of the graph
as we've them loaded. Like, what are the inputs and outputs of this group. The B here should never be a viable candidate (or at least, it's the most unlikely one), since it's neither an input or an output of that graph because it is already connected to other inputs and outputs within the group node itself.

maxInputs and maxOutputs if I understand correctly define how many input connections and output connections the nodes may have. Which for B will both be >0 because it has both an input and output connection.

The most viable candidate in this example is:

  • A is the input node, because it's at the start of the group (has no incoming connections)
  • C is the output node, because it's at the end of the group (has no outgoing connections)

So it's really:

group_nodes.sort(lambda node: node.name())  # sort by something consistent
input_node = None
output_node = None
for node in group_nodes:
    if input_node is None:
        if has_inputs_within_group(node):
            continue
        if not can_have_inputs(node):
            input_node = node
    if output_node is None:
        if has_outputs_within_group(node):
            continue
        if not can_have_outputs(node):
            continue
        output_node = node

This is a stupidly overly simplified example.

Or I am completely misinterpreting what we're solving?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems to me there is misunderstanding here. If I understand it correctly this is solution for reconnecting a nodes which are resolved from placeholder. If the placeholder is connected to upstream connection Input or downstream connection Output then we need to replicate it at first found resolved node, and this is usually single node with single or multiple connectable Inputs or singular Output. There might be multiple of those nodes, since the placehoders rules might be lose and multiple containers might be loaded in the scene - but only single one can be replicating its related placehoder's connection.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or are we @BigRoy talking about the same thing but in different way?

@BigRoy BigRoy Aug 14, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. There is a single placeholder node, from which we transfer the input and output connections to the "loaded group"
  2. We transfer these to the "assumed input" and "assumed output" node in the loaded group.

This number 2) is what we're computing here. From all the nodes we loaded (of a single load!) give me which node represents the first input node and which the output node so that we can transfer the connections from step 1).

The loaded group of nodes, may have any amount of nodes and connections.
From that loaded group - we must search for the node that we THINK is the input and the output; and that's where I'm describing there's a flaw in the logic.

We must exclude nodes that in the loaded group already have internal connections, because in a loaded group that has:

  • A-B-C

Then B must never be what we assume is the input or output node.

We may trigger this across multiple loaded groups, yes. But the logic as I understand it here is about finding the input and output of the group of ONE loaded container.

@moonyuet

moonyuet commented Jul 20, 2026

Copy link
Copy Markdown
Member

What's the state for this? I tested with #277 (comment), it still works fine. It doesn't work for the loader when we are using the viewer as output. (So did the initial commit.)
But I assume it is not for viewer as output or?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

sponsored This is directly sponsored by a client or community member type: bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

AY-7741_placeholder resolved with multiple items turns into disconnected

5 participants