Skin Pack (deterministic detail maps, CPU)
Deterministic albedo and normal maps, generated on CPU, no model download
- albedo
- normal
Here's a node that does something refreshingly unglamorous: it makes skin texture out of maths. No diffusion model, no texture synthesis network, no download. Give it a size and a seed and it hands you an albedo map and a matching normal map. Same seed, same bytes, forever.
That determinism is the point. If your character pipeline is supposed to be reproducible - re-run the workflow next month, get the same character - you cannot have the skin come out of a sampler. SkinPack is pure CPU, claims no GPU, and runs anywhere ComfyUI runs.
How it works
It builds a height field out of three fbm (fractional Brownian motion) noise layers at different frequencies - pores at 96 cells over two octaves, broad undulation at 12 cells over three, and fine lines at 48 cells over one - mixed at 0.45 / 0.35 / 0.20. That weighted mix is your skin microdetail: fine grain, plus larger organic variation, plus creases.
From the height field it derives the albedo by modulating a base skin tone (1.00, 0.930, 0.865) with a mild shade curve - 0.92 + 0.16 * height, so variations stay subtle rather than blotchy. The normal map comes from finite differences of the same height field (a central-difference gradient scaled by resolution), normalized and remapped into the 0.5-biased RGB encoding a normal map expects. Because albedo and normal are derived from the same field, they agree with each other - the pores you see are the pores you feel. That's not automatic in a lot of tile-and-paste texture workflows, and it's the difference between skin and noise.
Both maps come back as ComfyUI IMAGE tensors in [0,1] float, (1, H, W, 3), and they're generated in the pack's skin_surgery module - the same file that later applies them.
Inputs and outputs
size(default 512) - map edge in pixels. The widget lets you enter 256–2048, but the code only accepts 256, 512, 1024 or 2048 - the "closed vocabulary", as the docstring calls it. 300 fails at run time with a refusal.seed(default 20260906, 0 to 2^31−1) - pure determinism knob. Same seed and size, identical maps on any machine, GPU or not. A negative seed is refused outright, with a slightly grumpy error explaining that the-1"random" sentinel is minted upstream in the pack's card compose; a raw-1here means something bypassed that layer.
Two outputs: albedo and normal, both IMAGE. Wire them into SkinApply to put them on a body, and into a save node if you want the PNGs on disk. It's not an output node, so it only runs when something downstream wants it.
Install
cd /path/to/ComfyUI/custom_nodes
git clone https://github.com/JayDataEngineer/melite-poser-nodes.git
Restart ComfyUI, or search melite-poser-nodes in ComfyUI Manager. The pack's requirements.txt lists py-soma-x[anny], trimesh, xatlas - this node needs none of them. numpy, PIL and torch, all of which ComfyUI already has. Which means: if you're on a machine where the heavy deps are being difficult, SkinPack is one of the handful of pack nodes you can still use today.
Where people get burned
These are detail maps, not a character skin. You won't get a face, a tattoo, or a scar. You get tiling microdetail and pore-scale normals, which is exactly what "detail" means in a material stack. If you want identity on the body, that comes from the projected texture - this is the layer that sits over it.
The normal map is muted on purpose downstream. When SkinApply attaches these to a body, the glTF normalTexture is written with scale: 0.0. The pack's comment explains why, quoting their own bug report: UV-path bump through projection UV tangents produces a "mottled" skin and the normal map rides along for harvest rather than being applied. So don't be surprised when the normal channel seems to have no effect on the rendered result - that's the author's deliberate law in this version, not a bug you need to fix.
Deterministic also means uncorrelated with your mesh. The maps are generated in texture space from noise. They don't know where the body's UV seams are, so tiling relies on the sampler's repeat wrapping. Fine for a full-body skin pass; not a substitute for a proper UV-aware paint.
Refusals come as runtime errors. Size not in the vocabulary, negative seed - both raise SkinPack refused: .... The error text is specific enough to act on immediately, which is more than most packs manage.
Inputs (2)
| Name | Type | Default | Description |
|---|---|---|---|
| size | INT | 512256–2048 | — |
| seed | INT | 202609060–2147483647 | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| albedo | IMAGE | — |
| normal | IMAGE | — |