Skip to main content
Images drive a generation in three ways, and the field (plus how many images you put in it) picks the behavior. In the API’s own error text these carry short codes: i2v, ii2v, ir2v.
  • One keyframes entry (i2v): your image is on screen, pixel for pixel, as the opening frame. The clip animates out of it.
  • Two keyframes entries (ii2v): your images are the opening and closing frames. You pin both ends of time and the model generates the in-between.
  • reference_images (ir2v): the images control who or what appears. The model keeps the subject recognizable in a new scene; the images never show up on screen.
The decision rule: must this image appear in the video exactly as shot? Then keyframes. Do I also know how it must end? Two keyframes. Do I just need this subject in the video? Then reference_images. This notebook generates its own input images with FLUX.2 on the same API, so it runs end to end with nothing but a BFL_API_KEY. Any image works the same way: a photo, a render, a frame from another clip.

1. Setup

The client from the quickstart, plus b64: there is no upload service, so local files travel inline as base64 (public URLs work too). Images can be PNG, JPEG, or WebP.

2. Make the input images with FLUX.2

Four stills: one to animate, a matched before/after pair for the morph, and a two-view character sheet for the reference workflow. FLUX.2 returns in seconds, so generating inputs is the cheap part of this notebook. The same client works; only the model name and payload change. Two input-craft rules, both load-bearing:
  • The morph pair is one generation plus one edit, not two generations. Still B is made from still A with FLUX.2’s image input, so the pedestal, background, and light match exactly and only the subject changes. Generate the two ends independently and the video has to morph the room along with the swan.
  • The character sheet shows the subject twice in a single render. Two separate generations of “the same” character drift apart in the details, and a reference is only as good as its consistency.

3. One keyframe (i2v): your image is the opening frame

Each entry is {"image_url": <URL or base64>, "frame_index": <int>}. frame_index is a position at 24 fps, so frame 0 opens the clip: the still becomes the pixel-exact first frame and the video moves from there. Prompt the motion, not the scene. The frame already contains the scene; your prompt’s job is what happens next. Re-describing what’s in the frame (the lighting, the setting, the subject’s look) invites the model to re-imagine it instead of animating it. Say what moves, and when several things move, give them an order. The clip below turns a set dinner table into a physics problem: the room rotates 90 degrees and gravity follows. Two prompt choices carry it. The gravity vector is named (“the right-hand wall becomes the new floor”), and the collapse is sequenced (flames, then wine, then plates, then chair) so the model animates an order instead of a blur. Locking the camera to the room is what makes it read as “gravity turned” rather than “the camera rolled”.
The input still against the clip’s decoded frame 0, extracted losslessly: pixel for pixel, the still is the opening frame.

4. Two keyframes (ii2v): pin the start and the end

Add a second entry and the clip now ends on your second image: the closing frame sits at position duration × 24, which is why a start-plus-end morph needs an integer duration (with "auto" there is no defined closing position). Both stills are on screen, pixel for pixel, at their pinned frames; the model’s job is everything in between. You’ve pinned both ends of time, so the prompt’s job shrinks to how the change happens: name the stages and their order, and keep the camera still so the transformation is the only motion. Here the ends are the matched swan pair from the setup cell: same pedestal, same hall, same light, different swan. The model has to solve ten seconds of melting between them. End-frame pinning is newer than frame-0 pinning and the API marks it experimental: expect more variance between runs than the single-keyframe path, and re-roll a miss.

5. reference_images (ir2v): the subject, not the pixels

1 to 10 images that define identity. The model keeps the subject recognizable and composes a fresh scene from your prompt; the references never appear on screen. Multiple views of the subject (our two-view sheet) pin identity down harder than a single angle. In the prompt, point at the references explicitly (“the claymation badger from the reference images”) and re-list the anchors that must survive (striped face, brass spectacles, tweed waistcoat), then describe the new scene around them. The first clip also speaks. Identity comes from a sheet the model has never seen move, and the mouth is clay: “his clay mouth reshapes on every syllable” is what keeps the lip-sync reading as sculpted stop-motion instead of a smooth human mouth pasted on. The line is five words because a 5-second clip fits only a few seconds of speech.
Same references, new scene, hard lighting change. The sheet was shot flat and even; this scene is a single warm lantern on black water at night. Identity has to survive lighting the references never showed, which is exactly what the multi-view sheet buys. One action fills the 5 seconds, and the world, light, and sound all come from the prompt:
The same sheet kept the badger recognizable in both scenes, including one it was never lit for. For a character, a product, or a mascot across a campaign, make (or shoot) the sheet once, then write scenes.

Choosing, and the details that bite

  • One input field per request. keyframes and reference_images together return a 422.
  • No upload service: pass a public URL or base64. Oversized pixel dimensions are downscaled automatically; files over the limit are rejected.
  • Every frame_index must fit within duration × 24, and all must be unique.
  • aspect_ratio: "auto" picks the output ratio from your prompt and references.

Where to next