βοΈ Text to Image Generator
Text to Image Generator
- font
- canvas
- transcription
- highlight_font
- images
- framestamps_string
This is the engine room of Mana Nodes. It takes some text, a font, and a canvas, and renders a sequence of frames with that text drawn on them - which, once you send those frames to a video combiner, gives you animated captions and kinetic typography without leaving ComfyUI. When people posted those slick word-by-word text animations over AnimateDiff backgrounds back when this pack made the rounds on r/comfyui, this is the node doing the drawing.
Why you'd reach for it
Overlaying moving text on generated video is genuinely annoying in most tools. You either bounce out to a video editor or fight with some FFmpeg drawtext incantation. This node keeps it inside your graph: text comes in, an image batch comes out, and every downstream ComfyUI node treats those frames like any other images. Pair it with Speech Recognition and it'll auto-time captions to an audio track. Feed it a background image sequence through the canvas and you've got captions burned over your video.
How it works
The design is deliberately modular - this node is a socket that other Mana nodes plug into. You don't set the font here; you build a Font Properties node and wire it in. You don't set the background here; you build a Canvas Properties node and wire that in. This node's job is to lay the text out across frame_count frames according to those two configs, then paint each frame.
The inputs that matter:
font- required, comes from a Font Properties node (typeTEXT_GRAPHIC_ELEMENT). This is your typeface, size, color, and any animation.canvas- required, comes from a Canvas Properties node (typeCANVAS_SETTINGS). Dimensions, background, alignment, padding.text- the words to render. Plain multiline text works, but it also accepts a per-frame JSON-ish format so you can say "frame 1: HELLO, frame 10: WORLD" and time things by hand.frame_count- how many frames to output. This is your animation length.
Then three optional inputs earn their keep. transcription takes the output of a Speech Recognition node and formats the text automatically, building up lines of words until the canvas is full. highlight_font is a second Font Properties config used to emphasize the active word - this is how you get the karaoke-style highlight where the current word pops in a different color. And skip_first_frames trims the front of the sequence.
Outputs are images (the rendered frame batch, standard IMAGE) and framestamps_string - the timed text as a string, handy if the auto-transcription mis-timed a word and you want to save it, fix it by hand, and paste it back into text.
Installing it
Grab the whole pack. Easiest path is ComfyUI Manager - Install Custom Nodes, search Mana Nodes, install, restart. Manual route:
cd ComfyUI/custom_nodes
git clone https://github.com/ForeignGods/ComfyUI-Mana-Nodes.git
Then install the requirements from inside your venv - pip install -r requirements.txt - or, on the Windows portable build, .\python_embed\python.exe -s -m pip install -r requirements.txt --user. Restart ComfyUI. The generator itself just needs Pillow (pulled in by requirements); fonts ship in the pack's font_files folder.
Common issues
The one that trips everyone: this node does nothing on its own. If it errors or renders a blank frame, check that you've actually connected both a Font Properties node to font and a Canvas Properties node to canvas - they're required, not optional, and there's no sensible default for either.
Second, frame_count and the frame count of anything you feed the canvas need to agree, or your text and background will run for different lengths. And if you're animating font size, offset, or rotation, note that those animations live on the Font Properties / Scheduled Values side, not here - this node just renders whatever schedule it's handed.
Worth a heads-up: this modular version replaced an older all-in-one node called font2img. Old tutorials and example workflows floating around still reference that one, so if a downloaded workflow looks nothing like the node in front of you, that's why.
Inputs (7)
| Name | Type | Default | Description |
|---|---|---|---|
| font | TEXT_GRAPHIC_ELEMENT | β | |
| text | STRING | β | |
| canvas | CANVAS_SETTINGS | β | |
| frame_count | INT | 1 | β |
| transcriptionopt | TRANSCRIPTION | β | |
| highlight_fontopt | TEXT_GRAPHIC_ELEMENT | β | |
| skip_first_framesopt | INT | 0 | β |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| images | IMAGE | β |
| framestamps_string | STRING | β |