Home

Awesome

[!WARNING] Experimental Release: This plugin is currently in an experimental phase and is provided "as is" without warranty of any kind. It was originally developed for internal use and may contain issues or limitations. Use it at your own risk. Feedback and contributions are welcome but please keep in mind the experimental nature of this tool.

output.webm

Overview

FigmaToUnity is a specialized Unity tool that streamlines the UI development process by enabling the direct import of Figma page documents into Unity. The tool automatically converts Figma designs into UI Toolkit assets, allowing for quick and accurate integration of UI interfaces into your Unity games.

Features

NameDescription
Figma Import to UXML/USSThe tool imports and parses Figma page documents, transforming them into UXML and USS assets within Unity.
Element ManipulationEnables the manipulation of UI elements and the application of custom logic via Unity scripts, providing extensive control over the user interface.
Sync ChangesChanges made to UI elements in Figma can be readily fetched and updated in Unity, maintaining the integrity of the game's UI.
LimitationsRefer to the section below.

Installing

  1. Open Window > Package Manager
  2. Click the + button in the top-left corner
  3. Choose Add package from git URL...
  4. Enter https://github.com/TrackMan/Unity.Package.AsyncAwaitUtil.git
  5. Click the + button in the top-left corner
  6. Choose Add package from git URL...
  7. Enter https://github.com/TrackMan/Unity.Package.CommonUtils.git
  8. Click the + button in the top-left corner
  9. Choose Add package from git URL...
  10. Enter https://github.com/TrackMan/Unity.Package.FigmaForUnity.git

Dependencies

To integrate these dependencies, you must either manually include them in your project's manifest file or ensure they are automatically resolved through Unity's Package Manager registry.

Personal Access Token

To start using Figma Inspector, a Figma Personal Access Token is needed for API calls.

[!WARNING] The token is stored in raw format.

  1. Visit the Figma API Authentication Page.
  2. Click + Get personal access token to generate the token.
  3. Copy the generated token.
  4. Locate the Figma script in Unity's Inspector.
  5. Paste the token into the designated field.

Quick Start

Usage

Working with this plugin is done through using Figma component inspector FigmaInspector. In addition, components derived from the Element class should be created and added to the same GameObject hierarchy. These components serve a dual purpose:

  1. During the import phase, they assist in filtering and configuring various aspects of the document, such as frame selection and image handling.
  2. During runtime, they provide the functionality to manipulate UXML and USS data structures.

Figma Inspector

image

PropertyDescription
Panel SettingsA crucial asset enabling Unity to render UXML-based user interfaces within the Game View.
Source AssetThe UXML asset responsible for outlining the structural framework of the user interface.
Sort OrderSpecifies the rendering sequence of UXML assets when multiple Panel Settings instances exist within a project.
TitleDesignates the title from the Figma document URL for identification purposes.
AssetRepresents the UXML asset correlating with the corresponding asset within the UI document script. (Refer to the section above for further details)
Update ButtonsFacilitates UI updates, offering options to include or exclude the downloading of all associated images.
De-root and Re-order HierarchyAdjusts the organization of all frames based on each element's RootOrder property, optimizing the UI hierarchy.
Filter by PathWhen activated, this feature limits the download to only those UI frames that have associated scripts attached to the prefab, otherwise, all UI elements within the Figma document will be downloaded.
Additional Fonts DirectoriesProvides the capability to specify paths to any fonts that are incorporated within the UI, ensuring seamless visual consistency.

Folders Layout

This is how the final setup should look:

<UI folder>
  ├── UI.uxml
  ├── UI.uss
  ├── UI.asset
  ├── remaps_UI.json
  ├── Elements
  │   └── CustomElement.uxml
  ├── Images
  │   ├── AmazingImage.svg
  │   └── PerfectImage.png
  └── Fonts
      └── Inter-Regular.ttf

Please note that you need to place your custom fonts in a 'Fonts' folder. If you try to import a Figma document that includes a font which does not exist in the 'Fonts' folder, you will see a message in the console indicating which font is missing. You can also add an additional fonts directory using the appropriate property in the Figma object.

