v1.0.0 · Unity 2021.3+

FigSync LITE

The free way to bring Figma into Unity. Paste a Figma URL. Press Sync. Your frame lands in the scene as a real UGUI Canvas — with the right anchors, the right gradients, and the right rounded corners. FigSync LITE imports one frame per run; FigSync Full adds unlimited frames, incremental re-sync, the live Figma plugin and much more.

FREE · LITE edition Unity 2021.3+ UGUI / Canvas URP / Built-in Editor Tool
You're reading the LITE (free) edition docs. FigSync LITE imports via the Figma REST API (Personal Access Token), converting one top-level frame per run (up to 100 GameObjects) into a static UGUI Canvas — layout, images, text (default font), gradients and rounded corners. Sections below tagged FULL describe paid-edition features.
Upgrade to FigSync Full for unlimited / batched frames, incremental Sync & Diff (re-import & merge only what changed), the live Figma Bridge + offline ZIP, font matching & Google Fonts, interactive components (Button/Toggle/Input/ScrollView), responsive auto-layout, shadows & blur, 9-slice, sprite/prefab reuse, code generation and localisation.  → Get FigSync Full on the Asset Store ★

LITE vs Full — at a glance

Feature FigSync LITE (Free) FigSync Full
Figma → Unity UGUI import
Layout, anchors, images & text
Gradients & rounded corners
Online import (Figma URL + token)
Frames per import1Unlimited
GameObjects per import100 maxUnlimited
Font matching, Google Fonts download & TMP atlases (LITE uses default font)
Incremental Sync & Diff (re-import & merge)
Live Figma Bridge (plugin push)
Offline ZIP import
FigJam support
Interactive components (Button / Toggle / Input / ScrollView)
Responsive auto-layout (LayoutGroups)
Shadows & blur effects
9-slice borders
Sprite & prefab reuse (de-dup)
Code generation (binding scripts)
Localisation (Unity Localization / i2)
Import events (UnityEvents)

★ Upgrade to FigSync Full

Free-tier import cap. FigSync LITE imports one frame and up to 100 GameObjects per run. If a frame needs more, drawing stops at 100 and a notice appears — try a smaller frame, or upgrade to FigSync Full for designs of any size.

This document covers the FigSync workflow. Start with Installation and Quick Start; go deep on How It Works for the pipeline detail; reach Troubleshooting when something doesn't import the way you expect. Features marked FULL are part of FigSync Full, not the LITE edition.

Installation

Import once. The Hub window lights up from the menu.

From the Unity Asset Store

Open Package Manager
In Unity 2021.3 or later, open Window → Package Manager and switch the dropdown to My Assets.
Find FigSync, click Download then Import
Accept the import dialog with everything checked. The package lands at Assets/FigSync/.
Wait for compile
Unity recompiles editor scripts. First-time compile takes ~30 s; later imports are faster.
Open the Hub
Tools → FigSync. Everything you need — URL, sync, settings, status — is in one window.

Prerequisites

FigSync uses Unity packages that ship with a default Unity 2021.3+ install:

If TMP Essential Resources isn't imported yet, the first sync will surface a one-time warning. Run Window → TextMeshPro → Import TMP Essential Resources and re-sync.

What gets installed

Assets/FigSync/
  Editor/                     // Pipeline, drawers, settings, hub window
    Bridge/                   // Local HTTP bridge for the Figma plugin
    Drawers/                  // One drawer per Unity UGUI component
    Hub/                      // Tools → FigSync window + settings store
    Pipeline/                 // Numbered Step01..Step26 deterministic flow
    Settings/                 // Per-tab settings UI (UI Toolkit)
    Web/                      // Figma REST + Google Fonts clients
  Runtime/                    // Shaders, helper components, ScriptableObjects
    Components/               // FigSyncSyncHelper, dropshadow, blur, etc.
    Shaders/                  // SDF rounded-corner + gradient
  Generated/                  // Per-sync output: sprites, fonts, snapshot, report
  Documentation/              // You are hereProject
The Generated/ folder is yours. FigSync writes downloaded sprites, fonts, and the diff snapshot here. It's safe to re-sync anytime; the folder is rebuilt deterministically.

🔌 Figma Plugin FULL

The fastest path for FigJam files, complex frames, or offline sync.

🔒
Full edition. The FigSyncExporter plugin, the local Bridge and offline ZIP import are not included in LITE — LITE imports via a Figma URL + token. Upgrade to FigSync Full ★

