Figpot
Figma to Penpot converter and synchronizer, to not maintain multiple platforms 🎨🖌️
Install / Use
/learn @betagouv/FigpotREADME
figpot
This library is a Figma to Penpot converter and synchronizer supporting variants, it will fit your needs:
- To migrate from Figma to Penpot (one-time transfer)
- To provide your design system onto Penpot while keeping Figma as a source of truth (incremental transfers)
- It can be automated and requires no intervention
- Across synchronizations any file element will keep its unique identifier, so users relying on your file won't have bindings broken
[![npm package][npm-img]][npm-url] [![Build Status][build-img]][build-url] [![Downloads][downloads-img]][downloads-url] [![Issues][issues-img]][issues-url] [![Commitizen Friendly][commitizen-img]][commitizen-url] [![Semantic Release][semantic-release-img]][semantic-release-url]
Usage
One-time transfer
Prepare the minimal information:
- Open your Figma document inside the browser and copy its identifier (for
https://www.figma.com/design/CptbnRHeDv3pzOai91abcd/the ID isCptbnRHeDv3pzOai91abcd) - Open Penpot and create an empty file, and copy its identifier (for
https://design.penpot.app/#/workspace?team-id=yyy&file-id=3d04e89b-bff0-8115-8004-bc14b0d50123&page-id=zzzthe ID is3d04e89b-bff0-8115-8004-bc14b0d50123)
Make sure to have Node.js installed and simply run:
npx @betagouv/figpot deps # required to have a 100% complete synchronization, if not wanted use `--no-hydrate` on the following command
npx @betagouv/figpot document synchronize -d CptbnRHeDv3pzOai91abcd:3d04e89b-bff0-8115-8004-bc14b0d50123
The command will then ask you for tokens required to reach both Figma and Penpot. To avoid typing them each time, have a look at the Usage > Advanced section.
Note: Penpot user email and password are required to synchronize final details simulating a browser locally. If needed you can skip this with the parameter --no-hydrate. See the FAQ to better understand the hydratation process.
Incremental transfers
To have a real incremental experience the library needs to remember the bindings between Figma elements and those into Penpot. This takes place into a file named .../figpot/documents/figma_$ID/export/penpot_$ID/mapping.json that is saved locally.
If you intend to perform synchronizations from a new machine, or from a server that resets its storage at each start, you need to make sure saving and restoring this file each time.
Avoid command prompts
Variables
It's possible to prefill some environment variables to avoid typing information each time:
FIGMA_ACCESS_TOKEN(the token can be created from your account settings underPersonal access tokenssection, with read-only scopes likeFile content, File metadata, Library assets, Library content, Projects, Team library content)PENPOT_ACCESS_TOKEN(the token can be created from your account settings underAccess tokenstab)PENPOT_USER_EMAIL(email used for your account)PENPOT_USER_PASSWORD(password used for your account)
Optional ones:
PENPOT_BASE_URL(by default it'shttps://design.penpot.appbut it has to be changed in case you use a custom Penpot instance)
Warnings
Warnings to manually skip are emitted if:
- Your file size goes over Penpot recommandations (see the FAQ for more details)
- When synchronizing with no previous
mapping.json(we want to make sure you won't override a Penpot file by mistake)
In case of a CI/CD pipeline you want to automate this, you can use --ci as parameter to answer "yes" to all confirm prompts. Use it with caution.
More advanced usage
It's possible to:
- Filter Figma elements by names (it can be for colors, nodes, typographies, components)
- Replace fonts that you don't want to end into Penpot (it could be a defect on a Figma document you cannot edit)
- Process multiple synchronizations in 1 command
Please refer to the "Frequently Asked Questions" or to the commands documentation with npx figpot --help.
Frequently Asked Questions
Some Figma information seems lost during the transfer?
Make sure the Figma file you try to synchronize is in one of your workspace, otherwise the Figma access token won't be able to retrieve extra information like components or styles for colors and typographies.
It's also possible either this plugin does not implement the conversion yet, or that Penpot does not support this feature. In both cases, you are welcome to open an issue on the appropriate repository.
What is the purpose of the hydratation step?
"Hydratation" in the context of figpot is when we use a browser to have the Penpot file ready to use.
In fact, our core library is transforming and giving all the Figma information to Penpot but the latter relies on a few operations that only happen when the document is open into a browser:
- It creates thumbnails for some elements
- It gives each paragraph part a graphical position that cannot be inferred from the Figma data
So, at the end of a synchronization of "raw data", we hydrate the Penpot file by opening a hidden browser that will wait for those 2 operations to be done on all pages.
There are 2 drawbacks to this:
- It requires us to ask for your Penpot credentials (the API access token cannot be used to load the user interface)
- It is more compute-intensive (due to running a browser while rendering the entire Penpot file)
You can skip this final step with --no-hydrate, but you have to keep in mind the first user going onto the file inside his own browser may have to wait a few minutes the time the file is completly ready (depending on how big the file is). And in case the first user is a visitor through a link to share, this one won't see the exact result despite waiting because he has no rights for his file fetching to update the file.
Note: hydratation pushes updates to Penpot only when changes have been performed, most of the time this should be quick for a stable file.
How to easily save mapping.json across synchronizations?
If you are doing this from your own computer, in most cases you have nothing to do since the file is already persisted on the storage. If you cannot allow losing bindings you can go a step further by managing backups of this file:
- Either with a manual backup (copy to an external storage)
- Or by tracking the file with a Cloud storage service (Google Drive, etc.)
- Or by using a Git repository
Since we already rely on Git to develop this library, we chose to provide a helper for Git repositories.
The idea is that if you run figpot from a cloned repository, you are able to use the parameter --sync-mapping-with-git so it fetches the latest commits before starting, and it pushes the mapping file to the current branch once modified.
Please have a look at penpot-dsfr to see how a dedicated repository is used to regularly synchronize a few files from Figma to Penpot. Their use case is to effortlessly maintain a Penpot version of their design system from Figma.
Note: the file is pushed before updating the Penpot file. This way, in case of a partial update due to a failure, it prevents losing bindings already on the Penpot file and starting from scratch again.
What if Penpot is laggy or crashing after synchronization?
In you are in the case where Penpot lags so much that's unusable:
- Either you have too few memory available
- Or the Figma file size is over what Penpot can handle
First of all, remember that Penpot keeps evolving and is yet not as optimized as Figma can be. They are aware of people being able to use files onto Figma but not onto Penpot. They are currently rebuilding the rendering engine to improve this.
In the meantime, figpot provides a way to exclude elements from the Figma file like --exclude-page-pattern and --exclude-node-pattern. This can be helpful to reduce the number of elements to push to Penpot.
An example of application would be:
My team has a design system with light and dark themes into 1 Figma file, Penpot cannot handle this, so to make it usable into Penpot we decided to exclude all dark elements from the file. It has reduced by 2 the number of elements.
How to make big files not crashing figpot?
Your memory needs to handle both Figma and Penpot trees at the same time to compare them. Even if the library optimizes some operations, this is the greedy operation that cannot be much optimized and that totally depends on the memory capacity.
If you encounter issues like JavaScript heap out of memory, try to:
- Close any other application
- Make sure the command you run is not trying to synchronize multiple files at once
- Run the command on a computer with more memory (8GB or 16GB should be sufficient)
- Filter some nodes from the Figma file (they will be skipped)
How to synchronize multiple Figma files while keeping their components references between each other?
Currently when you convert a Figma file with figpot, all instances of remote components will loose their "component definition link" since the dependencies files are maybe not what you want to synchronize. To ease the user experience, we decided to keep this logic instead of assuming the library has to transfer all files (or almost all).
It may be implemented in the future, but it would require all expected files to be synchronized first, and the "binding operation" would appear after. This because Figma allows bidirectional dependencies ("file A" may rely on "file B" components, and "file B" may rely on "file A" components).
How to manage Penpot error referential-integrity?
When pushing modifications to Penpot we have to chunk them in multiple requests due to their server maximum constraints. For each request Penpot servers will take the entire file state and check its validity (which makes sense), but unfortunately since the release of variants inside Penpot,
