Nodes/ComfyUI Body Decal/Body Decal Apply (Advanced)
ComfyUI Node

Body Decal Apply (Advanced)

The one node that sticks tattoos, logos and scars onto bodies so they don't look pasted on

By verias·Created 3 months ago·Updated 3 months ago· 1
Body Decal Apply (Advanced)
  • image
  • decal
  • pose_keypoint
  • user_region_mask
  • clip_mask
  • depth_map
  • displacement_map
  • decal_alpha_mask
  • image
  • mask
  • debug_image
section_placement— Placement / Body Region —
placement_region
placement_side
placement_anchor0.20
placement_along_axis0.00
placement_across_axis0.00
section_region— Region Mask —
region_start_extend0.00
region_end_extend0.35
region_inner_width0.10
region_outer_width0.22
region_feather10
section_decal— Decal Size / Rotation —
decal_scale1.00
decal_height1.05
decal_width1.00
decal_base_rotation0
decal_rotation_offset0.0
manual_offset_x0
manual_offset_y0
warp_mode
section_alpha— Alpha / Blend —
blend_mode
opacity0.75
alpha_mode
alpha_threshold0.03
alpha_softness0.10
section_displacement— Displacement Warp —
displace_strength_x0.0
displace_strength_y8.0
displace_neutral0.50
depth_strength_x0.0
depth_strength_y0.0
depth_neutral0.50
section_debug— Debug —
debugtrue

This is the whole pack in one node: pose-aware placement, masking, perspective warp, displacement, and blending, all stuffed into a single "Body Decal Apply (Advanced)" box. If your goal is "put this chest tattoo on that character and make it look like it was always there," start here instead of stitching together the modular pipeline by hand. It's the workflow the README points most users to, and honestly that's the right call - you can wire the five-node version later once you know which dial you actually want to touch.

It's called "Advanced" because the input list is a wall - around forty widgets. Breathe. The author groups them with STRING inputs that are just section headers ("- Placement / Body Region -", "- Region Mask -", "- Decal Size / Rotation -"), and those header inputs do nothing except organize the UI. Ignore them entirely. What actually matters is a handful of widgets plus the optional inputs at the bottom.

How it works

The pipeline is: detect body → derive a placement region → size and warp the decal onto it → blend. Detection expects a pose_keypoint (POSE_KEYPOINT) input from DWPose - wire in a DWPreprocessor from ComfyUI ControlNet Aux Preprocessors, the same preprocessor family the KB treats as required for any serious pose work. From the keypoints it computes a body-part axis (say shoulder→elbow for upper_arm), builds a quad around it using the region_* widths, then resizes your decal to match the region's length.

From there the warp_mode pick: rotate_paste just rotates and drops the decal near the region anchor; perspective_quad does an actual projective warp so the decal leans with the limb instead of staying perfectly front-facing. Perspective is the one that makes chest and sleeve tattoos read as real. Alpha handling comes next (alpha_mode: use_image_alpha for PNGs with alpha, black_to_alpha/white_to_alpha for logos on solid backgrounds), then optional displacement and depth warps, then the final blend with a chosen blend_mode and opacity.

One behavior worth knowing before you pull your hair out: if no person is detected in the pose data, the node silently returns your image unchanged with an empty mask. No error, no warning. That's why the debug_image output exists - it draws the region axis, anchor points and quad so you can see what the node thinks it's aiming at.

The inputs that actually matter

  • image and decal - base photo and the thing to stick on it.
  • placement_region + placement_side - where on the body, and which side from the viewer's perspective. Eight regions: nose, neck_side, upper_arm, forearm, thigh, lower_leg, torso_side, torso_front.
  • warp_mode - rotate_paste (quick) vs perspective_quad (real warp).
  • blend_mode + opacity - multiply for dark tattoos, screen for glowing circuitry, normal for solid logos.

The optional inputs are where the flexibility hides: user_region_mask skips pose entirely and derives the placement region from any mask you feed (clothing, props, one-off edits - this is the manual path), and clip_mask, depth_map, and displacement_map add refinement. Outputs are image (the composite), mask (the final decal alpha), and debug_image.

Installing

Through ComfyUI Manager, search the pack title "ComfyUI Body Decal" and install. Or do it by hand:

cd ComfyUI/custom_nodes
git clone https://github.com/verias/comfyui-body-decal.git

Restart ComfyUI. Dependencies install themselves from requirements.txt - it's just numpy and Pillow, no heavy stack, and there are no model files to download. The optional bits (DWPose, Depth Anything) come from other packs you'll already have for ControlNet work.

Gotchas

If your decal renders but shows up as a black box, your source image has no alpha and you're on use_image_alpha - switch to black_to_alpha or white_to_alpha. If nothing renders at all, check the debug view: either no person was detected, or you left alpha_mode on none. And remember displacement only does something when you actually feed a displacement_map; the sliders can be turned up and nothing will happen otherwise.

Categoryimage/postprocessing/body decal

Inputs (44)

NameTypeDefaultDescription
imageIMAGE
decalIMAGE
section_placementSTRING— Placement / Body Region —
placement_regionCOMBO8 options: nose, neck_side, upper_arm, forearm, thigh, lower_leg, +2
placement_sideCOMBO2 options: viewer_left, viewer_right
placement_anchorFLOAT0.200–1
placement_along_axisFLOAT0.00-2–2
placement_across_axisFLOAT0.00-2–2
section_regionSTRING— Region Mask —
region_start_extendFLOAT0.00-1–1
region_end_extendFLOAT0.35-1–2
region_inner_widthFLOAT0.100–1
region_outer_widthFLOAT0.220–1.5
region_featherINT100–80
section_decalSTRING— Decal Size / Rotation —
decal_scaleFLOAT1.000.2–3
decal_heightFLOAT1.050.2–4
decal_widthFLOAT1.000.2–4
decal_base_rotationFLOAT0-180–180
decal_rotation_offsetFLOAT0.0-90–90
manual_offset_xFLOAT0-500–500
manual_offset_yFLOAT0-500–500
warp_modeCOMBO2 options: rotate_paste, perspective_quad
section_alphaSTRING— Alpha / Blend —
blend_modeCOMBO5 options: screen, add, normal, multiply, overlay
opacityFLOAT0.750–1
alpha_modeCOMBO5 options: use_image_alpha, black_to_alpha, white_to_alpha, luma_to_alpha, none
alpha_thresholdFLOAT0.030–1
alpha_softnessFLOAT0.100.001–1
section_displacementSTRING— Displacement Warp —
displace_strength_xFLOAT0.0-100–100
displace_strength_yFLOAT8.0-100–100
displace_neutralFLOAT0.500–1
depth_strength_xFLOAT0.0-100–100
depth_strength_yFLOAT0.0-100–100
depth_neutralFLOAT0.500–1
section_debugSTRING— Debug —
debugBOOLEANtrue
pose_keypointoptPOSE_KEYPOINT
user_region_maskoptMASK
clip_maskoptMASK
depth_mapoptIMAGE
displacement_mapoptIMAGE
decal_alpha_maskoptMASK

Outputs (3)

NameTypeDescription
imageIMAGE
maskMASK
debug_imageIMAGE