4. The tree

Every member is optional; a missing map is empty.

Esta página está em inglês; a tradução está a caminho.

4.1 tree#

json
"tree": {
  "seq": 12,
  "document": { },
  "pages": { },
  "nodes": { },
  "styles": { },
  "variableCollections": { },
  "variables": { },
  "libraries": { },
  "flows": { },
  "comments": { },
  "versions": { },
  "assets": { },
  "deletedComponents": { }
}
Member Type Meaning Section
seq integer, 0 or more seq of the last event folded into this tree. Informative: a new event takes the largest seq in the file plus one (5.1). 5.1
document object Document metadata. 4.2
pages map of page id to page The pages, ordered by index. 4.2
nodes map of node id to node Every node of every page, flat. 4.3 – 4.8
styles map of style id to style Paint, text, effect and grid styles. 4.9
variableCollections map of collection id to collection Variable collections with their modes. 4.10
variables map of variable id to variable Variables of all collections. 4.10
libraries map of library id to library Other design files this one uses, with a copy of what it uses. 4.11
flows map of flow id to flow Prototype flows and their starting points. 4.12
comments map of comment id to comment Comment threads and replies. 4.13
versions map of version id to version Named versions. 4.14
assets map of asset hash to asset Metadata of the images and fonts in the assets folder. 4.15
deletedComponents map of component id to snapshot Main components that were deleted while instances still used them. 4.16

Every member is optional; a missing map is empty. A map is written as {} when empty.

Maps, not arrays. Collections that two people can grow at the same time are JSON objects keyed by id, ordered (where order matters) by a fractional index member. Two branches that add an entry then never edit the same line of the tree, and events can name any entry by id. The Plugin API layer presents them as Figma’s arrays (figma.root.children, collection.modes, collection.variableIds).

Lists of values are arrays. Fills, strokes, effects, export settings, layout grids, reactions and similar lists are arrays, set and replaced as a whole, exactly as Figma’s immutable arrays (CMD-15).

4.2 Document and pages#

document

Member Type Default Meaning
id doc- id required Identity of the document. Libraries and ud:// links refer to it. Never changes, also not when the file is renamed or moved.
name string file name without .design Display name.
createdAt timestamp — When the document was created.
updatedAt timestamp — The latest at folded into the tree. Derived on read; written by consolidation.
colorProfile "SRGB", "DISPLAY_P3" "SRGB" Colour profile of the document (STY-4). Colour values are in this space.
library object or absent absent Present when the file publishes a library (VAR-7): {"name": string, "description": string}.
annotationCategories map of an- id to {label, color, index} the three built-in categories Categories of annotations (DEV-7). The built-in ids are behaviour, accessibility, interaction.
codeSyntaxPlatforms array of strings ["WEB","ANDROID","iOS"] Platforms offered in variable code syntax (VAR-5).

Page (tree.pages, key: pg- id)

Member Type Default Meaning
id pg- id required Same as the key.
type "PAGE" "PAGE" Present for symmetry with nodes.
name string "Page" Page name.
index fractional index required Order among pages (4.3).
backgrounds paint array [{"type":"SOLID","color":{"r":0.96,"g":0.96,"b":0.96}}] Canvas background (DOC-1). Figma’s name and shape.
explicitVariableModes map of collection id to mode id {} Modes chosen for the whole page (VAR-6).
prototypeBackgrounds paint array [] Background behind frames in the preview player.
guides array of {axis: "X" or "Y", offset} [] Ruler guides on the canvas.
pluginData, sharedPluginData as for nodes (4.4.10) {} Plugin data of the page.

A document has at least one page (DOC-1). The top-level nodes of a page have the page id as parent. A page’s prototype flows are the flows whose pageId is the page (4.12).

4.3 The node map, parent and the fractional index#

tree.nodes maps every node id to its node. There are no nested children arrays. The tree of layers is given by two members of every node:

Member Type Meaning
parent node id or page id The node or page that contains this node.
index fractional index Position among the children of parent.

The fractional index (DOC-3) is a non-empty string over the 62 characters 0-9, A-Z, a-z. Siblings are ordered by comparing their index strings character by character by code point ("0" < "9" < "A" < "Z" < "a" < "z"), a shorter string before a longer one that starts with it. This is plain string comparison in JavaScript and byte comparison in any language; a reader needs nothing else.

  • Ascending index is back to front, as Figma’s children: the first child is painted first, at the bottom; the last is on top. The Layers panel lists them reversed. In an auto layout frame, ascending index is also the flow order (first item first); itemReverseZIndex only changes the painting order.
  • Writers generate keys between neighbours. To put a node between siblings with keys a and b, a writer picks any key k with a < k < b. To put it first or last, any key below the first or above the last. The extension uses the algorithm of the fractional-indexing package (generateKeyBetween), whose keys look like a0, a1, a0V, Zz. Other writers may use any scheme that respects the order; readers never parse a key.
  • Moving a node changes only its own index (and parent, when it changes). No sibling is renumbered, so two branches that move or insert different nodes edit different lines.
  • Ties are broken by id. Two branches can insert at the same place and generate the same key. Siblings with equal index are ordered by their ids, compared the same way. A writer that inserts between two siblings with equal keys first gives one of them a fresh key (a node.reorder in the same group).
  • Keys grow. Repeated inserts at the same place make keys longer. Consolidation shortens long keys (section 7).

The same scheme orders pages, styles, variables within their collection, modes within their collection, flows within their page and annotation categories.

A node in the flat map, the button label of section 12:

json
"nd-2b7d9e4f6a10": {
  "type": "TEXT",
  "name": "Label",
  "parent": "nd-8a3f1c5e7b92",
  "index": "a0",
  "characters": "Button",
  "textStyleId": "st-4d6f8a0c2e1b",
  "fills": [{"type": "SOLID", "color": {"r": 1, "g": 1, "b": 1}}],
  "componentPropertyReferences": {"characters": "Label#a41c"}
}

