Nodes/comfyui-fvmtools/JB · Stitcher
ComfyUI Node

JB · Stitcher

Merge outfit, face, and location JSON under one character title — the assembler node

By ping1979ping·Created 7 months ago·Updated a day ago· 2
JB · Stitcher
    • raw_json
    • string
    ◄titlecharacter_1►
    ◄output_formatloose_keys►
    ◄input_1—►
    ◄input_2—►
    ◄input_3—►
    ◄input_4—►
    ◄input_5—►
    ◄input_6—►
    ◄input_7—►
    ◄input_8—►
    ◄input_9—►
    ◄input_10—►
    ◄input_11—►
    ◄input_12—►
    ◄input_13—►
    ◄input_14—►
    ◄input_15—►
    ◄input_16—►
    ◄input_17—►
    ◄input_18—►
    ◄input_19—►
    ◄input_20—►
    ◄input_21—►
    ◄input_22—►
    ◄input_23—►
    ◄input_24—►

    The JB suite's trick is that each piece is built separately and combined at the end. You build a face in JB · Builder, an outfit in JB · Outfit Block, a location in JB · Location Block - and Stitcher is the node that wraps them all under a single title and deep-merges them into one JSON document. Set title to character_1, wire in the three fragment strings, and out comes character_1: {outfit: {...}, face: {...}, location: {...}} as a single string for your text encoder.

    It's the multi-character assembler, too: chain a second Stitcher with title set to character_2 and feed both outputs into a parent Stitcher, and you've got two distinct named character blocks that won't bleed into each other - which is exactly the "two characters, same image" problem from every character-consistency guide, solved with structure instead of hoping the model keeps them apart.

    How the merge actually behaves

    Each input is parsed as JSON, then merged under the title with rules worth knowing:

    • Same-level scalar leaves: last input wins. If input_1 sets outfit: silk and input_2 also sets outfit: cotton, cotton wins.
    • Sub-fields merge recursively. A face: {hair: brown} from input_1 and a face: {eyes: blue} from input_2 combine into face: {hair: brown, eyes: blue} - nothing gets clobbered.
    • Arrays append. If two inputs both define a list, the lists concatenate.
    • Bare strings (a plain sentence, not JSON) get a synthetic __inputN key so they don't break the document.

    And a nice ergonomic touch: connect input_1 and the next input slot auto-spawns, up to input_24. So you can keep stacking fragments without hunting for a "plus" button. Empty unused slots are silently ignored.

    Inputs and outputs

    Inputs: title (default character_1), output_format (same trio as the rest of JB - pretty_json, compact_json, loose_keys), and the 24 string inputs. Outputs: raw_json (always strict) and string (chosen format). In the reference workflow, string goes to CLIPTextEncode positive and raw_json goes to a sidecar/save node for debugging or reuse.

    Installing

    cd ComfyUI/custom_nodes
    git clone https://github.com/ping1979ping/comfyui-FVMtools
    

    No extra dependencies; the whole JB suite ships together under FVM Tools/JB. Restart ComfyUI after cloning.

    The trap

    The "last wins" rule is positional, so input ordering is semantics - feed a fragment in the wrong order and a field silently changes value with no error. If you're building a big character tree, get in the habit of checking the raw_json output (feed it into a ShowText or Save Text node) once before you commit to a batch. And the title behavior is the thing people reach for second: if you set title to an empty string, you lose the wrapping block entirely, which changes what the downstream encoder sees. The title is the point - it's what anchors an attribute to a character in a multi-character document.

    CategoryFVM Tools/JB

    Inputs (26)

    NameTypeDefaultDescription
    titleSTRINGcharacter_1—
    output_formatCOMBOloose_keysnatural / sentences: prose for Krea 2 and Qwen encoders (sentences = full sentences with lead-ins, title prepended). loose_keys / pretty_json / compact_json: structured, for Ideogram 4 style JSON prompting.
    input_1optSTRING—
    input_2optSTRING—
    input_3optSTRING—
    input_4optSTRING—
    input_5optSTRING—
    input_6optSTRING—
    input_7optSTRING—
    input_8optSTRING—
    input_9optSTRING—
    input_10optSTRING—
    input_11optSTRING—
    input_12optSTRING—
    input_13optSTRING—
    input_14optSTRING—
    input_15optSTRING—
    input_16optSTRING—
    input_17optSTRING—
    input_18optSTRING—
    input_19optSTRING—
    input_20optSTRING—
    input_21optSTRING—
    input_22optSTRING—
    input_23optSTRING—
    input_24optSTRING—

    Outputs (2)

    NameTypeDescription
    raw_jsonSTRING—
    stringSTRING—