Start and End Frame Video API

Some video models support frames_to_video with a required start_frame and optional end_frame. Use this workflow when the beginning and final composition both matter.

Good use cases

  • Product transformation clips
  • Before/after interiors
  • Character movement between two poses
  • Controlled brand transitions

Example with Veo 3.1 Fast

curl https://img2vid.net/api/v1/generations \
  -H "Authorization: Bearer $BUBLE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "google/veo3.1-fast",
    "mode": "frames_to_video",
    "prompt": "Create an elegant transformation from the first frame to the final frame with smooth cinematic camera movement and realistic lighting continuity",
    "start_frame": "https://example.com/start.png",
    "end_frame": "https://example.com/end.png",
    "duration": "8s",
    "resolution": "720p",
    "aspect_ratio": "16:9"
  }'

Models with start/end frame support

  • google/veo3.1-fast
  • google/veo3.1-quality
  • doubao/seedance-2.0-fast
  • doubao/seedance-2.0
  • doubao/seedance-1.5-pro
  • kling/kling-v3

min_files: 1 means the start frame is enough. Add end_frame only when you need a controlled ending.

SDK examples

The SDK snippets below use the same public API shape as the HTTP examples: stable fields such as model, mode, prompt, and media URLs are passed directly, and model-specific options stay as flat generation parameters.

TypeScript / JavaScript

import { Buble } from '@buble/sdk';

const buble = new Buble();

const task = await buble.generations.create({
  model: 'google/veo3.1-fast',
  mode: 'frames_to_video',
  prompt:
    'Create an elegant transformation from the first frame to the final frame with smooth cinematic camera movement and realistic lighting continuity',
  start_frame: 'https://example.com/start.png',
  end_frame: 'https://example.com/end.png',
  duration: '8s',
  resolution: '720p',
  aspect_ratio: '16:9',
});

const result = await buble.generations.wait(task.data.id);
console.log(result.data);

Python

from buble_ai import Buble

client = Buble()

task = client.generations.create(
    model='google/veo3.1-fast',
    mode='frames_to_video',
    prompt='Create an elegant transformation from the first frame to the final frame with smooth cinematic camera movement and realistic lighting continuity',
    start_frame='https://example.com/start.png',
    end_frame='https://example.com/end.png',
    duration='8s',
    resolution='720p',
    aspect_ratio='16:9',
)

result = client.generations.wait(task["data"]["id"])
print(result["data"])

Go

package main

import (
    "context"
    "fmt"
    "log"

    buble "github.com/bublehq/sdks/go"
)

func main() {
    ctx := context.Background()
    client := buble.NewClient()

    task, err := client.Generations.Create(ctx, &buble.CreateGenerationRequest{
        Model:  "google/veo3.1-fast",
        Mode:   "frames_to_video",
        Prompt: "Create an elegant transformation from the first frame to the final frame with smooth cinematic camera movement and realistic lighting continuity",
        StartFrame: "https://example.com/start.png",
        EndFrame: "https://example.com/end.png",
        Params: map[string]any{
            "duration": "8s",
            "resolution": "720p",
            "aspect_ratio": "16:9",
        },
    })
    if err != nil {
        log.Fatal(err)
    }

    result, err := client.Generations.Wait(ctx, task.Data.ID)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("%+v\n", result.Data)
}

Rust

use buble::{Client, CreateGenerationRequest, WaitOptions};

#[tokio::main]
async fn main() -> buble::Result<()> {
    let client = Client::from_env();

    let task = client
        .generations()
        .create(
            CreateGenerationRequest::new("google/veo3.1-fast")
                    .mode("frames_to_video")
                    .prompt("Create an elegant transformation from the first frame to the final frame with smooth cinematic camera movement and realistic lighting continuity")
                    .start_frame("https://example.com/start.png")
                    .end_frame("https://example.com/end.png")
                    .param("duration", "8s")?
                    .param("resolution", "720p")?
                    .param("aspect_ratio", "16:9")?,
        )
        .await?;

    let result = client
        .generations()
        .wait(&task.data.id, WaitOptions::default())
        .await?;

    println!("{:?}", result.data);
    Ok(())
}

Swift

import Buble

let client = try BubleClient.fromEnvironment()

let task = try await client.generations.create(
    try CreateGenerationRequest(model: "google/veo3.1-fast")
            .mode("frames_to_video")
            .prompt("Create an elegant transformation from the first frame to the final frame with smooth cinematic camera movement and realistic lighting continuity")
            .startFrame("https://example.com/start.png")
            .endFrame("https://example.com/end.png")
            .param("duration", "8s")
            .param("resolution", "720p")
            .param("aspect_ratio", "16:9")
)

