Line Art
Render a 3D model as line art, ready to feed a ControlNet
- model
- image
Line Art is the bridge between the 3D side of ComfyTV and the 2D side. You point it at a 3D model and it renders a technical line drawing - the kind of clean, stylized line art that used to mean hours in a toon shader or a vectorizer. And because it defaults to white lines on black, what it actually hands you is a ready-to-use ControlNet lineart condition: generate a 3D scene, render the lines, and use them to pin the composition of a diffusion image. That's a workflow that's genuinely hard to build any other way.
ComfyTV is the canvas-style app layer on ComfyUI where every operation is its own node. Line Art sits in the 3D category because it consumes a COMFYTV_MODEL - a mesh from Mesh Primitive, a generated model, or an imported asset.
How it works. The renderer doesn't shade the surface - it detects edges in four categories you can toggle: silhouette (where the surface turns away from the camera), crease (sharp edges past a crease_angle), boundary (open mesh borders), and it can hide lines behind the surface using a BVH ray test (occlusion) so you get a proper line render instead of a wireframe. The result is drawn at thickness (in output pixels) onto a canvas sized by width/height. invert flips the palette: default gives white-on-black for ControlNet lineart preprocessors; flip it for black-on-white if that's what your model expects. The camera is set in the node body's 3D viewport (empty camera = auto-framed).
The inputs that matter. The force_run_token, project_id, parent_output_id and camera inputs are internal plumbing. The real controls:
model- the mesh to render. Required; the node errors without it.width/height- output canvas size (256–4096, step 64). Match your generation target.thickness- line width in pixels, 0.5–8.silhouette/crease/boundary- which edge classes to draw. All on by default; turnboundaryoff if raw mesh borders are making it messy.crease_angle- degrees (1–179, default 60) above which a shared edge counts as a crease.occlusion- on by default (BVH hide-behind-surface). Off gives the see-through wireframe look.invert- white-on-black (default) vs black-on-white.
The single output is image (a COMFYTV_IMAGE) - wire it straight into a ControlNet lineart slot or into any image stage downstream.
Install. Install the pack once:
cd ComfyUI/custom_nodes
git clone https://github.com/jtydhr88/ComfyTV
Restart ComfyUI (full restart, not a browser refresh) and the stage appears under ComfyTV → 3D. ComfyUI Manager - search "ComfyTV" - works too. Zero Python dependencies (the pack's pyproject.toml dependency list is empty) and no model files for the line render itself - you only need a mesh to feed it. The usual install trap applies: on Desktop or multi-install machines, clone into the running instance's path from the startup log or the node won't register.
Where people get burned. Feeding it a model with no clear silhouette - dense, noisy topology renders as a scribble no matter the settings; run a decimate or remesh first. Second: invert is easy to forget, and a ControlNet that was trained on black-on-white will do weird things if you hand it white-on-black. And occlusion being on is what separates a usable line render from a wireframe - if the output looks like a spiderweb, check that it hasn't been toggled off rather than blaming your mesh.
Inputs (14)
| Name | Type | Default | Description |
|---|---|---|---|
| force_run_token | INT | 00–2147483647 | Internal — bumped on Run to invalidate ComfyUI's input cache. |
| project_id | STRING | Internal — populated by the projectStore on the frontend. | |
| parent_output_id | INT | 00–2147483647 | Internal — lineage parent set by spawn handlers on the frontend. |
| width | INT | 1024256–4096 | — |
| height | INT | 1024256–4096 | — |
| thickness | FLOAT | 2.00.5–8 | Line width in output pixels. |
| silhouette | BOOLEAN | true | Edges where the surface turns away from the camera. |
| crease | BOOLEAN | true | Sharp edges — dihedral angle above the crease angle. |
| boundary | BOOLEAN | true | Open-mesh border edges. |
| crease_angle | FLOAT | 601–179 | Angle between face normals (deg) above which an edge counts as a crease. |
| occlusion | BOOLEAN | true | Hide lines behind the surface (BVH ray test). Off = wireframe-style see-through. |
| invert | BOOLEAN | false | Off: white lines on black (ControlNet lineart). On: black lines on white. |
| camera | STRING | Internal — view camera (position/target/fov JSON) set by the node body; empty = auto-framed. | |
| modelopt | COMFYTV_MODEL | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| image | COMFYTV_IMAGE | — |