HSL Range → Mask
The Little Node That Turns 'the Red Parts' Into an Actual Mask
- image
- mask
Every ComfyUI user eventually hits the same wall: "I need a mask of just the red car, or the green screen, or the blue sky." You could hand-paint it, or you could spend ten minutes explaining to a segmentation model what you want. HSL Range → Mask takes the boring, reliable shortcut: give it a colour range, get back a mask where every matching pixel is white and everything else is black. Six numbers in, one mask out.
It's the whole pack - this repo ships exactly one node, one ~100-line file, no models, no API key, no pip install of anything. About as safe a custom node as exists, which is worth saying out loud given that custom nodes run arbitrary code on your machine with no sandbox.
Why you'd reach for it
The classic jobs are chroma keying (cut a green-screen subject, drop in a new background) and isolating one object by colour for targeted inpainting. That second one is where the mask still wins over the newer instruction-edit models: an edit model re-renders the whole frame and drifts the pixels it wasn't asked to touch, while a mask guarantees everything outside it stays bit-identical. "Fix the red jacket, nothing else" is precisely the case where you want this node's kind of blunt certainty.
How it works
The node converts each pixel from RGB to HSL using Python's colorsys, then builds three boolean masks - hue in range, saturation in range, lightness in range - and ANDs them together. Hue runs 0–360 degrees, saturation and lightness 0–100. The output is a float32 MASK tensor, white where the colour matched, black elsewhere.
Two things to know before you start twisting dials:
- This is HSL, not HSV. Photoshop-style selectors usually speak HSV, and the two put "lightness" in different places. In HSL, fully saturated mid-tone colours sit at L≈50, and pure black and white live at the extremes. If you set a tight lightness range expecting HSV behaviour, you'll pull nothing.
- The mask is hard-edged. It's strictly 0 or 1 per pixel - no feathering, no tolerance ramp. Fine for chroma keying at full res, but if you're inpainting you'll often want to soften the result with a Blur node before it hits the VAE.
One genuinely nice touch in the code: the hue range wraps the 0/360 boundary automatically. Reds live at the very top and bottom of the hue wheel, so a range of 340→20 catches them all without you working out the arithmetic.
The inputs that matter
Seven inputs, and you'll really only tune four of them:
image- any IMAGE from your pipeline.start_hue/end_hue(0–360) - this is the actual colour you're after. Defaults are 0 and 360, i.e. everything.start_saturation/end_saturation(0–100) - widen this a little on real footage; compression and lighting mean "green" is rarely a single saturation value.start_lightness/end_lightness(0–100) - leave at full range unless shadows or highlights are leaking in.
With the defaults the node outputs all-white, and you narrow down until only what you want survives. That's the workflow - no cleverness required.
Wiring the output
The single output, mask, is a MASK tensor, not an image. The beginner stumble: you can't preview it directly. Run it through a MaskToImage to actually see it, or feed it straight into VAE Encode (inpaint) for targeted inpainting. Want to protect a region instead of paint one? Throw InvertMask at it. Building a selection from several colour families at once? Make a few of these and combine with MaskComposite.
Install
Easiest via ComfyUI Manager - search "HSL" or comfyui-hsl-mask-node, install, restart. Or the old-fashioned way:
cd ComfyUI/custom_nodes
git clone https://github.com/HelloWNW/comfyui-hsl-mask-node
then restart ComfyUI. You'll find it under image → masking → HSL Range → Mask. The README describes hand-copying a folder called hsl_mask_node, but a clone lands as comfyui-hsl-mask-node with __init__.py at the top level, which ComfyUI loads fine. No models download, no extra dependencies - the requirements are the Python standard library, numpy, and torch, all of which ComfyUI already has.
One honest caveat: the per-pixel conversion runs through a vectorised colorsys call, which is really a Python loop in a trench coat. On a single 1024×1024 frame it's a couple of seconds on CPU - fine. Don't feed it a batch of 4K frames in a tight loop and expect speed.
Not a flashy node. It doesn't need to be - it does one thing, does it with zero dependencies, and sits quietly between your image and every node that takes a mask.
Inputs (7)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| start_hue | FLOAT | 0.00–360 | — |
| end_hue | FLOAT | 360.00–360 | — |
| start_saturation | FLOAT | 0.00–100 | — |
| end_saturation | FLOAT | 100.00–100 | — |
| start_lightness | FLOAT | 0.00–100 | — |
| end_lightness | FLOAT | 100.00–100 | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| mask | MASK | — |