let result = try await client.generations.wait(task.data.id)
print(result.data)

Dart / Flutter

import 'package:buble/buble.dart';

Future<void> main() async {
  final client = BubleClient.fromEnvironment();

  final task = await client.generations.create(
    CreateGenerationRequest(
      model: 'google/veo3.1-fast',
      mode: 'frames_to_video',
      prompt:
          'Create an elegant transformation from the first frame to the final frame with smooth cinematic camera movement and realistic lighting continuity',
      startFrame: 'https://example.com/start.png',
      endFrame: 'https://example.com/end.png',
    ).withParams({
      'duration': '8s',
      'resolution': '720p',
      'aspect_ratio': '16:9',
    }),
  );

  final result = await client.generations.wait(task.data.id);
  print(result.data.raw);
}

Elixir

client = Buble.Client.new!()

{:ok, task} =
  Buble.Generations.create(client, %{
    model: "google/veo3.1-fast",
    mode: "frames_to_video",
    prompt:
      "Create an elegant transformation from the first frame to the final frame with smooth cinematic camera movement and realistic lighting continuity",
    start_frame: "https://example.com/start.png",
    end_frame: "https://example.com/end.png",
    duration: "8s",
    resolution: "720p",
    aspect_ratio: "16:9",
  })

{:ok, result} = Buble.Generations.wait(client, get_in(task, ["data", "id"]))
IO.inspect(result["data"])

Java

import ai.buble.sdk.BubleClient;
import ai.buble.sdk.Envelope;
import ai.buble.sdk.generations.CreateGenerationRequest;
import ai.buble.sdk.generations.GenerationTask;

public class Example {
    public static void main(String[] args) {
        BubleClient client = BubleClient.fromEnv();

        Envelope<GenerationTask> task = client.generations().create(
            CreateGenerationRequest.builder()
                    .model("google/veo3.1-fast")
                    .mode("frames_to_video")
                    .prompt("Create an elegant transformation from the first frame to the final frame with smooth cinematic camera movement and realistic lighting continuity")
                    .startFrame("https://example.com/start.png")
                    .endFrame("https://example.com/end.png")
                    .param("duration", "8s")
                    .param("resolution", "720p")
                    .param("aspect_ratio", "16:9")
                    .build()
        );

        Envelope<GenerationTask> result = client.generations().wait(task.getData().getId());
        System.out.println(result.getData().getStatus());
    }
}

.NET

using Buble.Sdk;
using Buble.Sdk.Generations;

var client = BubleClient.FromEnv();

var request = new CreateGenerationRequest
{
    Model = "google/veo3.1-fast",
    Mode = "frames_to_video",
    Prompt = "Create an elegant transformation from the first frame to the final frame with smooth cinematic camera movement and realistic lighting continuity",
    StartFrame = "https://example.com/start.png",
    EndFrame = "https://example.com/end.png",
}
.WithParam("duration", "8s")
.WithParam("resolution", "720p")
.WithParam("aspect_ratio", "16:9");

var task = await client.Generations.CreateAsync(request);
var result = await client.Generations.WaitAsync(task!.Data!.Id!);
Console.WriteLine(result.Data.Status);

PHP

<?php

use Buble\BubleClient;
use Buble\Generations\CreateGenerationRequest;

$client = BubleClient::fromEnv();

$request = new CreateGenerationRequest(
    model: 'google/veo3.1-fast',
    mode: 'frames_to_video',
    prompt: 'Create an elegant transformation from the first frame to the final frame with smooth cinematic camera movement and realistic lighting continuity',
    startFrame: 'https://example.com/start.png',
    endFrame: 'https://example.com/end.png',
);

$task = $client->generations()->create(
    $request
    ->withParam('duration', '8s')
    ->withParam('resolution', '720p')
    ->withParam('aspect_ratio', '16:9')
);

$result = $client->generations()->wait($task['data']['id']);
print_r($result['data']);

Ruby

require 'buble'

client = Buble::Client.new

task = client.generations.create(
  model: 'google/veo3.1-fast',
  mode: 'frames_to_video',
  prompt: 'Create an elegant transformation from the first frame to the final frame with smooth cinematic camera movement and realistic lighting continuity',
  start_frame: 'https://example.com/start.png',
  end_frame: 'https://example.com/end.png',
  duration: '8s',
  resolution: '720p',
  aspect_ratio: '16:9',
)

result = client.generations.wait(task['data']['id'])
puts result['data']