Nodes/From 3D to Campaign/Casa · layout
ComfyUI Node

Casa · layout

A design system in a node, so your headline can't end up on the balustrade

By meryboth·Created 25 days ago·Updated 25 days ago· 0
Casa · layout
  • image
  • asset
  • qa_report
◄format▾►
◄template▾►
◄language▾►
◄headline►
◄caption►
◄meta_left►
◄meta_right►

Most "add text to image" nodes give you a font size, a position and a colour, and then you place the caption over a bright sky by hand and ship something nobody can read. CasaLayout is the opposite bet: the grid, the type scale, the safe zones, the scrim, the brand mark and the AI disclosure are all decided by a design system, and the node's job is to apply it and report what it did wrong.

It's the last stage of the pack's pipeline - render, gate, upscale, then layout - and the one that turns an approved image into something you could actually post.

How the layout works

config/design.json holds a 12-column grid with a 72px margin, 24px gutter and 9px baseline. Every token scales with the canvas width (k = width / 1080), so a 1920px banner isn't a stretched 1080px feed post - it's the same system at a different size.

Three templates change the composition, not just the styling:

  • cover - image full-bleed, headline set in display type over a gradient scrim at the bottom.
  • shot - same full-bleed treatment, but the headline takes the body role: smaller, calmer, a caption under a photograph.
  • data - different beast. Paper-coloured background, a metadata rail across the top with a hairline rule under it, the headline, then your image in a plate below. This is the "1408 · 3 rooms · 182 m²" card.

For the two image templates the text band is measured before it's drawn: the node wraps and measures the headline and caption blocks, sizes the scrim gradient to fit them, and lays them out upward from the bottom safe zone. That's why a long headline doesn't collide with the brand mark - the geometry is computed, not eyeballed. The mark itself is drawn from code (pipeline/brand_mark.py, no asset file), and the AI disclosure is stamped at the bottom in the asset's own language, pulled from config/brand.json. Every language you publish in gets its disclosure in that language, which is the part of the workflow people forget until legal asks.

Four formats, each with its own safe zones: feed at 1080×1350 (4:5), story at 1080×1920 with 260px reserved at the top and 340px at the bottom for platform UI, link at 1200×630 for OG images, banner at 1920×1080.

Inputs and outputs

image in - that's the approved render, typically the upscale output. format and template as above, plus language, which selects the disclosure string. headline and caption are multiline strings you'd usually wire from CasaCopyCheck.headline and .caption. meta_left and meta_right are the small rail labels - in the master graph, VILLA CRESPO, BUENOS AIRES on the left and 8,66 x 50 M on the right, set in the wide-tracked metadata style.

Two outputs: asset (IMAGE) → SaveImage, and qa_report (STRING). The report is LAYOUT OK or LAYOUT ISSUES plus a list of overlapping type blocks.

What the QA does and doesn't do

Be precise about this one, because it's easy to misread. The node's own check is collisions only - it compares every pair of drawn type boxes and flags any that overlap by more than 4px in both axes. That's the bug a contrast check can't see, and it catches the case where a long generated headline runs into the brand lockup.

Contrast, minimum type size and "is there too much detail behind this text" live in the pack's CLI post builder, not in this node. The journal is candid about why that matters: the wordmark was once drawn straight to the canvas, bypassing QA entirely, and shipped at a contrast ratio of 2.4 over a bright sky. QA only sees what you route through it. If you're building your own graph off the node, prefer the cover/shot templates over hand-positioning text, and treat the scrim depth as something you can't inspect from the node output - open the file.

Install

ComfyUI Manager → From 3D to Campaign, or:

cd ComfyUI/custom_nodes
git clone https://github.com/meryboth/from-3d-to-campaign

Restart. No models and no npm needed for this node; it's PIL plus the pack's own pipeline/design.py. The typeface (Switzer, Fontshare licence, commercial use allowed) ships inside assets/fonts - the .comfyignore prunes the OTF folder from the registry package to keep it small, but the TTFs go along and the font lookup finds them. If you're on Linux and trim the repo down to the node file, the font resolver falls back to a C:/Windows/Fonts/arial.ttf path that doesn't exist and you'll get an exception. Keep the assets directory.

Where it bites

Generated headline lengths vary, and the system only reserves space for what you hand it. Feed a 200-character headline and the layout gets dense fast. The character limits in CasaCopySpec exist for this reason - they're not stylistic advice.

One size does not fit every format. A composition that sings at 1080×1350 can feel airy at 1920×1080 and crushed in a 1200×630 link card. Run the same piece through two formats before you decide the template is wrong.

Images are cover-fitted, not stretched. If your crop cuts something important, that's cropped from the centre - the node isn't making an editorial decision about which part of the building to keep.

Categoryfrom 3d to campaign

Inputs (8)

NameTypeDefaultDescription
imageIMAGE—
formatCOMBO4 options: feed, story, link, banner
templateCOMBO3 options: cover, shot, data
languageCOMBO3 options: es, en, pt
headlineSTRING—
captionSTRING—
meta_leftSTRING—
meta_rightSTRING—

Outputs (2)

NameTypeDescription
assetIMAGE—
qa_reportSTRING—