The key of the map is the id; the node object does not repeat it. Readers add id to the node object in memory.

Constraints on the structure (repairs in section 6):

  • A node’s parent exists, and following parent from any node ends at a page, without a cycle.
  • SECTION nodes have a page or another section as parent.
  • Children are allowed only under FRAME, GROUP, SECTION, COMPONENT, COMPONENT_SET, BOOLEAN_OPERATION, SLOT and (for slot content) instance slots (4.8). A GROUP or BOOLEAN_OPERATION has at least one child.
  • COMPONENT_SET has only COMPONENT children.

4.4 Shared node properties#

Every node has type, name, parent and index. All other properties are optional and take the default shown when absent. A property that a node type does not have (for example characters on a FRAME) is kept but ignored.

4.4.1 Identity, visibility and geometry#

Property Type Default Meaning
type node type (4.6) required Fixed when the node is created. Changed only by component.create and instance.detach.
name string by type and content (DOC-6) Layer name.
visible boolean true Shown or hidden.
locked boolean false Locked against selection on the canvas.
x, y number, px 0 Position of the node’s origin in its parent’s coordinate system: the parent frame’s top-left corner, or for children of a GROUP or BOOLEAN_OPERATION, the nearest ancestor frame or the page. Not stored for children in auto layout flow (4.5).
width, height number, px, 0 or more 100 Size. Not stored where derived: hug axes, fill axes, groups, booleans, auto-sized text (4.5).
rotation number, degrees 0 Counter-clockwise rotation about the node’s origin, in (-180, 180], as Figma.
flipX, flipY boolean false Mirrored along the node’s own vertical (flipX) or horizontal (flipY) axis. Figma has no such properties; the Plugin API layer composes relativeTransform from x, y, rotation, flipX, flipY and decomposes it on write.
description string "" Free text (DOC-4); for components, the documentation shown in the Assets panel.
documentationLinks array of {uri} [] Links of a component (CMP-7).

4.4.2 Constraints and layout as a child#

Property Type Default Meaning
constraints {horizontal, vertical} {"horizontal":"MIN","vertical":"MIN"} LAY-1. horizontal: MIN (left), MAX (right), STRETCH (left and right), CENTER, SCALE. vertical: the same for top and bottom.
layoutPositioning "AUTO", "ABSOLUTE" "AUTO" In an auto layout parent: in flow, or absolutely positioned with constraints (LAY-5).
layoutSizingHorizontal, layoutSizingVertical "FIXED", "HUG", "FILL" "FIXED" LAY-3. HUG only for auto layout frames and text; FILL only for children of auto layout frames.
minWidth, maxWidth, minHeight, maxHeight number, px, or absent absent Size limits (LAY-3).
gridRowAnchorIndex, gridColumnAnchorIndex integer, 0 or more auto-placed Cell of a child in a grid auto layout (LAY-4).
gridRowSpan, gridColumnSpan integer, 1 or more 1 Cells spanned.
gridChildHorizontalAlign, gridChildVerticalAlign "AUTO", "MIN", "CENTER", "MAX" "AUTO" Alignment within the cell.
scrollBehavior "SCROLLS", "FIXED", "STICKY_SCROLLS" "SCROLLS" Behaviour when the parent frame scrolls in a prototype (PRO-5).

layoutGrow and layoutAlign of the Plugin API are derived from the sizing properties and not stored.

4.4.3 Auto layout (frames, components, component sets, instances)#

Property Type Default Meaning
layoutMode "NONE", "HORIZONTAL", "VERTICAL", "GRID" "NONE" LAY-2, LAY-4.
layoutWrap "NO_WRAP", "WRAP" "NO_WRAP" Wrap for HORIZONTAL.
itemSpacing number, px 0 Gap between items.
counterAxisSpacing number, px 0 Gap between rows when wrapping.
paddingLeft, paddingRight, paddingTop, paddingBottom number, px 0 Padding per side.
primaryAxisAlignItems "MIN", "CENTER", "MAX", "SPACE_BETWEEN" "MIN" Alignment along the direction; SPACE_BETWEEN is gap “auto”.
counterAxisAlignItems "MIN", "CENTER", "MAX", "BASELINE" "MIN" Alignment across the direction.
counterAxisAlignContent "AUTO", "SPACE_BETWEEN" "AUTO" Distribution of wrapped rows.
itemReverseZIndex boolean false First item painted on top (LAY-2).
strokesIncludedInLayout boolean false Strokes count in the box (LAY-6).
gridRowCount, gridColumnCount integer, 1 or more 1 Tracks of a grid auto layout (LAY-4).
gridRowGap, gridColumnGap number, px 0 Gaps between tracks.
gridRowSizes, gridColumnSizes array of {type: "FIXED" or "FLEX" or "HUG", value} one FLEX 1 per track Track sizes; FLEX is a fraction (fr).
layoutGrids array of layout grids [] Column, row and uniform guides (LAY-8): {pattern: "COLUMNS" or "ROWS" or "GRID", alignment: "MIN" or "MAX" or "CENTER" or "STRETCH", count, gutterSize, offset, sectionSize, visible, color}, Figma’s shape.
gridStyleId st- id absent Layout grid style (4.9).
clipsContent boolean true for frames, false for components and instances Clip children to the frame, respecting corner radius (STY-8).
overflowDirection "NONE", "HORIZONTAL", "VERTICAL", "BOTH" "NONE" Prototype scrolling (PRO-5).
overlayPositionType, overlayBackground, overlayBackgroundInteraction Figma’s values "CENTER", {"type":"NONE"}, "NONE" How the frame shows when opened as an overlay (PRO-4).

