HT DWPose Constraint
Stop your pose-conditioned characters from dislocating
- dwpose_image
- constrained_pose
The pose you feed a ControlNet is a suggestion, and the model will happily invent an elbow that bends backward to obey it. DWPose skeletons are great - better hand detection than classic OpenPose, which is why pose workflows moved to them - but they're only as anatomically sane as the person or detector that produced them. HT DWPose Constraint is the referee: it takes a DWPose image, checks every joint angle against human limits, and pushes anything out of range back into place. Feed it a contorted pose map, get back one a human could actually do.
How it works
It doesn't run a detector and it doesn't call any API. The node reads the DWPose skeleton straight out of the image you give it, using the color-coded keypoints the standard pose renderers draw (nose is red, right shoulder orange, left ankle magenta, and so on). From the joint positions it computes angles - elbow, knee, shoulder, hip, neck, torso, ankle - and compares them to hard-coded anatomical limits: elbows stay between 0–160°, knees 0–150°, neck ±45°, and so on.
When a joint is out of range, it rotates the offending limb about its pivot to bring the angle back inside the limit. flexibility_factor scales those limits - 1.0 is normal human, under 1.0 makes the rig stiffer (great for realistic figures), over 1.0 loosens it for stylized/anime poses that genuinely flex more. It's a genuinely useful dial: most of the time you set it once per character style and forget it.
The toggle inputs are the rest of the pitch:
constrain_joints(default on) - the master switch for the whole angle-correction pass.force_limbs,force_hands,force_feet- snap those body parts into valid configurations even when the source pose is missing or garbled. Turn onforce_hands/force_feetif your pose generator keeps dropping digits.preserve_height(default on) - keep the skeleton's overall height when correcting, so you don't shrink or stretch the figure.
Output is a single constrained_pose image, ready to feed into your ControlNet preprocessor chain - usually replacing the raw DWPose output before the ControlNet apply node.
The workflow it belongs in
The typical setup is: image → DWPose estimator (from ControlNet Aux / ComfyUI ControlNet Aux) → this node → controlnet apply → sampler. You want the constraint before the ControlNet, so the conditioning is already sane. Where people get burned is putting it after the ControlNet - at that point the damage is done.
Installing and notes
Standard pack install - Manager, search "HommageTools for ComfyUI", or:
cd ComfyUI/custom_nodes
git clone https://github.com/ArtHommage/HommageTools.git
cd HommageTools && pip install -r requirements.txt
then restart. It uses OpenCV (cv2) internally, which is already present in a normal ComfyUI environment, so no extra model files.
One honest caveat: it works on the color-coded pose rendering, so it needs the standard DWPose color scheme as input - feed it the visual skeleton, not a raw keypoint JSON. And like everything in this pack, it's flagged experimental alpha, so expect the limits table to be tuned over time. For a quick sanity test, pipe in a pose with an obviously hyperextended knee and watch it get rotated back.
Inputs (7)
| Name | Type | Default | Description |
|---|---|---|---|
| dwpose_image | IMAGE | — | |
| flexibility_factor | FLOAT | 1.00.5–2 | — |
| constrain_joints | BOOLEAN | true | — |
| force_limbsopt | BOOLEAN | false | — |
| force_handsopt | BOOLEAN | false | — |
| force_feetopt | BOOLEAN | false | — |
| preserve_heightopt | BOOLEAN | true | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| constrained_pose | IMAGE | — |