alibaba/happy-horse/reference-to-video

Generate 1080p video with synchronized native audio from a text prompt and references. Aspect ratios: 16:9, 9:16, 1:1, 4:3, 3:4. Duration: 3–15s.
Inference
Commercial use
Partner

Input

Additional Settings

Customize your input with more control.

Result

Idle

What would you like to do next?

For every second of 720p video you generated, you will be charged $0.14/second. For 1080p video you will be charged $0.28/second.

Logs

Run Happy Horse 1.0: Reference to Video API

Generate a 1080p video with synchronized native audio from a text prompt and 1–9 reference images. Subject consistency is maintained across the clip using character tokens in your prompt.

Model ID: `alibaba/happy-horse/reference-to-video`
Provider: fal.ai
Commercial rights: Full commercial rights on all outputs


How it works

Supply between 1 and 9 reference images via `image_urls`. In your prompt, refer to each subject as `character1`, `character2`, ... `character9` — the order matches the order of your `image_urls` array.

For example, two reference images of people could be prompted as:

`"A dance battle between character1 and character2, cinematic lighting, smooth camera movement."`


Specifications

PropertyValue
Resolution720p, 1080p
Duration3–15 seconds
Aspect ratios16:9, 9:16, 1:1, 4:3, 3:4
Reference images1–9 images
Input image min size400px on shortest side (720p+ recommended)
Input image max size10 MB each
Input formatsJPEG, JPG, PNG, WEBP
Prompt lengthUp to 2,500 characters

Pricing

ResolutionPrice
720p$0.14 / second
1080p$0.28 / second

A 10-second clip at 1080p costs $2.80.


Quickstart

Install

JavaScript:

bash
npm install @fal-ai/client

Python:

bash
pip install fal-client
Set your API key
bash
export FAL_KEY="YOUR_API_KEY"
Submit a request

JavaScript:

js
import { fal } from "@fal-ai/client";

const result = await fal.subscribe("alibaba/happy-horse/reference-to-video", {
  input: {
    prompt: "A dance battle between character1 and character2, cinematic lighting, smooth camera movement.",
    image_urls: [
      "https://example.com/person-a.jpg",
      "https://example.com/person-b.jpg",
    ],
    aspect_ratio: "16:9",
    resolution: "1080p",
    duration: 5,
  },
  logs: true,
  onQueueUpdate: (update) => {
    if (update.status === "IN_PROGRESS") {
      update.logs.map((log) => log.message).forEach(console.log);
    }
  },
});

console.log(result.data.video.url);

Python:

python
import fal_client

def on_queue_update(update):
    if isinstance(update, fal_client.InProgress):
        for log in update.logs:
            print(log["message"])

result = fal_client.subscribe(
    "alibaba/happy-horse/reference-to-video",
    arguments={
        "prompt": "A dance battle between character1 and character2, cinematic lighting, smooth camera movement.",
        "image_urls": [
            "https://example.com/person-a.jpg",
            "https://example.com/person-b.jpg",
        ],
        "aspect_ratio": "16:9",
        "resolution": "1080p",
        "duration": 5,
    },
    with_logs=True,
    on_queue_update=on_queue_update,
)

print(result["video"]["url"])

Note: Reference images must be publicly accessible URLs. Use the storage helpers below if you need to upload local files first.


Input parameters

ParameterTypeDefaultDescription
`prompt`stringrequiredText description of the video. Reference subjects as `character1``character9` matching the order of `image_urls`. Max 2,500 characters.
`image_urls`list<string>required1–9 reference images. Min 400px shortest side, max 10 MB each. JPEG, JPG, PNG, or WEBP.
`aspect_ratio``"16:9"` | `"9:16"` | `"1:1"` | `"4:3"` | `"3:4"``"16:9"`Output video aspect ratio.
`resolution``"720p"` | `"1080p"``"1080p"`Output video resolution.
`duration`integer (3–15)`5`Clip length in seconds.
`seed`integer (0–2,147,483,647)Set for reproducible outputs.
`enable_safety_checker`boolean`true`Content moderation on input and output.

Output

json
{
  "video": {
    "url": "https://...",
    "content_type": "video/mp4",
    "file_name": "output.mp4",
    "file_size": 4404019,
    "width": 1920,
    "height": 1080,
    "fps": 24,
    "duration": 5.0,
    "num_frames": 120
  },
  "seed": 1234567
}

Queue API (long-running requests)

For clips longer than a few seconds, use the queue API to avoid blocking.

JavaScript:

js
import { fal } from "@fal-ai/client";

// Submit
const { request_id } = await fal.queue.submit("alibaba/happy-horse/reference-to-video", {
  input: {
    prompt: "character1 walks through a sunlit forest, cinematic.",
    image_urls: ["https://example.com/person-a.jpg"],
    duration: 15,
    resolution: "1080p",
  },
  webhookUrl: "https://your-server.com/webhook",
});

// Poll status
const status = await fal.queue.status("alibaba/happy-horse/reference-to-video", {
  requestId: request_id,
  logs: true,
});

// Fetch result once complete
const result = await fal.queue.result("alibaba/happy-horse/reference-to-video", {
  requestId: request_id,
});

console.log(result.data.video.url);

Python:

python
import fal_client

# Submit
handler = fal_client.submit(
    "alibaba/happy-horse/reference-to-video",
    arguments={
        "prompt": "character1 walks through a sunlit forest, cinematic.",
        "image_urls": ["https://example.com/person-a.jpg"],
        "duration": 15,
        "resolution": "1080p",
    },
    webhook_url="https://your-server.com/webhook",
)

request_id = handler.request_id

# Poll status
status = fal_client.status("alibaba/happy-horse/reference-to-video", request_id, with_logs=True)

# Fetch result once complete
result = fal_client.result("alibaba/happy-horse/reference-to-video", request_id)

print(result["video"]["url"])

Uploading files

If your reference images aren't already hosted, upload them before submitting.

JavaScript:

js
import { fal } from "@fal-ai/client";

const file = new File([imageBuffer], "reference.jpg", { type: "image/jpeg" });
const url = await fal.storage.upload(file);

// Use `url` in your image_urls array

Python:

python
import fal_client

url = fal_client.upload_file("path/to/your/reference.jpg")

# Use `url` in your image_urls list

Client-side usage

Security: Never expose your `FAL_KEY` in browser or mobile code. Route requests through a server-side proxy: set `FAL_KEY` as a server environment variable and have your frontend call your own backend endpoint, which forwards the request to fal.