primaryAxisSizingMode and counterAxisSizingMode of the Plugin API are derived from layoutSizingHorizontal and layoutSizingVertical and not stored.

4.4.4 Appearance#

Property Type Default Meaning
opacity number, 0 – 1 1 Layer opacity (STY-7).
blendMode Figma’s BlendMode "PASS_THROUGH" for frames, groups, sections, components, instances; "NORMAL" otherwise PASS_THROUGH, NORMAL, DARKEN, MULTIPLY, LINEAR_BURN, COLOR_BURN, LIGHTEN, SCREEN, LINEAR_DODGE, COLOR_DODGE, OVERLAY, SOFT_LIGHT, HARD_LIGHT, DIFFERENCE, EXCLUSION, HUE, SATURATION, COLOR, LUMINOSITY.
fills paint array (4.7) [], except [{"type":"SOLID","color":{"r":1,"g":1,"b":1}}] for frames and components created by the Frame tool Fills, bottom first (STY-1).
fillStyleId st- id absent Paint style for the fills (4.9).
strokes paint array [] Strokes (STY-5).
strokeStyleId st- id absent Paint style for the strokes.
strokeWeight number, px 1 Weight of all sides.
strokeTopWeight, strokeRightWeight, strokeBottomWeight, strokeLeftWeight number, px strokeWeight Per-side weights of frames and rectangles.
strokeAlign "INSIDE", "CENTER", "OUTSIDE" "INSIDE" for closed shapes, "CENTER" for lines and open vectors Stroke position.
strokeCap "NONE", "ROUND", "SQUARE", "ARROW_LINES", "ARROW_EQUILATERAL", "TRIANGLE_FILLED", "CIRCLE_FILLED", "DIAMOND_FILLED" "NONE" Caps of open paths. Per-vertex caps are in the vector network (4.6.4).
strokeJoin "MITER", "BEVEL", "ROUND" "MITER" Joins.
strokeMiterLimit number 4 Miter limit.
dashPattern array of numbers, px [] Dash and gap lengths; empty is solid.
effects effect array (4.7.5) [] Shadows and blurs, in order (STY-6).
effectStyleId st- id absent Effect style.
cornerRadius number, px 0 All corners of a rectangle, frame, component, instance, polygon or star.
topLeftRadius, topRightRadius, bottomRightRadius, bottomLeftRadius number, px cornerRadius Independent corners (DRW-3). Written only when they differ; each one written wins over cornerRadius for its corner.
cornerSmoothing number, 0 – 1 0 Smooth corners (squircle); 0.6 is iOS style (DRW-3).
isMask boolean false This node masks the siblings above it, up to the end of the parent (DRW-8).
maskType "ALPHA", "VECTOR", "LUMINANCE" "ALPHA" How the mask applies.

4.4.5 Bindings and modes#

Property Type Default Meaning
boundVariables object {} Bindings of properties to variables (VAR-4), Figma’s shape: {"itemSpacing": {"type":"VARIABLE_ALIAS","id":"vr-…"}, "topLeftRadius": {…}}. Paints, effects and layout grids carry their own boundVariables inside the array entry.
explicitVariableModes map of collection id to mode id {} Mode chosen for a collection on this frame and its descendants (VAR-6).
componentPropertyReferences object {} Properties of a layer inside a component that are driven by a component property: {"characters": "Label#a41c", "visible": "Show icon#5d02", "mainComponent": "Icon#77b0"} (CMP-5).

A bound or styled property keeps a plain value next to the reference. itemSpacing stays written when boundVariables.itemSpacing exists; fills stays written when fillStyleId exists. The reference wins when it resolves; the plain value is the fallback when the variable or style is missing (deleted on another branch, library unavailable). Writers write the resolved value when they bind and do not update it afterwards. This is Figma’s model, and it keeps a file readable without resolving references.

4.4.6 Export settings#

exportSettings (EXP-1) is an array, default [], in Figma’s shape:

json
"exportSettings": [
  {"format": "PNG", "suffix": "@2x", "constraint": {"type": "SCALE", "value": 2}},
  {"format": "SVG", "svgOutlineText": true, "svgIdAttribute": false, "svgSimplifyStroke": true, "useAbsoluteBounds": false}
]

format is PNG, JPG, WEBP, SVG or PDF; constraint.type is SCALE, WIDTH or HEIGHT.

4.4.7 Prototype reactions#

reactions (PRO-1 – PRO-4) is an array, default [], in Figma’s shape. Durations and delays are in seconds, as in Figma.

json
"reactions": [
  {
    "trigger": {"type": "ON_CLICK"},
    "actions": [
      {
        "type": "NODE",
        "destinationId": "nd-6b8d0f2a4c1e",
        "navigation": "NAVIGATE",
        "transition": {"type": "SMART_ANIMATE", "easing": {"type": "EASE_OUT"}, "duration": 0.3},
        "preserveScrollPosition": false
      }
    ]
  }
]
Part Values
trigger.type ON_CLICK, ON_HOVER, WHILE_HOVERING (Figma: ON_HOVER with revert), ON_PRESS, WHILE_PRESSING, ON_DRAG, ON_KEY_DOWN (with keyCodes, device), MOUSE_ENTER, MOUSE_LEAVE, MOUSE_DOWN, MOUSE_UP, AFTER_TIMEOUT (with timeout).
actions[].type NODE (with navigation: NAVIGATE, CHANGE_TO, OVERLAY, SWAP, SCROLL_TO), BACK, CLOSE, URL (with url), SET_VARIABLE (with variableId, variableValue), SET_VARIABLE_MODE (with variableCollectionId, variableModeId), CONDITIONAL (with conditionalBlocks).
transition.type DISSOLVE, SMART_ANIMATE, MOVE_IN, MOVE_OUT, PUSH, SLIDE_IN, SLIDE_OUT, SCROLL_ANIMATE; absent is instant. With direction and matchLayers where Figma has them.
easing.type LINEAR, EASE_IN, EASE_OUT, EASE_IN_AND_OUT, EASE_IN_BACK, EASE_OUT_BACK, EASE_IN_AND_OUT_BACK, CUSTOM_CUBIC_BEZIER (with easingFunctionCubicBezier), GENTLE, QUICK, BOUNCY, SLOW, CUSTOM_SPRING (with easingFunctionSpring).

