Badge Height Layer (DAELab)
Turn your flat colour art into six legal heights — no gradients allowed
- images
- height_mask
- height_image
- unmatched_mask
- height_profile
What this is for
A badge is a physical object with a fixed number of levels. It's stamped or cast in stages: empty (cut out), then five surfaces stacked up from the base. There is no "63% height" in the manufacturing sense, and if you hand a generative model a smooth gradient and call it a height map, it will confidently invent bevels and ramps that don't exist in the tooling.
Badge Height Layer (DAELab) is how you produce a height field that's legal by construction. You give it your flat colour-separated artwork. You pair each colour with a level - Cut Out, or Layer 1 through Layer 5. Out comes a discrete height map where every pixel is one of exactly six values: 0.0, 0.2, 0.4, 0.6, 0.8, 1.0. No interpolation, no feathering, nothing to hallucinate.
It's the step between "design" and "geometry", and it's one of the few nodes in this pack with no API call and no cost attached.
How it works
The node holds a list of colour groups, each with enabled, color, threshold and layer - up to 16 of them, edited in the node's own panel rather than as plain widgets. For every pixel it computes the Euclidean RGB distance to each enabled group's colour, accepts it if it's within that group's threshold (0–255 range), and assigns the pixel to the closest match. On an exact tie it takes the higher layer, which is a small, sensible tie-break for a physical stack.
Everything else is deliberately dumb: the assigned layer number divided by five becomes the height, so Layer 3 is 0.6. The height map is emitted as a MASK, and mirrored as a three-channel grayscale IMAGE so you can look at it or hand it to an image model as a structure reference.
Alpha gets respected. If your input has an alpha channel, fully transparent pixels are forced to 0.0 and counted as matched-but-transparent, not as unmatched - so a transparent background doesn't show up in your "something went wrong" mask.
unmatched_mask is the honest output and the one to actually check: every pixel that hit no colour and wasn't transparent, in white. A clean run has an empty one. A run where half the artwork is white means you forgot to add the background colour, and every downstream stage will treat that white as height zero.
height_profile is a structured payload - configured layers, which layers actually got pixels, per-layer pixel counts, unmatched count, transparent count. It goes into Badge Height Establish Prompt Builder, which uses it to describe only the levels that exist, so your prompt can't ask a model for a Layer 3 that matched nothing.
The inputs and outputs
images - one input, required, your flat colour artwork. Everything else is configured in the node's panel.
Outputs: height_mask (the discrete height field), height_image (grayscale preview / structure reference), unmatched_mask (check this), height_profile (feed the prompt builder).
Install
cd ComfyUI/custom_nodes
git clone https://github.com/TeutonicMepheles/ComfyUI-DAELab-Custom-Nodes-Library.git
# restart ComfyUI, then hard-refresh the browser
The panel is JavaScript in the pack's web/ directory. Install without restarting, or update without clearing cache, and you get a node with no colour groups UI - which looks like a broken install and is almost always a stale front end. The Python side also reads its configuration out of the workflow itself (extra_pnginfo), so a job submitted as a bare API prompt with no workflow attached configures itself with zero groups.
Where people get burned
Gradients and antialiasing. A colour-ID drawing with soft edges produces unmatched pixels along every boundary, because a half-blended pixel is within nobody's threshold. That's why the pack insists on a clean colour-ID source: flatten the art before it gets here, or raise thresholds and accept muddy boundaries. This node does not feather, on purpose.
Cut outs sharing a colour with solids. If your cut-out regions and your flat base happen to be the same RGB, no threshold can separate them - the node has nothing to go on. Give cut outs their own unique placeholder colour in the flat art.
Overlapping tolerances. Two similar colours with wide thresholds will fight, and nearest-distance means the outcome depends on which colour is closer per-pixel, which can split a region in half. Tighten thresholds or give the regions distinct colours.
Trusting the profile you didn't read. height_profile telling you "Configured but empty: Layer 3" is the node warning you that you paid for a height configuration that doesn't exist in the art. Read it before generating anything.
Inputs (1)
| Name | Type | Default | Description |
|---|---|---|---|
| images | IMAGE | — |
Outputs (4)
| Name | Type | Description |
|---|---|---|
| height_mask | MASK | — |
| height_image | IMAGE | — |
| unmatched_mask | MASK | — |
| height_profile | BADGE_HEIGHT_PROFILE | — |