LED Billboard Message
Upload a blank billboard and overlay text. Generate a smooth zoom in shot revealing your message.
About
This ComfyUI workflow, titled 'LED Billboard Message,' is designed to seamlessly overlay text onto a blank billboard image and create a smooth zoom-in video that reveals your message. The workflow utilizes several nodes, including LoadImage for importing the billboard base, and GeminiImage2Node for integrating text onto the image. KlingStartEndFrameNode is used to define the start and end frames of the zoom-in effect, ensuring a smooth transition. SaveImage and SaveVideo nodes are employed to export the final image and video outputs.
The custom nodes from comfyui_essentials facilitate advanced operations like RegexReplace for text manipulation, enhancing the workflow's versatility.
What you provide
- Reading the workflow
Runs in ComfyUI. This workflow can't run on this page. Open it in Comfy Cloud with everything loaded, or download it for your own ComfyUI.
Try in CloudInside the workflow
A read-only preview of the node graph. Open it in Comfy Cloud or download it to edit the nodes.
Loading the graph
Open full-size workflow preview- Author
- Rob
Requires custom nodes
- Reading the workflow
Use this workflow from code
Generated from the workflow graph and inputs when possible; stored examples are shown otherwise. Review credentials and endpoints before running code, which may incur charges.
What you need
- Runs on
- Comfy Cloud
- Key
- COMFY_API_KEY
- Your files
- Uploaded by the code from their urls
Needs a paid Cloud plan and credits.
# Python 3.10+: pip install comfy-sdk==0.4.0
import os
from comfy_sdk import Comfy
api_key = os.environ.get("COMFY_API_KEY", "").strip()
if not api_key: raise RuntimeError("Set COMFY_API_KEY")
os.environ.setdefault("COMFY_BASE_URL", "https://cloud.comfy.org")
client = Comfy(api_key=api_key)
workflow = client.workflows.from_json({
"10": {
"class_type": "LoadImage",
"inputs": {
"image": "UPLOADED_image_FILENAME"
},
"_meta": {
"title": "Load Billboard Image"
}
},
"11": {
"class_type": "GeminiImage2Node",
"inputs": {
"aspect_ratio": "auto",
"images": [
"59:59",
0
],
"model": "gemini-3-pro-image-preview",
"prompt": "Task: Realistic composite of text content onto an LED billboard mockup, preserving original composition.\n\nInput Image(s):\n- Input 1 (Scene): Billboard mockup structure and environment. The screen area is the target destination.\n- Input 2 (Content): Source image containing text/logotype (NOT THE BACKGROUND COLOR)\n\nProcess:\n1. Identify the screen surface area in Input 1.\n2. Treat only the text of Input 2 (NOT the background color) as the content to be overlayed onto the screen.\n3. Apply a perspective transformation to the entire Input 2 content canvas so it perfectly matches the angle, orientation, and boundaries of the billboard screen in Input 1.\n4. Render the transformed content with an illuminated LED matrix aesthetic.\n\nTechnical Requirements:\n- **Composition & Scale Consistency (Crucial):** The relative scale and positioning of the text as seen within the boundaries of Input 2 MUST be maintained. Do NOT scale up the text object to fill the billboard screen. If the text is small in Input 2, it must remain small relative to the screen size in the final output, surrounded by the appropriate amount of black padding.\n- **Color & Light:** The active text pixels must be the exact hexadecimal color of image 2 text. They should emit a bright, illuminated glow (halation) typical of LED signage.\n- **Screen Texture:** The entire screen surface (both lit text and unlit background padding) must show a visible, realistic grid texture of individual LED pixel diodes.\n- **Integration:** The physical structure of the billboard framing and the surrounding environment from Input 1 must be preserved exactly.\n\nOutput: The final image showing the scene from Input 1, with the screen displaying the exact composition of Input 2 (without the solid background color) as a glowing, pixelated LED array.",
"resolution": "2K",
"response_modalities": "IMAGE+TEXT",
"seed": 11111,
"system_prompt": "You are an expert image-generation engine. You must ALWAYS produce an image.\nInterpret all user input—regardless of format, intent, or abstraction—as literal visual directives for image composition.\nIf a prompt is conversational or lacks specific visual details, you must creatively invent a concrete visual scenario that depicts the concept.\nPrioritize generating the visual representation above any text, formatting, or conversational requests."
},
"_meta": {
"title": "Nano Banana Pro (Google Gemini Image)"
}
},
"12": {
"class_type": "LoadImage",
"inputs": {
"image": "UPLOADED_image_2_FILENAME"
},
"_meta": {
"title": "Load Text Overlay Image"
}
},
"19": {
"class_type": "SaveImage",
"inputs": {
"filename_prefix": "ComfyUI-last_frame",
"images": [
"11",
0
]
},
"_meta": {
"title": "Save Image"
}
},
"20": {
"class_type": "KlingStartEndFrameNode",
"inputs": {
"aspect_ratio": "16:9",
"cfg_scale": 0.5,
"end_frame": [
"11",
0
],
"mode": "pro mode / 5s duration / kling-v2-5-turbo",
"negative_prompt": "",
"prompt": "LED billboard text morphs, pixel glyphs flicker and cascade like a digital waterfall, individual LED cells pulse and brighten as new letters materialize, slight camera zoom in revealing more billboard detail and closer framing on screen, maintaining the textured LED grid with radiant glow against black panel. ",
"start_frame": [
"33",
0
]
},
"_meta": {
"title": "Kling Start-End Frame to Video"
}
},
"21": {
"class_type": "SaveImage",
"inputs": {
"filename_prefix": "ComfyUI-first_frame",
"images": [
"33",
0
]
},
"_meta": {
"title": "Save Image"
}
},
"23": {
"class_type": "SaveVideo",
"inputs": {
"filename_prefix": "video/ComfyUI-video",
"format": "auto",
"format.codec": "auto",
"video": [
"20",
0
]
},
"_meta": {
"title": "Save Video"
}
},
"33": {
"class_type": "GeminiImage2Node",
"inputs": {
"aspect_ratio": "auto",
"images": [
"49:24",
0
],
"model": "gemini-3-pro-image-preview",
"prompt": [
"72",
0
],
"resolution": "2K",
"response_modalities": "IMAGE+TEXT",
"seed": 12345,
"system_prompt": "You are an expert image-generation engine. You must ALWAYS produce an image.\nInterpret all user input—regardless of format, intent, or abstraction—as literal visual directives for image composition.\nIf a prompt is conversational or lacks specific visual details, you must creatively invent a concrete visual scenario that depicts the concept.\nPrioritize generating the visual representation above any text, formatting, or conversational requests."
},
"_meta": {
"title": "Nano Banana Pro (Google Gemini Image)"
}
},
"58": {
"class_type": "PrimitiveInt",
"inputs": {
"value": 300
},
"_meta": {
"title": "Expand Image Borders by %"
}
},
"71": {
"class_type": "PrimitiveStringMultiline",
"inputs": {
"value": ""
},
"_meta": {
"title": "Describe the Outpainted Region"
}
},
"72": {
"class_type": "RegexReplace",
"inputs": {
"case_insensitive": True,
"count": 0,
"dotall": False,
"multiline": False,
"regex_pattern": "<description>",
"replace": [
"71",
0
],
"string": [
"73",
0
]
},
"_meta": {
"title": "Replace Text (Regex)"
}
},
"73": {
"class_type": "PrimitiveStringMultiline",
"inputs": {
"value": "Task: Canvas Expansion and Content Cleanup\n\nInput Image: Contains main header text, subtext, and central visual content.\n\nProcess & Requirements:\n\n1. **Text Cleanup (Removal):**\n * Identify and completely remove the \"subtext\" element.\n * Reconstruct the area beneath the removed subtext to match the immediate surrounding background texture and lighting flawlessly.\n\n2. **Header Preservation (Constraint):**\n * Isolate the \"main header text.\"\n * Ensure this header remains in its exact original position. It must not shift during the canvas expansion process.\n\n3. **Outpainting (Generation):**\n * Expand the canvas borders to fill the transparent blank area. The original pixel information MUST remain, only generate within the transparent blank area.\n * **Content Generation:** The newly generated areas must seamlessly extend outside the existing background context and MUST include the following elements if specified: <description>\n * **Technical Consistency:** Ensure perfect continuity of lighting, shadows, color palette, texture, and perspective from the original image edges into the new expanded areas. The transition between original and new content must be invisible.\n\nOutput: A larger canvas image with the subtext removed, the main header locked in place, and the surrounding environment naturally expanded."
},
"_meta": {
"title": "Prompt Template"
}
},
"49:24": {
"class_type": "ImagePadForOutpaint",
"inputs": {
"bottom": [
"49:32",
0
],
"feathering": 40,
"image": [
"11",
0
],
"left": [
"49:28",
0
],
"right": [
"49:28",
0
],
"top": [
"49:32",
0
]
},
"_meta": {
"title": "Pad Image for Outpainting"
}
},
"49:27": {
"class_type": "GetImageSize",
"inputs": {
"image": [
"49:58",
0
]
},
"_meta": {
"title": "Get Image Size"
}
},
"49:28": {
"class_type": "SimpleMath+",
"inputs": {
"a": [
"49:27",
0
],
"b": [
"49:47",
0
],
"value": "(a * b) / 2"
},
"_meta": {
"title": "Calculate left/right pixel expand"
}
},
"49:32": {
"class_type": "SimpleMath+",
"inputs": {
"a": [
"49:27",
1
],
"b": [
"49:47",
0
],
"value": "(a * b) / 2"
},
"_meta": {
"title": "Calculate top/bottom pixel expand"
}
},
"49:45": {
"class_type": "PreviewImage",
"inputs": {
"images": [
"49:24",
0
]
},
"_meta": {
"title": "Preview Image"
}
},
"49:47": {
"class_type": "SimpleMath+",
"inputs": {
"a": [
"58",
0
],
"b": 0,
"value": "a / 100"
},
"_meta": {
"title": "Calculate % to decimal value"
}
},
"49:58": {
"class_type": "ImageScaleToTotalPixels",
"inputs": {
"image": [
"11",
0
],
"megapixels": 1,
"resolution_steps": 1,
"upscale_method": "lanczos"
},
"_meta": {
"title": "Scale Image to Total Pixels"
}
},
"59:15": {
"class_type": "ResizeAndPadImage",
"inputs": {
"image": [
"12",
0
],
"interpolation": "area",
"padding_color": "black",
"target_height": [
"59:16",
1
],
"target_width": [
"59:16",
0
]
},
"_meta": {
"title": "Resize And Pad Image"
}
},
"59:16": {
"class_type": "GetImageSize",
"inputs": {
"image": [
"10",
0
]
},
"_meta": {
"title": "Get Image Size"
}
},
"59:59": {
"class_type": "BatchImagesNode",
"inputs": {
"images.image0": [
"10",
0
],
"images.image1": [
"59:15",
0
]
},
"_meta": {
"title": "Batch Images"
}
}
})
# Replace each example.com URL with a public URL of your file.
workflow.set_input("10", "image", client.assets.from_url("https://example.com/replace-with-a-url/image"))
workflow.set_input("12", "image", client.assets.from_url("https://example.com/replace-with-a-url/image_2"))
# run() also passes api_key to the partner nodes in this workflow.
job = client.run(workflow, api_key=api_key)Questions & answers
The LoadImage node supports common formats like JPEG and PNG. Ensure your billboard image is in one of these formats for compatibility.
The speed can be adjusted by modifying the start and end frames in the KlingStartEndFrameNode. Increasing the frame range will slow down the zoom effect.
Yes, you can return to the GeminiImage2Node to edit the text and reprocess the image and video outputs as needed.
You can adjust the text size and positioning in the GeminiImage2Node to ensure it fits appropriately on the billboard surface.