A destinationId that names no node makes the action inert; the reader keeps it and ud lint reports it.

4.4.8 Developer handoff#

Property Type Default Meaning
devStatus {type, description, at} or absent absent DEV-5 and DOC-8, on frames, sections and components. type is "READY_FOR_DEV" or "COMPLETED". at is the time the status was set; writers copy the event’s at into it, so the compare view can find the design as it was.
annotations array [] DEV-7, Figma’s shape: {"label": string, "labelMarkdown": string, "properties": [{"type": "width"}], "categoryId": "accessibility"}.
accessibility object {} DEV-8: {"role": string, "name": string, "description": string, "headingLevel": 1-6, "focusOrder": integer, "altText": string, "decorative": boolean}. Our own; Figma has no equivalent.
codeMap object or absent absent DEV-4, on components and component sets: the code component this maps to (below).
traces array of {file, item} [] INT-1: Project Board items this node realises, for example {"file": "planning.pb", "item": "REQ-12"}. file is relative to the design file.

A code map entry:

json
"codeMap": {
  "component": "Button",
  "source": "src/ui/Button.tsx",
  "language": "tsx",
  "props": {
    "Size": {"prop": "size", "values": {"sm": "sm", "md": "md", "lg": "lg"}},
    "Label#a41c": {"prop": "children"},
    "Show icon#5d02": {"prop": "icon", "when": true}
  }
}

Keys of props are component property keys (4.8). Mappings in the ud.codeMap setting override the file.

4.4.9 Annotations as nodes#

Measurement annotations, connectors and sticky notes that stand on the canvas are nodes of their own (CONNECTOR, STICKY, 4.6.8). Annotations attached to a node are the annotations property above.

4.4.10 Plugin data#

Property Type Default Meaning
pluginData map of plugin id to map of key to string {} Private data of a plugin or script: setPluginData(key, value) in the Plugin API writes pluginData[<plugin id>][key]. Scripts run by use_figma have the plugin id ud.
sharedPluginData map of namespace to map of key to string {} Data shared between plugins: setSharedPluginData(namespace, key, value).

Values are strings, as in Figma. Setting a value to "" removes the key (Figma’s rule); in a merge patch the key is set to null. Because the patch merges per key (5.9), two branches that write different keys both survive. Pages, styles, variables and collections have the same two properties.

4.5 Derived values#

These are computed by the core on every surface and never written (LAY-9, ARC-001):

Derived value From
x, y of children in auto layout flow the parent’s auto layout and the children’s sizes
width and height on HUG and FILL axes content and parent
geometry of GROUP and BOOLEAN_OPERATION the union of their children
geometry of auto-sized text (textAutoResize WIDTH_AND_HEIGHT or HEIGHT) the text engine (TXT-5)
text lines, glyph positions, vectorPaths the text engine and the vector network
instance sublayers the main component and the overrides (4.8)
variant properties of a component its name (Size=md, State=Default)
absolute positions, render bounds, relativeTransform, absoluteTransform the stored geometry
resolved variable values bindings, modes and aliases (4.10)

A derived value found in the file (hand edit, older writer) is ignored and dropped at the next consolidation. ud get_metadata and ud inspect report derived values for readers that do not run the core.

4.6 Node types#

Node types and type-specific properties. Every type has the shared properties of 4.4 that apply to it.

type DOC-2 name Has children Type-specific properties
FRAME Frame yes auto layout (4.4.3), corner radii, clipsContent
GROUP Group yes none; geometry derived
SECTION Section yes sectionContentsHidden, devStatus (DOC-8)
RECTANGLE Rectangle, Image no corner radii
ELLIPSE Ellipse no arcData
LINE Line no width is the length; height is 0
POLYGON Polygon no pointCount
STAR Star no pointCount, innerRadius
VECTOR Vector, Arrow no vectorNetwork
BOOLEAN_OPERATION BooleanOperation yes booleanOperation
TEXT Text no text properties (4.6.6)
COMPONENT Component yes auto layout, componentPropertyDefinitions, codeMap
COMPONENT_SET ComponentSet yes (components) auto layout, componentPropertyDefinitions, codeMap
INSTANCE Instance derived; slot content stored componentId, libraryId, componentProperties, overrides
SLOT Slot yes, in a component slotPropertyKey
SLICE Slice no exportSettings only
CONNECTOR Connector no connector properties (4.6.8)
STICKY StickyNote no text, authorVisible

4.6.1 Rectangle and image#

A rectangle’s corners are cornerRadius, the four corner properties and cornerSmoothing. An image is a rectangle with an image fill (4.7.4); the Image tool names it after the file. There is no image node type.

4.6.2 Ellipse#

arcData (DRW-3), Figma’s shape: {"startingAngle": 0, "endingAngle": 6.2831853, "innerRadius": 0}. The angles are in radians, as in Figma, so that the Plugin API maps one to one; this is the only angle in the format not in degrees. innerRadius is a ratio from 0 to 1 (donuts). Default: a full ellipse.

4.6.3 Polygon and star#

pointCount, integer 3 or more, default 3 for polygons and 5 for stars. innerRadius of a star is the ratio of inner to outer radius, 0 to 1, default 0.38.