Figma class

During the update process the Figma class retrieves data based on the Uxml and Query attributes of the Element scripts. It then utilizes this data while producing UXML asset.

[!WARNING] Element scripts should be attached to the same game object to which the Figma script is also attached.

Element class (OnInitialize, OnRebuild, Custom Elements)

The Uxml and Query attributes define the structure of the Uxml asset and, consequently, the appearance of your UI. The type of the field following the Query attribute defines the UI element itself and, consequently, its behavior (VisualElement, Button, Label, etc.). Field types are written into UXML. Therefore, if you change the field type (for example, from VisualElement to Button), you will need to perform a Figma Update to regenerate the UXML. Each element can override OnInitialize and OnRebuild methods which can be used to do any initial setup operations.

[Uxml("TestPage/TestFrame", UxmlDownloadImages.Everything, UxmlElementTypeIdentification.ByElementType)]
[AddComponentMenu("Figma/Samples/Test")]
public class Test : Element
{
	const int minCircles = 1;
	const int maxCircles = 7;

	#region Fields
	[Query("Header")] Label header;

	[Query("CloneButton", Clicked = nameof(Clone))] Button cloneButton;
	[Query("RemoveButton", Clicked = nameof(Remove))] Button removeButton;
	[Query("CloneContainer", StartRoot = true)] VisualElement cloneContainer;
	[Query("CloneCircle", EndRoot = true)] PerfectCircle cloneCircle;

	[Query("SyncButton", Clicked = nameof(Sync))] Button syncButton;
	[Query("SyncContainer")] VisualElement syncContainer;
	[Query("SyncContainer/SyncCircle")] PerfectCircle syncCircle;

	[Query("FunctionDescription", Hide = true)] Label functionDescription;
	#endregion

	#region Methods
	protected override void OnInitialize() => cloneContainer.style.flexWrap = Wrap.NoWrap;
	protected override void OnRebuild() => header.text = "Welcome to Figma Test Frame!";

	void Clone()
	{
		if (cloneContainer.childCount == maxCircles) return;

		cloneCircle.Clone(cloneContainer);
	}
	void Remove()
	{
		if (cloneContainer.childCount == minCircles) return;

		cloneContainer.Remove(cloneContainer.Children().First());
	}
	void Sync()
	{
		void RandomColor(int index) => syncContainer.Children().ElementAt(index).style.backgroundColor = Random.ColorHSV();

		syncCircle.Sync(syncContainer, RandomColor, Enumerable.Range(0, Random.Range(1, maxCircles + 1)));
		syncCircle.Hide();

		functionDescription.Show();
	}
	#endregion
}

Custom element example

public class PerfectCircle : SyncButtonSimple<int>
{
	public new class UxmlFactory : UxmlFactory<PerfectCircle> { }

	#region Methods
	public override bool IsVisible(int index, int data) => true;
	#endregion
}

UxmlAttribute