FigSync ships with a Figma plugin called FigSyncExporter. Installed in Figma, it captures the full plugin-API node tree (which is richer than REST), bundles every fill image and pre-rendered vector raster, and pushes the result to Unity over a local HTTP bridge. The Unity Hub picks up the push automatically — no copy/paste of node ids.

Why use the plugin path

☀️ FigJam support

Stickies, connectors, shape-with-text only appear in the plugin's node tree — FigJam files won't import via REST.

⚡ One-click push

Hit Send to Unity in Figma; Unity starts the sync. No personal-access token to create and no URL to paste — you push straight from the file you're designing.

📁 Offline iteration

Each push saves a .figsync.zip bundle locally; you can re-sync from disk later without Figma being open.

📊 Richer geometry

Plugin API exposes fillGeometry path data on every vector node; REST is occasionally sparser.

Install the plugin

In Figma, open the Plugins menu
Menu → Plugins → Development → Import plugin from manifest...
Point at the bundled manifest
In Unity, run Tools → FigSync → Open Figma Plugin Folder (or browse to Assets/FigSync/FigmaPlugin/), then select manifest.json. Tip: Tools → FigSync → Set Up Figma Bridge… walks you through this with live connection status.
Verify the bridge is running
In Unity, open Tools → FigSync → Settings → Auth. The status pill should read Bridge: listening on 127.0.0.1:8473.
Push from Figma
Open the FigSyncExporter plugin from your Plugins menu, choose scope (Current page / All pages), click Export. Unity receives the bundle and starts a sync.
The bridge is loopback-only. The HTTP listener binds to 127.0.0.1 and accepts only CORS requests originating from Figma's domains. No external network traffic.

Quick Start

Zero to a synced Canvas in about a minute.

Open the Hub
Menu: Tools → FigSync. The window has tabs for Source, Settings, and Status.
Set your Figma token
Paste a Personal Access Token via Tools → FigSync → Set Figma Personal Access Token (or the token badge in the Hub).
Paste a Figma URL
Copy a frame URL from Figma (right-click frame → Copy link). Paste into the Figma URL field in the Hub's Sync tab.
Click Sync
The pipeline runs its deterministic steps with per-step status. LITE imports one top-level frame per run; first sync takes ~10-90 s depending on sprite count.
Inspect the scene
A FigSync Canvas GameObject appears in the active scene. The frame renders in the Game view as a static UGUI hierarchy — layout, images and text (default font).
Need the whole design, not one frame? FigSync Full imports unlimited frames in a batch, re-syncs incrementally (only redrawing what changed while preserving your edits), and adds the live Figma plugin. Upgrade to FigSync Full ★

How It Works

A 27-step deterministic pipeline, runnable resumable cancellable.

Source Flatten Tag & Classify Hash & Diff Draw Sprites & Fonts Finalise

Each sync runs as a sequence of named steps. Steps log their start and finish to the Console (look for the [FigSync] prefix); the Hub window mirrors the same status as a per-step progress strip. A failed step stops the pipeline early; the scene either keeps the prior state intact (if the failure happened pre-Draw) or surfaces the partial result with a HelpBox explaining where it broke.

Steps, in order

StepWhat it does
DownloadNodesLoads the Figma node tree from REST, the plugin bundle, or local cache.
WrapInPageEnsures the document root is wrapped in a CANVAS / PAGE node for uniform traversal.
ClearCachesResets per-sync sidecars (UnchangedNodeIds, DeferredNodeIds, external-children rescue map).
FlattenWalks the tree depth-first; produces a FlatList of NodeAux entries with parent/depth indices.
TagTags each node by FigmaType + manual sidecar markers (Frame, Text, Image, Vector, Mask, Shadow, Page, etc.).
ClassifyImagesDecides which nodes route through the PNG raster path vs the procedural draw path.
PropagateInsideDownloadableMarks descendants of a Downloadable parent so they aren't drawn separately.
HashComputes a 128-bit content hash per node (visual properties + children) using xxHash3.
NameFolders / NameFiles / NameStylesheetClassesResolves Figma names through the sanitiser into Unity-safe folder, file, and class names.
PickRootFramesIdentifies top-level frames worth surfacing in the diff window.
ShowDiffWindowIf a prior snapshot exists, compute the diff and prompt the user to confirm or defer roots.
LoadPrefabMatchesWires Figma node ids back to existing scene GameObjects with matching FigSyncSyncHelper stamps.
DrawHierarchyThe main draw pass. One GameObject per Figma node; one drawer per tag.
RePickRootFrames / CountTags / SpritePathsPost-Draw planning for sprite IO.
DownloadSprites / FlushSpritesPulls /v1/images PNGs (or reads them from the plugin bundle); writes them to Generated/.
GenerateSprites / SliceSprites / ColorizeSpritesProcedural sprite synthesis for nodes that don't need raster (white quads, solid fills).
DedupeSpritesHash-merges visually identical sprite outputs so the project doesn't double-store them.
DownloadFontsResolves font families through Google Fonts (Webfonts API or fontsource fallback), bakes TMP _SDF assets.
FrameworkFinalisePer-backend post-pass: rounded corners, shadows, layout drivers, text binding, FigJam canvas dots.
DiagnosticReportWrites _figsync_report.json (telemetry) and _figsync_snapshot.json (hash snapshot for next-run diff).

