Nodes/ComfyUI Schematic/Schematic Construction
ComfyUI Node

Schematic Construction

A full projective-geometry annotation plate, computed from your photo, not drawn on top of it

By jeremieLouvaert·Created 2 months ago·Updated 19 days ago· 0
Schematic Construction
  • image
  • pixelate_mask
  • image
  • overlay_only
  • overlay_alpha
  • element_table
seed42
detection_modecombined
block_size16
threshold28
max_circles26
min_distance70
min_radius8
max_radius46
focus_a_x0.15
focus_a_y0.88
focus_b_enabledtrue
focus_b_x0.82
focus_b_y0.14
focus_clear0.055
rays_a30
rays_b20
ray_jitter0.050
sphere_count4
sphere_inner0.34
sphere_outer0.84
sphere_span98
marker_size0.0020
marker_shapecircle
marker_filltrue
marker_every1
label_every3
lune_density34
scale_ticks50
scale_label_every5
type_scale1.00
exit_labels_every2
callout_count2
data_column_enabledtrue
data_column_rows15
zone_count3
pixel_size14
zone_size_min44
zone_size_max92
pixel_stroketrue
palettewhiteOnDark
bg_color#101014
stroke_color#FFFFFF
line_weight1.00
overlay_opacity1.00
image_opacity1.00
frame_text_size9.0
frame_text_tlDESIGN & STRATEGY
frame_text_trAKURATE
frame_text_bl
frame_text_br
elements
pixelate_zones
off_zones_x0.000
off_spheres_x0.000
off_rays_x0.000
off_marks_x0.000
off_focus_x0.000
off_scale_x0.000
off_annot_x0.000
off_frame_x0.000
off_zones_y0.000
off_spheres_y0.000
off_rays_y0.000
off_marks_y0.000
off_focus_y0.000
off_scale_y0.000
off_annot_y0.000
off_frame_y0.000

If Schematic Overlay is the one-stop "annotated product shot" look, Schematic Construction is the heavy sibling: it lays a full projective-geometry plate over the photo - two convergent ray pencils, concentric spheres, computed intersections, a graduated scale, a running data column - the whole Kepler-era diagram apparatus. This is the node you reach for when you want a render to read as a measured drawing, something that looks like it was produced by an astronomer with a pencil and a very long ruler, rather than a sticker sheet.

The through-line is that everything on the plate is computed, not drawn. Every label sits on a point the geometry actually produced. If Overlay is decoration, Construction is argument - and the seed doesn't just shuffle content, it chooses among valid layouts.

How it works

The pipeline starts with the same detection engine as Overlay: the image is scored on a block_size grid, points above threshold become the anchors, and two foci shoot rays at them. The primary focus (focus_a_x / focus_a_y) carries a convergent ray pencil (rays_a), and the secondary focus (focus_b_enabled, rays_b) is what produces the interesting intersections - the tooltip's point: the second pencil creates the non-trivial quadratic intersections where B's rays cut A's spheres. focus_clear keeps the focus itself untangled by starting rays a fixed fraction out from it.

Concentric spheres (sphere_count, sphere_inner, sphere_outer, sphere_span) sit about the primary focus, and the annotation engine computes every ray-meets-sphere intersection. marker_every thins the markers, label_every thins the labels, and a label collision resolver silently drops any label it can't place cleanly - so annotation thins out exactly where the geometry is densest. That's a feature, not a bug; without it the plate would be unreadable mush.

Then the micrographic dressing: a hatched lune (lune_density), a graduated scale on the outer sphere (scale_ticks), frame-exit labels giving each ray its index and true bearing (exit_labels_every), leader callouts (callout_count), and the running IDX / ANG / REF data column (data_column_rows). Three weight classes - datum, construct, fine - keep the hierarchy readable, and line_weight scales them together.

The inputs that matter

  • image - the photograph. Its own tooltip is the whole philosophy: "It is never altered outside a pixelate zone."
  • seed - the big one. It picks focus positions within their legal bands, which detected points the rays aim through, sphere radii, which gap carries the lune, and which intersections become pixelate zones. Same seed, same plate - deterministic across a batch.
  • focus_a_x / focus_a_y, focus_b_enabled - where the geometry converges. Everything resolves to focus A, so nudging it re-aims the whole plate.
  • rays_a / rays_b / sphere_count - density of the two pencils and the spheres. This is where you control how busy the plate is.
  • palette - only three options here: whiteOnDark, blackOnLight, or custom (with bg_color / stroke_color). The tooltip's advice is spot on: use blackOnLight on a light photograph, because polarity is how this node stays legible rather than shadowing every stroke.
  • elements (optional) - the addressable-elements override string. One per line, e.g. rays_b: off or spheres: +0.02,-0.01, with offsets as normalised canvas fractions so they survive a resolution change. Every group also has its own off_*_x / off_*_y offset widgets.
  • pixel_size - mosaic tile size; 1 disables pixelation. The sample zones land on computed intersections, so every patch sits on an event the construction produced.

Outputs and where they wire

