ReShot Pose Map
The tightest leash on a dance — and what it throws away
- images
- pose
- keypoints_json
ReShot Pose Map turns your video frames into OpenPose-style skeletons: coloured stick figures on black, tracked and smoothed across the clip, hands drawn, face not. Put it in front of a pose ControlNet - MiniMax H3's Fun ControlNet with condition: pose, Wan's VACE control_video, anything trained on pose - and your reference performance's limbs get copied onto a character who looks nothing like the person in the clip.
It is the tightest leash you can put on a body, and the most destructive one, and the field has spent two years arguing about that. DWPose, the estimator underneath controlnet_aux's famous pose images, throws away depth and contact information before the model ever sees the driving video. That's the shape of the trade: the skeleton guarantees the limbs are right and guarantees nothing else - not how far the fighter is from the wall, not whether the foot is planted on the ledge. Our Wan coverage quotes a long-time user making the point from the other side: depth "will confine the alterations to exactly the boundary of the depth map," which is why a garment change wanting more room than the silhouette you fed it doesn't work. Depth = the space and the set. Pose = the body, exactly. If limbs are the point (dance, martial arts), pose. If the character must occupy the same space as the furniture, depth.
Worth knowing that the approach is losing an argument inside the research: Z.ai's SCAIL-2 shipped as an open motion-transfer model by removing the skeleton, and got cross-identity and animal driving out of it. For a ControlNet, though, a skeleton is what the checkpoint was trained on.
How it works
Frames go through DWPose - a YOLOX-L person detector plus RTMPose whole-body - and come back as 134 keypoints per person per frame. Then the interesting part: people are tracked across frames by IoU, joints that dip briefly below the draw threshold are held rather than dropped, and every joint gets a One-Euro filter. Only then is the frame drawn: 18 body joints in OpenPose's colours, limbs as ellipses at 60% brightness, hands as rainbow-edged segments, stroke widths scaled to the frame - the visual language the pose ControlNets were trained on.
Inputs and outputs
images- frames as one IMAGE batch[T, H, W, 3].fit_to-none/h3/seedance/wan, center-cropping to ×32 or ×16 as needed.h3for the H3 Fun ControlNet.hands- on by default, and why grips and catches survive instead of turning to mush.face- off by default, and the author's reason is good: the face is the one thing this pipeline exists to discard. Turn it on only if a downstream model wants face landmarks.smooth- leave it on. Raw per-frame estimates jitter, and a video model reads jitter as motion.detect_every- run the detector every N frames and follow skeletons in between; 3 by default, and a cut re-detects immediately. The tooltip prices1at roughly 2.5× slower on CPU - a real cost on a long clip for a marginal gain.
Outputs: pose (IMAGE batch, same frame count, source size unless fit_to cropped) and keypoints_json - a STRING with every skeleton in the pack's own reshot-pose/1 format: per frame, per person, a stable id, 134 [x, y] points and scores. That export is the sleeper feature: a free, cleaned motion-capture file. Save it with a text node or parse it yourself.
Install
ComfyUI Manager → ComfyUI-ReShot, or clone plus one pip line:
cd ComfyUI/custom_nodes
git clone https://github.com/maosika-ai/ComfyUI-ReShot
python -m pip install -r ComfyUI-ReShot/requirements.txt
The pose half needs onnxruntime, which requirements.txt pulls in as part of reshot[pose]. That's the CPU build: works everywhere, slow - around 300 ms per frame on an M2 Max. For an NVIDIA card, install the GPU build into the same Python:
python -m pip install onnxruntime-gpu
First pose run downloads about 340 MB of ONNX weights into the Hugging Face cache. Same China caveat as everything in this pack: export HF_ENDPOINT=https://hf-mirror.com before starting ComfyUI.
Common issues
- Black output frames - nobody was found in the clip. The node warns in the console and gives you black frames; a video model fed an all-black control video has nothing to follow. Check the console line reporting people-per-frame.
- Skeletons teleport or swap between people - crowded shots or heavy occlusion.
detect_every: 1helps, at a CPU cost. - Slow - you're on the CPU half of
onnxruntime. Installonnxruntime-gpuand confirm the console says it's loading DWPose rather than sitting there quietly. - Dimensions don't match the rest of the graph -
fit_tocenter-cropped. Setnoneor match it on every branch.
Pass the whole clip as one batch, and check the crop: fit_to changes the frame size, so masks elsewhere in the graph need to agree.
Inputs (6)
| Name | Type | Default | Description |
|---|---|---|---|
| images | IMAGE | Video frames as an IMAGE batch [T, H, W, 3]. | |
| fit_to | COMBO | none | Center-crop to the model's frame-size multiple (h3: x32, seedance/wan: x16). fps is not changed here — use ReShot Pose Video for that. |
| handsopt | BOOLEAN | true | Draw the 21-point hands (grips and gestures). |
| faceopt | BOOLEAN | false | Draw the 68 face points. Off by default: the face shape is what ReShot throws away. |
| smoothopt | BOOLEAN | true | Track people across frames, hold joints that dip briefly, One-Euro smooth. Off = raw per-frame output. |
| detect_everyopt | INT | 31–30 | Run the person detector every N frames and follow the skeletons in between (cuts always re-detect). 1 = every frame, ~2.5x slower on CPU. |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| pose | IMAGE | — |
| keypoints_json | STRING | — |