What happens at Draw time

The Draw step iterates the FlatList. Each entry is either reused, deferred, or freshly drawn:

What happens at Finalise time

After every node has a GameObject, a per-backend Finalise pass runs second-pass work that needs the full hierarchy in place:

🔒 Authentication

Three options. Pick one. Or two.

Option 1 — Personal Access Token

Simplest path. Generate a token at figma.com/settings (Personal access tokens section), paste it into Tools → FigSync → Settings → Auth → Personal Access Token. The token stays in EditorPrefs (base64-obfuscated, never written to assets) and is sent only over HTTPS to Figma's REST API.

Option 2 — OAuth

Click Sign in with Figma in the Auth tab. A browser tab opens Figma's consent screen; after approval Figma redirects to a one-shot local listener on 127.0.0.1 with the auth code. FigSync exchanges that for an access + refresh token pair and stores both in EditorPrefs (same obfuscation as the PAT). Refresh tokens rotate automatically; expired tokens trigger a transparent refresh on next call.

Option 3 — The Figma plugin FULL

No tokens needed. Install the plugin in Figma and push directly. The plugin reads node data using its own Figma plugin sandbox permissions; FigSync receives an HTTPS-style ZIP bundle over a loopback port. No credentials leave your machine.

 TokenOAuthPlugin
Setup time30 s1 min (browser hop)2 min (plugin install)
Re-auth neededNever (until you revoke)Refresh auto-rotatesNever
FigJam filesNo (REST limitation)No (REST limitation)Yes
Offline syncNoNoYes (saved ZIPs)
Rate limitedYes (Figma policy)Yes (Figma policy)No
What's storedOne token in EditorPrefsAccess + refresh tokens in EditorPrefsNothing
You can combine paths. Keep a token configured as a fallback while using the plugin as your daily driver. FigSync prefers the plugin bundle when one is freshly pushed, falls back to REST when a URL is pasted directly.

🌐 The Hub Window

One window, every control. Tools → FigSync.

Source tab

The everyday surface. Paste a Figma URL, choose the source mode (Live URL, Offline ZIP, Bridge push), and click Sync. A status strip across the top of the window mirrors what's happening behind the scenes — current step, elapsed time, last warning. A right-side panel shows the last sync's diagnostic summary (node count, sprite count, fonts bound, missing fonts, anything that went sideways).

Settings tabs

Each tab edits one slice of the FigSyncProjectSettings ScriptableObject (lives at Assets/FigSync/FigSyncProjectSettings.asset; commit it). Changes apply on next sync.

In LITE the FULL tabs appear as locked upgrade cards.

🔍 Diff & Re-sync FULL

🔒
Full edition. LITE performs a clean full import every run (no diff window, no selective merge, no edit-preserving re-sync). Incremental Sync & Diff is part of FigSync Full. Upgrade ★

Re-sync without losing the work you did between syncs.

After every successful sync FigSync writes a hash snapshot of the node tree to Generated/_figsync_snapshot.json. On the next sync, the pipeline diffs the incoming nodes against that snapshot before any scene mutation. The result is a per-root summary of what would change.

The diff window

When there's at least one change, the diff window opens before DrawHierarchy:

What "preserve" means at the GameObject level

Three cases survive a re-sync identically:

📝 Inspector edits

Material overrides, animation triggers, references wired in the inspector — persisted on the unchanged GameObjects.

📚 Added components

Anything you've added — controllers, behaviours, audio sources — stays attached to the same GameObject across syncs.

📋 Added children

Non-FigSync children dropped under a synced GameObject are rescued and re-parented to the freshly-drawn replacement if the parent's hash changed.

First sync, no snapshot

