EzFlex-LoopStart
The front door of a ComfyUI loop, and why round one is always empty
- initial value1
- initial value2
- initial value3
- initial value4
- initial value5
- initial value6
- initial value7
- initial value8
- initial value9
- initial value10
- initial value11
- initial value12
- initial value13
- initial value14
- initial value15
- initial value16
- initial value17
- initial value18
- initial value19
- initial value20
- _ezfeed1
- _ezfeed2
- _ezfeed3
- _ezfeed4
- _ezfeed5
- _ezfeed6
- _ezfeed7
- _ezfeed8
- _ezfeed9
- _ezfeed10
- _ezfeed11
- _ezfeed12
- _ezfeed13
- _ezfeed14
- _ezfeed15
- _ezfeed16
- _ezfeed17
- _ezfeed18
- _ezfeed19
- _ezfeed20
- index
- value1
- value2
- value3
- value4
- value5
- value6
- value7
- value8
- value9
- value10
- value11
- value12
- value13
- value14
- value15
- value16
- value17
- value18
- value19
- value20
You cannot draw a loop in ComfyUI. Not "it's awkward" - the engine rejects it. A link that points backwards is a dependency cycle, and the graph walker throws on it. Which is a problem, because the interesting jobs in 2026 are loops: generate a 30-second video in six chunks and feed each chunk the last frame of the one before it, or run the same face-detailer pass three times at descending denoise. So every pack that solves this does the same thing: it doesn't draw the loop, it unrolls it. The prompt gets rewritten between rounds - the body cloned, the next round's inputs written in as literal values - and the queue runs it as a straight line.
EzFlex-LoopStart is the node that surfaces what that unrolling produces: which round you're on, and the values carried in from the last one. It does exactly one job, and the pack's own comment says so - "hand the previous LoopEnd's product back to this round."
What the panel and the ports actually do
The panel has a single field: index, the starting round, 0 by default. Read-only at runtime. You set where the loop begins; the loop increments from there, one per pass.
Outputs, in order: index (INT) first, always - that's the one you wire into the index input of EzFlex-PromptHelper, EzFlex-MediaLoader, or EzFlex-TimeLine so each round reads the right card or the right segment. Then value1 through value20, which are dynamic: a port appears once you've connected something to the matching port on the LoopEnd, and not before.
Inputs: an optional index (leave it unwired and the panel value wins; wire it if an upstream node, like Easy-Use's forLoop index, should decide the start round) plus initial value1 through initial value20 - one per value port.
The initial values are the whole subtlety. Round one has no previous round, so valueN outputs whatever you put on initial valueN; from round two onward the fed-back value overrides it. If you leave an initial unwired, round one hands the downstream node nothing - which is fine for a node with an optional input, and a hard error for torch.cat, a VAE encode, or anything else that needs a real tensor. The classic case is the long-video chunk loop: LoopEnd.value1 receives the last frame of the current segment, LoopStart.value1 hands it to the next segment's conditioning - and on the first segment there is no last frame, so you feed the initial frame (or a still you want the motion to start from) into initial value1 and the body never sees a None.
Installing it
Same pack, same two lines. ComfyUI Manager → search EzFlex (pack title Comfyui-EzFlex-Presets) → install → restart. By hand:
cd ComfyUI/custom_nodes
git clone https://github.com/blackbossokok/Comfyui-EzFlex-Presets
# then restart ComfyUI
Dependencies are almost nothing: the only extra is mutagen, for reading audio/video tags - pip install -r requirements.txt inside the folder, or pip install mutagen. llama-cpp-python, gguf and onnx are optional and deliberately kept out of requirements so Manager never kicks off a compile. The pack wants ComfyUI 0.3.13+ because it uses the official i18n endpoint. It's a personal AI-assisted project with Chinese-first docs, so treat it as a power tool you debug yourself rather than a supported product - there's essentially no English-language discussion of it to fall back on.
Wiring it without hurting yourself
Full contract, in order: LoopStart.index → the index input of whatever needs to know which round it is. LoopStart.valueK → the body node that consumes the carried data. The body's output → LoopEnd.valueK. Done. Nothing goes from LoopEnd back to LoopStart on the canvas. The feed is implicit; a real wire closes the cycle and you get Dependency cycle detected.
When it doesn't work
- Round one dies on a
None. You skipped aninitial value. Wire the same kind of data you expect LoopEnd to carry back. - It runs once and stops. No paired
EzFlex-LoopEnd, or the End's round counter is 0. You'll see a line about it in the terminal - the loop nodes print rather than fail, so read the console, not the canvas. Dependency cycle detected. You wired End → Start. Delete it.- The loop seems to skip the body. The body is defined by reachability: everything downstream of the Start, stopping at the End. Anything fed from outside the loop keeps its original wire and is not cloned, so it's computed once and reused.
- Only the last round's values survive. That's
EzFlex-LoopEndworking as designed -out1..out20are the final round's carried values. To keep every round, carry a list: merge each round's product withEzFlex-MergeListand hand the merged list back through avalueKport.
One pleasant side effect: each round's clone gets different literal inputs, so the cache key changes and the body genuinely re-executes - no always-rerun tricks needed in the body.
Inputs (42)
| Name | Type | Default | Description |
|---|---|---|---|
| config | STRING | {} | Loop Start panel state (start round). Kept as a serialisable widget so the round counter survives save / load. |
| indexopt | INT | 0 | Start round (0 = from the first). Also becomes the index output value of the first round. Leave unwired to use the panel value. |
| initial value1opt | * | Initial value 1. Used as value1 on the first round, before any feed-back arrives. Wire the same kind of data you expect LoopEnd value1 to carry back. Optional, but required if the downstream node cannot accept a missing value. | |
| initial value2opt | * | Initial value 2. Used as value2 on the first round, before any feed-back arrives. Wire the same kind of data you expect LoopEnd value2 to carry back. Optional, but required if the downstream node cannot accept a missing value. | |
| initial value3opt | * | Initial value 3. Used as value3 on the first round, before any feed-back arrives. Wire the same kind of data you expect LoopEnd value3 to carry back. Optional, but required if the downstream node cannot accept a missing value. | |
| initial value4opt | * | Initial value 4. Used as value4 on the first round, before any feed-back arrives. Wire the same kind of data you expect LoopEnd value4 to carry back. Optional, but required if the downstream node cannot accept a missing value. | |
| initial value5opt | * | Initial value 5. Used as value5 on the first round, before any feed-back arrives. Wire the same kind of data you expect LoopEnd value5 to carry back. Optional, but required if the downstream node cannot accept a missing value. | |
| initial value6opt | * | Initial value 6. Used as value6 on the first round, before any feed-back arrives. Wire the same kind of data you expect LoopEnd value6 to carry back. Optional, but required if the downstream node cannot accept a missing value. | |
| initial value7opt | * | Initial value 7. Used as value7 on the first round, before any feed-back arrives. Wire the same kind of data you expect LoopEnd value7 to carry back. Optional, but required if the downstream node cannot accept a missing value. | |
| initial value8opt | * | Initial value 8. Used as value8 on the first round, before any feed-back arrives. Wire the same kind of data you expect LoopEnd value8 to carry back. Optional, but required if the downstream node cannot accept a missing value. | |
| initial value9opt | * | Initial value 9. Used as value9 on the first round, before any feed-back arrives. Wire the same kind of data you expect LoopEnd value9 to carry back. Optional, but required if the downstream node cannot accept a missing value. | |
| initial value10opt | * | Initial value 10. Used as value10 on the first round, before any feed-back arrives. Wire the same kind of data you expect LoopEnd value10 to carry back. Optional, but required if the downstream node cannot accept a missing value. | |
| initial value11opt | * | Initial value 11. Used as value11 on the first round, before any feed-back arrives. Wire the same kind of data you expect LoopEnd value11 to carry back. Optional, but required if the downstream node cannot accept a missing value. | |
| initial value12opt | * | Initial value 12. Used as value12 on the first round, before any feed-back arrives. Wire the same kind of data you expect LoopEnd value12 to carry back. Optional, but required if the downstream node cannot accept a missing value. | |
| initial value13opt | * | Initial value 13. Used as value13 on the first round, before any feed-back arrives. Wire the same kind of data you expect LoopEnd value13 to carry back. Optional, but required if the downstream node cannot accept a missing value. | |
| initial value14opt | * | Initial value 14. Used as value14 on the first round, before any feed-back arrives. Wire the same kind of data you expect LoopEnd value14 to carry back. Optional, but required if the downstream node cannot accept a missing value. | |
| initial value15opt | * | Initial value 15. Used as value15 on the first round, before any feed-back arrives. Wire the same kind of data you expect LoopEnd value15 to carry back. Optional, but required if the downstream node cannot accept a missing value. | |
| initial value16opt | * | Initial value 16. Used as value16 on the first round, before any feed-back arrives. Wire the same kind of data you expect LoopEnd value16 to carry back. Optional, but required if the downstream node cannot accept a missing value. | |
| initial value17opt | * | Initial value 17. Used as value17 on the first round, before any feed-back arrives. Wire the same kind of data you expect LoopEnd value17 to carry back. Optional, but required if the downstream node cannot accept a missing value. | |
| initial value18opt | * | Initial value 18. Used as value18 on the first round, before any feed-back arrives. Wire the same kind of data you expect LoopEnd value18 to carry back. Optional, but required if the downstream node cannot accept a missing value. | |
| initial value19opt | * | Initial value 19. Used as value19 on the first round, before any feed-back arrives. Wire the same kind of data you expect LoopEnd value19 to carry back. Optional, but required if the downstream node cannot accept a missing value. | |
| initial value20opt | * | Initial value 20. Used as value20 on the first round, before any feed-back arrives. Wire the same kind of data you expect LoopEnd value20 to carry back. Optional, but required if the downstream node cannot accept a missing value. | |
| _ezfeed1opt | * | Internal feed-back slot written by the loop expander. Not a canvas port. | |
| _ezfeed2opt | * | Internal feed-back slot written by the loop expander. Not a canvas port. | |
| _ezfeed3opt | * | Internal feed-back slot written by the loop expander. Not a canvas port. | |
| _ezfeed4opt | * | Internal feed-back slot written by the loop expander. Not a canvas port. | |
| _ezfeed5opt | * | Internal feed-back slot written by the loop expander. Not a canvas port. | |
| _ezfeed6opt | * | Internal feed-back slot written by the loop expander. Not a canvas port. | |
| _ezfeed7opt | * | Internal feed-back slot written by the loop expander. Not a canvas port. | |
| _ezfeed8opt | * | Internal feed-back slot written by the loop expander. Not a canvas port. | |
| _ezfeed9opt | * | Internal feed-back slot written by the loop expander. Not a canvas port. | |
| _ezfeed10opt | * | Internal feed-back slot written by the loop expander. Not a canvas port. | |
| _ezfeed11opt | * | Internal feed-back slot written by the loop expander. Not a canvas port. | |
| _ezfeed12opt | * | Internal feed-back slot written by the loop expander. Not a canvas port. | |
| _ezfeed13opt | * | Internal feed-back slot written by the loop expander. Not a canvas port. | |
| _ezfeed14opt | * | Internal feed-back slot written by the loop expander. Not a canvas port. | |
| _ezfeed15opt | * | Internal feed-back slot written by the loop expander. Not a canvas port. | |
| _ezfeed16opt | * | Internal feed-back slot written by the loop expander. Not a canvas port. | |
| _ezfeed17opt | * | Internal feed-back slot written by the loop expander. Not a canvas port. | |
| _ezfeed18opt | * | Internal feed-back slot written by the loop expander. Not a canvas port. | |
| _ezfeed19opt | * | Internal feed-back slot written by the loop expander. Not a canvas port. | |
| _ezfeed20opt | * | Internal feed-back slot written by the loop expander. Not a canvas port. |
Outputs (21)
| Name | Type | Description |
|---|---|---|
| index | INT | — |
| value1 | * | — |
| value2 | * | — |
| value3 | * | — |
| value4 | * | — |
| value5 | * | — |
| value6 | * | — |
| value7 | * | — |
| value8 | * | — |
| value9 | * | — |
| value10 | * | — |
| value11 | * | — |
| value12 | * | — |
| value13 | * | — |
| value14 | * | — |
| value15 | * | — |
| value16 | * | — |
| value17 | * | — |
| value18 | * | — |
| value19 | * | — |
| value20 | * | — |