This attribute specifies the Element (a frame, and it's children) that we want to import from Figma document.

AttributeDescription
RootDefines the root path within the Figma document where this frame originates, inclusive of the canvas path.
ImageFilteringSpecifies the strategy for downloading images from the Figma document.
TypeIdentificationIndicates the method for identifying the types of elements, whether based on their name or their classification under Element classes.
PreserveLists any additional paths that should be maintained as-is in the imported document.

QueryAttribute

This attribute specifies the sub element (inside of the Element) parameters (like path to element, or what should happen when you click button).

Event NameDescription
PathThe path used in the UI query.
ClassNameThe class name of the element.
ImageFilteringEnum specifying how images are downloaded or filtered.
ReplaceNodePathPath to the node that will be replaced.
ReplaceNodeEventEvent that triggers the node replacement.
ReplaceElementPathPath to the element that will be replaced.
RebuildElementEventEvent that triggers the element to be rebuilt.
StartRootSpecifies that element path will be new root for the following elements.
EndRootSpecifies the end of StartRoot.
NullableSpecifies if the element can be null.
ClickedName of the method to be invoked when the element is clicked.
TemplateTemplate to be used for the element (creates a separate uxml file).
UseTrickleDownSpecifies if events should trickle down through the element hierarchy.
ChangeEventEvent triggered when an element's state changes.
MouseCaptureOutEventEvent triggered when mouse capture is lost.
ValidateCommandEventEvent triggered to validate a command.
ExecuteCommandEventEvent triggered to execute a command.
DragExitedEventEvent triggered when a drag operation exits the element.
DragUpdatedEventEvent triggered when a drag operation is updated.
DragPerformEventEvent triggered when a drag operation is performed.
DragEnterEventEvent triggered when a drag operation enters the element.
DragLeaveEventEvent triggered when a drag operation leaves the element.
FocusOutEventEvent triggered when the element loses focus.
BlurEventEvent triggered when the element is blurred.
FocusInEventEvent triggered when the element gains focus.
FocusEventEvent triggered when the element is focused or loses focus.
InputEventEvent triggered when the element receives input.
KeyDownEventEvent triggered when a key is pressed down.
KeyUpEventEvent triggered when a key is released.
GeometryChangedEventEvent triggered when the element's geometry changes.
PointerDownEventEvent triggered when a pointer is pressed down.
PointerUpEventEvent triggered when a pointer is released.
PointerMoveEventEvent triggered when a pointer is moved.
MouseDownEventEvent triggered when a mouse button is pressed.
MouseUpEventEvent triggered when a mouse button is released.
MouseMoveEventEvent triggered when the mouse is moved.
ContextClickEventEvent triggered on a context click (right-click).
WheelEventEvent triggered when the mouse wheel is moved.
MouseEnterEventEvent triggered when the mouse enters the element.
MouseLeaveEventEvent triggered when the mouse leaves the element.
MouseEnterWindowEventEvent triggered when the mouse enters the window containing the element.
MouseLeaveWindowEventEvent triggered when the mouse leaves the window containing the element.
MouseOverEventEvent triggered when the mouse is over the element.
MouseOutEventEvent triggered when the mouse is out of the element.
ContextualMenuPopulateEventEvent triggered to populate the contextual menu.
AttachToPanelEventEvent triggered when the element is attached to a panel.
DetachFromPanelEventEvent triggered when the element is detached from a panel.
TooltipEventEvent triggered to display a tooltip.
IMGUIEventEvent triggered for IMGUI rendering.

ISubElement

This interface serves as an identifier, signifying that within the IRootElement hierarchy, an element exists which can function as a component based on the VisualElement class.

IRootElement

This interface acts as a marker, indicating that an element within the IRootElement hierarchy is capable of functioning as a component derived from the VisualElement class.

Visual Element Style

The imported USS file contains all the classes used by Visual Elements. USS is inspired by CSS and has a similar syntax. To manipulate properties in your code, you should use the techniques described below.

Changing Element Appearance

To change the appearance of a VisualElement, you should manipulate its style properties. For example, to set the top margin of an element to 3:

element.style.marginTop = 3;

Reading Element Style Data

If you need to read style data from a VisualElement, you should use its resolved style properties. For example, to retrieve the value of the top margin:

float margin = element.resolvedStyle.marginTop;

You can find the list of all supported properties in the official Unity documentation.

Visual Element Extensions

When working with VisualElements, there are various visual element extensions that allow you to find/clone/replace/etc elements:

VisualElement rectangle = element.Find<VisualElement>("Rectangle");
VisualElement elementClone = options.Clone();
element.Replace(newElement);

Limitations

FeatureDescription
Unique Frame NamesEach frame must have a unique name to ensure proper functionality.
Vector ConstraintsVectors should be visible, should not contain Image Fills, and, where possible, should be grouped into Unions.
Fill LimitationsEach UI element can contain only a single Fill attribute.
Auto-Layout RestrictionsStroke borders are not supported within Auto-Layout configurations.
Alignment ConstraintsHorizontal and vertical centering cannot be mixed within the same parent element; doing so will default the alignment to center-center.
Circle RepresentationFor optimal visual rendering, circles should be implemented using rectangles rather than ellipses.

Not implemented