The diff window is skipped on first sync — nothing to compare against. The pipeline writes a snapshot at the end. Every sync from the second onwards benefits from the diff path.

📐 Auto-Layout FULL

🔒
Full edition. LITE bakes pixel-faithful absolute positions (which look correct for a static import). Responsive UGUI LayoutGroups are part of FigSync Full. Upgrade ★

Figma's auto-layout maps to UGUI LayoutGroup + ContentSizeFitter end-to-end.

A Figma frame with auto-layout becomes a Unity GameObject with the matching HorizontalLayoutGroup, VerticalLayoutGroup, or GridLayoutGroup, plus a ContentSizeFitter when the sizing mode is "Hug contents". Children flow in the same direction, with the same padding, gap, and primary/counter alignment.

What's wired

What's not wired

See the dedicated Known Limitations for the specifics:

🔗 Constraints (Anchors)

Figma per-axis constraints drive UGUI anchors so layouts respond to Canvas resize.

Every Figma child carries a per-axis constraint (Min / Max / Center / Stretch / Scale). FigSync maps them onto the child's anchorMin / anchorMax + offsetMin / offsetMax so the child reacts the right way when its parent rect changes size.

Figma constraintHorizontal effectVertical effectUnity anchors
MinPinned to leftPinned to top(0,1) — (0,1)
MaxPinned to rightPinned to bottom(1,0) — (1,0)
CenterCentered horizontallyCentered vertically(0.5,0.5) — (0.5,0.5)
StretchResizes with parent (L/R)Resizes with parent (T/B)(0,*) — (1,*)
ScaleScales proportionallyScales proportionally(0,0) — (1,1)

Re-sizing the root Canvas at runtime should re-flow the design exactly the way it would in Figma's preview.

🌈 Gradients

Four gradient kinds, rendered procedurally in one SDF shader.

FigSync renders Figma gradients on the GPU instead of baking them to a texture. Four kinds are supported: GRADIENT_LINEAR, GRADIENT_RADIAL, GRADIENT_ANGULAR, and GRADIENT_DIAMOND — the full set Figma can author. Multi-stop ramps up to 4 stops render natively; 5+ stop ramps collapse to first + last + two middle stops (see Known Limitations).

How gradients render

The same FigSync/RoundedCorner SDF shader that handles rounded corners also handles gradients. The two are composed at the fragment level: gradient sampled first, alpha multiplied by the corner SDF, output to screen. One Image + one Material per node, no extra draw call.

What's preserved

Rounded Corners

SDF rounded corners with per-corner radii, stroke band, drop shadow, inner shadow.

