h4 - Universal Buffer
The universal buffer that kills the one-cycle lag in loops
- image_in
- buffered_data
H4_ImageBuffer is the "hold my data between loops" node, and despite the name it isn't image-only - the tooltip says it stores anything: images, latents, text. The problem it solves is a real one in ComfyUI's loop workflows. Loops in ComfyUI work by feeding a node's output back into its own input, but there's a classic one-cycle drive lag: on the first pass, the value the loop wants isn't there yet, so the workflow either stalls or processes garbage. A buffer node catches the data on one cycle and hands it back on the next, smoothing the loop into a continuous pipeline.
The mechanism is dead simple and honest: it keeps a global store. Wire something into image_in and it buffers it (returning the same data as a passthrough); leave image_in empty and it looks up whatever was buffered last and returns that. Nothing in between, no clever caching. It's the anti-lag glue that h4's loop tutorials and the Traffic/Mission Control suite rely on.
The input
- image_in - a
*wildcard: image, latent, string, anything. Connect it to store data; leave it empty to load what was stored on the previous run.
The output
- buffered_data - the stored value, or the most recently buffered one when the input is empty.
Installing
Standard h4_Live install: ComfyUI Manager → search "h4_Live", or:
cd ComfyUI/custom_nodes
git clone https://github.com/m3rr/h4_Live
restart. Pure Python, no dependencies, no models. It's in the pack's core logic family, and the whole pack is designed to be loop-friendly - this is one of the nodes that makes that claim real.
Where people get burned
The gotchas are the shape of the buffer itself. First, it's a global store, not a per-node one - the source comments confirm it overwrites whatever was buffered before, so two buffers in one workflow can clobber each other. If you're buffering two different things, give them distinct paths or you'll get cross-talk. Second, it's stateful: the buffered value persists until something else buffers over it, so a workflow can behave differently on its second run if your loop doesn't reset. And third, the "empty input = load last" behavior means a disconnected buffer silently returns stale data rather than failing loudly - which is convenient in loops and a trap when you forget it's there.
Keep it simple: use one buffer per loop, store at the top of the cycle, load where the lag was biting, and verify your loop's first iteration explicitly. It's a small node with a narrow job, and it does that job well.
Inputs (1)
| Name | Type | Default | Description |
|---|---|---|---|
| image_inopt | * | Wire ANYTHING here (Image, Latent, etc) to Store. Leave empty to Load. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| buffered_data | * | — |