D2 Moss Prompt
The layout JSON nobody wants to hand-write
- prompt
The half of the pair that writes the JSON
MOSS-Image accepts a structured layout prompt: a summary block describing the whole image, then an items list where each entry has a label, a caption, an optional text, and a bbox. Plus two fields almost everyone gets wrong on the first attempt - bbox_coord_space: "abs_centralized" and bbox_format: "yxyx". Mangle either one and the model happily renders garbage from coordinates it interpreted in the wrong frame.
D2 Moss Prompt assembles all of that for you. You feed it one or more D2 Moss Item nodes and a description of the scene; it emits a single-line JSON string. It's not a text encoder and doesn't touch a model - it's a string builder with opinions, and the opinions are the useful part.
Worth saying out loud: JSON prompting isn't magic. On LLM-encoded models, structure helps because it gives the model clean separation between fields - which is also why a well-structured paragraph can do the same job. What's different here is that the boxes are load-bearing. This is regional prompting with the boxes handed to the model directly.
How it works
item_count is the control surface. A small front-end extension (web/D2_MossPrompt.js) watches that widget and adds or removes moss_item_1…moss_item_N sockets to match. On the Python side the node declares no fixed item inputs at all - it accepts whatever arrives and loops 1..item_count, keeping only slots that carry a real D2_MOSS_ITEM. Then it checks that every item's mask has matching dimensions, strips comment lines from your scene description, and builds the dict:
{"summary":{"meta":["poster"],"canvas":"single","caption":"…"},"items":[…],"bbox_coord_space":"abs_centralized","bbox_format":"yxyx"}
Serialised compact, one line, non-ASCII preserved. Empty fields are omitted rather than sent as blank strings - no meta key if you left it blank, no caption if the description is empty. A blank field disappears instead of confusing the model with "".
The inputs that matter
meta - comma-separated tags for the kind of image: poster, photograph, or illustration, anime. The node splits on commas, trims whitespace and drops empties, so it goes out as a proper JSON array. This is the field to actually think about; it steers the whole aesthetic.
summary_caption - the scene and style in plain language, multiline. # and // at the start of a line are treated as comments and removed - handy for notes in a template, annoying the first time you write a caption beginning with a hash.
canvas_type - leave it at single. Fair warning: it's free text, not a dropdown, so nothing stops you typing Single. Only single is documented upstream, and your typo goes into the JSON unvalidated.
item_count - 1 to 50. Default 2.
moss_item_1…N - the sockets that appear as you raise item_count. This is where the D2 Moss Item outputs connect.
Output is one prompt STRING. Wire it into the text-encoder node of your MOSS-Image workflow, the same box you'd type a normal prompt into.
Installing it
Same pack as D2 Moss Item, so if you installed one you have the other. Manager: search D2 Nodes ComfyUI. Or:
cd ComfyUI/custom_nodes
git clone https://github.com/da2el-ai/D2-nodes-ComfyUI
Restart, then both nodes show up under D2/Text. Dependencies are just piexif and charset-normalizer. The pack moved to ComfyUI's V3 node schema at v32.0.0 and the README warns that older builds can't load it - if the import fails, update ComfyUI or pin a pre-v32 tag.
Setting up the other end
The node builds the prompt; it can't make MOSS obey it. From the upstream user guide, the settings that matter for layout adherence: around 1M–2M total pixels at multiples of 16, 50+ steps, CFG 3.0, Euler, shift 5.0, plus their suggested negative - nsfw, worst quality, bad anatomy, watermark, jpeg artifact. Run it at 20 steps and CFG 7 and the boxes get loosely interpreted, which looks exactly like broken coordinates.
Where people get burned
Lowering item_count while things are connected. The extension removes the sockets; get the order wrong and you're left with dangling links. Disconnect the extras first, then drop the count.
Silent under-counting. The Python side keeps only slots holding a real item, so item_count of 3 with two wired gives you a valid two-item prompt and no complaint. Count connections before you count masks.
Size mismatch. Items built from masks of different dimensions can't share a coordinate origin, so the node refuses. The error is Japanese, アイテムのマスクサイズが揃っていません, followed by the offending sizes - "mask sizes don't match", and the fix is to draw all masks on one canvas of one size.
Debugging JSON by eye. The output is one compact line with no spaces. Wire prompt into a text preview node once and look at it - a stray curly quote pasted in from a reference, or a caption attached to the wrong item, is invisible otherwise.
Expecting boxes to be honoured literally. Layout prompts are experimental and only the fields in the official guide are supported. Treat it as strong guidance; if a box is being ignored, tighten the item caption and the summary before you touch coordinates.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| meta | STRING | — | |
| canvas_type | STRING | single | — |
| summary_caption | STRING | — | |
| item_count | INT | 21–50 | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| prompt | STRING | — |