ComfyUI Node

Unified Prefix

The Unified Prefix Node

By noelkim12·Created 12 months ago·Updated 12 months ago· 1
Unified Prefix
  • portrait_image
  • video_image
  • portrait_fullprefix
  • portrait_image
  • video_fullprefix
  • video_image
  • frame_fullprefix
  • frame_image
character_nametest
pad_portrait3
pad_run3
pad_frame5
gap_timeout_sec1.5

If you generate the same character across days of sessions - portraits one night, animation frames the next - your save folder is probably a disaster zone of 00001.png, copy_final_v3.png and existential dread. NoelUnifiedPrefix hands you a ready-made Save Image prefix like Risu/portrait_032 or Risu/animation_002/00007 and keeps the counters going between sessions, so you never overwrite an earlier take and never have to mentally reconstruct where the last run stopped. It's the "naming files so you don't have to" node.

It's a text/counter utility, not a generator - you wire its prefix strings into Save Image's filename_prefix and let it count for you. For character work specifically (keeping one character's output in its own folder tree), that's a surprisingly large quality-of-life win.

How it works

The node keeps a small JSON state file (character_counters.json inside the pack's _state folder) with a counter block per character_name: a portrait counter, a run counter, a frame counter, and a timestamp. Feed an image into portrait_image and it bumps the portrait counter and returns {character}/portrait_{###}. Feed a frame into video_image and it does the run/frame dance: if the gap since the last video frame is bigger than gap_timeout_sec, it starts a new animation run (run counter up, frame back to 1) - that's how it knows a fresh batch is a fresh animation_00N folder.

State is saved to disk under a thread lock on every run, which is why the counters survive restarts and even queue crashes.

Inputs that matter

  • character_name (default test) - the folder name. Set this one, or everything piles under test/.
  • pad_portrait / pad_run / pad_frame (defaults 3/3/5) - zero-padding width per counter.
  • gap_timeout_sec (default 1.5) - the time gap that triggers a new animation run. Keep it small for real-time frame streaming; bump it if you generate frames slowly and don't want every other frame to become a new run.
  • portrait_image / video_image (optional) - the triggers that actually advance the counters. They're also passed straight through as the portrait_image / video_image outputs, so you can daisy-chain the node into the middle of a graph without extra wires.

Outputs: portrait_fullprefix, video_fullprefix, frame_fullprefix (the strings for Save Image), plus the two image pass-throughs. frame_fullprefix is nested - {character}/animation_{###}/{#####} - so frames land inside their run's folder.

Installing it

Same pack as its sibling, so this is a one-time setup:

cd ComfyUI/custom_nodes
git clone https://github.com/noelkim12/ComfyUI-NoelTextUtil

then restart ComfyUI, or search ComfyUI-ComfyUI-NoelTextUtil in ComfyUI Manager. No models, no dependencies, pure Python plus a bit of frontend.

Where people get burned

  • The state file ships with the repo and is git-tracked. That means your clone arrives with a leftover Risu test entry at portrait 32, and - the real trap - a git pull to update the pack can roll your carefully counted output back to that shipped state. If your counters matter, back up _state/character_counters.json before updating.
  • The counters only move when the image inputs fire. If you generate a batch without connecting portrait_image, you'll get the same prefix every time and silently overwrite. The node counts what flows through it, not what you think you queued.
  • It's ComfyUI's own formatting you're feeding. The source comment is blunt: leave Save Image's subfolder empty and put the prefix in filename_prefix, or the two conventions collide.

Is it essential? No - you could hand-roll these strings. But if you're running hundreds of portrait takes of one character, "never think about numbering again" is a real feature, and this is the cheapest version of it you'll find.

CategoryNoel/Prefixes

Inputs (7)

NameTypeDefaultDescription
character_nameSTRINGtest
pad_portraitINT31–10
pad_runINT31–10
pad_frameINT51–10
gap_timeout_secFLOAT1.50–60
portrait_imageoptIMAGE
video_imageoptIMAGE

Outputs (6)

NameTypeDescription
portrait_fullprefixSTRING
portrait_imageIMAGE
video_fullprefixSTRING
video_imageIMAGE
frame_fullprefixSTRING
frame_imageIMAGE