Bug
Any TEXT node with layoutSizingHorizontal: "HUG" (or vertical) gets silently rewritten to
"FIXED" during conversion, baking in a literal pixel width pulled from the node's bounding box
at the time of conversion — instead of staying content-hugging.
Root cause
packages/backend/src/altNodes/jsonNodeConversion.ts has a fallback meant for empty frames:
// If layout sizing is HUG but there are no children, set it to FIXED
const hasChildren = "children" in jsonNode && jsonNode.children &&
Array.isArray(jsonNode.children) && jsonNode.children.length > 0;
if (jsonNode.layoutSizingHorizontal === "HUG" && !hasChildren) {
jsonNode.layoutSizingHorizontal = "FIXED";
}
This is correct for an empty frame (HUG with nothing inside to hug around is meaningless). But a
TEXT node never has a children array — its content is characters, a string, not child
elements. So this check reads every TEXT node as "nothing to hug" and forces FIXED on all of them,
regardless of whether they actually had text.
Repro
Any HUG-sized text layer. Concretely, from a real file: a label set to layoutSizingHorizontal: "HUG" with absoluteBoundingBox.width: 133. Plugin output emits width: 133px instead of leaving
it to size to content. The pixel value always matches the bounding box at conversion time — that's
the tell.
Impact
The width is correct only in the exact layout context it was converted in. It breaks the moment
surrounding layout differs even slightly (different container width, different sibling content, a
label that should wrap differently) — text that should stay flexible instead carries a stale,
hardcoded size.
Suggested fix
I've opened a PR with a minimal fix: extract the check into a small function and make it
explicitly return false for TEXT nodes regardless of children. Happy to adjust if you'd rather
handle it differently.
Bug
Any TEXT node with
layoutSizingHorizontal: "HUG"(or vertical) gets silently rewritten to"FIXED"during conversion, baking in a literal pixel width pulled from the node's bounding boxat the time of conversion — instead of staying content-hugging.
Root cause
packages/backend/src/altNodes/jsonNodeConversion.tshas a fallback meant for empty frames:This is correct for an empty frame (HUG with nothing inside to hug around is meaningless). But a
TEXT node never has a
childrenarray — its content ischaracters, a string, not childelements. So this check reads every TEXT node as "nothing to hug" and forces FIXED on all of them,
regardless of whether they actually had text.
Repro
Any HUG-sized text layer. Concretely, from a real file: a label set to
layoutSizingHorizontal: "HUG"withabsoluteBoundingBox.width: 133. Plugin output emitswidth: 133pxinstead of leavingit to size to content. The pixel value always matches the bounding box at conversion time — that's
the tell.
Impact
The width is correct only in the exact layout context it was converted in. It breaks the moment
surrounding layout differs even slightly (different container width, different sibling content, a
label that should wrap differently) — text that should stay flexible instead carries a stale,
hardcoded size.
Suggested fix
I've opened a PR with a minimal fix: extract the check into a small function and make it
explicitly return
falsefor TEXT nodes regardless ofchildren. Happy to adjust if you'd ratherhandle it differently.