4.6.4 Vector and vector network#

vectorNetwork (DRW-4) in Figma’s shape. Coordinates are px in the node’s own coordinate system.

json
"vectorNetwork": {
  "vertices": [
    {"x": 0, "y": 0},
    {"x": 24, "y": 0, "strokeCap": "ARROW_LINES"},
    {"x": 12, "y": 18, "cornerRadius": 2, "handleMirroring": "ANGLE_AND_LENGTH"}
  ],
  "segments": [
    {"start": 0, "end": 1},
    {"start": 1, "end": 2, "tangentStart": {"x": 0, "y": 8}, "tangentEnd": {"x": 6, "y": 0}},
    {"start": 2, "end": 0}
  ],
  "regions": [
    {"windingRule": "NONZERO", "loops": [[0, 1, 2]], "fills": [{"type": "SOLID", "color": {"r": 0, "g": 0, "b": 0}}]}
  ]
}
  • vertices[]: x, y; optional strokeCap, strokeJoin, cornerRadius, handleMirroring (NONE, ANGLE, ANGLE_AND_LENGTH).
  • segments[]: start and end are vertex indexes; tangentStart and tangentEnd are handle offsets, absent for a straight segment. A vertex used by more than two segments is a branch.
  • regions[]: closed areas, each a list of loops of segment indexes, with windingRule (NONZERO, EVENODD) and optional fills and fillStyleId. An area that is in no region is not filled: this is how a fill is toggled per area.

The whole network is one property: an edit replaces it. An arrow drawn with the Arrow tool (DOC-2) is a VECTOR with two vertices whose end vertex has an arrow strokeCap.

4.6.5 Boolean operation#

booleanOperation: "UNION", "SUBTRACT", "INTERSECT", "EXCLUDE", default "UNION" (DRW-5). Children stay editable; the result is derived. Flatten replaces the node by a VECTOR (a node.delete and a node.create in one group).

4.6.6 Text with styled runs#

Property Type Default Meaning
characters string "" The text. Line breaks are \n; paragraph breaks are \n too (Figma’s model).
fontName {family, style} {"family":"Inter","style":"Regular"} Figma’s style names ("Semi Bold", CMD-15).
fontSize number, px 12
fontVariations map of axis tag to number {} Variable font axes, e.g. {"wght": 550, "opsz": 14} (TXT-4). Our own.
letterSpacing {unit: "PIXELS" or "PERCENT", value} {"unit":"PERCENT","value":0}
lineHeight {unit: "AUTO"} or {unit: "PIXELS" or "PERCENT", value} {"unit":"AUTO"}
textCase "ORIGINAL", "UPPER", "LOWER", "TITLE", "SMALL_CAPS", "SMALL_CAPS_FORCED" "ORIGINAL"
textDecoration "NONE", "UNDERLINE", "STRIKETHROUGH" "NONE"
textAlignHorizontal "LEFT", "CENTER", "RIGHT", "JUSTIFIED" "LEFT" TXT-3.
textAlignVertical "TOP", "CENTER", "BOTTOM" "TOP"
textAutoResize "NONE", "WIDTH_AND_HEIGHT", "HEIGHT", "TRUNCATE" "WIDTH_AND_HEIGHT" TXT-1.
textTruncation "DISABLED", "ENDING" "DISABLED" Ellipsis.
maxLines integer or absent absent Lines before the ellipsis.
paragraphSpacing, paragraphIndent, listSpacing number, px 0
hangingPunctuation, hangingList boolean false
leadingTrim "NONE", "CAP_HEIGHT" "NONE" TXT-3.
openTypeFeatures map of feature tag to boolean {} e.g. {"TNUM": true, "LIGA": false, "SS01": true} (TXT-4).
hyperlink {type: "URL", value} or {type: "NODE", value} or absent absent
textStyleId st- id absent Text style (4.9).
styledRuns array [] Ranges that differ from the node-level values (below).

Node-level text properties apply to the whole text. styledRuns (TXT-2) lists ranges whose properties differ:

json
"styledRuns": [
  {"start": 0, "end": 9, "fontName": {"family": "Inter", "style": "Bold"}},
  {"start": 20, "end": 35, "fills": [{"type": "SOLID", "color": {"r": 0.23, "g": 0.36, "b": 0.97}}], "hyperlink": {"type": "URL", "value": "https://softforge.dev"}},
  {"start": 36, "end": 80, "listOptions": {"type": "UNORDERED"}, "indentation": 1}
]
  • start and end are offsets in UTF-16 code units, end exclusive, as Figma’s setRange… functions.
  • Runs are sorted by start and do not overlap. A run carries only the properties that differ from the node.
  • A run may carry: fontName, fontSize, fontVariations, letterSpacing, lineHeight, textCase, textDecoration, fills, fillStyleId, textStyleId, hyperlink, openTypeFeatures, boundVariables; and, covering whole paragraphs only, listOptions ({type: "ORDERED" or "UNORDERED" or "NONE"}), indentation, paragraphSpacing, paragraphIndent.
  • characters and styledRuns belong together: a writer that changes the text writes both in the same set. A reader that finds runs beyond the end of the text cuts them to the text, and drops runs that become empty (9.2).

4.6.7 Slot#

SLOT (CMP-5) is a frame-like container inside a component. It has the frame properties and slotPropertyKey, the key of the SLOT component property that exposes it. Its children in the main component are the default content. In an instance, content placed into the slot is stored as real nodes (4.8).

4.6.8 Slice, connector and sticky note#

  • SLICE: geometry and exportSettings; not rendered.
  • CONNECTOR (DOC-2): connectorStart and connectorEnd, each {"endpointNodeId": id, "magnet": "AUTO" or "TOP" or "LEFT" or "BOTTOM" or "RIGHT" or "CENTER"} or {"position": {x, y}}; connectorLineType (ELBOWED, STRAIGHT, CURVED); connectorStartStrokeCap, connectorEndStrokeCap; text (a nested text object with characters and text properties); strokes as usual.
  • STICKY (DOC-2): text as above, fills, authorVisible (boolean), authorName (string).