Same three image outputs as Overlay - image (full composite), overlay_only (the plate without the photo, for compositing elsewhere), overlay_alpha (a 0-to-1 mask of everywhere a vector element was drawn) - plus a fourth:

  • element_table - a STRING listing the resolved element table. The README's trick: paste any line back into elements and edit it - that's how you nudge individual elements without hunting for widgets.

Install and getting comfortable

Same install as the whole pack - ComfyUI Manager (search "ComfyUI Schematic") or:

cd ComfyUI/custom_nodes
git clone https://github.com/jeremieLouvaert/ComfyUI-Schematic

Restart, and it appears under AKURATE/Schematic alongside Overlay and Voronoi. Only dependency is Pillow (already in ComfyUI), no models. If the annotation looks too small, that's type_scale (it scales all annotation, and the tooltip notes the type stays a fixed fraction of canvas - it's texture, not content, so it won't hold up to heavy upscaling). If the plate is too dense, raise marker_every and label_every rather than dropping the whole thing. And if you're overwhelmed by the ~45 inputs, ignore almost all of them at first: set image, pick a palette, nudge focus_a_x / focus_a_y, and let seed do the layout roulette. It's a fiddly node - that's the point - and it's the only one I've seen that ships a derivation document for why each line is where it is.

CategoryAKURATE/Schematic

Inputs (70)

