Fidget: a Figma-shaped UI library for Nim
Figma based UI library for nim, with HTML and OpenGL backends.
At a glance
- What is it?
- Fidget is a cross platform UI library for Nim that borrows its object model from Figma, with an HTML backend and an OpenGL backend and a Figma plugin that exports a design straight to Nim code. Its philosophy is deliberately subtraction, with almost no layout primitives, and the project warns that it is still in heavy development.
- Who is it for?
- Adopt Fidget if you are writing a natively compiled Nim application with a user interface and you want the object model your designer already uses, plus the option of the same code compiling to JavaScript for the web. Do not adopt it for a project that needs a mature widget set, a deep layout system or a mobile target, since the iOS and Android backends are described as proof of concept and the library itself as still in heavy development.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 60 days ago.
- What is it written in?
- Mainly Nim, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A UI library shaped like a design tool
Fidget aims to provide performant, natively compiled, cross platform user interfaces, and the README lists the targets as the web with HTML5, Windows, macOS, Linux, and iOS and Android through OpenGL. The library is written in Nim and installed with a single command:
nimble install fidgetWhat makes it different from a typical cross platform UI toolkit is where the model comes from. Fidget leverages Figma, and it does so by shipping a Figma plugin, in the figma_plugin directory with its source in code.ts, that exports a design directly to Fidget code. The intent is stated plainly: you change the spacing in Figma and re-export, rather than adjusting numbers in a layout system by hand.
The second half of the design decision is the language the exported code arrives in. Fidget uses plain Nim procs, Nim templates, if statements and for loops, and it provides only the minimal primitives found in Figma. The README is explicit that this is a deliberate avoidance: instead of a custom language, XML templates, HTML, Jinja templates or CSS, the library stays inside the imperative idioms a Nim programmer already writes.
The result is a library that feels like writing a program that draws a picture, which is either exactly what you want or exactly what you do not.
Nodes, relative positions and a tiny layout vocabulary
The philosophy section lists the rules, and together they form a coherent model.
Everything is a node, and there are four kinds: Group, Rectangle, Image and Text. Nodes are positioned relative to their parent. Nodes carry a minimal set of properties that match Figma's. Resizing works the way Figma's constraints work, and layout works the way Figma's auto layout works. That is the whole object model, and it is small enough to hold in your head.
The layout vocabulary is where the subtraction goes furthest. The README states that there are very few layout primitives: align left, center, right, both or scale on the X axis, and top, center, bottom, both or scale on the Y axis. There is no margin, no padding, no float, no absolute or relative positioning, no border box, no flex, no recycle view controllers, no stack layout and no constraints system.
What replaces them is arithmetic. The README's advice is that if you want to do something fancy, do a little math, and that a simple formula is often smaller, simpler and easier to reason about than a layout puzzle. A for loop positions a list of items directly, because there is no list controller to configure. A Nim proc or template holds a reusable fragment, because there are no CSS classes to define.
Whether that trade works depends on what you are building. A screen with a dozen fixed elements will be a pleasure. A screen with deep nesting, flexible text reflow and many breakpoints will feel like reimplementing a layout engine by hand, because that is what it amounts to.
Imperative rendering: every frame is drawn from scratch
The rendering model is described in a section titled imperative UI style, and it is the part of the design that has real performance consequences.
Each UI frame is drawn completely from start to finish, in code you control. Use of callbacks is discouraged. After any event, whether from the user, from data or from a timer, the UI is redrawn, and the README says it is redrawn in an efficient way that allows this.
The two backends achieve that efficiency differently. With HTML, a modification cache is used so that only a minimal amount of DOM changes are needed, which is the trick that keeps a full redraw from being a full DOM rewrite. With OpenGL, the whole screen is redrawn using as few state transitions as possible, batching everything into a texture atlas and a single global vertex buffer.
The texture atlas point is the significant one for the OpenGL path. Rather than binding a texture per node, the assets are packed into one atlas so a frame becomes a small number of draw calls against one buffer. That is the standard technique for immediate mode renderers and it is the reason the approach can be fast at all, since the naive version of draw everything each frame would spend all its time on state changes.
The design is coherent, and it is also the reason the library suits particular applications: applications where the state is simple, the screen is redrawn as a whole, and the number of distinct assets is small enough to fit in an atlas.
The minimal sample in full
The README's minimal example is short enough to read in one go, and it shows the shape of the whole model in a dozen lines:
import fidget, vmath
proc drawMain() =
frame "main":
box 0, 0, 620, 140
for i in 0 .. 4:
group "block":
box 20+i*120, 20, 100, 100
fill "#2B9FEA"
windowFrame = vec2(620, 140)
startFidget(drawMain)A proc called drawMain declares a frame named main, places a box, loops five times creating a group per iteration with a box inside it, and sets the fill colour. The positioning arithmetic is right there in the loop, 20+i*120 for the x coordinate, which is exactly the point the README makes about doing the maths yourself. The window size is a vec2 from the vmath library, and startFidget begins the event loop.
There is no layout container, no style object and no configuration file. The screen is a function of the code, and the code is a function of the data.
Running the examples and the test suite
The examples live in the examples directory of the repository, with folders for areas, demo, gradaui, hn, minimal, padofcode and padoftext, and the README shows how to build the minimal one from a fresh clone:
git clone https://github.com/treeform/fidget
cd fidget
nimble install
cd examples/minimal
nim c -r minimalEach example folder is compiled the same way, and the native examples for Windows, macOS and Linux are run with the compile-and-run flag:
nim c -r bars.nim
nim c -r hovers.nim
nim c -r inputs.nim
nim c -r padoftext.nim
nim c -r padofcode.nim
nim c -r basic.nimThe same examples run in a browser, compiled to JavaScript instead, after which you open the generated HTML file:
nim js bars.nim
nim js hovers.nim
nim js inputs.nim
nim js padoftext.nim
nim js padofcode.nim
nim js basic.nimThat second list is the clearest statement of the cross platform claim in the project, since it is the same source producing a native window and a web page.
The tests have their own runner, and the flags show what it does: the native compiler is used, a screenshot is taken and the run is limited to a single frame.
nim c -r tests/run --compile --native --testOneFrameThe Figma plugin is compiled separately, with the TypeScript compiler run in the figma_plugin folder, after which you add the folder as a development plugin inside Figma.
Backend support is uneven, and the project says so
The backend list in the README is a ranking, not a claim of parity, and the wording is the warning.
HTML is the best supported. Windows is next best. Mac has less support and Linux has less support. iOS and Android are described as proof of concept only. The list is prefaced with the note that these are the backends that are planned, which is a further qualification on top of the unevenness.
Read as a whole, the project has one production-shaped target, the web, and one that is close behind it on Windows, with the desktop Unix backends and the two mobile platforms trailing well behind. Anyone planning an application for iOS or Android with this library is choosing a proof of concept, and the README's own banner warns that the library is still in heavy development.
The release history adds a data point. The tagged versions are 0.7.10 from 2022-08-21, 0.7.9 from 2021-12-16 and 0.7.8 from 2021-05-29, while the last push to the repository was on 2026-08-23. So there have been commits in the last couple of months and no release for four years. That combination is typical of a project whose author is still working on it without cutting versions, and it means pinning to a release means pinning to 2022 code.
The rest of the repository is a conventional Nim project: a fidget.nimble file for the package, config.nims files for configuration, src for the sources, tests for the suite, docs for the documentation and the images the README embeds.
Why Nim, and what the licence allows
The README makes the case for the host language, and it is a short argument with two parts.
Nim is described as easy on the eyes like Python but typed, and as performant as C. It can compile to JavaScript, C, C++ and Objective-C. For a UI library, the language features that matter are advanced templates and macros, which the README says make a good domain specific language and make writing UIs straightforward, intuitive and cross platform. The templates are also what a Figma export targets, since the exported code is meant to be read and edited by a Nim programmer rather than generated into a framework's XML.
The licence is MIT, with a LICENSE file at the root of the repository. That is a permissive licence with no copyleft obligations, no requirement to publish changes and no network use clause, so Fidget can be embedded in a commercial or closed application without conditions. This is a description of the terms rather than legal advice.
The project also points at a talk, Fidget: Let's rethink UI development with Nim, presented at NimConf 2020, which is the most direct way to understand the argument the library is making, and an API reference published on nimdocs.com for the function-level details.
Editorial conclusion
Adopt Fidget if you are writing a natively compiled Nim application with a user interface and you want the object model your designer already uses, plus the option of the same code compiling to JavaScript for the web. Do not adopt it for a project that needs a mature widget set, a deep layout system or a mobile target, since the iOS and Android backends are described as proof of concept and the library itself as still in heavy development. Verify first that your platform is one of the two that are properly supported, the HTML backend or Windows, that the Nim compiler you use can build the project, and which tagged release you are pinning, because the newest published release is 0.7.10 from 2022 while the repository has seen commits since.
Frequently asked questions
How do I install the Fidget library for Nim?
With nimble install fidget. The library is published as a Nimble package and the README lists the API reference at nimdocs.com/treeform/fidget.
Which platforms does Fidget support well?
The HTML backend is the best supported and Windows is next best, with less support on Mac and Linux, while iOS and Android are described as proof of concept only. The README also warns that the library is still in heavy development.
How do I run the Fidget examples?
Clone the repository, run nimble install, then cd into an example folder and compile it with nim c -r, for example nim c -r minimal in examples/minimal. The same examples run in a browser when compiled with nim js instead.
How does the Figma plugin fit into the Fidget workflow?
The plugin lives in the figma_plugin folder and is compiled with the TypeScript compiler. You then add that folder as a development plugin inside Figma, and from there a design can be exported directly to Fidget code.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/treeform-fidget)Was this useful?