4.7 Paints and effects#

4.7.1 Colours and units#

Quantity Unit or shape
Length, position, size, radius, spacing, font size px, as a JSON number
Rotation degrees, counter-clockwise (except arcData, radians, 4.6.2)
Opacity, ratios, corner smoothing 0 to 1
Colour {"r": 0.231, "g": 0.357, "b": 0.965, "a": 1}, floats from 0 to 1 in the document’s colour profile
Duration, delay seconds
Timestamp UTC text YYYY-MM-DDTHH:MM:SS.sssZ (5.6)

Where Figma uses an RGB colour with a separate opacity, so does the file: the color of a SOLID paint is {r, g, b} without a, and its transparency is the paint’s opacity. Everywhere else (gradient stops, effects, layout grids, variable values of type COLOR) a colour has a. A reader that finds a in a solid paint’s color multiplies it into the paint’s opacity.

Numbers are written with at most 6 significant decimals; writers round, readers accept any JSON number.

4.7.2 Paint#

Every paint has type and optional visible (default true), opacity (default 1) and blendMode (default "NORMAL").

type Members Requirement
SOLID color {r,g,b}; boundVariables {"color": alias} STY-1
GRADIENT_LINEAR, GRADIENT_RADIAL, GRADIENT_ANGULAR, GRADIENT_DIAMOND gradientTransform (2×3 matrix [[a,b,c],[d,e,f]] in the node’s unit square), gradientStops ([{"position": 0-1, "color": {r,g,b,a}, "boundVariables": {"color": alias}}]) STY-1, STY-2
IMAGE imageHash (sha256-…), scaleMode, imageTransform, scalingFactor, rotation, filters STY-3, section 4.7.4

4.7.3 Variable-bound paints#

A paint bound to a variable keeps its plain colour as the fallback (4.4.5):

json
{"type": "SOLID", "color": {"r": 0.231, "g": 0.357, "b": 0.965}, "boundVariables": {"color": {"type": "VARIABLE_ALIAS", "id": "vr-7b9d1f3a5c7e"}}}

A variable from a library is named by a qualified id, "lib-…/vr-…" (4.11).

4.7.4 Image paint#

json
{
  "type": "IMAGE",
  "imageHash": "sha256-9c2f0e6b1a7d3c5e8f4b2a1d0c9e7f6a5b4c3d2e1f0a9b8c7d6e5f4a3b2c1d0e",
  "scaleMode": "FILL",
  "rotation": 0,
  "filters": {"exposure": 0, "contrast": 0.1, "saturation": 0, "temperature": 0, "tint": 0, "highlights": 0, "shadows": 0}
}
Member Type Default Meaning
imageHash sha256-<64 hex> required Content hash of the image file in the assets folder (section 8).
scaleMode "FILL", "FIT", "CROP", "TILE" "FILL" STY-3.
imageTransform 2×3 matrix identity Crop rectangle, for CROP.
scalingFactor number 1 Tile scale, for TILE.
rotation 0, 90, 180, 270 0 Degrees.
filters object of numbers from -1 to 1 all 0 exposure, contrast, saturation, temperature, tint, highlights, shadows.

4.7.5 Effect#

Figma’s shape (STY-6):

type Members
DROP_SHADOW color {r,g,b,a}, offset {x,y}, radius (blur), spread, blendMode, showShadowBehindNode, visible
INNER_SHADOW color, offset, radius, spread, blendMode, visible
LAYER_BLUR radius, visible
BACKGROUND_BLUR radius, visible

Each effect may carry boundVariables for color, radius, spread, offsetX, offsetY.

4.8 Components, instances, overrides and slots#

Main component. A COMPONENT node is a frame that other nodes can instantiate (CMP-1). It and its descendants are ordinary nodes in the node map. A COMPONENT_SET holds COMPONENT children that are its variants (CMP-4); a variant’s properties come from its name, Size=md, State=Default.

Component property definitions (CMP-5) are on the component, or on the component set for a set:

json
"componentPropertyDefinitions": {
  "Size": {"type": "VARIANT", "defaultValue": "md", "variantOptions": ["sm", "md", "lg"]},
  "Label#a41c": {"type": "TEXT", "defaultValue": "Button", "description": "Button text"},
  "Show icon#5d02": {"type": "BOOLEAN", "defaultValue": false},
  "Icon#77b0": {"type": "INSTANCE_SWAP", "defaultValue": "nd-0e2c4a6b8d1f", "preferredValues": [{"type": "COMPONENT", "key": "nd-0e2c4a6b8d1f"}]},
  "Content#c3e1": {"type": "SLOT", "description": "Body of the card"}
}

Keys are Figma’s: a variant property is its plain name; any other property is <name>#<4 hex digits>, the suffix chosen at random when the property is created so that renaming the property keeps its key. Layers inside the component refer to these keys through componentPropertyReferences (4.4.5). For a variant property, variantOptions is derived from the variants’ names and written only by consolidation.

Instance. An INSTANCE node shows a copy of its main component. Its sublayers are not stored; they are derived from the main component every time it is read, which is what makes a main component change reach every instance at once (CMP-2).

Property Type Default Meaning
componentId node id or qualified id required The main component, or a variant of a set. lib-…/nd-… for a library component (4.11). When it names a component in tree.deletedComponents, the instance renders from that snapshot (4.16).
componentProperties map of property key to value {} Values that differ from the definitions’ defaults: {"Label#a41c": "Sign in", "Size": "lg"}. Plain values; the Plugin API layer adds type from the definition.
overrides map of override path to merge patch {} Changed properties of sublayers (below).
other shared properties from the main component A property written on the instance itself overrides the main component’s root; one not written follows it.

