REF] Write Sampling
Bank your character's look before you animate
- ref_bank
- sampler
- opt_attn_map
- masks
- SAMPLER
- SIGMAS
Reference-UNet animation works in two passes, and WriteSampler is the first one. The idea, from AnimateAnyone-style pipelines, is that before you generate any animation frames you run your still reference image through the UNet once and capture the per-block attention features it produces. Then, during the actual animation, you paste those captured features back in at every frame so the moving character stays glued to the reference. WriteSampler is the capture half - the "write" that fills the bank.
Mechanically, it's a SAMPLER replacement, not a standalone node. You set sampler_name to REFERENCE_WRITE and it performs exactly one model forward pass on the reference latent - no denoising loop, just a single evaluation to grab the features. That's the whole trick: the reference is encoded in one step, the selected attention blocks dump their pre-attention features into the shared ref_bank, and you're done. (You can also pick any normal sampler name if you want the write pass to be a real multi-step sampling, but REFERENCE_WRITE is what the example workflow uses.)
The inputs that actually matter:
ref_bank(required) - theREF_BANKfrom aCreateRefBanknode. This same wire must feed the read pass too; the bank is just a shared dict that travels the graph.sampler_name,start_percent,end_percent- which fraction of the write pass actually records features. Keep the defaults (0 to 1) unless you know why you're trimming.mask_dilation- an int, default 3. When you pass amasksregion, it dilates that mask so the captured features spill a few pixels into the surrounding context. Smooths seams; 0–10 range.opt_attn_map(optional) - anATTN_MAPfromConfigRefMapAdv/CustomRefMapSD1controlling which attention blocks record. Leave it unplugged and it uses the full SD1.5 map automatically.masks(optional) - aMASKso only part of the reference gets written.
Outputs are SAMPLER and SIGMAS. The SIGMAS output is effectively a stub - the example workflow feeds it straight into the sigmas input of a SamplerCustom for the write pass, because that sampler wants some sigmas and this node provides a trivial [0]. The SAMPLER goes into the sampler's sampler slot.
To use it you need the reference UNet side of things loaded: in a FollowYourEmoji graph that's the FYE_referencenet-fp16.safetensors from Kijai's HF repo in models/unet/, with a ConfigureRefNet on top so the blocks know they're being written to.
Install: Manager → search "ComfyUI-RefUNet", or git clone https://github.com/logtd/ComfyUI-RefUNet into custom_nodes/, restart. No Python deps. The classic mistake is running the write pass with a different ref_bank wire than the read pass - the bank is a plain Python dict, so a second CreateRefBank silently gives you an empty read. One bank, both samplers. And remember this is 2024-era code that monkey-patches ComfyUI internals; if a ComfyUI update ever breaks BasicTransformerBlock, this pack is usually the first thing to notice.
Inputs (8)
| Name | Type | Default | Description |
|---|---|---|---|
| sampler_name | COMBO | 35 options: REFERENCE_WRITE, euler, euler_cfg_pp, euler_ancestral, euler_ancestral_cfg_pp, heun, +29 | |
| start_percent | FLOAT | 0.000–1 | — |
| end_percent | FLOAT | 1.000–1 | — |
| ref_bank | REF_BANK | — | |
| mask_dilation | INT | 30–10 | — |
| sampleropt | SAMPLER | — | |
| opt_attn_mapopt | ATTN_MAP | — | |
| masksopt | MASK | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| SAMPLER | SAMPLER | — |
| SIGMAS | SIGMAS | — |