Text Box Auto Wrap
When you need words on a picture, ComfyUI has no text node — this one fixes it
- IMAGE
- MASK
Base ComfyUI ships with a lot, but it won't draw a single letter onto an image for you. There's no built-in text renderer - your prompt feeds the CLIP encoder, it doesn't become pixels. So the day you need a subtitle, a card text box, or a watermark, you're browsing third-party text nodes. TextBoxAutoWrap is the one inside Ky11le's small draw_tools pack, and it earns the "auto": it wraps text to a fixed box, squeezes it to fit, and hands you both the rendered image and a matching mask for compositing.
What it actually is
draw_tools is a three-node utility pack - Detect Inner Box, Paste Into Frame, and this one - under the DrawTools category. No models, no checkpoints, no API key: it's pure Pillow drawing at CPU speed, milliseconds per run. One honest warning: the README is in Chinese and only documents the other two nodes. TextBoxAutoWrap is fully in the code and registered in __init__.py, but the README never mentions it. The docs rotted behind the code; treat them as stale.
The ancestry leaks out of the knobs: the info_schema lists the Python module as custom_nodes.ygo_tools - clearly lifted from a card-text / visual-novel tool. Hence stroke outlines, right-alignment, and digits rendered smaller than letters. Game-card conventions, and they make this the node to reach for when text should look like it belongs in a UI.
How the wrapping works
The interesting part is the auto-fit. The node measures the real pixel width of every character in your chosen font (Pillow's getlength), so proportional fonts wrap correctly - no "10 characters per line" guesswork. It wraps onto a virtual canvas box_width / hscale wide, then LANCZOS-resizes back to box_width × box_height and sharpens. That resize is the auto-shrink: more text → wider canvas → smaller horizontal scale.
The gotcha hiding inside: the scale is horizontal only. Height never changes, so as text grows, letters get narrower rather than uniformly smaller - condensed type, great for a card box, weird for paragraphs. That's what min_hscale (default 0.6) caps; squished text means the mechanism is working, not bugging out.
The inputs that matter
info_schema lists fourteen inputs; you'll actually touch about six:
- text - the words (multiline widget). It strips your newlines and re-wraps everything, so you can't force a line break.
- font_path - a plain text field pointing at a
.ttf/.otfon disk. More below; this is the trap. - box_width / box_height - the pixel size of the output (and the box text wraps into).
- font_size - point size; bigger text pushes the auto-shrink harder.
- max_lines and base_chars_per_line - together they decide how much text "fits" before the squeeze kicks in; the defaults of 3 lines × 10 chars are basically a card text box.
- font_hex / stroke_hex - colors, but in RRGGBBAA order with alpha at the end (
#FFFFFFFFis opaque white). A plain#FFFFFFsilently getsFFappended, and a malformed string just falls back to white - no error, which is its own kind of mean.
Beyond those: stroke_width/stroke_hex outline the text, enable_small_caps + small_caps_scale render digits at ~80% height (despite the name, only numerals shrink), letter_spacing is self-explanatory, and align_right flips the alignment.
Outputs and wiring
Two outputs: IMAGE and MASK. The IMAGE is RGBA - real alpha in the 4th channel, unusual for ComfyUI tensors - so if a downstream node expects plain RGB, use the MASK instead. It's the same text drawn white-on-black, stroke included, and composites cleanly via Image Composite Masked or similar. One quirk: the MASK comes out with an extra leading dimension [1,1,H,W]; if a node rejects the shape, squeeze it to [1,H,W].
Installing it
Two ways, both boring in a good way. Via ComfyUI Manager → Custom Nodes Manager, search "draw_tools", install, restart. Or by hand:
cd ComfyUI/custom_nodes
git clone https://github.com/Ky11le/draw_tools
cd draw_tools
pip install -r requirements.txt
Restart ComfyUI and the nodes appear under DrawTools. No model files to fetch. The requirements.txt lists opencv-python, torch, and numpy, but this node itself only touches Pillow - which ComfyUI already ships - so it's one of the friendlier installs around.
The one thing that bites everyone
font_path is not a file-browser widget - it's a raw string, so you type the whole path yourself. Windows: C:\Windows\Fonts\arial.ttf. Linux: /usr/share/fonts/truetype/dejavu/DejaVuSans.ttf or wherever your fonts live. Get it wrong and the first run dies with a "cannot open resource" error. There's no built-in font list - that, plus the RRGGBBAA hex format, is basically all the confusion this node causes.
Second: keep stroke_width small. The stroke re-renders each glyph at every offset in a square around it - (2w+1)² draws per character, so 5 on a long sentence gets slow. 1–2 looks right on card text and stays instant.
Bottom line: it's a niche node, but for game-card text, subtitles, or watermark-style overlays it does one job well - and it's the only node in its pack that renders text at all. The hand-typed font path and RRGGBBAA hex are the price of admission; know those and it just works.
Inputs (15)
| Name | Type | Default | Description |
|---|---|---|---|
| text | STRING | — | |
| font_path | STRING | — | |
| box_width | INT | 51264–4096 | — |
| box_height | INT | 25664–4096 | — |
| font_size | INT | 484–512 | — |
| letter_spacing | INT | 0-20–100 | — |
| base_chars_per_line | INT | 101–100 | — |
| max_lines | INT | 31–10 | — |
| min_hscale | FLOAT | 0.600.3–1 | — |
| font_hex | STRING | #FFFFFFFF | — |
| stroke_width | INT | 00–20 | — |
| stroke_hex | STRING | #000000FF | — |
| enable_small_caps | BOOLEAN | false | — |
| small_caps_scale | FLOAT | 0.800.5–1 | — |
| align_right | BOOLEAN | false | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| IMAGE | IMAGE | — |
| MASK | MASK | — |