Skip to content

fix: preserve node rotation, true size, ink bounds, and explicit line breaks - #420

Open
gillianrode-123 wants to merge 1 commit into
GLips:mainfrom
gillianrode-123:fix/preserve-rotation-transforms
Open

fix: preserve node rotation, true size, ink bounds, and explicit line breaks#420
gillianrode-123 wants to merge 1 commit into
GLips:mainfrom
gillianrode-123:fix/preserve-rotation-transforms

Conversation

@gillianrode-123

Copy link
Copy Markdown

Problem

The simplifier currently loses three classes of design facts:

  1. Rotation. absoluteBoundingBox is the axis-aligned box around a rotated node — inflated and corner-anchored. A 100x148.75 rectangle at -18.3° is reported as an unrotated 141.6x172.6 box at the wrong position, and the angle is unrecoverable from the output. Any design with tilted elements (photo collages, decorative scatter, badges) cannot be implemented faithfully from the simplified data: consumers render everything upright and oversized.
  2. Ink bounds. For text-on-path and vector nodes, the layout box says nothing about where the rendered ink sits, so an exported asset placed at the reported box lands in the wrong place.
  3. Explicit line breaks. Figma's (what Shift+Return inserts) passes through unescaped while \n/ are escaped to \n markers, so a designer's manual break silently collapses into a space in HTML and the text re-wraps differently from the design.

Root cause for 1–2: the REST requests never pass geometry=paths, so Figma never sends relativeTransform/size, and the transformer only reads bounding boxes.

Change

  • Request geometry=paths on getRawFile/getRawNode.
  • When a node (or its parent group) is rotated beyond a 0.05° epsilon, emit rotation (degrees, Figma sign: counter-clockwise positive; CSS equivalent is rotate(-<rotation>deg) with transform-origin: top left), and switch dimensions/locationRelativeToParent to the true unrotated size and the pre-rotation top-left from relativeTransform (already parent-relative). Children of rotated groups take this path even when locally unrotated so nested transforms compose.
  • Emit renderBounds (parent-relative absoluteRenderBounds) for vector-class nodes (TEXT_PATH, VECTOR, BOOLEAN_OPERATION, STAR, LINE, POLYGON) when ink differs from the layout box by more than 1px.
  • Treat like \n/ in both the line splitter and the markdown escaper.

Backward compatibility

  • Unrotated nodes under unrotated parents produce byte-identical output (covered by a test).
  • New fields are optional additions to SimplifiedLayout.
  • geometry=paths increases the raw REST payload server-side; the simplified output only grows by the new fields on affected nodes.

Validation

  • 5 new vitest cases (src/tests/rotation-transform.test.ts); full suite passes (255 tests).
  • Validated against a production Figma file: 30 rotated nodes (a marketing collage, including nested book+icon groups) cross-checked against independent Figma plugin-API measurements of the same nodes — rotation matched within 0.12°, sizes and positions exactly, and nested groups composed to the correct absolute angles (-30° / 17.73° / 2.77°).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant