Nodes/ComfyUI-FLUX-BFL-API/Flux 3 Keyframes (BFL)
ComfyUI Node

Flux 3 Keyframes (BFL)

The glue node that makes Flux 3 I2V keyframes actually usable

By gelasdev·Created 2 years ago·Updated about a month ago· 49
Flux 3 Keyframes (BFL)
    • keyframes
    timingeven
    start_image
    image_2
    time_20.00
    image_3
    time_30.00
    image_4
    time_40.00
    image_5
    time_50.00
    image_6
    time_60.00
    image_7
    time_70.00
    image_8
    time_80.00
    image_9
    time_90.00
    end_image
    end_time5.00

    The name undersells this node. Flux 3 Keyframes doesn't generate anything - it's the small, boring node that makes the interesting one work. If you've ever stared at the keyframes socket on Flux 3 Video I2V (BFL) and wondered what on earth it wants, this is the answer: it wants a JSON string that Black Forest Labs' API uses to know which frame goes where in your clip. You could type that by hand. You don't want to.

    This is a cloud-wrapper pack, remember. Nothing runs on your GPU - your frames go up to api.bfl.ai, BFL does the video math on their hardware, and you pay per request. That's the whole deal with gelasdev's ComfyUI-FLUX-BFL-API. The Keyframes node is the piece that packages your images into the exact payload that API expects, without you ever learning its JSON schema.

    What it does

    The node gives you up to ten image sockets: start_image, eight middles (image_2 through image_9), and end_image. Each takes a base64 string (from the Image to Base64 (BFL) node) or a plain image URL. Empty sockets are simply skipped - so a three-frame clip with just a start, a middle, and an end works fine, and so does a full ten-image sequence.

    The one input that matters is timing, which is a two-way switch:

    • even - the connected images are sent as a plain list. The first starts the clip, the last ends it, and everything in between falls evenly across the duration. Simple, and usually what you want on a first pass.
    • custom - every image gets an explicit timestamp as a [seconds, image] pair. The API won't let you mix timed and untimed frames, so the node pins everything: start_image at 0, each middle at its own time_N widget, and end_image at end_time.

    In custom mode, end_time doubles as the clip length when the video node's duration is set to auto - the video just runs to the last frame's second, rounded up. That's a neat trick worth knowing: set end_time and you don't have to touch the duration dropdown at all.

    Output and wiring

    One output: keyframes (STRING). Run it straight into the keyframes socket on Flux3VideoI2V_BFL, and you're done. That's the whole workflow - Keyframes node in, I2V node out.

    Getting it installed

    Same story as the rest of the pack. Easiest via ComfyUI Manager - search for "ComfyUI-FLUX-BFL-API" and install. Manual route:

    cd ComfyUI/custom_nodes
    git clone https://github.com/gelasdev/ComfyUI-FLUX-BFL-API.git
    cd ComfyUI-FLUX-BFL-API
    pip install -r requirements.txt
    

    The dependency list is basically just torch, which you already have. The video nodes need ComfyUI ≥ 0.3.30 for the native VIDEO type, so update if you're on something older. Then put your BFL API key in the pack's config.ini - or better, keep it in a Flux Config (BFL) node wired into the video node, since config.ini has a habit of getting overwritten when the pack updates. That's a real community pain point with this pack.

    Where people get burned

    The node is pretty forgiving, but three things trip people up. First, if you use three or more plain images with even timing and the video node's duration is left on auto, BFL will reject the request - the API insists on a set duration for multi-frame keyframes. Second, in custom mode the node warns (doesn't fail) if you give two images the same timestamp, or if end_time isn't the largest time - in which case your "end" image won't actually end the video. Third, remember these are base64 strings flowing through wires; a single 4K frame can make the payload enormous, so sizing down before encoding is genuinely worth it.

    CategoryBFL/Flux3

    Inputs (20)

    NameTypeDefaultDescription
    timingCOMBOeveneven: images fall evenly across the clip; custom: start at 0, middles at their time widgets, end at end_time
    start_imageoptSTRINGBase64 image (from Image to Base64) or image URL
    image_2optSTRINGBase64 image (from Image to Base64) or image URL
    time_2optFLOAT0.000–20Second to pin the matching image at — only used when timing is "custom"
    image_3optSTRINGBase64 image (from Image to Base64) or image URL
    time_3optFLOAT0.000–20Second to pin the matching image at — only used when timing is "custom"
    image_4optSTRINGBase64 image (from Image to Base64) or image URL
    time_4optFLOAT0.000–20Second to pin the matching image at — only used when timing is "custom"
    image_5optSTRINGBase64 image (from Image to Base64) or image URL
    time_5optFLOAT0.000–20Second to pin the matching image at — only used when timing is "custom"
    image_6optSTRINGBase64 image (from Image to Base64) or image URL
    time_6optFLOAT0.000–20Second to pin the matching image at — only used when timing is "custom"
    image_7optSTRINGBase64 image (from Image to Base64) or image URL
    time_7optFLOAT0.000–20Second to pin the matching image at — only used when timing is "custom"
    image_8optSTRINGBase64 image (from Image to Base64) or image URL
    time_8optFLOAT0.000–20Second to pin the matching image at — only used when timing is "custom"
    image_9optSTRINGBase64 image (from Image to Base64) or image URL
    time_9optFLOAT0.000–20Second to pin the matching image at — only used when timing is "custom"
    end_imageoptSTRINGBase64 image (from Image to Base64) or image URL
    end_timeoptFLOAT5.000–20Second the end image lands at (timing "custom") — with duration "auto" this is the clip length

    Outputs (1)

    NameTypeDescription
    keyframesSTRING