Line Gap Closer
Weld broken line-art endpoints together before your region fill leaks everywhere
- image
- closed_line
- closure_overlay
- segments_json
Rough pencil lines don't close shapes. There's always a gap where a stroke ended a hair short of the next one, and that's fine for sketching - until you try to fill the drawing, at which point every one of those tiny holes becomes a leak for your bucket fill or your colorizer. Line Gap Closer is the node that hunts down those broken endpoints and welds them with short connector strokes. It's the middle step of the OpenToonz-inspired pipeline in ComfyUI-OpenToonzLineTools: clean the blue rough → close the gaps → find the fillable regions → colorize. Without this step, the region finder downstream will happily label "hair" and "background" as one continuous shape because the ink never actually closed.
How it works
No neural network here, just classic image morphology. The node binarizes the input (pixels darker than threshold count as line), then runs Zhang-Suen thinning to reduce everything to a 1-pixel skeleton. Endpoints are the skeleton pixels with exactly one neighbor. From each endpoint it traces a bit along the line to learn its direction, then connects pairs whose endpoints are close enough (closing_distance, in pixels) and heading in compatible directions (spot_angle, in degrees). Closure strokes get drawn in via Bresenham/anti-aliased lines.
That direction check is the clever bit. Naive "connect anything within X pixels" code merges unrelated lines constantly; requiring the two strokes to point at each other is what keeps the welds mostly sensible.
Inputs that matter
closing_distance(default 18) - the real dial. How big a gap it will bridge in pixels. Raise it for loose rough sketches; lower it when it starts welding things that shouldn't meet.spot_angle(default 75) - direction tolerance. Lower = stricter, fewer false connections; higher = closes more ambiguous gaps.threshold(default 180) - how dark a pixel must be to count as line. Match it to what your line art actually looks like.max_endpoints(default 600) - the safety cap. When the endpoint count blows past it, the node skips instead of spraying chaotic connections, and tells you so.line_width(default 1) - stroke width of the closures. Keep it at 1–2; thicker muddies the art.
Outputs
closed_line is the one you wire forward into Color Region Finder. closure_overlay is the one you actually look at - black original lines with every new closure stroke in red, which makes it obvious in one glance whether it's behaving. segments_json dumps the closure segment coordinates plus a skip reason when it bailed out, so you're never guessing whether a gap got bridged or ignored.
Installing it
ComfyUI Manager, search comfyui-opentoonz-line-tools, or clone:
cd ComfyUI/custom_nodes
git clone https://github.com/l2dnjsrud/ComfyUI-OpenToonzLineTools.git
Restart and you'll find it under manga/opentoonz-line-tools. Dependencies are numpy, opencv-python, and Pillow - no torch reinstall (the README is explicit: don't upgrade torch from this pack), no model downloads. It's CPU-only and instant.
Where people get burned
The big one is feeding it a full manga page. The README says it outright: this node is designed for panel crops, not full pages. A full page has thousands of endpoints from layout borders, balloons, and perspective grids, so you'll hit the max_endpoints cap and get the "endpoint_count_exceeded" skip reason in the JSON. Crop your panel first. The other classic failure is over-connecting - unrelated strokes getting welded - which usually means closing_distance is too generous or spot_angle too loose; drop both and re-check the overlay. Also worth knowing: this pack is tiny and young (zero reddit chatter, barely-used on comfy.icu), so the defaults are a starting point, not gospel. The red overlay exists for a reason - trust it over your hopes.
Inputs (6)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| threshold | INT | 1800–255 | — |
| closing_distance | INT | 181–256 | — |
| spot_angle | FLOAT | 750–180 | — |
| line_width | INT | 11–16 | — |
| max_endpoints | INT | 6002–10000 | — |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| closed_line | IMAGE | — |
| closure_overlay | IMAGE | — |
| segments_json | STRING | — |