Nodes/GIF Toolkit/GIF Text Designer (legacy single-layer)
ComfyUI Node

GIF Text Designer (legacy single-layer)

One caption, dragged into place

By oekobudde·Created 28 days ago·Updated 26 days ago· 1
GIF Text Designer (legacy single-layer)
  • images
  • style
  • preview
◄enabledtrue►
◄textLET'S GO!►
◄fontDejaVuSans-Bold.ttf►
◄font_size34►
◄font_color#ffff00►
◄x_percent50.0►
◄y_percent15.0►
◄background_enabledfalse►
◄background_color#000000►
◄background_opacity160►
◄padding8►
◄corner_radius8►
◄outline_enabledtrue►
◄outline_color#000000►
◄outline_width2►
◄shadow_enabledfalse►
◄shadow_color#000000►
◄shadow_offset_x2►
◄shadow_offset_y2►
◄line_spacing4►
◄preview_frame0►

The pack used to have one text node. It put a single caption on a frame, let you drag it with the mouse, and returned a style object. Then version 0.4.0 shipped the three-layer Multi-Text Designer and this one got relabelled legacy single-layer. It still works, and for one line of text it's still arguably nicer: fewer widgets, less to look at, no layer tabs to click through.

The rule of thumb I'd use: one caption, use this. Two or three (a title, a lower-third, a corner badge), use the Multi-Text Designer.

How it works

Mechanically it's exactly the same idea as its successor. The node runs once per Run, picks the frame at preview_frame, saves it to ComfyUI's temp directory as a PNG, and returns both a style object and a rendered single-frame preview. A bundled frontend extension draws a canvas on the node body from that temp image, renders the text on top, and handles the mouse - click the text to select it, drag it anywhere on the frame, and the resulting position gets written back into the node's x_percent and y_percent widgets when you let go.

Position is stored as a percentage, so it survives the resize to GIF output size - the whole point of not storing pixels. The renderer treats those percentages as the centre of the text, and the same Python code paints the preview and the exported frames, so the placement you drag is the placement you get.

Like the multi-layer designer, this node declares itself always-changing (IS_CHANGED returning NaN) so the preview refreshes on every Run. That's the standard ComfyUI idiom for a node that must fire each time, and it does mean the cache behind it is defeated - the graph re-renders your source frames rather than reusing them.

The inputs and output that matter

  • images (IMAGE) - the prepared batch you're placing text on.
  • enabled (BOOLEAN, default true) - master switch. Off and frames pass through untouched.
  • text (STRING, multiline) - centre-aligned when it wraps, so two-line captions stay balanced on their anchor.
  • x_percent / y_percent (FLOAT) - the caption's centre, in percent of frame. Written by dragging; editable by hand for precision.
  • preview_frame (INT) - which frame the canvas shows.
  • font, font_size (6–256), font_color, plus the background / outline / shadow / line-spacing group. Background opacity is 0–255, shadow offsets −64 to 64.

Outputs: style (GIF_TEXT_STYLE) → GIF Text Overlay, and preview (IMAGE) → a Preview Image node. It's an output node, so it runs on every execution.

Install

Manager → search GIF Toolkit → Install → full restart, or:

cd ComfyUI/custom_nodes
git clone https://github.com/oekobudde/ComfyUI-GIFToolkit.git

The drag UI is a web extension, so it registers at startup - a browser refresh alone won't bring it up after a fresh clone. No pip dependencies from this pack; ComfyUI-VideoHelperSuite is needed separately for loading frames.

Common issues

It's a black box with text floating on it before the first Run. Documented and intentional. The node renders a black frame with your text until real frames arrive; Run once and the source appears behind the caption.

The text won't drag. Check enabled is on and text isn't empty. Empty text has no hit-box - the click falls through to nothing.

A workflow migrated from the multi-layer node renders only one line. Right, this is a single-layer node; there's no layers_json here, just one text field. If a shared workflow expects three layers, you need the Multi-Text Designer.

The font a workflow specifies isn't in the list. The dropdown is built by scanning your machine's font directories. Different machine, different list. Re-pick the font; if the name can't be resolved at render time the node falls back to PIL's default font instead of failing.

Small text looks fine on the canvas and mushy in the GIF. The canvas scales the frame to fit the node. At 320-pixel output, anything under about 14 px is going to be mud - set the size against the real preview, and increase font_size rather than shrinking the margin.

CategoryGIF Toolkit/Text

Inputs (22)

NameTypeDefaultDescription
imagesIMAGE—
enabledBOOLEANtrue—
textSTRINGLET'S GO!—
fontCOMBODejaVuSans-Bold.ttf48 options: PIL Default, DejaVuSansMono-Bold.ttf, DejaVuSerif.ttf, DejaVuSansMono-Oblique.ttf, DejaVuSansMono.ttf, DejaVuSerif-Bold.ttf, +42
font_sizeINT346–256—
font_colorSTRING#ffff00—
x_percentFLOAT50.00–100—
y_percentFLOAT15.00–100—
background_enabledBOOLEANfalse—
background_colorSTRING#000000—
background_opacityINT1600–255—
paddingINT80–128—
corner_radiusINT80–128—
outline_enabledBOOLEANtrue—
outline_colorSTRING#000000—
outline_widthINT20–32—
shadow_enabledBOOLEANfalse—
shadow_colorSTRING#000000—
shadow_offset_xINT2-64–64—
shadow_offset_yINT2-64–64—
line_spacingINT40–64—
preview_frameINT00–9999—

Outputs (2)

NameTypeDescription
styleGIF_TEXT_STYLE—
previewIMAGE—