Nodes/ComfyUI-Universal-Timer/πŸŽ›οΈ Universal Timer
ComfyUI Node

πŸŽ›οΈ Universal Timer

Universal Timer Puts a Stopwatch On the Canvas, Not in the Menu Bar

By hermankwanΒ·Created 7 days agoΒ·Updated 6 days agoΒ· 0
πŸŽ›οΈ Universal Timer
      β—„workflow_typeImageβ–Ί
      β—„total_count1β–Ί

      What this thing actually is

      Universal Timer is a big, dumb, extremely readable stopwatch that sits on your graph as a node. Red seven-segment digits, an all-caps status line, a color picker. You drop it into a workflow, hit Queue, and watch 00:00:00 start climbing while your sampler grinds through a 60-step run at 1024Γ—1024.

      That's the pitch, and it's a real niche, because the timing you already have lives in the wrong place. Crystools puts a progress bar and elapsed time up in the menu bar; rgthree adds one across the top of the window; comfyui-profiler writes per-node timings as labels on the nodes. All fine. But when you're recording a screen or staring at 40 nodes wondering whether the sampler or the upscale killed your coffee break, a clock in the graph is the one you can point at. That was the original ask for this class of tool - progress without panning.

      It doesn't break time down per node, though - one elapsed clock for the run, plus a progress counter. Need "which node is slow"? You want a profiler.

      How it works, mechanically

      The Python side is about 90 lines. UniversalTimer registers as an output node with zero outputs - RETURN_TYPES = (), OUTPUT_NODE = True. So it's a pure terminal: nothing wires out of it, and it exists only so the executor will fire it. When it runs, it stamps a start time in a module-level manager object, increments a completed counter, and broadcasts a websocket event (universal_timer_update) carrying the current count, the total, and which unit label to draw.

      The clock itself is frontend work. A JS extension patches app.queuePrompt, so hitting Queue posts to a small /universal_timer/reset route and starts a 100ms repaint loop - which is why the digits tick smoothly between server events instead of jerking forward once per node. All the LED drawing (segments, colon, swatches) is canvas painting in onDrawBackground.

      IS_CHANGED returns float("NaN"), the usual trick for forcing a node to re-run every time. On most nodes that's a trap - it poisons the cache behind them. Here it's free, since the timer has no upstream.

      The two widgets, and the outputs

      Two fields, and only one of them does anything.

      total_count (INT, 1–999999, default 1) is the functional one - the denominator of the [ 3 / 12 ] readout. The author's rule, from the README: native tensor batching (batch_size = 4 in a KSampler) is one execution cycle, so leave it at 1 and read the elapsed time as a single unit. Sequential loops - a loop node, a batch image loader, anything that re-triggers the graph N times - set total_count to N, and the counter walks up as the timer node re-executes each round.

      workflow_type (enum: Image, Video, Audio, Prompt, Training, Custom) is a label. Genuinely, literally a label - it maps to IMAGES, FRAMES, CLIPS, STEPS, EPOCHS, ITEMS and that's the whole effect. Image pipelines output images even if you spent three hours doing ControlNet passes in the middle; that's the author's classification rule. Don't go looking for hidden behavior in it.

      Outputs: none. Not a hidden one - none at all. Anything queued through the API gets an empty result, so treat it as UI-only.

      Installing it

      Manager is the sane path: Custom Nodes Manager β†’ search ComfyUI-Universal-Timer β†’ Install β†’ restart. Or manually:

      cd ComfyUI/custom_nodes
      git clone https://github.com/hermankwan/ComfyUI-Universal-Timer
      

      Then restart. Find it by right-clicking the canvas β†’ utils β†’ Universal Timer, or search the name.

      No models, no build step, no requirements.txt. pyproject.toml lists aiohttp, but the code only imports that and server.PromptServer, both shipped with ComfyUI - so nothing extra installs.

      Where people get burned

      This is v0.1.0 from a single author, first commit October 2026, with essentially no community track record yet. Judge it accordingly: it won't break your workflow (no inputs, no outputs, no dependencies), but don't expect polish.

      The pause is cosmetic. Hover the counter and click [ PAUSE ] and you freeze the display, not the job - generation keeps going and the progress count keeps updating.

      Refresh the page mid-run and the clock restarts. Elapsed time is frontend accounting, reset on load; the current / total counter re-syncs on the next tick. Clicking the digits zeroes it too.

      Requeueing mid-run doesn't reset it. The reset endpoint ignores requests while a run is in flight, so queueing three prompts in a row gives you one continuous clock across all three rather than three clean timings.

      It's a canvas-painted node, so Nodes 2.0 is a risk. Every pixel is custom drawing code - exactly the class of node ComfyUI's Vue-based frontend rewrite has broken across other packs. If the digits render wrong or the hover zones stop responding, switch back to the legacy canvas.

      And the boring one: it has to be in the executed graph. Bypass it or mute its group and you get no timing - the node is the trigger.

      Categoryutils/timer

      Inputs (2)

      NameTypeDefaultDescription
      workflow_typeCOMBOImage6 options: Image, Video, Audio, Prompt, Training, Custom
      total_countINT11–999999β€”

      Outputs (0)

      No outputs