Happy Horse Reference to Video (Ace Data Cloud)
One to nine images, no LoRA, and a character who survives the shot
- status
- task_id
- video_url
- trace_id
Character consistency is the oldest unsolved problem in this hobby, and the honest 2026 answer for stills is "stop generating, start editing" - show the model your character and let it look at the reference while it works. Reference conditioning is the video version of that same move, and it's the one part of the video stack where the hosted models are still meaningfully ahead of what most people run locally.
What it does
You hand it between one and nine reference images and a prompt, and it generates a clip conditioned on them. No LoRA training, no IP-Adapter, no dataset. Good for: keeping a face or an outfit stable across a shot, locking a product or a prop, or pinning a look you liked. It's the node to reach for when a plain text-to-video prompt keeps reinventing your character halfway through the clip.
Where it differs from its two siblings in this pack: Image to Video has one first frame and inherits the aspect ratio from it; Text to Video invents everything from the prompt. This one sits in the middle - references inform identity and detail, but the frame is generated fresh, so you get a full ratio widget (16:9, 9:16, 1:1, 4:3, 3:4) and a full duration widget (3–15s, default 5). resolution is 720P or 1080P. model gives you happyhorse-1.1-r2v by default, or happyhorse-1.0-r2v.
The reference list is a text field, not a socket
reference_image_urls is a multiline string, and it accepts two formats: a JSON array, or one URL per line. Both are parsed, duplicates are dropped, and first-seen order is preserved. Every URL must be public HTTPS - no local paths, no http://, no private addresses - because the API fetches them from its own side. Same hosting problem as the image-to-video node: export, upload somewhere publicly readable, paste the link.
https://cdn.example.com/char-front.jpg
https://cdn.example.com/char-profile.jpg
Or the same thing as ["https://cdn.example.com/char-front.jpg", "https://cdn.example.com/char-profile.jpg"]. If you send a malformed array you get "Reference images must be a JSON URL array or one per line", and more than nine gets you "Use 1–9 reference images". Nine is more references than most models accept, which is genuinely useful - but read the next paragraph before you fill all nine slots.
Prompting it
There's no @tag syntax here. Some of the closed video models let you bind a specific reference to a specific output; this one just takes a list, which means the prompt has to do the binding work. Name the references in prose and say what each is for - which image carries the face, which carries the wardrobe, which is mood only. Vague prompts with five mixed references is how you get a soup of all five. Fewer, cleaner references beat a large set, and the reference set is what carries identity while the prompt carries action. Keep those two jobs separate.
Install and key
Manager → search Happy Horse → publisher acedatacloud, package Happy Horse by Ace Data Cloud → install → restart. Manual route:
cd ComfyUI/custom_nodes
git clone https://github.com/AceDataCloud/HappyHorseComfyUI.git
cd HappyHorseComfyUI && python -m pip install -r requirements.txt
export ACEDATACLOUD_API_KEY='paste-your-key-here'
ACEDATACLOUD_API_TOKEN also works, and the key must be in the environment of the ComfyUI process itself. Only requests gets installed; there's no model to download and no GPU work happening locally.
Wiring it up
Outputs are the same four strings as the rest of the pack: status, task_id, video_url, trace_id. This is a paid asynchronous submit, so treat video_url as coming later: take task_id into Happy Horse Retrieve Task, take its video_url into Happy Horse Load Video, and drop the resulting video into Save Video.
Run the submit graph once. Output nodes re-execute on every Queue press, so a second press buys a second clip - and reference-to-video is the most expensive way to be careless here, because iterating on a reference set tempts you to re-queue while the last job is still pending. It isn't done. Wait for the ID to resolve.
Inputs (8)
| Name | Type | Default | Description |
|---|---|---|---|
| prompt | STRING | Keep this character consistent across the shot. | — |
| reference_image_urls | STRING | — | |
| model | COMBO | happyhorse-1.1-r2v | 2 options: happyhorse-1.1-r2v, happyhorse-1.0-r2v |
| resolution | COMBO | 720P | 2 options: 720P, 1080P |
| ratio | COMBO | 16:9 | 5 options: 16:9, 9:16, 1:1, 4:3, 3:4 |
| duration | INT | 53–15 | — |
| watermark | BOOLEAN | false | — |
| seed | INT | -1-1–2147483647 | — |
Outputs (4)
| Name | Type | Description |
|---|---|---|
| status | STRING | — |
| task_id | STRING | — |
| video_url | STRING | — |
| trace_id | STRING | — |