Nodes with a non-zero corner radius receive a FigSyncRoundedCorner runtime component (built on Unity's BaseMeshEffect). The component encodes the corner radii, stroke width, drop-shadow offset, and inner-shadow offset into the mesh's UV channels — one shader draws every effect against the SDF distance field, no extra GameObjects or quads.

What's encoded

Why an SDF shader instead of PNG raster

SDF stays crisp at any scale — rounded buttons look right at 0.5x and 4x zoom alike. PNG raster would force a fixed-resolution bake that aliases under scale. The SDF path also unifies stroke + corner + shadow into a single draw call, so a screen with 50 rounded panels is 50 draw calls, not 200.

Shadows & BackgroundBlur FULL

🔒
Full edition. Drop / inner shadows and layer / background blur are part of FigSync Full; LITE imports the flat fill only. Upgrade ★

Drop shadow, inner shadow, layer blur, and Figma's signature glass effect.

Drop & inner shadow

Up to four stacked drop shadows and four stacked inner shadows per node, all rendered against the same SDF. No extra GameObjects, no overlay quads — just additional uniforms on the shared material. Stacking is preserved: Figma's first shadow is the topmost layer.

Layer blur

A Figma LayerBlur effect on a leaf node renders procedurally by widening the SDF edge. On a node with children, the procedural path can't blur the descendants — FigSync routes the whole subtree to the PNG raster path where Figma bakes the blur server-side, then displays the result as a Unity sprite.

Background blur (the glass effect)

A Figma BackgroundBlur blurs whatever sits behind the consumer node — the iOS-style frosted-glass look. FigSync ships a procedural backdrop:

Background blur requires a Camera-mode Canvas. Screen Space - Overlay canvases don't go through Unity's camera-render path, so the compositor has nothing to snapshot. Switch the canvas to Screen Space - Camera with a Render Camera assigned and the compositor picks up the change on its next tick. Scene view can show smeared sampling for the same reason; verify in Game view.

Text & Fonts

TMP text rendering with mixed inline styles. Font matching & download are FULL.

🔒
In LITE: text imports (size, colour, alignment, wrapping, rich-text) on the default TMP font. Font-family matching, Google Fonts download and TMP atlas baking are FULL. Upgrade ★

Text rendering

Every Figma TEXT node becomes a Unity TextMeshProUGUI. Size, alignment, line height, letter spacing, and colour map directly. Multi-line text wrap respects the bbox width; single-line bbox-height nodes get NoWrap so labels overflow horizontally instead of stacking.

Automatic font download FULL

The DownloadFonts step resolves every font family used in the file through:

  1. Your Google Fonts API key, if you've set one in Settings → Auth (returns TTFs from gstatic.com directly).
  2. The public Google Fonts CSS endpoint as fallback.
  3. The Fontsource CDN for variable fonts Google ships only as WOFF2.
  4. The Adobe Edge font index for non-Google families.

Each resolved TTF is imported as a Unity Font and baked into a TMP _SDF.asset at Generated/Fonts/<Family>-<Weight>.asset. On subsequent syncs the baked asset is reused — no re-download.

Fonts that didn't resolve FULL

For proprietary families (Whyte, Figma Hand, custom) or Google variable fonts that don't ship a TTF download path (Inter, Newsreader), the import surfaces a one-shot dialog at the end of the sync listing what to drop in. Save the TTFs to Assets/FigSync/Generated/Fonts/ using the convention <Family>-<weight>.ttf (e.g. Inter-400.ttf); the next sync auto-binds them to every matching text component.

Mixed inline styles

A single Figma text node can mix weights, italics, underlines, and strikethroughs per character. FigSync reads the per-segment styling and emits TMP rich-text tags (<b>, <i>, <u>, <s>) for the segments that diverge from the node-level base style. Cross-family inline segments keep their weight + italic but render in the base family asset (see Known Limitations for the TMP atlas reason).

🎨 Sprites & Atlases

Auto-classified, auto-deduped, auto-sliced.

Some nodes can't be drawn procedurally — complex vector icons, photo fills, baked illustrations. For those, FigSync pulls a PNG from Figma's /v1/images endpoint (or reads the pre-rendered PNG from the plugin bundle), saves it under Generated/<FolderName>/<NodeName>.png, and binds it as an Image.sprite.

How classification works

The ClassifyImages step decides per-node whether to route to the raster path:

Dedup FULL

The DedupeSprites step hashes every freshly-written PNG; duplicates (same pixel content) collapse to a single asset on disk with the other nodes pointing at it via reference. Cuts asset count and binary size sharply on screens with repeated iconography.

Slicing (9-slice) FULL

The SliceSprites step looks for the manual sidecar convention — a node named BG/9slice or with a tag suffix — and writes 9-slice border data into the sprite asset's border field so UGUI Image rendering with type Sliced reuses the same texture across multiple sizes.

☀️ FigJam Support

Stickies, connectors, shape-with-text, and the signature dotted canvas.

FigJam files are first-class. The pipeline auto-detects FigJam at the editor level (the editorType field in meta.json, with a node-type heuristic fallback for older exports) and switches on FigJam-specific rendering paths.

What's rendered natively

The dotted canvas backdrop

FigJam's signature dotted-grid canvas isn't a Figma node — it's painted by FigJam itself behind whatever's on the page. Frames that look "white on left, dotted on right" actually have a transparent right half with the canvas dots showing through. FigSync detects FigJam files and injects a _FigJamCanvasDots Image as the lowest sibling under each page. The tile is 24×24 px, opaque, with a soft grey dot — matches FigJam's rendered look in side-by-side comparisons.

Inline icons over text

FigJam tutorial frames often place an icon (.key / ctrl / esc) over a run of whitespace inside a text node ("Press           and drag"). Figma renders the space narrow enough to fit the icon; TMP renders it wider and forces an early wrap. FigSync rewrites runs of 3+ consecutive spaces as <space=Npx> TMP tags so the line wraps where Figma intends it to.

🔧 Settings

One ScriptableObject. Safe to commit.

Settings live as a ScriptableObject at Assets/FigSync/FigSyncProjectSettings.asset. Edit through the Hub window's tab views, or select the asset and use the Inspector.

🔒
LITE settings tabs. Main, Auth, Images & Sprites, Text & Fonts and Debug are available in LITE. The Buttons, Shadows, Localisation, Prefab Creator, Script Generator and Import Events tabs configure FULL features and appear as locked upgrade cards. See FigSync Full ★
FieldDefaultDescription
Output FolderAssets/FigSync/GeneratedWhere sprites, fonts, snapshots, and reports land. Must be inside Assets/.
BackendUGUITarget framework. UGUI is the shipping backend.
Force RefreshfalseSkips the 24h REST cache for the next sync. Use when Figma was edited very recently and you don't want a stale node tree.
Bridge Port8473Local HTTP port the Figma plugin pushes to. Change only on collision; tell the plugin to match.
Render ModeScreen Space - CameraDefault Canvas render mode for new imports. Switch to World Space for VR/AR or 3D-anchored UI.
Debug VerbosityInfoConsole log level — Silent / Errors / Warnings / Info / Verbose. Verbose prints per-node decisions.

Tokens (Personal Access Token, OAuth refresh, Google Fonts API key) are stored separately in EditorPrefs with base64-XOR obfuscation. They never write to assets or version control.

Known Limitations

What FigSync doesn't fully render, why, and how to work around it.

Gradients — capped at 4 stops

The SDF shader carries a 4-stop ramp uniform. Figma ramps with 5+ stops are flattened to first + last + two middle stops by FigmaJsonDeserialiser.AppendStop. Rare in practice.

Gradients — angular 2-stop seam

frac() produces a hard edge at the axis direction for 2-stop angular ramps. Designers can hide this by adding a 3rd wrap-around stop whose colour matches the first stop at position 1.0.

Auto-layout — Wrap mode not implemented

Figma's HORIZONTAL, VERTICAL, and GRID auto-layout modes are wired end-to-end. WRAP (a horizontal layout that wraps to a new row when it overflows) falls through to free-position layout. Designs using wrap render with baked positions and won't reflow.

Auto-layout — Grid is uniform cells only

UGUI's GridLayoutGroup requires one cellSize for every cell. Figma's auto-grid model supports variable column widths and row heights ("track sizing"); FigSync flattens that to equal cells derived from frame size minus padding/gaps. Visually correct when the designer used "fill" track sizing across the board; non-uniform tracks lose their per-cell sizes.

Auto-layout — SPACE_BETWEEN uses injected spacers

UGUI's LayoutGroup has no native SPACE_BETWEEN, so FigSync inserts invisible LayoutElement GameObjects (marked FigSyncLayoutSpacer) between every adjacent pair of children. They absorb the leftover slack equally — visually the same as Figma's SPACE_BETWEEN. Side effect: N-1 extra GameObjects per SPACE_BETWEEN frame.

Auto-layout — constraints on flow children are ignored

When a child sits inside an auto-layout FRAME and isn't marked ABSOLUTE-positioned, its Figma constraints (Stretch / Center / Pin) don't drive its anchors — the parent's LayoutGroup owns placement. The child still resizes correctly when the LayoutGroup re-flows; it just can't independently stretch to parent edges the way a free-position child can. Designers who need that behaviour should toggle the child to "absolute position" in Figma.

Gradients — runtime Image.color.a tween ignored

Gradient sampling uses per-stop alpha as the output alpha, so per-stop fades work, but a runtime Image.color.a tween on the Graphic itself doesn't dim the gradient. Designers who want a runtime fade should add a transparent stop to the ramp (or animate a CanvasGroup parent).

Effects — LayerBlur on a frame with children falls back to PNG

LayerBlur on a leaf node renders procedurally via SDF-edge widening. On a node with children, the procedural path can't blur the children, so the classifier routes the whole subtree to the Downloadable PNG path where Figma bakes the blur server-side. Slightly heavier on import, indistinguishable at runtime.

Mixed inline text — segment can't override base style downward

TMP's rich-text grammar has <b> / <i> / <u> / <s> to turn flags on, but no inline "force off" counterpart. If the node-level base style is bold and a segment is regular, the regular segment still renders bold. Pick the lightest weight as the base style and let segments add emphasis.

Mixed inline text — cross-family segments stay on the base family

TMP's <font="X"> tag only resolves under Resources/Fonts & Materials/. FigSync writes baked atlases under the per-import output folder. The segment's weight + italic carry through (synth-bold / synth-italic from the base font); only the family doesn't switch. DownloadFonts still pulls the segment-specific TTF + .asset, so a future TMP_StyleSheet integration could close this gap.

BackgroundBlur — Scene view shows smeared sample

The compositor's RenderTexture is filled by the Canvas's Render Camera. In Game view the rendering camera and the source camera match, so UVs line up. In Scene view the editor camera is rendering the consumer but the RT was filled by the source camera — UVs land on unrelated pixels and "smear" as the editor camera moves. Verify the look in Game view, not Scene view.

BackgroundBlur — Overlay canvas not supported

Screen Space - Overlay bypasses Unity's camera-render pipeline, so there's no Camera.Render hook to snapshot canvas content. Switch the canvas to Screen Space - Camera and assign a Render Camera. The compositor picks up the change on its next tick.

Strokes — image-fill strokes don't render

The procedural path renders solid + gradient strokes. Image-fill strokes are not represented in the SDF shader and silently disappear. Rare; designers typically use solid colours for strokes.

Effects — inner shadow caps at 4 layers

Figma allows arbitrary stacked inner shadows; FigSync renders the first 4. Real designs with 5+ stacked inner shadows are essentially nonexistent.

Render pipelines — HDRP untested

Shaders are written in Built-in HLSL and ship URP-tested. HDRP variants haven't been validated end-to-end. The BackgroundBlur compositor specifically needs URP's render-graph to accept the depth-buffered RT.

This is the single source of truth for FigSync's known trade-offs. If you hit something not listed here, mail ragendom@gmail.com with a minimal repro.

💡 Troubleshooting

Common failure modes, what they mean, how to recover.

Sync errors

403 Forbidden from FigmaAction required

Your Personal Access Token doesn't have access to the file, or the token was revoked.

What to do: In Figma, confirm you have at least view permission on the file. Generate a fresh token in figma.com/settings and paste it into Settings → Auth.

429 Rate LimitedAuto-retry

Too many Figma API requests in a short window.

What to do: The pipeline waits the cooldown Figma returns in the Retry-After header and resumes automatically. If it keeps tripping, wait for the cooldown to clear, or use the Figma plugin path, which exports directly from the file you're working on (no token or URL needed).

Bridge: port already in useAction required

Another process is holding port 8473 (or your configured Bridge Port).

What to do: Either close the offending process, or change Bridge Port in Settings → Auth and re-import the plugin manifest in Figma so they agree.

TMP Essential Resources missingAction required

The Text rendering relies on TMP's default fallback assets, which aren't in the project yet.

What to do: Run Window → TextMeshPro → Import TMP Essential Resources, accept the import dialog, re-sync.

Common issues

The whole canvas is white / nothing renders

The most common cause is that the Canvas's Render Camera was deleted between syncs. Check FigSync Canvas in the scene — its Canvas component should have Render Mode = Screen Space - Camera with a non-null Render Camera. Re-assign and the design appears.

Fonts are wrong / Inter when I asked for Roboto (FULL edition)

Most often: the font wasn't on Google Fonts, fontsource, or any of the public CDNs. The diagnostic dialog at the end of the sync lists exactly which families didn't resolve. Drop the .ttf files into Assets/FigSync/Generated/Fonts/ as <Family>-<weight>.ttf and re-sync.

An icon appears blurry / pixelated

The node was routed to the PNG raster path and rendered at a smaller-than-display resolution. Try resizing the source frame in Figma (Figma's /v1/images renders at the frame's absoluteRenderBounds), or convert the node to a Vector if Figma can express it that way — vector nodes mesh procedurally and stay crisp at any scale.

A shadow / corner radius is missing on one node

The node was probably classified Downloadable (raster path), in which case Figma's PNG already contains the shadow/corner baked in. If the PNG is missing the effect, check the effect's Visible toggle in Figma — FigSync respects it. For procedural-path nodes (solid colour frames), inspect the GameObject's FigSyncRoundedCorner and confirm the radii are non-zero.

Re-sync overwrote my edits

FigSync preserves edits on nodes whose hash didn't change. If a node's content changed in Figma, its hash changes, and the GameObject is rebuilt — that's the intended behaviour. To prevent that for a specific frame, untick it in the Diff Window before clicking Continue; the frame stays as-is until you re-include it.

Sync hangs at DownloadFonts (FULL edition)

Google Fonts or fontsource is unreachable, or your network is filtering them. Sync can complete without fonts — the import surfaces a Missing fonts dialog and you can drop TTFs in manually. If you're behind a corporate proxy, set the Google Fonts API key in Settings → Auth to use the Webfonts Developer API instead of the public CSS endpoint.

Enable verbose logging when in doubt

Set Debug Verbosity = Verbose in Settings → Debug and re-sync. Every step logs its inputs, decisions, and counts to the Console with the [FigSync] prefix. The diagnostic report at Generated/_figsync_report.json also captures the full per-node decision trace.

FAQ

Quick answers to the questions that come up most.

Does FigSync work with FigJam?

Yes, through the Figma plugin path. FigJam-only node types (Sticky, ShapeWithText, Connector) aren't exposed by Figma's public REST API, so the plugin is required for FigJam files. Plain Figma Design files work over both paths.

Does it work offline?

Yes, after the first sync. Each plugin push saves a .figsync.zip bundle under Library/FigSync/Bridge/; you can re-sync from that bundle without Figma open. The REST path requires internet to fetch the latest node tree (a 24-hour cache softens that).

Can I use the synced UI in builds (mobile / WebGL / console)?

Yes. The output is a plain Unity UGUI Canvas — sprites are .png assets, fonts are TMP _SDF.asset, layout is LayoutGroup + ContentSizeFitter. Nothing in the runtime is editor-only. FigSync's own runtime components (rounded corner, drop shadow, blur compositor) are plain MonoBehaviours that work in any build target.

Does it support HDRP?

The UGUI canvas itself works on any pipeline. The shipping shaders target Built-in / URP and haven't been end-to-end-tested on HDRP. BackgroundBlur specifically needs URP's render-graph; on Built-in it works without the depth buffer. We'd love HDRP reports if you hit issues.

What about other UI frameworks (UI Toolkit etc.)?

UGUI is the shipping backend in v1.0. Other UI frameworks (UI Toolkit and similar) aren't supported today.

What happens to my scene if a sync fails halfway?

Steps before Draw are read-only — if they fail, the scene is untouched. Once Draw starts, the prior snapshot is loaded; if a step fails mid-Draw, the scene shows whatever was drawn up to that point, with a HelpBox naming the failing step. The hash snapshot is only written on full success, so the next sync diffs against the last known-good state — mid-failure runs don't poison the diff baseline.

Can two designers work on the same file?

Yes — both sync the same URL. Each sync writes deterministically (same node id → same GameObject name → same file path), so a teammate pulling your branch and re-syncing produces the same scene. Commit the Generated/ folder if you want the sprites + fonts to ship with the repo; or treat it as a build artifact and re-sync on first checkout.

How big is the runtime overhead?

The synced Canvas is a plain UGUI Canvas. FigSyncRoundedCorner is a BaseMeshEffect that adds <0.1 ms per canvas rebuild for typical screens. FigSyncBackgroundBlurCompositor samples one RenderTexture per consumer per frame — cheap on desktop, noticeable on mobile if you have 10+ blurred panels visible at once. Drop shadows are mesh-vertex effects, not extra draw calls.

How do I roll back a bad sync?

Ctrl-Z. Every sync wraps its scene mutations in a single Undo group, so one undo reverts the entire sync. The Generated/ folder is also versionable — if you commit it, git revert rolls back the sprite/font side too.

My team has multiple developers. Do we each need a license?

Yes. Per Unity Asset Store policy, each seat that uses the asset needs its own license.

📬 Support

Need help? Reach out.

📧

Get in Touch

Bug reports, feature requests, licensing questions — reach out and we'll get back to you.

✉ ragendom@gmail.com

We typically respond within 24–48 hours.

💬 Before contacting
  • Check the Troubleshooting section
  • Skim Known Limitations
  • Set Debug Verbosity = Verbose and re-sync to capture context
  • Open Generated/_figsync_report.json — the failure is usually visible there
📋 Helpful info to include
  • Unity version (e.g. 2022.3.30f1)
  • FigSync version (v1.0.0)
  • Render pipeline (Built-in / URP / HDRP)
  • Auth path (Token / OAuth / Plugin)
  • Steps to reproduce + Console output
Refunds within 14 days are handled by Unity directly via the Asset Store FAQ.

Ready for the full workflow?

You're on FigSync LITE (free). FigSync Full unlocks unlimited frames, incremental Sync & Diff, the live Figma Bridge & offline ZIP, font matching & Google Fonts, interactive components, auto-layout, shadows & blur, 9-slice, sprite/prefab reuse, code generation and localisation.

★ Upgrade to FigSync Full

Enjoying FigSync LITE?

A short Asset Store review helps other developers discover FigSync and keeps the updates flowing. It only takes 30 seconds.

⭐ Leave a Review on the Asset Store

u3d.as/1oGH

FigSync LITE v1.0.0 · Built for Unity 2021.3+ · Upgrade to Full ★

Support: ragendom@gmail.com · Asset Store: u3d.as/1oGH