Override paths. A sublayer of an instance is named by the ids of the nodes from the main component down to it, joined by /. For a layer nd-b directly inside the main component the path is nd-b. For a layer nd-d inside a nested instance nd-c whose component contains nd-d, the path is nd-c/nd-d.

json
"overrides": {
  "nd-2b7d9e4f6a10": {"fills": [{"type": "SOLID", "color": {"r": 0.1, "g": 0.1, "b": 0.1}}]},
  "nd-5a1c3e7f9b20/nd-0d2f4b6a8c1e": {"visible": false},
  "nd-5a1c3e7f9b20": {"componentId": "nd-1e3a5c7d9f02"}
}
  • An override is a merge patch of the sublayer’s properties (5.9): it holds only what differs.
  • componentId in an override swaps a nested instance (CMP-3, CMP-6).
  • The derived id of a sublayer is <instance id>/<override path>, for example nd-e7a9c1b3d5f0/nd-2b7d9e4f6a10. The Plugin API returns it as the sublayer’s id, ud accepts it wherever a node id is accepted, and setting a property on it writes an instance.override event.
  • An override whose path no longer matches a layer of the main component (the layer was deleted, or the instance was swapped) is kept but has no effect; it applies again if the layer returns. ud lint reports such dormant overrides; instance.reset removes them.

Slots. Content placed into a slot of an instance (CMP-5) is stored as ordinary nodes whose parent is the derived id of the slot: "parent": "nd-e7a9c1b3d5f0/nd-7f9b1d3c5e2a". When the instance has content in a slot, that content replaces the slot’s default content. If the slot disappears from the main component, its content nodes are orphans (6.5).

Detach. instance.detach turns the instance into a FRAME with the same id and writes its derived sublayers as real nodes with new ids (5.11.4).

4.9 Styles#

tree.styles maps st- ids to styles (VAR-1).

Member Type Default Meaning
type "PAINT", "TEXT", "EFFECT", "GRID" required Figma’s StyleType.
name string required Groups by /: Brand/Primary.
index fractional index required Order among styles of the same type.
description string ""
paints paint array [] PAINT styles.
text properties as in 4.6.6 as in 4.6.6 TEXT styles: fontName, fontSize, fontVariations, letterSpacing, lineHeight, paragraphSpacing, paragraphIndent, textCase, textDecoration, leadingTrim, openTypeFeatures.
effects effect array [] EFFECT styles.
layoutGrids layout grid array [] GRID styles.
boundVariables object {} Bindings of the style’s values.
hiddenFromPublishing boolean false Not offered by the library.
pluginData, sharedPluginData {}

Nodes refer to styles with fillStyleId, strokeStyleId, effectStyleId, textStyleId and gridStyleId, and keep the plain values next to the reference (4.4.5). A change of a style changes every user at once, because the style wins when it resolves.

4.10 Variables, collections, modes and aliases#

Variable collection (tree.variableCollections, key vc- id, VAR-2):

Member Type Default Meaning
name string required
index fractional index required Order among collections.
modes map of md- id to {name, index} required, at least one Modes, ordered by index. Figma’s modes array is derived from it.
defaultModeId md- id the mode with the lowest index The mode used when nothing chooses one.
hiddenFromPublishing boolean false
pluginData, sharedPluginData {}

Variable (tree.variables, key vr- id):

Member Type Default Meaning
name string required Groups by /: color/bg/surface. Unique within the collection.
variableCollectionId vc- id required Its collection.
index fractional index required Order within the collection; Figma’s variableIds is derived from it.
resolvedType "COLOR", "FLOAT", "STRING", "BOOLEAN" required
valuesByMode map of mode id to value or alias {} A value of the type (a colour is {r,g,b,a}), or {"type": "VARIABLE_ALIAS", "id": "vr-…"} (VAR-3).
description string ""
scopes array of Figma’s VariableScope ["ALL_SCOPES"] Where the variable is offered (VAR-5): ALL_FILLS, FRAME_FILL, TEXT_FILL, STROKE_COLOR, GAP, CORNER_RADIUS, WIDTH_HEIGHT, FONT_SIZE, …
codeSyntax map of platform to string {} {"WEB": "var(--color-bg)", "ANDROID": "colorBg", "iOS": "Color.bg"} (VAR-5).
hiddenFromPublishing boolean false
pluginData, sharedPluginData {}

Resolution. The value of a variable for a node is found as follows:

  1. The mode: the nearest explicitVariableModes entry for the variable’s collection, on the node or an ancestor, then on the page; else the collection’s defaultModeId.
  2. The value: valuesByMode[mode]; if absent, valuesByMode[defaultModeId]; if absent, the type’s zero (transparent black, 0, "", false), with a warning from ud lint.
  3. An alias is resolved again from step 1, for the aliased variable’s collection, with the same node. A chain longer than 32 or a cycle resolves to the type’s zero and is reported (9.2). Writers refuse to create a cycle (VAR-3).

valuesByMode merges per mode (5.9): two branches that set the Light and the Dark value of one variable both survive.

4.11 Libraries#

A file that publishes a library has document.library (4.2). A file that uses one lists it in tree.libraries (VAR-7):

Member Type Default Meaning
path string required Path of the library file relative to this file, with / separators: ../design-system/tokens.design. May point into node_modules for a git-tracked package.
documentId doc- id required The library’s document.id. A reader that finds another document at path looks for this id among the .design files of the workspace before it reports the library as missing.
name string the library’s name Display name.
enabled boolean true Offered in the Assets panel.
acceptedHash tree hash or absent absent The library’s tree hash (6.9) at the last accepted update (VAR-8). A seq cannot name a state across branches, so a hash does.
imported object {} Copies of what this file uses from the library, as of acceptedHash (below).

