Nodes/ComfyUI-StoryMaker/StoryMakerSinglePortraitNode
ComfyUI Node

StoryMakerSinglePortraitNode

Same Person in Every Scene, No LoRA Training Required

By tanglaoya321·Created 2 years ago·Updated 2 years ago· 18
StoryMakerSinglePortraitNode
  • image
  • mask_image
  • IMAGE
prompt
negative_prompt
seed0

You know the loop. You generate a character you love, then the next scene gives you their evil twin. Keeping one person recognizable across a sequence of images is the oldest complaint in local generation, and this node is one of the few that tackles it head-on: no LoRA training, no dataset - you feed it one photo of the character, a mask, and a prompt, and it renders that same person in whatever scene you describe.

StoryMakerSinglePortraitNode is the flagship node of the tanglaoya321/ComfyUI-StoryMaker pack, a thin wrapper around RedAIGC's StoryMaker research model (arXiv 2409.12576). The whole pack is exactly one folder of Python that wraps a diffusers pipeline - the author's README is a single line, "a simple ComfyUI wrapper of StoryMaker," and that's an accurate description. It's the node to reach for when you want to tell a story: office worker scene one, office worker at the beach scene two, same face, same clothes.

How it works

Under the hood this is SDXL with an identity adapter bolted on, straight out of the IP-Adapter FaceID / InstantID family. On the first run the node loads an anime-style SDXL base (huaquan/YamerMIX_v11 from HuggingFace), then attaches the StoryMaker adapter (mask.bin). When you hit Generate it does three things:

  1. Runs InsightFace's buffalo_l detector over your image and grabs the largest face it finds.
  2. Converts that face into an ArcFace embedding plus a CLIP image embedding, and injects them through the adapter's cross-attention path so identity steers generation.
  3. Runs 25 steps of SDXL at a fixed 1280×960 with CFG 7.5, using your mask_image to define the region where the identity is applied.

That mask_image input is easy to undersell. It's not an inpainting mask in the img2img sense - it tells StoryMaker where the face lives so the adapter can pin identity there. In practice you want a white blob covering the face and head, roughly like the example masks in the repo. Feed it a full-image white mask and consistency degrades.

The inputs that matter

Of the five inputs, three are things you actually think about:

  • image - your reference portrait. One clear photo, good lighting, face unobstructed.
  • mask_image - the face-region mask. This one decides how well identity holds.
  • prompt - describe the scene and the person's actions ("a person is taking a selfie, wearing a red hat, volcano in the distance"). You don't need to describe the face; the adapter has it.

negative_prompt is the usual junk list ("bad quality, low quality, disfigured…") and seed is there for reproducibility. The single IMAGE output is a full 1280×960 render - wire it straight into a Save Image or Preview Image node. There's no batch size, no resolution control, no sampler selection. This is a "give me one picture, well done" node, not a fiddly one.

Installing it

ComfyUI Manager (search "StoryMaker") or:

cd ComfyUI/custom_nodes
git clone https://github.com/tanglaoya321/ComfyUI-StoryMaker

then restart ComfyUI. The requirements file lists only insightface and opencv-python, but the code also needs diffusers, transformers, and accelerate - install those too if they're missing:

pip install diffusers transformers accelerate insightface opencv-python

Then the downloads. The repo ships no models, so the first run grabs the ~6.5 GB SDXL base and the CLIP image encoder from HuggingFace, and you must place the StoryMaker face adapter at ComfyUI-StoryMaker/StoryMaker/checkpoints/mask.bin (download it from RED-AIGC/StoryMaker on HuggingFace). InsightFace's buffalo_l detector (~326 MB) auto-downloads, though the upstream README warns the default link is flaky - if detection fails, drop buffalo_l into StoryMaker/models/ by hand. Expect a multi-gigabyte first run and don't panic when it looks frozen; it isn't.

Where people get burned

  • Every generation unloads and reloads the whole model. The node tears down the pipe after each run, so consecutive generations each pay the full load cost. Queue three scenes and you'll wait minutes between them. This is by design in the code, not a bug.
  • VRAM. SDXL fp16 plus the adapter plus a face detector wants roughly 10 GB and up, more if your ComfyUI is already heavy.
  • Only the largest face counts. If InsightFace finds no face, the node errors out; if your reference has two faces, the bigger one wins.
  • The output comes off the VAE without the usual denormalize (the upstream pipeline has it commented out), so if your result looks dark or clamped, that's the first thing to suspect.

One honest caveat: this pack hasn't been touched since October 2024, and the community has largely moved past IP-Adapter-style identity work toward edit models and LoRAs. It's also anime-leaning because of its YamerMIX base. But if your style fits and your GPU fits, it's a genuinely turnkey way to keep one face across a whole story - and nothing else in the pack needs different setup, so the other two nodes are ready the moment this one works.

There's also the license footnote that applies to the whole identity stack: InsightFace's model weights are non-commercial research only. Fine for personal fun and experiments; not for selling the results.

CategoryStoryMaker

Inputs (5)

NameTypeDefaultDescription
imageIMAGE
mask_imageIMAGE
promptSTRING
negative_promptSTRING
seedINT00–18446744073709550000

Outputs (1)

NameTypeDescription
IMAGEIMAGE