Nodes/MOSS BBox 1000 Converter/MOSS BBox 1000 → Native
ComfyUI Node

MOSS BBox 1000 → Native

Your 0–1000 layout boxes aren't MOSS-Image coordinates yet

By b4ldur·Created 3 days ago·Updated 3 days ago· 4
MOSS BBox 1000 → Native
    • moss_native_json
    ◄layout_json{ "summary": { "meta": ["minimal graphic design"], "canvas": "single", "caption": "A clean full-bleed poster with a centered geometric shape and a title." }, "items": [ { "label": "object", "caption": "A solid background filling the entire canvas.", "bbox": [0, 0, 1000, 1000] }, { "label": "object", "caption": "A geometric shape in the center of the poster.", "bbox": [300, 300, 700, 700] }, { "label": "text", "caption": "A short title near the top of the poster.", "text": "EXAMPLE", "bbox": [50, 250, 150, 750] } ], "bbox_coord_space": "relative_1000", "bbox_format": "yxyx" }►
    ◄width1248►
    ◄height1680►

    MOSS-Image landed its weights on 16 October 2026, and one of its headline features is layout control: you hand it a JSON blob describing what goes where, and it tries to obey. The catch is buried in the format. MOSS wants boxes in absolute pixels measured from the centre of the canvas, as abs_centralized yxyx - so on a 1024×1024 render your axes run −512 to +512, and y grows downward. Every example in the official docs is hand-tuned to one resolution, which means the moment you change your Empty Latent size, all your carefully placed boxes are wrong.

    This node is the adapter. You author layouts on a boring top-left 0–1000 grid, tell the node your render size, and it spits out native MOSS JSON you can paste straight into the positive prompt.

    Why a grid at all

    The wider trend is real: bounding boxes moved from something you bolt on after the fact - region masks, attention surgery, all the Latent Couple descendants that break on every new architecture - to something baked into the caption schema the model was trained on. Ideogram 4 was the loud first example. MOSS-Image is the open-weights version of the same idea, with text rendering as its party trick.

    And the grid part isn't cosmetic. If you're generating these layouts with an LLM - and you should be, MOSS prompt JSON is tedious to hand-write - a model is far more reliable at "box from 300 to 700 on a thousand-point scale" than at "box from −624 to 624 pixels on a canvas whose size I haven't decided yet." Zero-to-a-thousand is resolution-independent, so the same layout survives a switch from square to portrait. The pack ships a ready-made system prompt for exactly this loop at prompts/SYSTEM_PROMPT.md.

    The mechanism

    It's arithmetic. For each axis:

    x_native = (x_grid / 1000 - 0.5) * width
    y_native = (y_grid / 1000 - 0.5) * height
    

    The shipped core.py does that in pure integer math with half-away-from-zero rounding (Python's round() uses banker's rounding, which would give you lopsided symmetric boxes), so a full-bleed [0,0,1000,1000] always comes out as exactly [-h/2, -w/2, h/2, w/2]. No model, no network calls, no requirements.txt to break. The pack is one node, MIT, v0.1.0.

    Inputs and output

    Three fields, all required, and no hidden ones:

    • layout_json - a multiline string holding your layout. It expects a summary object (meta as 1–4 style strings, canvas set to "single", a non-empty caption) and a non-empty items array, plus "bbox_coord_space": "relative_1000" and "bbox_format": "yxyx". You don't have to strip markdown - the parser skips ahead to the first JSON object containing both summary and items, so a fenced block pasted out of a chat window just works.
    • width and height - the exact pixel dimensions of the generation latent. Step of 16, range 16–16384. Defaults are 1248×1680.

    The single output is moss_native_json, a compact JSON string with bbox_coord_space flipped to abs_centralized. Wire it into the text input of the positive text-encoding node in your MOSS-Image workflow. In ComfyUI's UI you'll need to right-click that widget and convert it to an input first, since this node outputs a STRING rather than a conditioning.

    Install

    This pack doesn't load MOSS-Image - you need the official plugin and weights separately (search MOSS-Image in ComfyUI Manager, or follow the repo's comfyui/ instructions). Then:

    cd ComfyUI/custom_nodes
    git clone https://github.com/b4ldur/ComfyUI-MOSS-BBox1000.git
    

    Restart, and look for MOSS BBox 1000 → Native under MOSS-Image/layout. There's nothing to download; the node has no dependencies of its own.

    Where people get burned

    Width/height mismatch is the big one. Native coordinates are absolute, so if the node says 1248×1680 and your latent is 832×1216, your boxes don't just look wrong - they land in the wrong place at the wrong scale. Set the node to the generation size, not your upscaler's output.

    Don't feed it pixels. Hand it a layout that's already abs_centralized and it throws Input is already native abs_centralized. Do not convert it again. Same story for bbox_format anything other than yxyx. These errors are a feature; double conversion is silent-ruin territory.

    Square boxes aren't square. X and Y scale independently, so [300,300,700,700] on a 1248×1680 canvas gives you a tall rectangle. If you need a true circle, author it per-aspect-ratio.

    Thin boxes can vanish. A box one grid unit wide rounds to the same pixel on both edges and the node refuses it with box became zero-area. Push the coordinates apart.

    text is not a caption. label: "text" items require a literal text field with the exact words to render, and label: "object" items are rejected if they carry one. Boxes are strong hints, not constraints - the pack's own docs say adherence is approximate. Pad generously, especially for text.

    There's also a standalone converter for batching layouts outside ComfyUI, and the unit tests run fine without ComfyUI installed - more than most node packs can say:

    python tools/convert.py examples/layout_1000.json --width 1248 --height 1680 -o out.json
    python -m unittest discover -s tests -v
    
    CategoryMOSS-Image/layout

    Inputs (3)

    NameTypeDefaultDescription
    layout_jsonSTRING{ "summary": { "meta": ["minimal graphic design"], "canvas": "single", "caption": "A clean full-bleed poster with a centered geometric shape and a title." }, "items": [ { "label": "object", "caption": "A solid background filling the entire canvas.", "bbox": [0, 0, 1000, 1000] }, { "label": "object", "caption": "A geometric shape in the center of the poster.", "bbox": [300, 300, 700, 700] }, { "label": "text", "caption": "A short title near the top of the poster.", "text": "EXAMPLE", "bbox": [50, 250, 150, 750] } ], "bbox_coord_space": "relative_1000", "bbox_format": "yxyx" }—
    widthINT124816–16384—
    heightINT168016–16384—

    Outputs (1)

    NameTypeDescription
    moss_native_jsonSTRING—