Qualified ids. A reference to something in a library is the library id, a slash and the id inside the library: lib-1f3b5d7a9c0e/nd-8a3f1c5e7b92, lib-1f3b5d7a9c0e/vr-7b9d1f3a5c7e. It is accepted wherever the local id would be: componentId, style ids, variable aliases, boundVariables.

Imported copies. imported keeps everything this file uses from the library, so the file renders when the library is missing, on another branch or not yet updated:

json
"imported": {
  "nodes": { "nd-8a3f1c5e7b92": { }, "nd-2b7d9e4f6a10": { } },
  "styles": { "st-4d6f8a0c2e1b": { } },
  "variableCollections": { "vc-2c4e6a8b0d1f": { } },
  "variables": { "vr-7b9d1f3a5c7e": { } }
}

Each map has the shape of the tree’s map of the same name, with the library’s ids. For a component, the copy holds the component and all its descendants. The copies are what instances and references use; the library file itself is read only to find updates. When the library’s current tree hash differs from acceptedHash, the editor shows “Updates available” (VAR-8); accepting writes a library.accept event that carries the new copies and the new hash.

4.12 Prototype flows#

tree.flows maps fl- ids to flows (PRO-6, DOC-1):

Member Type Default Meaning
pageId page id required The page the flow belongs to.
name string required
index fractional index required Order among the page’s flows.
nodeId node id required The starting frame.
description string ""
device {type, rotation} {"type":"NONE"} Device frame of the preview player.
background colour page background Background in the player.

Figma’s page.flowStartingPoints is derived from the page’s flows.

4.13 Comments#

tree.comments maps cn- ids to comments (COL-3):

Member Type Default Meaning
parentId cn- id or absent absent Absent for the first comment of a thread; the thread’s first comment for a reply.
message string required Text; mentions are written @<name>.
by string required Author: the by of the creating event.
at timestamp required Time: the at of the creating event.
editedAt timestamp absent Last edit.
anchor object required for a thread, absent for replies {"nodeId": id, "offset": {x, y}} pinned to a node, or {"pageId": id, "x": n, "y": n} pinned to a point of the canvas.
mentions array of strings [] Names mentioned (git authors).
reactions map of reaction to array of names {} Reactions as short codes without colons, e.g. {"+1": ["Ada"], "eyes": ["Grace"]}.
resolved boolean false On a thread: resolved.

Replies are ordered by at, then by id. A thread whose anchor node was deleted keeps its last absolute position on its page.

4.14 Named versions#

tree.versions maps vs- ids to named versions (COL-2):

Member Type Meaning
title string Required.
description string Default "".
by, at string, timestamp From the version.save event.
treeHash tree hash The tree hash (6.9) of the document the version names: every event before the version.save folded. Written by the writer of the event.

The version is the document as it was just before its version.save event, in file order. A seq would not name that state across branches (two branches give one number to different events), so the hash does; it also tells whether a working copy is still at the version (--if-version, CLI-001).

Consolidation keeps versions (COL-2). The document as it was at a version is computed from the WAL when the version.save event is still in it; otherwise it is read from the git history of the file, from the last commit whose file still holds the version.save event (ud versions show <id>), and checked against treeHash. A version older than both is listed but cannot be previewed.

4.15 Asset metadata#

tree.assets maps content hashes to metadata of the files in the assets folder (section 8):

Member Type Meaning
kind "image", "font" Required.
mime string image/png, image/jpeg, image/webp, image/gif, image/avif, image/svg+xml, font/ttf, font/otf, font/woff2.
ext string File extension without the dot: the file is <hash>.<ext>.
bytes integer File size.
width, height integer, px Images: intrinsic size.
name string Original file name, for display.
family, style string Fonts: the font’s family and Figma-style style name.

The bytes are never in the design file (NFR-3).

4.16 Deleted components#

tree.deletedComponents maps the id of a deleted main component (COMPONENT or COMPONENT_SET) to a snapshot of its subtree, taken when it was deleted while instances still used it (CMP-2):

Member Type Meaning
nodes map of node id to node The component and all its descendants, as they were in tree.nodes just before the delete, with their ids as keys and their parent and index as they were. For a COMPONENT_SET, the set, its variants and their descendants.
deletedAt, deletedBy timestamp, string The at and by of the deleting event.
json
"deletedComponents": {
  "nd-8a3f1c5e7b92": {
    "deletedAt": "2026-10-08T09:00:00.000Z",
    "deletedBy": "Grace",
    "nodes": {
      "nd-8a3f1c5e7b92": {"type": "COMPONENT", "name": "Button", "parent": "pg-6f7e8d9c0b1a", "index": "a0", "…": "…"},
      "nd-2b7d9e4f6a10": {"type": "TEXT", "name": "Label", "parent": "nd-8a3f1c5e7b92", "index": "a0", "…": "…"}
    }
  }
}
  • Instances keep rendering. An instance whose componentId names an entry here derives its sublayers from the snapshot exactly as from a live component, overrides included, and the editor marks it “Deleted component”. The same file therefore renders the same whatever the reader has seen before (2.1), and the snapshot survives consolidation (section 7).
  • The snapshot is a copy, not a component. It is not on any page, is not offered in the Assets panel, and no event changes it. instance.detach works on such an instance as on any other.
  • Restore. component.restore (5.11.3) puts the nodes back into tree.nodes with their ids and removes the entry, as Figma’s “Restore component”. Ids are never reused (5.5), so the ids are free.
  • Dropped when unused. Consolidation drops an entry no instance refers to any more (7).

How the snapshot gets there is in node.delete (5.11.2).