Spline Mask — Edit/Track/Flow-Path
One spline node for edit, track, and flow-path masks
- image
- mask
- coords_json
- spline_data_out
- info_json
- bbox
Most mask nodes in ComfyUI are one-trick ponies: draw a shape, get a mask. SplineMaskMEC is the pack's unified spline node, and it packs three different jobs behind a single mode dropdown - a canvas-based spline editor, a video tracker, and a procedural "flow path" pattern generator. The pitch from the author is that one control-point canvas drives all three, so the JSON you draw in edit mode is the same shape of data the tracker and the flow generator consume.
It's a replacement too. The pack's __init__.py is explicit: SplineMaskMEC replaces three legacy nodes (SplineMaskEditorMEC, SplineMaskTrackerMEC, SplinePathFlowMaskMEC), which are gone from the registry. If you see old workflows referencing those, this is their home now.
How it works - the three modes
edit- rasterize a single closed or open spline to a mask. Thespline_typedropdown is where the flavor lives:catmull_rom(passes through points),bezier(tangent handles),polyline(straight), plusb_spline/nurbs/natural_cubic/cardinalfor smooth approximating curves. Control resolution withsamples_per_segment.track- Lucas-Kanade optical-flow tracking across a video. You pin keyframes (a list of{frame, points}inspline_data) and the node tracks the spline's control points through the footage, blending with simple lerp according totracking_weight(1 = pure LK, 0 = pure lerp).klt_windowsizes the LK window;stroke_widthhandles open splines.flow_path- forget masking; this generates an animated procedural pattern along the spline path - ribbon, wave, dust, river, smoke, sawtooth, fbm, curl noise, lightning, and more (13 patterns).framescontrols the animation length,amplitude/frequency/turbulenceshape the modulation,flow_direction(forward/reverse/bidirectional/oscillate) sets how it moves, andseedmakes it reproducible.
There are a lot of knobs, but the tooltips tell you which mode each applies to ([edit], [track], [flow_path], [all]), and irrelevant ones are ignored - the author is careful about that.
The inputs and outputs that matter
For a first workflow you'll touch maybe five:
mode- edit / track / flow_path.spline_data(STRING) - the payload from the JS canvas; keyframe list in track mode.spline_type,closed,samples_per_segment- curve shape and resolution.feather_radius- edge softness in edit/track.- In track mode:
tracking_weightandklt_window. In flow_path mode:pattern,frames,seed.
The outputs are the interesting part, because this node feeds the rest of the graph, not just a preview:
mask(MASK) - the rasterized result.coords_json(STRING) - SAM-compatible point coordinates from edit mode, so your drawn spline can seed a SAM prompt instead of only a mask.spline_data_out(SPLINE_DATA) - structured spline data, for feeding trackers.info_json(STRING) - mode diagnostics.bbox(BBOX) - the axis-aligned bounding box of your control points, which feeds the pack's bbox pipeline.
That coords_json output is worth highlighting: draw a rough spline, then hand the points to SAM for a clean mask. Model-free authoring, model-assisted finishing.
Installing it
Standard pack install:
cd ComfyUI/custom_nodes
git clone https://github.com/Code2Collapse/ComfyUI-CustomNodePacks.git
restart ComfyUI or use Manager → "CustomNodePacks", confirm [MEC] Loading MaskEditControl node pack … in the console. CPU + small VRAM, no models required - this node is pure geometry and OpenCV, so no downloads.
Where people get burned
Expect to set tracking_weight deliberately. Pure LK (1.0) can wander on texture-less plates; pure lerp (0.0) ignores the footage entirely; the sweet spot is usually 0.6–0.8. And remember flow_path isn't a mask of your spline - it's an animation along it, so don't wire it where you wanted a plain filled region. Read which mode a knob belongs to before turning it; there are a lot of knobs, but each one is scoped.
Inputs (32)
| Name | Type | Default | Description |
|---|---|---|---|
| mode | COMBO | edit | edit: rasterize a single spline (closed/open) to a mask. track: Lucas-Kanade multi-keyframe tracker across a video. flow_path: procedural pattern along the spline (waves/dust/lightning…). |
| spline_data | STRING | [] | Spline payload from the JS canvas. edit/flow_path: single shape list. track: keyframes list [{frame:int, points:[[x,y],…]}, …]. |
| spline_type | COMBO | catmull_rom | [edit/flow_path] interpolation method. catmull_rom/natural_cubic/cardinal pass through the points; b_spline/nurbs are smooth approximating curves; bezier uses tangent handles; polyline = straight. |
| closed | BOOLEAN | true | [all] closed loop vs open path |
| samples_per_segment | INT | 202–128 | [all] curve resolution per segment |
| feather_radius | FLOAT | 0.00–64 | [edit/track] gaussian edge feather |
| invert | BOOLEAN | false | [edit/flow_path] invert mask |
| smoothing | BOOLEAN | true | [edit] enable spline smoothing |
| centripetal_alpha | FLOAT | 0.500–1 | [edit] Catmull-Rom alpha (0.5 = centripetal) |
| width | INT | 00–16384 | [edit/flow_path] output width (0 = inherit image) |
| height | INT | 00–16384 | [edit/flow_path] output height (0 = inherit image) |
| mask_color | STRING | #ff00ff | [edit] preview overlay color (hex) |
| mask_opacity | FLOAT | 0.400–1 | [edit] preview overlay opacity |
| tracking_weight | FLOAT | 0.700–1 | [track] lerp/tracker blend (1=pure LK, 0=pure lerp) |
| klt_window | INT | 215–51 | [track] Lucas-Kanade window size |
| stroke_width | INT | 31–64 | [track] stroke width for open splines |
| pattern | COMBO | ribbon | [flow_path] procedural pattern |
| thickness | FLOAT | 12.00–1024 | [flow_path] base stroke thickness |
| amplitude | FLOAT | 8.00–1024 | [flow_path] modulation amplitude |
| frequency | FLOAT | 2.00–64 | [flow_path] modulation frequency |
| turbulence | FLOAT | 0.000–4 | [flow_path] noise turbulence strength |
| turbulence_scale | FLOAT | 1.000.01–32 | [flow_path] noise spatial scale |
| edge_softness | FLOAT | 1.00–32 | [flow_path] edge softness in pixels |
| taper_start | FLOAT | 0.000–1 | [flow_path] start-end taper amount |
| taper_end | FLOAT | 0.000–1 | [flow_path] tail-end taper amount |
| frames | INT | 11–4096 | [flow_path] number of animation frames |
| animation_speed | FLOAT | 0.0500–4 | [flow_path] phase advance per frame |
| flow_direction | COMBO | forward | [flow_path] flow direction |
| mod_decay | FLOAT | 0.000–4 | [flow_path] modulation falloff over time |
| seed | INT | 00–4294967295 | [flow_path] noise seed |
| use_embedded_editor | BOOLEAN | true | [flow_path] show embedded spline preview |
| imageopt | IMAGE | [edit/track/flow_path] reference / source video frames |
Outputs (5)
| Name | Type | Description |
|---|---|---|
| mask | MASK | Rasterized mask (B,H,W). |
| coords_json | STRING | SAM-compatible point coords (edit mode); '[]' otherwise. |
| spline_data_out | SPLINE_DATA | Structured spline data (edit mode); pass-through input otherwise. |
| info_json | STRING | Mode diagnostics: edit→bbox_json, track→info, flow_path→params. |
| bbox | BBOX | AABB of control points as [x,y,w,h]; [0,0,0,0] when N/A. |