NameTypeDefaultDescription
imageIMAGEThe photograph the plate is drawn over. It is never altered outside a pixelate zone.
seedINT420–2147483647Chooses among valid LAYOUTS as well as content: focus positions within their legal bands, which detected points the rays aim through, sphere radii, which gap carries the lune, which intersections become zones.
detection_modeCOMBOcombinedWhat the detector scores. Drives where every ray aims and where zones land.
block_sizeINT164–96Detection block size in pixels, as Overlay's.
thresholdINT280–255Minimum block score to accept a point.
max_circlesINT261–200Maximum detected points the pencils can aim through.
min_distanceINT701–1000Minimum spacing between detected points, in pixels.
min_radiusINT81–500Smallest detected-point radius. Only visible when detection_circles is enabled in `elements`, since the circles are the one element that draws a point's radius.
max_radiusINT461–500Largest detected-point radius. Only visible when detection_circles is enabled in `elements`.
focus_a_xFLOAT0.150–1Primary focus X, as a fraction of width. Everything converges here; the seed varies it within a band.
focus_a_yFLOAT0.880–1Primary focus Y, as a fraction of height.
focus_b_enabledBOOLEANtrueThe second focus. The astronomical reference has two, and the second pencil is what produces the non-trivial intersections.
focus_b_xFLOAT0.820–1Secondary focus X, as a fraction of width.
focus_b_yFLOAT0.140–1Secondary focus Y, as a fraction of height.
focus_clearFLOAT0.0550–0.3Rays start this far out from the focus, as a fraction of the short side, so the focus stays clear instead of tangling. Applies identically to BOTH foci.
rays_aINT300–200Rays in the primary pencil.
rays_bINT200–200Rays in the secondary pencil.
ray_jitterFLOAT0.0500–0.5Angular scatter applied to each ray, in radians.
sphere_countINT40–24Concentric spheres about the primary focus.
sphere_innerFLOAT0.340.02–2Innermost sphere radius, as a fraction of the short side.
sphere_outerFLOAT0.840.02–3Outermost sphere radius, as a fraction of the short side.
sphere_spanFLOAT985–360Angular sweep of the sphere arcs, in degrees.
marker_sizeFLOAT0.00200.0002–0.02Intersection marker radius, as a fraction of the short side.
marker_shapeCOMBOcircleShape drawn at every computed intersection. The two crosses are stroke-only by nature and ignore marker_fill.
marker_fillBOOLEANtrueFill the marker, or draw its outline only. Ignored for the cross shapes.
marker_everyINT11–20Mark every Nth computed intersection. Raise it to thin the plate.
label_everyINT31–40Label every Nth marked intersection.
lune_densityINT344–200Hatch lines in the lune, the shaded band between two rays across one sphere gap.
scale_ticksINT502–400Graduations along the outer sphere.
scale_label_everyINT51–40Number every Nth graduation.
type_scaleFLOAT1.000.3–3Scales all annotation. Type stays a fixed fraction of canvas, so it is sub-legible at any resolution: it is texture, not content.
exit_labels_everyINT21–40Label every Nth ray where it leaves the frame, with its index and true bearing.
callout_countINT20–20Leader callouts into micro-blocks.
data_column_enabledBOOLEANtrueThe running IDX / ANG / REF column keyed to the ray table.
data_column_rowsINT151–60Rows in the data column.
zone_countINT30–40Pixelate sample zones, placed on computed intersections so each patch sits on an event the construction produced.
pixel_sizeINT141–200Mosaic tile size, identical to Overlay's. 1 disables pixelation.
zone_size_minFLOAT442–1000Smallest zone half-extent in pixels. Each zone is drawn a size at random between min and max, so the patches vary instead of being a uniform grid. Set min equal to max for Overlay's fixed-size behaviour.
zone_size_maxFLOAT922–1000Largest zone half-extent in pixels. Zone spacing is computed from THIS value, so patches never overlap even when a small one lands beside a large one.
pixel_strokeBOOLEANtrueOutline each zone, as Overlay does.
paletteCOMBOwhiteOnDarkInk polarity. Use blackOnLight on a light photograph: polarity is how this node stays legible, rather than shadowing every stroke.
bg_colorSTRING#101014Background behind the photograph and the ground of the overlay_only output. Only applies when palette is set to custom, and it is hidden in `image` at image_opacity 1.0 since the photograph covers it.
stroke_colorSTRING#FFFFFFInk colour. Only applies when palette is set to custom.
line_weightFLOAT1.000.1–6Scales all three weight classes together. The classes themselves are fixed by the spec.
overlay_opacityFLOAT1.000–1Opacity of every drawn mark.
image_opacityFLOAT1.000–1Opacity of the photograph under the plate.
frame_text_sizeFLOAT9.01–60Corner text size, per mille of the short side.
frame_text_tlSTRINGDESIGN & STRATEGYTop-left plate text.
frame_text_trSTRINGAKURATETop-right plate text.
frame_text_blSTRINGBottom-left plate text.
frame_text_brSTRINGBottom-right plate text.
elementsoptSTRINGPer-ELEMENT overrides, one per line: 'rays_b: off', 'spheres: +0.02,-0.01', 'g_annot: +0.00,+0.03'. Offsets are normalised canvas fractions applied after anchoring. Read element_table for every valid name.
pixelate_zonesoptSTRINGExtra zone centres as 'x,y;x,y', exactly as Overlay parses them.
pixelate_maskoptMASKExtra zone centres taken from a mask, exactly as Overlay does.
off_zones_xoptFLOAT0.000-1–1Offset the g_zones group as a unit: the pixelate sample zones. Normalised canvas fraction, applied after anchoring, so members keep their shared edges.
off_spheres_xoptFLOAT0.000-1–1Offset the g_spheres group as a unit: the concentric spheres and their captions. Normalised canvas fraction, applied after anchoring, so members keep their shared edges.
off_rays_xoptFLOAT0.000-1–1Offset the g_rays group as a unit: both ray pencils. Normalised canvas fraction, applied after anchoring, so members keep their shared edges.
off_marks_xoptFLOAT0.000-1–1Offset the g_marks group as a unit: the computed intersections, their labels and the lune. Normalised canvas fraction, applied after anchoring, so members keep their shared edges.
off_focus_xoptFLOAT0.000-1–1Offset the g_focus group as a unit: both focus marks and their labels. Normalised canvas fraction, applied after anchoring, so members keep their shared edges.
off_scale_xoptFLOAT0.000-1–1Offset the g_scale group as a unit: the graduated scale and its numerals. Normalised canvas fraction, applied after anchoring, so members keep their shared edges.
off_annot_xoptFLOAT0.000-1–1Offset the g_annot group as a unit: frame-exit labels, callouts, the data column, detection circles. Normalised canvas fraction, applied after anchoring, so members keep their shared edges.
off_frame_xoptFLOAT0.000-1–1Offset the g_frame group as a unit: the four corner plate texts. Normalised canvas fraction, applied after anchoring, so members keep their shared edges.
off_zones_yoptFLOAT0.000-1–1Offset the g_zones group as a unit: the pixelate sample zones. Normalised canvas fraction, applied after anchoring, so members keep their shared edges.
off_spheres_yoptFLOAT0.000-1–1Offset the g_spheres group as a unit: the concentric spheres and their captions. Normalised canvas fraction, applied after anchoring, so members keep their shared edges.
off_rays_yoptFLOAT0.000-1–1Offset the g_rays group as a unit: both ray pencils. Normalised canvas fraction, applied after anchoring, so members keep their shared edges.
off_marks_yoptFLOAT0.000-1–1Offset the g_marks group as a unit: the computed intersections, their labels and the lune. Normalised canvas fraction, applied after anchoring, so members keep their shared edges.
off_focus_yoptFLOAT0.000-1–1Offset the g_focus group as a unit: both focus marks and their labels. Normalised canvas fraction, applied after anchoring, so members keep their shared edges.
off_scale_yoptFLOAT0.000-1–1Offset the g_scale group as a unit: the graduated scale and its numerals. Normalised canvas fraction, applied after anchoring, so members keep their shared edges.
off_annot_yoptFLOAT0.000-1–1Offset the g_annot group as a unit: frame-exit labels, callouts, the data column, detection circles. Normalised canvas fraction, applied after anchoring, so members keep their shared edges.
off_frame_yoptFLOAT0.000-1–1Offset the g_frame group as a unit: the four corner plate texts. Normalised canvas fraction, applied after anchoring, so members keep their shared edges.

Outputs (4)

NameTypeDescription
imageIMAGE
overlay_onlyIMAGE
overlay_alphaMASK
element_tableSTRING