Nodes/ComfyUI LC123 Nodes/LC Skin Upscale
ComfyUI Node

LC Skin Upscale

Put the pores back without re-rolling the face

By lonecatone23·Created about a month ago·Updated about 13 hours ago· 17
LC Skin Upscale
  • image
  • upscale_model
  • mask
  • image
  • skin_mask
modedetail 1x
blend0.75
mask_sourceinput+chroma
mask_sensitivity0.55
mask_feather0.45
tile512
overlap32

"Too smooth skin" is the oldest complaint in this hobby and still the first one people make about a brand-new architecture - it's why the Z-Image Turbo writeups of 2026 open with the skincare-ad problem. The usual answers all involve sampling again: FaceDetailer, a low-denoise img2img pass, SeedVR2. Every one of those invents a face.

LC Skin Upscale is the other kind of fix. One CNN upscale model, applied where a mask says, composited back over the original pixels. No sampler, no seed, no CFG - and, per the author, not a stack and not Ultimate SD Upscale. It sits between "leave the skin alone" and "run the face through a generative detailer".

How it actually works

Building the matte. mask_source decides where the effect lands. input uses only the MASK you wire in. chroma ignores your mask and derives one from skin-colour heuristics - RGB ranges plus a CIELAB chroma window, box-blurred and thresholded with mask_sensitivity as the dial. input+chroma is the AND of the two. The matte then gets feathered, and the node crops to its bounding box (padded 16px, snapped to a multiple of eight).

Running the model on the crop. It hands that crop to your UPSCALE_MODEL through Comfy's tiled scaler, and retries at half the tile size if it runs out of VRAM. Then:

  • detail 1x resizes the model's output back down to the crop's size and pastes it in. Nothing gets bigger. This is the mode for 1× skin models like 1xSkinContrast-High-SuperUltraCompact or 1x-ITF-SkinDiffDetail-Lite-v1.
  • scale keeps the model's native factor - the canvas genuinely grows, unmasked area bilinear, masked area run through the model. Only for when you wanted pixels.

Final pixels are original × (1 − mask × blend) + patch × (mask × blend) - the strength you get is mask and blend multiplied, not either alone.

It's a preview node underneath (a PreviewImage subclass), which is where the on-node before/after wipe comes from. Outputs are image (composited, batch-preserved) and skin_mask.

The inputs worth touching

  • upscale_model - load it with the core UpscaleModelLoader from ComfyUI/models/upscale_models, and load a 1× skin model, not a generic 4×. The author's daily is 1xSkinContrast-High-SuperUltraCompact.
  • blend - 0 is the original image, 1 is a full replacement under the matte. The pack's own recipe is 0.75, dropping to 0.55–0.65 on already-sharp Krea plates.
  • mask_source - input if you're wiring a proper person mask, which is the recommended path.
  • mask_feather - soft edge on the composite matte, and the one to nudge if you can see where the patch ends (0.45 in the author's recipe).
  • tile / overlap - the author's numbers are 256 / 16 on large plates, on the grounds that 512 is slower for very little gain. tile: 0 means "try the whole crop and shrink if it OOMs".

Install

Manager: search ComfyUI_LC123_nodes. Manually:

cd ComfyUI/custom_nodes
git clone https://github.com/lonecatone23/ComfyUI_LC123_nodes

Then restart. __init__.py has to sit directly in that folder - if you unzipped a pack zip inside an existing clone and ended up with ComfyUI_LC123_nodes/ComfyUI_LC123_nodes/, move the inner files up a level. The console should print an LC123 load line when it comes up. No pip dependencies, but the maskers and the models don't ship with it.

Grab the 1× skin CNN from the pack's model table (openmodeldb, or notkenski/upscalers on HuggingFace) and drop it in:

ComfyUI/models/upscale_models/1xSkinContrast-High-SuperUltraCompact.pth

For the mask, the author's example workflow wires a LayerMask: PersonMaskUltra V2 matte with face + body on. That node lives in chflame163's LayerStyle Advance, not here.

Where it goes wrong

Loading a 4× model in detail 1x. You pay 4× the time, then throw three-quarters of the pixels away. The README warns about this first, and it's invisible in the output - it just gets slow.

The empty-matte no-op, and skin-coloured leaks. If the bounding box comes back empty, or blend is effectively zero, the node hands you the original frame unchanged - so "I ran it and nothing happened" usually means the chroma heuristic found no skin (heavy makeup, green screen, cool grade) or mask_source: input with a mask that's black everywhere. Check skin_mask first. The opposite failure is just as common: the auto matte happily swallows tan fabric, wood and warm walls, so lower mask_sensitivity or wire a real person mask - which is the recommended path anyway, since mask_source ships as input+chroma and quietly falls back to auto-skin if you wire nothing. Related trick: input with no MASK wired gives an all-white matte, i.e. a full-frame 1× pass.

It's a detail pass, not a detail generator. A CNN can't invent a nose, and it won't rescue a soft source - that's SeedVR2's or a face detailer's job. Run it at native resolution, before you upscale, on skin that's clean but too smooth.

PersonMaskUltra friction. It wants mediapipe, and "No module named 'mediapipe'" is a long-running annoyance in the wild. If the mask side breaks, that's a separate pack's dependency, not LC123's.

CategoryLC123/image

Inputs (10)

NameTypeDefaultDescription
imageIMAGESource image (batch ok).
upscale_modelUPSCALE_MODELOne CNN upscaler. 1× SkinContrast for detail.
modeCOMBOdetail 1xdetail 1x = paste back at original size. scale = keep the model's native factor.
blendFLOAT0.750–1How hard the upscaled patch replaces the original under the mask.
mask_sourceCOMBOinput+chromainput = wired mask only. chroma = auto skin. input+chroma = AND.
mask_sensitivityFLOAT0.550–1Auto-skin reach when chroma is used.
mask_featherFLOAT0.450–1Soft edge on the composite matte.
tileINT5120–2048CNN tile size. 0 = try full crop, shrink on OOM.
overlapINT320–256Tile overlap in pixels.
maskoptMASKPerson / skin matte from RMBG or similar. Stay external.

Outputs (2)

NameTypeDescription
imageIMAGE
skin_maskMASK