comfyui-superside-nodes
Custom ComfyUI nodes wrapping fal.ai models for image editing, image-to-video, upscaling, vision/language, and region selection - built for Superside production workflows.
Nodes (72)
A text LLM inside ComfyUI, zero VRAM, 16 models to pick from
Ask a frontier vision model about up to six images at once
One dial for the whole interior-style LoRA prompt — no more melted furniture
The fancier Bria background swap — prompt or reference image, up to four takes
The one Bria node that actually gives you the exact hex color
Bria's older background swap — text prompt only, and that's the appeal
Brightness, contrast, saturation and per-channel offsets — without touching a model
Pull a generative edit's color back toward the original, no API needed
The boring glue node that every modular workflow quietly needs
Process just the face, not the whole frame — and stitch the result back pixel-exact
5 — This Node Cuts It Out of 3:4
The upscaler for portraits that sits between inpaint and resize — not a generic 2x
Crop an image to its mask's bounding box — the handiest little utility in the pack
Your Workflow Just Spent Real Money — Here's the Receipt
One-click detailed captions, no prompt writing — Florence-2 Large, via fal
Ask Florence-2 to find the face, and get a mask plus crop coordinates back
FLUX Kontext Max — context-aware generation from up to four reference images
FLUX.1 Pro Fill — the inpaint model that treats the mask as a condition, not an afterthought
Edit a video with a sentence — 'make it anime, keep everything else the same'
The closed model, with a mask that actually holds
GPT Image 2 editing, done properly — mask modes, sensible sizing, and a 4K ceiling explained
Grok Imagine's edit, plus the prompt it actually used
Grok Imagine v2 Edit in ComfyUI, With the Crop-Stitch Trap Pre-Solved
Grow it, blur it, get an inverted copy for free
Ideogram Upscale without the Ideogram tab — a generative upscaler for your ComfyUI graph
Before/after labels without the afterthought — a labeled side-by-side compare node
A side-by-side A/B node that's honest about what it isn't — no slider, no surprise
The node that pastes things back — masked compositing for every region fix
One-click skin retouch without the prompt engineering — fal's retouch model, wired in
Scale to a megapixel target, not a side — the working-resolution workhorse
Juggernaut-grade realism, hosted — Flux-lineage img2img without the 24GB
Kling 2.1 from a still — three quality tiers, one node, and the gotcha about URLs
Kling 2.5 Turbo Pro — the cinematic tier, no quality dial to get wrong
Load Image, zero surprises — the pack's own version of the node you use a hundred times a day
Batch-load a whole folder into one IMAGE tensor — and don't forget it normalizes sizes
Draw your own product detail sheet — no AI picking the close-ups
See the mask, not the numbers — a grayscale preview for MASK tensors
MASK to grayscale IMAGE — the type conversion that unblocks half your graph
Nano Banana Pro inside ComfyUI — Google's edit model, up to 4K, no Cloud project
Nano Banana V2, the edit node with the extra dials — seeds, web search, thinking
Same product, same frame, every SKU — local product normalization with no AI
PASD super-resolution — ControlNet-guided upscaling with no local weights
Build a portrait mask by checking boxes — eyes, lips, hair, clothing, merged
Preview Image without the output clutter — temp-preview, same contract
The Prompt Box That's Honestly Just a Text Box — and That's Fine
A 4,000-character prompt with four holes in it
Splitting Text for Multi-Image Nodes
Ten poses in one node, not ten copies of your prompt
Cap the Long Edge Without Doing Aspect-Ratio Math Yourself
Bring the Result Back Up to the Original's Exact Size, Every Time
Tell SAM 3 'the left earbud' and Get a Mask Back, Thanks to fal
A Self-Contained Pack's Answer to Output
Enhance the Scene, Leave the Dimmer Switch and the Logo Alone
One Dial That Turns 'Photorealistic' From a Guess Into a Knob
Seedance Lite for Video When You Don't Need 1080p
1080p Video With an End-Frame Handoff
Ten Reference Images and One Coherent Edit
Change One Element, Keep the Rest of the Frame Intact
SeedVR2 Upscaling Without the Quantization Dance (or the GPU)
Upscale a Video With Temporal Consistency, Uploads Included
Z-Image Turbo Skin Inpainting When the Workflow JSON Can't Carry a LoRA URL
Five Settings Between 'Airbrushed' and 'Zoom Lens on a Pore'
One ruler for every product view
The Node That Turns a Product Photo Into a Spec Sheet, Automatically
Paste a Processed Crop Back Into the Original, Seam Included
Stop Guessing What That String Output Is — Make the Node Show You
Topaz's Ten Upscale Models, Dialed In From Inside ComfyUI
The Superside image-to-image node
What the Superside wrapper gets you (and the URL gotcha)
Superside White Balance
Z-Image Turbo inpainting with your own LoRA, in one fal call
The Superside trainer
ComfyUI Superside Nodes
Custom ComfyUI nodes wrapping fal.ai models for image editing, image-to-video, upscaling, vision/language, and region selection - built for Superside production workflows.
Install
-
Clone this repo into your ComfyUI
custom_nodesdirectory.Windows:
cd ComfyUI_windows_portable\ComfyUI\custom_nodes git clone https://github.com/Superside/comfyui-superside-nodes.gitMac:
cd ComfyUI/custom_nodes git clone https://github.com/Superside/comfyui-superside-nodes.git -
Install dependencies (into whichever Python environment ComfyUI itself runs on):
pip install -r requirements.txt -
Restart ComfyUI. All nodes appear under the Superside category in the node menu.
Updating
Pull the latest nodes from your repo folder, then restart ComfyUI (new nodes and widget UIs only load on restart):
git pull origin main
If git pull reports local changes, stash them first: git stash → git pull origin main → git stash pop.
Recent updates
- Stitch Region: the feather no longer erases a thin mask. A Gaussian of radius R over a structure a few pixels wide - a spectacle rim, a cable, a strap - spreads it out and drops the mask's peak far below 1: a 24px feather on an 8px rim left it at 0.125, so the paste was 13% applied and the pasted object came through as a washed-out ghost of whatever lay underneath. The mask is now scaled back up by the lost peak, so the core stays solid while the outer falloff stays soft.
- The result-text display no longer serialises.
web/js/show_text.jssaved its read-only display widget intowidgets_values, which took the slot the next widget added on the Python side would claim - a saved""then landed on an INT input and ComfyUI refused to run the node ("an input value has the wrong type"). The display is a view of the last run, so it is markedserialize = falseand the load-time restore is gone. If you hit that error on a workflow saved earlier, set the affected widget back to its default once and re-save. - Florence-2 Smart Region Selector: parity with the retired nb2 selector. Adds the
glassesregion type (Florence answers the bare nouneyeglassesfar more reliably than a long description, which comes back with the front rim alone), plusmask_blur_percent,detection_mode(auto / segmentation / grounding_bbox, with auto preferring a grounding box for a face) andupload_max_dimension. These were the settings the working glasses try-on pipeline depended on. - Grok v2 Edit:
reference_max_dimension. Caps the reference images on upload so they cannot out-resolve the image being edited, without touching image_1. - Stitch Region: white-halo decontamination and mask dilation. Ported from the retired
comfyui-inpaint-cropstitch-nb2stitch, which had both and the Superside one did not.decontaminate_edge(default ON) takes the destination's own colour where the feathered mask is weak, so an editor that returns the object over a white background no longer leaks a bright halo into the seam;mask_expand_pixelsdilates a too-tight segmentation before feathering. - Crop to Region can lock the crop's shape. New
crop_aspect(defaultregion (as detected), so nothing changes unless you set it): the crop grows on its short axis until it reaches the chosen ratio, so a small region no longer comes out square from the per-axismin_sizefloor. This ports the per-region hints the retiredcomfyui-inpaint-cropstitch-nb2pack carried - glasses want16:9at ~2752 px long side with ~18% context, a face wants1:1. - New: Crop to Size (anchored). Force an image to exact pixel dimensions with a choice of anchor (center / top-center / bottom-center / middle-left / middle-right / corners), scaling by one factor first so the output always fills the target and is never distorted. Built for formats the models cannot generate - Grok Imagine has no 4:5, so take its 3:4 and crop 6% of the height with
topto keep the head. - Text Preview now displays on its own.
SupersideTextPreviewNodeexists so this repo does not depend on the siblingsuperside-utility-nodespackage, but it was missing fromweb/js/show_text.js, so the incoming string never rendered on the node - it only worked if that other package happened to be installed. It is registered now. - Z-Image Turbo Inpaint+LoRA is now priced ($0.02 per output megapixel, read from fal's own model page), the AnyLLM text/vision routers are registered so their calls show up in the report, and
MANUAL_PRICESlets you record a measured per-call cost for the endpoints fal bills by GPU-second or token. - Grok Imagine v2 Edit is now crop-stitch safe. New
output_size(defaultmatch input image_1) returns the edit at image_1's exact pixel size with the aspect ratio preserved, so it drops into an inpaint crop-stitch graph in place of GPT Image 2 without the stitch node stretching the result. - New: cost tracking for every fal call. Each fal-backed node now shows its fal.ai price on the node, every call is priced into an in-memory ledger, and the new Superside Fal Cost Report node prints the breakdown and the run total. See Cost tracking.
- New: Grok Imagine Image v2 Edit. Wraps
xai/grok-imagine-image/v2.0/edit— same controls as the quality endpoint (up to 3 reference images,aspect_ratio,resolution1k/2k,output_format,num_images,sync_mode) plus aqualitylevel (low/medium). - Sunburst now uses fal's queued path, and a dropped connection retries. The endpoint was missing from
QUEUED_ENDPOINTS, so it ran through the synchronous call and held one HTTP connection open for the whole generation. Atquality: maxthat outlives fal's edge and comes back as "Server disconnected without sending a response" - which was also absent from the transient-error list, so it failed on the first try instead of retrying. - Sizing audit across the image nodes. The size a node asks for and the size that comes back are now checked wherever the request carries explicit dimensions (GPT Image 2 / Sunburst, Seedream V4.5 and V5 Pro in
custommode, Z-Image Inpaint+LoRA withmatch_input_resolution): a reframe raises, because the picture was recomposed rather than resized; a shortfall in area only warns, since pipelines like the Z-Image skin pass deliberately generate below the source resolution and resize back afterwards. Two tooltips that claimed anautopreset "keeps the input's size" were corrected - it hands the choice to the model, and on Z-Image fal's auto presets land near a 512 px short side. - New: Prompt Variants + Prompt Slots. A pool of interchangeable prompt fragments (
----separated, optionally labelled) emitted at random, cycled by seed, or fixed by index, and a template node that drops it into a{key}placeholder in a long prompt. For running one instruction prompt across a set of poses without copying the prompt per pose, and without losing which pose produced which image. - Manual Detail Sheet — boxes keep their exact geometry across a reload. A box's width is derived from its height and the image's aspect ratio, and the restore path used to re-derive it before any image was known - against the 1.5 fallback - then persist the result. Every reopen nudged the boxes wider or narrower, and it compounded. Restoring is now verbatim; only the image the node is actually handed, a change to
aspect_ratio, or your own drag re-derives anything. - Manual Detail Sheet — the box preview no longer waits for a run. It used to look only at the node directly upstream, so behind a Normalize Product (which carries no thumbnail) it stayed blank until the graph ran, and blank again on every reload - with nothing to position the boxes against. It now walks up the chain to the nearest image it can show, marks it as a stand-in, and remembers the exact post-run image across reloads.
- Manual Detail Sheet — selectable crop aspect ratio. New
aspect_ratiodropdown (1:1,4:5,2:3,9:16,16:9); the boxes are drawn, dragged and scroll-resized at the chosen ratio. Defaults to1:1, so existing saved workflows are unchanged. - New: Architectural Style Dial. Prompt driver for interior / real-estate generation with three styles (
transitional,traditional,modern) × room × realism level, described through general material/palette categories. Ships withmodules/architectural_styles_glossary.txt. - Z-Image Turbo Inpaint+LoRA — stack up to 3 LoRAs. Three generic
lora_N_url/lora_N_scaleslots so you can paste any HuggingFace/resolve/…safetensorsLoRA (the Skin-Detail variant keeps its URLs hidden for cog-comfyui/Replicate).
API key
There is no config file and the key is never stored in this repository. Every node has an api_key text input - the normal flow is to paste your key directly into that widget on each node. Ask your project lead for the key.
Opt-in FAL_KEY fallback: if the api_key input is left blank, the node falls back to the FAL_KEY environment variable. This is for automated/headless deployments (e.g. a Replicate pipeline) that would otherwise have to embed the key as literal text inside the workflow JSON - where it can leak into request logs - and can instead pass it via a redacted env var. When a key is pasted into the input, the fallback never engages, so the manual flow is unchanged. If both are blank, the node fails immediately with a clear error.
Only rely on the env fallback in isolated, single-tenant deployments where whoever can submit a workflow is trusted with the key. On a shared multi-tenant ComfyUI backend, keep passing an explicit per-workflow
api_key- that input requirement is the access-control gate.
Cost tracking
Every fal-backed node reports what it costs, so a workflow can be priced before and after it runs.
On the node. Every fal-backed node shows its price in small green text just under the node body, e.g. fal $0.04 (low) / $0.06 (medium) per 1K image, $0.06 / $0.08 per 2K..., and the full text is in the node's tooltip (hover the title). Long notes are truncated to the node's width, and the line is hidden below 50% zoom. Nodes that make no fal call show nothing. The prices live in modules/fal_pricing.py and are attached to the node description at registration time, so there is nothing to maintain per node file; web/js/price_note.js draws them. It paints on the canvas rather than adding a widget on purpose - a widget would shift widgets_values in every saved workflow.
After the run. Drop a Superside Fal Cost Report node in the graph and it adds up everything the Superside nodes called. All nodes share one API helper, so the report covers every node in this package without any wiring per node.
scope:this run(calls since this report node last reported) orsession (since ComfyUI started).- Wire the last image of your pipeline into
after_image(or any string intoafter_text). ComfyUI does not guarantee that an input-less node runs last, and these inputs force the ordering. - Outputs
report(STRING - the breakdown, also shown on the node),total_usd(FLOAT) andcalls(INT). clear_after_reportempties the ledger once it has reported, so the next run starts from zero.
The ledger is in memory only: it starts empty on every ComfyUI restart and nothing is written to disk.
What is and isn't priced. 20 of the endpoints this package calls publish a per-call price, and those are computed exactly from the request and the response (output count, resolution, quality, megapixels, video seconds, training steps). The rest are billed by GPU-second (Florence-2, Juggernaut, Bria background replace) or by token consumption (GPT Image 2, GPT Image 2.5 Sunburst, Gemini Omni Flash, the AnyLLM routers), and fal publishes no per-call figure for them. Those calls are counted and listed separately rather than guessed at, so the reported total is always a real lower bound and never silently wrong:
TOTAL 4 priced call(s) $0.4870 USD
1 call(s) could not be priced:
- openai/gpt-image-2/edit
fal bills this endpoint by token consumption, which depends on prompt
and image size - no per-call price is published
The total above EXCLUDES those calls.
Filling in the unpriced ones. For a GPU-second or token-billed endpoint you can read the real per-request cost off fal's usage dashboard once and record it in MANUAL_PRICES in modules/fal_pricing.py:
MANUAL_PRICES = {
"fal-ai/florence-2-large/caption-to-phrase-grounding": 0.0012,
"openrouter/router/vision": 0.004,
}
Those calls then count toward the total and are labelled as measured by hand rather than published by fal.
Keeping prices current. fal changes prices. From the repo root:
python -m modules.fal_pricing --check
That re-reads fal's live catalogue and prints any endpoint whose published amounts no longer match the snapshot in PUBLISHED_AMOUNTS (a reworded blurb stays quiet; a real price move shows up). Update the note, the snapshot and SOURCE_DATE for anything it lists. It also probes each endpoint id that is missing from fal's listing: [UNLISTED] means the id still resolves and is fine to call (it just has no published price - fal-ai/topaz/upscale/image, fal-ai/crystal-upscaler and fal-ai/bytedance/seedance/v1/lite/reference-to-video are all in this bucket, verified 2026-09-09), while [GONE] means fal no longer serves it and the node needs a new id.
fal is the only source of truth for what you are actually billed - treat these numbers as close estimates, not an invoice.
Node reference
Every node's display name in ComfyUI's search/menu is prefixed with "Superside " (e.g. Superside Seedream V5 Pro Edit, Superside Bria Background Standardizer) - type "Superside" in the node search to see the whole set.
Nodes are grouped by task below. For every node: Inputs lists required inputs first, then optional ones (with defaults); Outputs lists the return values in order.
Image editing & generation
Seedream V5 Pro Edit (SupersideSeedreamV5ProEditNode)
Grounded, region-precise editing with ByteDance Seedream V5 Pro - changes one element while keeping the rest of the frame intact. Up to 10 reference images.
- Inputs:
prompt,image_1,api_key· optional:image_2-image_10,size_mode(preset/custom),image_size(preset, defaultauto_2K),width/height(custom mode),output_format(jpeg/png),num_images(1-6),enable_safety_checker,sync_mode - Outputs:
images(IMAGE),info(STRING - result URL)
Seedream V4.5 Edit (SupersideSeedreamV45EditNode)
Broader multi-reference editing (up to 10 images) with higher max resolution and multi-image output.
- Inputs:
prompt,image_1,api_key· optional:image_2-image_10,size_mode,image_size(up toauto_4K),width/height,num_images,max_images,seed(-1 = random),enable_safety_checker,sync_mode - Outputs:
images(IMAGE),info(STRING)
Nano Banana Pro Edit (SupersideNanoBananaProEditNode)
Context-aware image editing, up to 6 reference images, up to 4K output.
- Inputs:
prompt,image_1,api_key· optional:image_2-image_6,num_images,aspect_ratio,output_format,resolution(1K/2K/4K),sync_mode - Outputs:
images(IMAGE),description(STRING)
Nano Banana V2 Edit (SupersideNanoBananaV2EditNode)
Same family as Pro, with extra controls: seed, safety tolerance, web search grounding, reasoning depth.
- Inputs:
prompt,image_1,api_key· optional:image_2-image_6,num_images,seed,aspect_ratio,output_format,safety_tolerance,sync_mode,resolution(0.5K-4K),limit_generations,enable_web_search,thinking_level - Outputs:
images(IMAGE),description(STRING)
GPT Image 2 Edit (SupersideGPTImage2EditNode)
OpenAI GPT Image 2 editing with mask-based inpainting. Sizing is driven by a single size control. Default match input + resolution keeps the input image's own aspect ratio (a tall portrait stays tall) and scales it to the chosen resolution - so you just pick 4K for the biggest output without knowing the exact ratio. Other options: match input (original) (sends size=auto and lets the model pick - this is not a guarantee of the input's size, a 3712x4608 input has come back at 736x896, so reach for it only when you want the model to decide), a fixed aspect ratio, or custom pixels. GPT Image 2 caps total output to ~8 MP, so 4K gives ~3840 px on the long edge at 16:9 (true UHD), ~2880 at 1:1; a portrait input scales to ~2528x3264. When the request carries explicit dimensions the node holds the API to them: it raises if the returned aspect ratio drifts more than 4% (the picture was reframed, not resized) or if the area falls below half what was asked for, and logs the clamp when the endpoint trims to its megapixel budget with the aspect intact. Measured: match input + resolution at 2K on a 3712x4608 source requests 1648x2048 and returns exactly 1648x2048. Uses fal's queued execution path internally (polls until complete).
Masking is controlled by a single mask_mode: off - edit whole image (default; ignores mask_image, for crop-stitch pipelines where a separate node masks), guide model (soft) (sends the mask so GPT focuses edits on the white area), or lock outside mask (hard) (also composites the result back only inside the mask so everything outside stays pixel-identical - best for standalone inpainting). invert_mask flips the white=edit convention.
- Inputs:
prompt,image_1,api_key· optional:image_2-image_6,mask_image,size(match input + resolution/match input (original)/ aspect ratio /custom pixels),resolution(1K/2K/4K, used withmatch input + resolutionor an aspect ratio),width/height(used withcustom pixels, multiples of 16),mask_mode(off / soft / hard),invert_mask,quality(auto/low/medium/high),num_images,output_format,sync_mode - Outputs:
images(IMAGE),info(STRING)
GPT Image 2.5 Sunburst Edit (SupersideGPTImage25SunburstEditNode)
OpenAI GPT Image 2.5 Sunburst editing (openai/gpt-image-2.5/sunburst/edit). Same input shape and the same single size / mask_mode controls as GPT Image 2 Edit above - it subclasses that node - plus two fields of its own and a wider quality range.
quality adds xhigh and max on top of auto/low/medium/high. Billing is per token and climbs steeply with quality, so high stays the default; treat xhigh and max as deliberate choices.
background (auto/transparent/opaque) needs output_format png or webp for transparency. output_compression (0-100, 0 = leave it to the API) applies to jpeg and webp only.
Because the endpoint takes a real mask_url, mask_mode lock outside mask (hard) gives a genuine masked inpaint here - the model is told which pixels it may touch, and the result is composited back inside the mask.
- Inputs:
prompt,image_1,api_key· optional:image_2-image_6,mask_image,size,resolution,width/height,mask_mode(off / soft / hard),invert_mask,quality(auto/low/medium/high/xhigh/max),num_images,output_format,sync_mode,background,output_compression - Outputs:
images(IMAGE),info(STRING)
Grok Imagine Image Quality Edit (SupersideGrokImagineImageQualityEditNode)
xAI Grok Imagine editing, up to 3 reference images, returns the model's revised prompt.
- Inputs:
prompt,image_1,api_key· optional:image_2,image_3,aspect_ratio,resolution(1k/2k),output_format,num_images,sync_mode - Outputs:
images(IMAGE),revised_prompt(STRING)
Grok Imagine Image v2 Edit (SupersideGrokImagineImageV2EditNode)
xAI Grok Imagine v2.0 editing (xai/grok-imagine-image/v2.0/edit), up to 3 reference images, returns the model's revised prompt. Same controls as the quality endpoint plus a quality level (low/medium). aspect_ratio defaults to auto, which keeps the first input image's ratio.
Crop-stitch inpainting. Unlike GPT Image 2, Grok takes no width/height - only aspect_ratio + resolution - so it cannot be asked for the crop's exact pixel size. The stitch node rescales the edit straight onto the crop rectangle, so an edit with any other aspect ratio comes back visibly stretched. output_size (default match input image_1) closes that gap: the result is scaled to cover image_1 and centre-cropped to its exact size, never squashed. Keep aspect_ratio on auto so Grok follows image_1's own ratio and there is next to nothing to crop. Pick fal native only when you want the raw aspect_ratio + resolution output.
reference_max_dimension caps the long side of image_2/image_3 on upload while image_1 always goes at full size (0 disables it). Grok's API takes one flat list of "images to edit" with no designated base, so a reference that out-resolves image_1 can end up driving the output - a 4700px product reference against a 2700px crop can come back as the product rather than the edited crop.
Grok has no mask input: every wired image is a reference the model blends in. In a crop-stitch graph wire only cropped_image into image_1 and leave image_2/image_3 for real reference photos - feeding a mask image in there paints the mask's white area into the edit.
- Inputs:
prompt,image_1,api_key· optional:image_2,image_3,aspect_ratio,resolution(1k/2k),quality(low/medium),output_format,num_images,sync_mode,output_size(match input image_1/fal native),reference_max_dimension - Outputs:
images(IMAGE),revised_prompt(STRING)
Flux Kontext Max Multi-Image Node (SupersideFluxKontextMaxMultiImageNode)
FLUX.1 Kontext [Max] context-aware generation from up to 4 images.
- Inputs:
prompt,api_key· optional:image_1-image_4,seed,guidance_scale,num_images,safety_tolerance(1-6),output_format,aspect_ratio - Outputs:
IMAGE
Juggernaut Flux Pro Image-to-Image (SupersideJuggernautFluxProImg2ImgNode)
High-realism image-to-image stylization.
- Inputs:
image,prompt,api_key· optional:strength,num_inference_steps,seed,guidance_scale,num_images,enable_safety_checker - Outputs:
IMAGE
Wan 2.5 Image-to-Image (SupersideWan25ImageToImageNode)
Single or dual-reference editing with Wan 2.5.
- Inputs:
prompt,image_1,api_key· optional:image_2,negative_prompt,image_size,num_images(1-4),seed - Outputs:
IMAGE
Image Retouch (SupersideImageRetouchNode)
One-click retouch/clean-up of an image (skin, blemishes, imperfections) using fal.ai's image-editing retouch model (fal-ai/image-editing/retouch). No prompt needed - just connect an image.
- Inputs:
image,api_key· optional:guidance_scale(default 3.5),num_inference_steps(default 30),lora_scale(retouch strength, default 1.0),seed(-1 = random),enable_safety_checker,sync_mode - Outputs:
image(IMAGE),info(STRING - result URL)
Portrait sections (fal SAM 3)
Portrait Sections (SupersidePortraitSectionsNode)
In-house, fal-based replacement for a local face-parsing model. Toggle which facial/portrait sections (skin, nose, eyes, eyebrows, ears, mouth, lips, hair, hat, glasses, earrings, neck, necklace, clothing) to include in one merged MASK - e.g. as an EXCLUSION mask so a retouch pass skips eyes/lips/hair - using SAM 3 (fal-ai/sam-3/image), one call per active toggle only, merged with OR. Each active section also has a <section>_opacity (0-1, default 1.0): 1.0 writes it fully white (in a downstream composite that pastes the original back, that means 100% original = no retouch there); a lower value writes it gray so the composite blends partially (e.g. clothing_opacity = 0.5 -> 50% original / 50% generated = partial retouch on clothing). Default 1.0 everywhere reproduces the old binary mask exactly. Trade-off vs. a dedicated local face-parsing network: SAM 3 is promptable/open-vocabulary rather than a fixed pixel-labeled taxonomy (boundaries may be slightly less crisp) and costs one extra fal call per active toggle. For the partial-opacity gray to survive to the composite, the downstream mask nodes must preserve gray - Superside Grow Mask With Blur and Superside Resize To Match both do.
- Inputs:
image,api_key· optional: one BOOLEAN per section (defaults mirror the original re-skin workflow's exclusion set: nose/eyes/ears/mouth/lips/hair/hat on, the rest off), one<section>_opacityFLOAT per section (default 1.0),padding_percent,partial_feather_percent(feathers the edge of partial-opacity sections only, so their blend has a soft edge instead of a hard/doubled line; default 0 = off),partial_contract_percent(erodes partial-opacity sections inward before feathering so the soft edge stays inside the region instead of bleeding a ring onto surrounding skin - set it near/above the feather value; default 0 = off),glasses_prompt_override,glasses_box_center_x/y+glasses_box_width/height(optional GroundingDINO-style box for the glasses section) - Outputs:
mask(MASK),info(STRING, JSON of which sections were used),color_preview(IMAGE)
Skin retouch / re-skin (Z-Image)
Both nodes below target the same base model (Z-Image Turbo, Tongyi-MAI) on purpose - a LoRA trained with the trainer is guaranteed to apply correctly with the inpaint node, unlike mixing a LoRA/checkpoint across unrelated model families (e.g. a Krea 2 Trainer LoRA has nowhere to plug in, since Krea 2 has no img2img/inpainting endpoint on fal; a Flux-trainer LoRA on Flux-Krea-Lora crosses checkpoints).
Z-Image Turbo Inpaint+LoRA (SupersideZImageInpaintLoraNode)
Masked image-to-image (inpainting) with Z-Image Turbo (fal-ai/z-image/turbo/inpaint/lora), optionally with up to two stacked LoRAs (fal's LoRAInput list supports up to 3 - lora_url is the main trained face/skin LoRA slot, skin_detail_lora_url is a second, optional slot for a dedicated skin-texture-detail LoRA; both are applied together in the same single call, since there's no separate local-style "refiner pass" here). Drop-in replacement for a local VAEEncode -> SetLatentNoiseMask -> LoRA loader -> KSampler -> VAEDecode chain as a single fal.ai call. strength plays the same role as a KSampler's denoise (1.0 = fully regenerate the masked area, 0.0 = untouched). match_input_resolution (default ON) requests generation at the input's own resolution rounded to a multiple of 16 while preserving aspect ratio - but internally clamps the request to a ~2048px long-edge ceiling, since asking the endpoint for a custom size above that doesn't yield more detail, it silently falls back to a fixed square size instead (confirmed empirically). Pair with Superside Crystal Upscaler afterward for real added detail beyond that ceiling.
- Inputs:
image,mask(native MASK, white = area to regenerate),prompt,api_key· optional: three generic stackable LoRA slotslora_1_url+lora_1_scale,lora_2_url+lora_2_scale,lora_3_url+lora_3_scale(fal allows up to 3 LoRAs per call; any LoRA in any slot - paste adiffusers_lora_fileURL, e.g. a HuggingFace/resolve/main/<file>.safetensorsraw URL, not a/blob/page - plus its weight). Older graphs usinglora_url/skin_detail_lora_urlstill work (mapped onto slots 1/2). Also:strength(default 0.4),num_inference_steps(max 8, few-step model),seed,num_images,image_size(autokeeps the input's own size),control_scale/control_start/control_end,enable_prompt_expansion,enable_safety_checker,output_format,acceleration,match_input_resolution(default ON) - Outputs:
image(IMAGE),info(STRING - result URL)
Z-Image Skin-Detail Inpaint, fixed LoRA (SupersideSkinDetailZImageLoraNode)
Same Z-Image Turbo inpainting as the node above, but with both LoRA URLs hardcoded in the node code instead of exposed as inputs. Use it on cog-comfyui / Replicate deployments, whose weights preflight scans every string in the exported workflow JSON and rejects the run if any is a raw model-weight URL (.safetensors etc.) not in its curated manifest. Because lora_url / skin_detail_lora_url are not declared as inputs here, they can never be serialized into the JSON, so the scan has nothing to catch. Inherits all inpainting logic from SupersideZImageInpaintLoraNode (bug fixes apply to both). For a normal ComfyUI instance not subject to that scan, use the generic node above where lora_url is editable.
- Inputs: identical to Z-Image Turbo Inpaint+LoRA minus
lora_urlandskin_detail_lora_url(both hardcoded).lora_scale/skin_detail_lora_scaleremain. - Outputs:
image(IMAGE),info(STRING - result URL)
FLUX.1 Pro Fill (SupersideFluxProFillNode)
Dedicated inpainting/outpainting model (fal endpoint fal-ai/flux-pro/v1/fill) - an alternative architecture to the Z-Image node above for the same re-skin use case. Unlike Z-Image Turbo Inpaint+LoRA (a "masked image-to-image" call - image + mask + strength, blended in afterward), FLUX.1 Fill is architected end-to-end for inpainting: the masked image and mask are fed to the model as explicit conditioning channels, not blended in afterward, which in practice tends to hold the unmasked region much closer to pixel-identical. Trade-off: no strength knob (always fully regenerates the masked region) and no LoRA support on this base endpoint (a LoRA variant exists as fal-ai/flux-lora/inpainting, but would need a LoRA retrained against FLUX's own base weights - LoRAs aren't portable across model families).
- Inputs:
image,mask,prompt,api_key· optional:seed(-1 = random),num_images,output_format(png/jpeg),safety_tolerance(1-6, default 2),enhance_prompt - Outputs:
image(IMAGE),info(STRING - result URL)
Skin Intensity Prompt (SupersideSkinIntensityPromptNode)
One dial (5 levels, "very subtle" to "extreme") for skin-texture intensity, so tuning strength doesn't mean hand-editing three separate fields every time. Outputs a matched prompt fragment + lora_scale + strength for the chosen level - wire prompt_fragment into Superside Combine Prompt's part2, and lora_scale/strength into Z-Image Turbo Inpaint+LoRA. No API key, no model call.
- Inputs:
level(5 presets, default3 - medium) - Outputs:
prompt_fragment(STRING),lora_scale(FLOAT),strength(FLOAT)
Scene Realism Dial (SupersideSceneRealismPromptNode)
Generic (not skin-specific) counterpart of the Skin Intensity Dial: one dial (5 levels) for how hard to push photorealism when enhancing an arbitrary scene region. Outputs a matched realism prompt_fragment + lora_scale + strength. Wire prompt_fragment into Superside Combine Prompt's part2 and strength into Z-Image Turbo Inpaint+LoRA (no LoRA needed for a plain realism pass; lora_scale only matters if a generic detail LoRA is wired). No API key, no model call.
- Inputs:
level(5 presets, default3 - medium) - Outputs:
prompt_fragment(STRING),lora_scale(FLOAT),strength(FLOAT)
Architectural Style Dial (SupersideArchitecturalStylePromptNode)
Prompt driver for interior / real-estate image generation, built for a LoRA trained on three interior styles: transitional, traditional, modern. Composes a prompt fragment from three axes - style × room × realism level. Crucially, the style is described through general material / fabric / surface / metal / palette / light categories (the character of the style), not an exhaustive furniture inventory: the LoRA already learned the look, and cramming 8-10 specific objects into one prompt causes clutter, duplicated/melted objects and malformations. room adds only a minimal scene anchor (e.g. a bedroom with a bed and nightstands); level controls photographic detail and drives strength / lora_scale. Rooms: any, living_room, bedroom, kitchen, dining_room, bathroom, hallway. Optional trigger_word is prepended verbatim (for a LoRA trained with a trigger token), include_base appends the shared "warm evening real-estate photography" look, and include_room_anchor toggles the scene anchor. No API key, no model call. The vocabulary master lives in modules/architectural_styles_glossary.txt as two layers: Layer A (general descriptors, mirrored by the node) and Layer B (detailed per-room catalogs kept as reference for training captions - never dumped into one inference prompt).
- Inputs:
style(transitional / traditional / modern),room(7 options, defaultany),level(5 presets, default3 - medium) · optional:trigger_word(STRING),include_base(BOOL, default ON),include_room_anchor(BOOL, default ON) - Outputs:
prompt_fragment(STRING),lora_scale(FLOAT),strength(FLOAT)
Scene Exclusion Mask, generic (SupersideSceneExclusionMaskNode)
Generic, non-face counterpart of Superside Portrait Sections for a scene enhancement pass: build one EXCLUSION mask of the parts to PROTECT (composite the original back over them). Instead of fixed facial toggles, give it an exclude_people toggle plus a plain list of things to protect (exclude_prompts, one target per line, e.g. dimmer switch, wall outlet, brand logo); each is segmented with SAM 3 (fal-ai/sam-3/image) and merged. Same re-skin principle: enhance the region you want, protect everything this mask covers. Per-target opacity (partial protection), feather_percent and contract_percent (soft edge that stays inside the target), padding_percent (grow the merged mask). Pair with Grow Mask With Blur + Image Composite Masked (source = original, destination = enhanced).
- Inputs:
image,api_key· optional:exclude_people(default ON),exclude_prompts(multiline list),opacity(default 1.0),feather_percent,contract_percent,padding_percent,selection_mode(merge_all / largest / first),max_masks - Outputs:
mask(MASK),info(STRING, JSON),color_preview(IMAGE)
Z-Image LoRA Trainer (SupersideZImageLoraTrainerNode)
Trains a LoRA on Z-Image Turbo (fal-ai/z-image-turbo-trainer-v2) from a batch of images - e.g. close-up skin/imperfection references for a realistic-skin LoRA. Zips the batch locally and uploads it; every image shares the same default_caption (no per-image caption UI here - pass a pre-built zip with matching .txt files via images_zip_url for per-image captions).
- Inputs:
images(IMAGE batch, 10+ recommended),default_caption(include your trigger word),api_key· optional:steps(default 2000),learning_rate(default 0.0005),images_zip_url(overrides the IMAGE batch) - Outputs:
lora_file_url(STRING) - feed straight intoZ-Image Turbo Inpaint+LoRA'slora_url
Background tools
There are three Bria background nodes - pick by what you actually want:
| Want… | Use | How | |---|---|---| | Exact solid hex color background, subject untouched | Bria Background Standardizer (Hex Color) | Deterministic: cut out subject + composite onto the exact color. No generative model, no quality drift, no invented shadows. | | A generated scene background (studio, room, outdoors) | Bria Replace Background V2 or Bria Background Replace | Prompt-driven, generative (re-lights the scene). Neither can produce an exact flat hex color, and both may subtly alter the subject. |
Note: the two "Replace" nodes are generative - if you prompt them for a flat "#F2F2F1" background you'll get an approximate grey with a gradient/shadow, not the exact color, and the subject may change. For an exact catalogue-flat hex background, always use the Standardizer.
Bria Background Standardizer - Hex Color (SupersideBriaBackgroundStandardizerNode)
Cuts out the subject with Bria RMBG 2.0 (fal-ai/bria/background/remove) and composites it locally onto an exact solid hex color - no generative model touches the subject or the background pixels. Use this to batch-homogenize backgrounds (e.g. avatar sets, eCommerce catalogues) without any quality drift.
- Inputs:
image,hex_color(e.g.#F5F5F5),api_key· optional:edge_feather(0-15px, softens the cutout edge),sync_mode - Outputs:
image(IMAGE),info(STRING - resolved hex + source cutout URL)
Bria Replace Background V2 (SupersideBriaReplaceBackgroundNode)
Prompt-driven background replacement with realistic lighting/perspective, using Bria's Replace Background V2 model (fal endpoint bria/replace-background). The simpler of the two generative replace nodes - text prompt only.
- Inputs:
image,prompt,api_key· optional:negative_prompt,steps_num,seed(-1 = random),sync_mode - Outputs:
image(IMAGE),info(STRING - result URL)
Bria Background Replace (SupersideBriaBackgroundReplaceNode)
Bria's newer, richer generative background-replace model (fal endpoint fal-ai/bria/background/replace), separate from the V2 above. Adds reference-image guidance, prompt refinement, a fast/quality toggle, and multiple variations per run.
- Inputs:
image,prompt,api_key· optional:ref_image(IMAGE - reference background to guide the look),negative_prompt,num_images(1-4),refine_prompt(default ON),fast(ON = faster, OFF = higher quality),seed(-1 = random),sync_mode - Outputs:
image(IMAGE),info(STRING - result URL)
Video-to-video
Gemini Omni Flash Edit (SupersideGeminiOmniFlashEditNode)
Edit an existing video with a simple text instruction (e.g. "Make this video anime. Keep everything else the same.") using Google Gemini Omni Flash. Connect a LoadVideo node directly to video - the node uploads it to fal.ai internally, no manual URL needed. Uses fal's queued execution path internally (polls until complete). Not available for editing uploaded videos in the EEA, Switzerland, or the UK; voice editing and audio references are not supported.
- Inputs:
video(VIDEO),prompt,api_key - Outputs:
video(VIDEO - connect directly to SaveVideo/PreviewVideo),video_url(STRING, direct fal.ai link)
Image-to-video
Kling 2.1 Image-to-Video (SupersideKling21ImageToVideoNode)
Three quality tiers in one node.
- Inputs:
prompt,image,model_tier(master/pro/standard),api_key· optional:tail_image(end-frame, Pro tier only),duration(5/10s),negative_prompt,cfg_scale - Outputs: video URL (STRING)
Kling 2.5 Turbo Pro Image-to-Video (SupersideKling25TurboProImageToVideoNode)
Top-tier cinematic single-tier model, better motion fluidity than 2.1.
- Inputs:
prompt,image,api_key· optional:duration(5/10s),negative_prompt,cfg_scale - Outputs: video URL (STRING)
Seedance Lite Image-to-Video (SupersideSeedanceLiteImageToVideoNode)
Cost-efficient tier, up to 4 reference images.
- Inputs:
prompt,reference_image_1,api_key· optional:reference_image_2-4,aspect_ratio,resolution(480p/720p),duration,camera_fixed,seed,enable_safety_checker - Outputs: video URL (STRING)
Seedance Pro Image-to-Video (SupersideSeedanceProImageToVideoNode)
Higher quality tier, up to 1080p, with end-frame control.
- Inputs:
prompt,image,api_key· optional:end_image,aspect_ratio,resolution(480p/720p/1080p),duration,camera_fixed,seed,enable_safety_checker - Outputs: video URL (STRING)
Wan 2.5 Image-to-Video (SupersideWan25ImageToVideoNode)
Supports audio-driven video generation and prompt expansion.
- Inputs:
prompt,image,api_key· optional:audio_url(WAV/MP3, 3-30s),resolution(480p/720p/1080p),duration(5/10s),negative_prompt,enable_prompt_expansion,seed - Outputs: video URL (STRING)
Upscaling
Crystal Upscaler (SupersideCrystalUpscalerNode)
Portrait/facial-detail-specialized upscaler (fal endpoint fal-ai/crystal-upscaler, Clarity AI's upscaling tech). Meant to sit right after a generative inpaint pass (e.g. Z-Image Turbo Inpaint+LoRA) and before resizing back to the original resolution - since that generator has a real ceiling around ~2048px on its longest edge (see above), "more detail" beyond that ceiling has to come from a dedicated upscale pass on the result, not from asking the generator for a bigger image.
- Inputs:
image,api_key· optional:scale_factor(1-4, default 2),creativity(0-1, how much the upscaler can invent vs. stay literal, default 0),output_format(png/jpg) - Outputs:
image(IMAGE),info(STRING - result URL)
Ideogram Upscale (SupersideIdeogramUpscaleNode)
Prompt-guided upscaling with resemblance/detail sliders.
- Inputs:
image,api_key· optional:prompt,resemblance,detail,expand_prompt,seed - Outputs:
IMAGE
PASD Upscaler Node (SupersidePASDUpscalerNode)
Pixel-aware stable diffusion super-resolution with ControlNet guidance and wavelet color correction.
- Inputs:
image,api_key· optional:scale,steps,guidance_scale,conditioning_scale,prompt,negative_prompt - Outputs:
IMAGE
SeedVR2 Upscale Image (SupersideSeedVR2UpscaleImageNode)
Seamless upscaler with target-resolution or scale-factor mode.
- Inputs:
image,api_key· optional:upscale_mode(target/factor),upscale_factor,target_resolution(720p-2160p),seed,noise_scale - Outputs:
IMAGE
SeedVR Upscale Video (SupersideSeedVRUpscaleVideoNode)
Video upscaling with temporal consistency. Connect a LoadVideo node directly to video - no manual URL needed.
- Inputs:
video(VIDEO),api_key· optional:upscale_factor,seed - Outputs:
video(VIDEO - connect directly to SaveVideo/PreviewVideo),video_url(STRING, direct fal.ai link)
Topaz Upscale Image (SupersideTopazUpscaleImageNode)
10 Topaz model variants (Standard, CGI, High Fidelity, Recovery, Redefine, Wonder, etc.) with face enhancement, denoise, sharpen, and creative-recovery controls.
- Inputs:
image,api_key· optional:model(10 variants),upscale_factor,crop_to_fill,output_format,subject_detection,face_enhancement(+creativity/strength),sharpen,denoise,fix_compression,strength,creativity,texture,prompt,autoprompt,detail - Outputs:
IMAGE
Vision & language
Any LLM Text (SupersideAnyLLMTextNode)
Text-only chat/completion across many models via OpenRouter on fal.ai (Gemini, Claude 4.6, GPT, Llama, Grok, Kimi).
- Inputs:
prompt,api_key· optional:system_prompt,model(16 options, defaultgoogle/gemini-2.5-flash),reasoning,temperature,max_tokens - Outputs:
output(STRING),reasoning(STRING)
Any LLM Vision (SupersideAnyLLMVisionNode)
Multi-image (up to 6) vision Q&A across many models, with auto-rescale for large images.
- Inputs:
prompt,api_key· optional:image_1-image_6,system_prompt,model(21 options),reasoning,priority(latency/throughput),auto_rescale_images,max_image_dimension,temperature,max_tokens - Outputs:
output(STRING),reasoning(STRING)
Florence-2 Detailed Caption (SupersideFlorence2CaptionNode)
Fixed-purpose auto-caption generator (no prompt needed).
- Inputs:
image,api_key - Outputs:
STRING(caption)
Region selection
Both region selectors below share the same output contract, so they're interchangeable in downstream masking/inpainting workflows.
Florence-2 Smart Region Selector (SupersideFlorence2RegionSelectorNode)
Single-region selection (face/upper body/lower body/full body/custom object) using Florence-2 segmentation, with a grounding fallback.
- Inputs:
image,region_type,api_key· optional:custom_text(only whenregion_type=object),selection_mode(largest/merge_all),padding_percent,return_rect_mask - Outputs:
mask(MASK),mask_image(IMAGE),info(STRING, JSON),center_x,center_y,crop_width,crop_height(INT)
SAM 3 Smart Region Selector (SupersideSAM3RegionSelectorNode)
Broader vocabulary than Florence (garments, vehicle parts, accessories) plus multi-mask/scoring modes. box_prompts support lets an upstream Florence-2 selector's box hand SAM 3 exactly where to look (the old GroundingDINO+SAM two-stage pattern) instead of relying on text alone to both find and segment a sub-part (e.g. a glasses frame without the lens).
- Inputs:
image,region_type(19 presets incl.object),api_key· optional:custom_text,selection_mode(largest/first/merge_all),padding_percent,return_rect_mask,return_multiple_masks,max_masks,include_scores,include_boxes - Outputs:
mask(MASK),mask_image(IMAGE),info(STRING, JSON),center_x,center_y,crop_width,crop_height(INT)
Crop By Region (SupersideCropByRegionNode) + Stitch Region (SupersideStitchRegionNode)
A pair for processing a small region instead of a whole image: Crop By Region consumes a region selector's center_x/center_y/crop_width/crop_height outputs and crops image+mask around it (with a padding margin, rounded to a diffusion-friendly multiple), returning the exact crop_x/crop_y/crop_w/crop_h used. Stitch Region pastes the processed crop back into the full-resolution original at that exact position afterward - resizing the crop to crop_wxcrop_h first (so it lands pixel-perfect even if the generator returned a slightly different size) and feathering the paste mask edge (Gaussian blur) so the seam blends instead of showing a hard rectangle.
- Crop By Region inputs:
image,mask,center_x,center_y,crop_width,crop_height· optional:padding_percent(default 25),multiple_of(default 64),min_size(default 512) - Crop By Region outputs:
image(IMAGE),mask(MASK),crop_x,crop_y,crop_w,crop_h(INT) - Stitch Region inputs:
destination,source,crop_x,crop_y,crop_w,crop_h· optional:mask(full-res, same one fed into Crop By Region - if omitted, the whole crop rectangle is pasted),feather_pixels(default 24) - Stitch Region outputs:
image(IMAGE)
Product detail sheets
Smart Detail Sheet (SupersideSmartDetailSheetNode)
Finds the most visually interesting close-up details in a product photo, crops each one from the source photo, upscales the crops locally (Lanczos, no extra API call), and composites everything into one final image: the original photo plus the enlarged detail callouts - like a product spec sheet. Each crop is a fixed-size square centered on the detected detail's center point (not the model's raw bounding box edges), which keeps crops consistent and robust to imprecise or oddly-shaped boxes. Layout adapts to the original's aspect ratio (side column for portrait, row below for landscape/square), and the detail block is kept within a size range relative to the original so it's always legible without ever overwhelming the source photo. Crops that land on a flat/blank region (a missed detection) are automatically discarded.
Detection has two modes, picked via product_category:
-
auto (default): a vision LLM (
model) freely picks whichevernum_detailsdetails look most interesting (textures, logos, hinges, pads, seams, materials, etc), returning JSON bounding boxes. Retries automatically if the model returns prose instead of JSON, a zero-size box, or overlapping/duplicate zones. -
eyewear: instead of leaving detection up to the LLM's free-form judgement (which in testing sometimes conflated distinct zones, e.g. placing "nose pad" and "hinge" on the same spot), this locates exactly 3 fixed zones - the nose pad, the hinge screw, and a temple tip - using Florence-2's grounding endpoint (a dedicated vision-grounding model, the same one behind
Florence-2 Smart Region Selector), which proved far more spatially accurate for this task. Overridesnum_detailsandmodel. -
Inputs:
image,api_key· optional:product_category(auto/eyewear, default auto),num_details(1-6, default 3, ignored for eyewear),detail_hint(free text to steer the model, auto mode only),crop_scale(1-4x, default 2),model(gemini-2.5-flash/gemini-2.5-pro/gpt-4o/claude-sonnet-4.6, default gpt-4o, auto mode only),crop_size_percent(each crop's square size as a percent of the original's shorter side, default 35%) -
Outputs:
image(IMAGE, the composited sheet),info(STRING, JSON with the kept details, discard count, and settings used)
Prompt Variants (SupersidePromptVariantsNode)
Holds a pool of interchangeable prompt fragments and emits one. Blocks are separated by a line containing only ---, and a block may open with a # label line that names it without becoming part of the text. Built for try-on generation, where one long instruction prompt stays fixed and only a short fragment - the pose - changes per run: the ten poses live in one node instead of ten copies of the long prompt.
- Inputs:
variants(the pool),mode(random / cycle / fixed),seed,index - Outputs:
text(STRING, the block),label(STRING),index(INT, 1-based),count(INT)
random picks by seed, cycle emits block seed mod count, fixed emits block index. Set the seed widget to increment and use cycle to walk the whole pool one block per run; use fixed to sit on one block while you judge it. Every mode is a pure function of the inputs - there is no counter hidden in the node - so re-running a workflow reproduces the prompt it produced before, and index/label record which block was used.
Prompt Slots (SupersidePromptSlotsNode)
One long template with named holes in it. The template carries {pose}, {spec} and so on; each slot input fills the placeholder named by its key widget. Keeps a 4,000-character instruction prompt in one editable place while the parts that change per run - a pose fragment from Prompt Variants, a live SKU description from a vision node - arrive on wires.
- Inputs:
template,key_1-key_4(defaultpose,spec,slot3,slot4) · optional:slot_1-slot_4(STRING inputs) - Outputs:
prompt(STRING),info(STRING)
An unfilled slot is removed rather than left as a literal {pose} for the model to read. info names every mismatch it finds - a placeholder nothing fills, a slot whose key the template never uses, a {key} left in the text - because a wire that silently does nothing is the failure worth catching.
Manual Detail Sheet (SupersideManualDetailSheetNode)
The manual counterpart to Smart Detail Sheet: instead of an AI choosing the detail crops, you draw them yourself on an interactive image preview built into the node. A row of numbered on/off buttons above the image turns each of up to 6 boxes on or off; every active box appears on the image, where you drag it to move and scroll over it to resize. An aspect_ratio dropdown sets the shape of every box - 1:1, 4:5, 2:3, 9:16 or 16:9 (width:height); changing it reshapes all boxes in place, and drawing/resizing keeps that ratio. On run, the active boxes are cropped at the chosen ratio, upscaled locally (Lanczos), and composited alongside the original into the same product-spec-sheet layout as the Smart node (side column for portrait originals, row below for landscape/square). No AI detection and no API key - the node never leaves the machine. Boxes that land on a flat/blank area are discarded automatically.
- Inputs:
image· optional:aspect_ratio(1:1 / 4:5 / 2:3 / 9:16 / 16:9, default 1:1),crop_scale(1-4x, default 2),boxes(internal - set by dragging on the preview; not meant to be edited by hand) - Outputs:
image(IMAGE, the composited sheet),info(STRING, JSON with the kept boxes, discard count, crop scale, and aspect ratio)
The widget shows an image from the moment you connect one, plus a live crop-preview thumbnail per active box so you can confirm each detail is inside its box before generating. Where the node feeding it is a compute node with no thumbnail of its own (Normalize Product, a resize), the widget walks back up the chain to the nearest node that has one - usually the LoadImage - and shows that, labelled upstream preview because a node in between may pad or reframe the image. After a run it swaps to the exact image it was handed and drops the label, and it remembers that across a workflow reload.
Normalize Product (SupersideNormalizeProductNode)
Places a catalogue product photo into a consistent frame so a fixed set of detail crops lands on the same spot across every SKU. It detects the product against the light catalogue background, then centers it with a fixed margin - so the product always occupies the same relative area, and fractional crop boxes (e.g. pre-positioned once in a Manual Detail Sheet per profile) stay aligned across the whole catalogue. In the default keep resolution (pad) mode it never downscales - it crops to the product and pads with the margin at native resolution, so there's no quality loss. No AI, no API key. Feed it into a Manual Detail Sheet whose boxes you've set once per profile (front / side / 3-4).
- Inputs:
image· optional:mode(keep resolution (pad) / fixed canvas (scale), default keep resolution),margin_percent(default 8),output_width/output_height(fixed-canvas mode only, default 1024),fit(contain/width/height, fixed-canvas mode only),background_hex(empty = auto-match the photo's backdrop),threshold(product-vs-background sensitivity, default 12),detect_pad_percent(default 2) - Outputs:
image(IMAGE, normalized),info(STRING, JSON with the detected bbox, sizes, and settings used)
SKU Reference Sheet (SupersideSkuReferenceSheetNode)
Lays three or four product views out on one sheet at a single shared scale, with a DETAILS strip of close-ups. Connect front plus any of side / three_quarter / three_quarter_additional; the layout follows how many are wired - with four views the DETAILS strip becomes a band between the two rows, with three it takes the cell the missing view leaves free. Dividers separate the panels so a downstream editing model reads them as separate photographs rather than one blended image.
It replaces a chain of Normalize Product -> Manual Detail Sheet -> ImageStitch -> Resize, and the reason is not tidiness: that chain cannot hold one scale across the views. Each Normalize sizes its own canvas from its own product, and ImageStitch then matches edges by resizing a whole panel. Measured on one catalogue SKU the product was 2117 / 2105 / 2114 px wide across the three views - already consistent - but 754 / 808 / 891 px tall, so the canvases came out 897 / 961 / 1060 and the stitch rescaled them against each other. Seeing every view at once is what makes one pixels-per-unit possible, so a millimetre of frame is the same number of pixels in every panel.
With auto_logo on, the first DETAILS slot finds the brand mark by itself: Florence-2 proposes one candidate per view and the vision model picks the one that actually carries a mark. The two steps are both needed - the logo sits in a different place on different brands (printed on the lens and readable only head-on for one, an emblem on the temple visible only at an angle for another), and Florence returns no confidence to choose by. If it finds nothing, or no api_key is set, the slot is left out and the sheet is still produced.
The DETAILS strip fills three slots on its own. BRIDGE and JOINT are cut from the product box rather than detected, because they sit in the same place on any pair of glasses - asked to ground "the bridge between the two lenses", Florence returned the whole frame on 3 of 5 frames, since a bridge is part of a continuous structure with no edge of its own; the fixed fractions were right on 5 of 5, and across 11 frames BRIDGE was right 11/11 and JOINT 10/11. JOINT misses on wrap-around sports frames, whose temple sits further back than the outer corner - override that slot through detail_boxes for those. The logo is the opposite case and is detected, because its position moves by brand: on three brands it was found on the lens, on the temple and engraved on the bridge.
- Inputs:
front· optional:side,three_quarter,three_quarter_additional,max_long_side(default 5000),margin_percent(default 6),gap_px(divider width, default 14),background_threshold(default 12),detail_boxes(JSON list of{view, x1, y1, x2, y2, caption}, fractions of that view's product box),auto_bridge(default ON),auto_joint(default ON),auto_logo(default OFF),api_key(only forauto_logo) - Outputs:
image(IMAGE, the sheet),info(STRING, JSON with the views used, the shared scale, the detail captions and the final size)
Image utilities (no API key needed)
Resize To Match (SupersideResizeToMatchNode)
Resizes an image (and optionally a mask) to exactly match a reference image's width/height - a pure full-frame resize, no cropping or repositioning, so there's no coordinate drift. No-ops if the sizes already match. Built for closing a full-frame generate-at-working-resolution pipeline: generate/composite at a smaller working resolution (e.g. via Superside Image Scale To Total Pixels), then resize the result (and its mask) back up to the true original size for the final composite - regardless of what working resolution was used upstream.
- Inputs:
image,reference_image· optional:mask,upscale_method(lanczos/bicubic/bilinear/nearest, default lanczos) - Outputs:
image(IMAGE),mask(MASK)
Resize (Long Side) (SupersideResizeLongSideNode)
Scales an image so its longest side hits a target size, preserving aspect ratio - handy for capping the biggest dimension of catalogue images before further processing.
- Inputs:
image,max_long_side(default 2048) · optional:only_downscale(default ON - only shrink, never enlarge; OFF forces the long side to exactly the target),resample(lanczos/bicubic/bilinear/nearest, default lanczos) - Outputs:
image(IMAGE),width(INT),height(INT)
Color Grading (SupersideColorGradingNode)
Local color grading: brightness, contrast, saturation (multiplicative factors, 1.0 = no change) plus additive per-channel R/G/B offsets. No API, no model call. Alpha is preserved.
- Inputs:
image,brightness(0-3, default 1),contrast(0-3, default 1),saturation(0-3, default 1),R/G/B(-255 to 255 offset, default 0) - Outputs:
image(IMAGE)
Color Match (SupersideColorMatchNode)
Transfers the color character of a reference image onto another image (Reinhard mean/std transfer in LAB or RGB). The right fix for generative color drift when you still have the clean original: set image = the drifted edit and reference = the original, and it pulls skin/hair/lighting back toward the source. Works even when pose/framing changed, since it matches global statistics, not pixels. ignore_background measures color from the subject only (not the large white backdrop) and leaves the background untouched — ideal for catalogue shots on white. For deep NB2 pipelines where reference isn't a perfect clean original (or the subject mask is small/noisy), nb2_passes_since_reference > 0 applies a study-derived directional pre-correction (hue rotated back from red, saturation trimmed, brightness lifted, RGB curve nudged — per-pass averages from the NB2 color-drift study) to the subject before the Reinhard match, so the match has less residual drift to work against. Leave it at 0 (default) for the normal case; the output is then byte-for-byte identical to before this input existed.
- Inputs:
image,reference· optional:strength(0-1, default 1),method(LAB (Reinhard) / RGB),match_luminance(default ON — also matches brightness/contrast),ignore_background(default ON),nb2_passes_since_reference(default 0 = off),nb2_bias_strength(default 1.0, scales that pre-correction) - Outputs:
image(IMAGE)
White Balance (SupersideWhiteBalanceNode)
Neutralizes a color cast by calibrating RGB from a neutral/white reference - built for the warm/red color drift that accumulates when you run an image through a generative editor repeatedly (e.g. Nano Banana Pro/V2). Measures a reference and rescales each channel so "white" reads as white again, preserving brightness. Local, no API key.
- Inputs:
image,mode(manual_sample / auto_white_patch / gray_world) · optional:sample_x,sample_y,sample_size(manual patch position/size),auto_percentile(auto mode),strength(0-1, default 1),preserve_luminance(default ON) - Outputs:
image(IMAGE) - Tip:
manual_sampleis the most reliable - pointsample_x/sample_yat an area you know should be white/neutral (e.g. a catalogue's white background).
Crop to Size (anchored) (SupersideCropToSizeNode)
Force an image to exact pixel dimensions, choosing which part survives. Scales by a single factor until the image covers the target, then cuts - so the result is always exactly the requested size and never squashed. Use it for a format the model cannot generate: Grok Imagine's aspect_ratio has no 4:5, so generate 3:4 (the nearest taller ratio) and crop 6% of the height here. Cropping to 4:5 from 1:1 instead would throw away 20% of the width.
anchor is the full 3x3 grid (center, top-center, bottom-center, middle-left, middle-right, and the four corners) and picks the part that stays put - top-center keeps the head in a portrait, center shaves the crown and the chin equally. The bare edge names (top, left, ...) are still accepted. fit can be set to crop only to cut the pixel rectangle without any scaling (a source smaller than the target then stays at its own size rather than being padded). An optional mask is cropped with identical geometry so it stays aligned.
- Inputs:
image,target_width,target_height,anchor(9 positions) · optional:fit(cover/crop only),mask,resample - Outputs:
image(IMAGE),mask(MASK),width(INT),height(INT)
Cost reporting
Fal Cost Report (SupersideFalCostReportNode)
Adds up every fal.ai call made by Superside nodes and prints the cost breakdown on the node. See Cost tracking for how pricing works and which endpoints cannot be priced.
- Inputs:
scope(this run/session (since ComfyUI started)) · optional:after_image(IMAGE, wire your last image here so this node runs last),after_text(STRING),clear_after_report - Outputs:
report(STRING),total_usd(FLOAT),calls(INT)
Utility (no API key needed)
These nodes make no fal.ai calls, so they don't have an api_key input.
Prompt Box (SupersidePromptBoxNode)
A simple text box - write a prompt, connect the STRING output anywhere. Displays the text in the node UI.
- Inputs:
prompt - Outputs:
prompt(STRING)
Prompt Splitter (SupersidePromptSplitterNode)
Splits one prompt into up to 10 separate STRING outputs using a separator symbol - useful for feeding individual prompts into multi-image nodes.
- Inputs:
prompt,separator(default*) - Outputs:
text_1...text_10(STRING)
Core / infrastructure equivalents (no fal.ai dependency)
In-house reimplementations of core ComfyUI nodes and a handful of small third-party utility nodes, so a workflow built entirely from this package has no dependency on any other custom_nodes package (or on core ComfyUI's own node set) for these basic operations. Each is a faithful, same-contract replacement (same inputs/outputs/widgets) for the node it replaces:
| Superside node | Replaces | Package replaced |
|---|---|---|
| SupersideLoadImageNode | LoadImage | core ComfyUI |
| SupersideSaveImageNode | SaveImage | core ComfyUI |
| SupersidePreviewImageNode | PreviewImage | core ComfyUI |
| SupersideImageScaleToTotalPixelsNode | ImageScaleToTotalPixels | core ComfyUI |
| SupersideImageCompositeMaskedNode | ImageCompositeMasked | core ComfyUI |
| SupersideMaskToImageNode | MaskToImage | core ComfyUI |
| SupersideMaskPreviewNode | MaskPreview+ | comfyui_essentials |
| SupersideGrowMaskWithBlurNode | GrowMaskWithBlur | comfyui-kjnodes |
| SupersideCutByMaskNode | Cut By Mask | masquerade-nodes-comfyui |
| SupersideCombinePromptNode | CR Combine Prompt | ComfyUI_Comfyroll_CustomNodes |
| SupersideImageCompareNode | CR Simple Image Compare | ComfyUI_Comfyroll_CustomNodes |
| SupersideImageComparerNode | Image Comparer (rgthree) | rgthree-comfy (simplified: static side-by-side, no interactive slider - that requires the original's frontend JS widget) |
| SupersideLoadImagesFromFolderNode | Load Images From Folder (KJ) | comfyui-kjnodes |
| SupersideTextPreviewNode | Text Preview Node | superside-utility-nodes (sibling package) |
Package layout
comfyui-superside-nodes/
├── __init__.py # Node registration (NODE_CLASS_MAPPINGS, etc.)
├── modules/
│ ├── base_node.py # SupersideFalNode, ImageProcessingMixin, APIClientMixin, API_KEY_INPUT_SPEC
│ ├── fal_pricing.py # fal price table per endpoint + cost estimators (`--check` for price drift)
│ ├── fal_cost_ledger.py # In-memory record of every fal call and its cost
│ └── <node files>
├── web/js/show_text.js # Read-only result-text display widget for select nodes
├── web/js/price_note.js # Draws each node's fal price under the node
├── requirements.txt
└── README.md
Architecture notes
SupersideFalNode.get_client(api_key)builds afal_client.SyncClient(key=api_key)scoped to that single call - no global environment mutation, so multiple nodes with different keys never interfere with each other.ImageProcessingMixinhandles tensor→PNG upload and API-response→tensor conversion.VideoProcessingMixindoes the same for ComfyUI's native VIDEO type (comfy_api.latest.InputImpl.VideoFromFile) - video nodes accept aLoadVideooutput directly and return a VIDEO connectable toSaveVideo/PreviewVideo, with no manual URL copying required.APIClientMixin.call_api(client, endpoint, arguments)picks synchronous vs. queued execution automatically based on the endpoint - slow endpoints (GPT Image 2, Seedream V5 Pro/V4.5, Gemini Omni Flash) go through fal.ai's queue viasubscribe()with a bounded client-side timeout, since a single long-held connection is prone to mid-flight disconnects on multi-minute generations; everything else uses the faster synchronous path.- All nodes are registered under the Superside category.