Iterating an array of nodes, each of which can have children
Collection initializer
You can improve and simplify your code by first tuning the Node.

make it IEnumerable&lt;T&gt; and consequently remove the Children and HasChildren properties because now we can use LINQ's Any
let the Name property take care of the formatting and keep the value clean in a dedicated field
replace AddChild with the Add method to be able to use collection initializer
replace the array with a root node

Example:
public class Node&lt;T&gt; : IEnumerable&lt;Node&lt;T&gt;&gt;
{
    private readonly T _value;

    private readonly List&lt;Node&lt;T&gt;&gt; _children = new List&lt;Node&lt;T&gt;&gt;();

    public Node(T value) =&gt; _value = value;

    public T Value =&gt; _value;

    public string Name =&gt; $&quot;Node #{_value}&quot;;

    public void Add(Node&lt;T&gt; node) =&gt; _children.Add(node);

    public override string ToString() =&gt; Name;

    public IEnumerator&lt;Node&lt;T&gt;&gt; GetEnumerator() =&gt; _children.GetEnumerator();

    IEnumerator IEnumerable.GetEnumerator() =&gt; GetEnumerator();
}


Enumerator
Now you can improve the algorithm by using the Enumerator. There is no need for any indexes or tuples. What you need to do is to GetEnumerator from each node and MoveNext on it until it is now longer possible to continue or continue from a sub node if it contains Any.
The enumerator will keep the current state allowing you to continue iterating on child nodes and resume from the parent node later that's why you need to re-push the current node back to the stack.
An extension for the Node&lt;T&gt; could look like this:
public static IEnumerable&lt;Node&lt;T&gt;&gt; Flatten&lt;T&gt;(this Node&lt;T&gt; root)
{
    var stack = new Stack&lt;IEnumerator&lt;Node&lt;T&gt;&gt;&gt;();
    stack.Push(root.GetEnumerator()); // start with the root node

    yield return root; // return the root node
    
    while (stack.Any())
    {
        var node = stack.Pop();
        while (node.MoveNext())
        {
            yield return node.Current;
            if (node.Current.Any())
            {
                stack.Push(node); // re-add the node to continue later
                stack.Push(node.Current.GetEnumerator()); // continue from here now
                break; // we'll continue from &quot;node&quot; later, when node.Current is enumerated
            }
        }
    }
}


Example
You can now create nodes like arrays without confusing parenthesess when adding subnodes:
var nodes = new Node&lt;int&gt;(0)
{
    new Node&lt;int&gt;(1),
    new Node&lt;int&gt;(2),
    new Node&lt;int&gt;(3)
    {
        new Node&lt;int&gt;(4),
        new Node&lt;int&gt;(5)
        {
            new Node&lt;int&gt;(6)
            {
                new Node&lt;int&gt;(7)
            },
            new Node&lt;int&gt;(8)
            {
                new Node&lt;int&gt;(9),
                new Node&lt;int&gt;(10)
            },
            new Node&lt;int&gt;(11)
        }
    },
    new Node&lt;int&gt;(12)
};

after flattening it
nodes.Flatten().Select(n =&gt; n.Name).Dump();

you'll get:

Node #0 
Node #1 
Node #2 
Node #3 
Node #4 
Node #5 
Node #6 
Node #7 
Node #8 
Node #9 
Node #10 
Node #11 
Node #12