Using Figma to develop styles for Nvidia Omniverse extensions
In this article I will show you a method to design and create styles for use in Nvidia Omniverse extensions. Given some limitations of standard development in Omniverse, we use an external graphics tool, such as Figma. This allows you to iterate faster on design and then transfer the results to code. This may increase aesthetic appeal of the extension which makes it more satisfying for your users.
As you may have seen from my previous articles, I have been developing extensions on the Nvidia Omniverse platform. The type of extensions I focus on have a user interface and are embedded within the larger Isaac Sim application. You can think of these extensions as small applications themselves and associate considerations for user experience.
Why do you use an external tool?
Developing styles using the standard development loop can be done, but the process is slow which can prohibit investing the effort. This longer feedback cycle time causes developers to defer styling in favor of more impactful features of their extensions. If not deferred to a later time, developers may avoid all the troubles and stick with the default styles which, in my opinion, have issues.
Why is the process slower?
- Lack of hot-reloading, loss of state on update
If you are testing the styles and behavior of a feature which requires some manual steps to setup the required conditions, every time you update and save to observe changes you will need to reapply those manual steps. The more steps the more prohibitive. - Non-intuitive structure, Lower knowledge transfer
Some of the Omniverse Widgets (standard platform components) have internal structure which as far as I know is not documented. For example, styling the text color of aButton
requires targeting theLabel
within the Button. If you have a background with web platform and CSS, such as me, you expect styles from the Button to cascade or be inherited by children, but they are not. (Update: See method at end for discovering structure) - Decreased interop from other platforms
Omniverse uses its own ColorShade class, spacing, and alignment paradigms which take time to become familiar with rather than being able to directly re-use existing knowledge.
Other Limitations or Significant Differences from CSS
- Lack of composability of styles in consuming code
In CSS, you can define classclassA
,classB
, andclassC
and in the consuming code such as HTML, you can apply all three class names to a single element. This allows composing styles without modifying CSS:<div class=”classA classB classB”></div>
and they are automatically merged by a set of processing rules with selector precedence.
From the documentation, I think this is not possible in Omniverse. You could still compose by assigning different style snippets to variables and then composing those variables in python using:style_a
,style_b
style_c
Button:merged_style = {
**style_a,
**style_b,
**style_c,
}
- However, this merging requires splitting the styles you want to compose into separate variables, declaring a single merge name, and update consuming code with the name which seems like more steps with less flexibility.
Back to the reasons for using and External Tool
As briefly described above, using Figma allows rapid iteration on the design and once desired look is achieved it can be transferred to Omniverse. I will admit design is not as important in Omniverse extensions compared to other platforms because there is usually a much smaller target audience. Also, that audience is unlikely to have an alternative. This means they MUST use the extension despite poor UX.
Applications on other platforms may see orders of magnitude more users and there is abundance of competition which drives up quality. Over the decades many frameworks and tools evolve, and these set the ideal or expected developer experience to have for the Omniverse platform.
Create Components in Figma
In most applications you will have classes of buttons which are styled differently to imply the difference in priority or consequences do the user.
I chose to use the types: Primary, Secondary, Normal, and Danger
I won’t explain how to create these components and design tokens as there are much better resources for learning that material such as Official Documentation or YouTube tutorials. This article’s purpose is to propose this technique or method for other Omniverse developers and explain the advantages.
My Figma experience is only intermediate, thus I will restrict to the basic button components for this article. However, the same technique could be applied to any component you have the ability to create. Hopefully I can write an update in the future with controls which have complex behaviors like dropdowns or menus.
1. Create the components
Play around with the colors, padding, and spacing until you get something you like.
2. Test the Components
Use the “Present” or “Preview” feature to test the components behavior.
3. Extract the values from Tokens or Primitives
I choose to keep the same Hue for the button variables and only change the Saturation and Lightness. This ensures consistency and makes updating only require a single variable change.
I could not find how to make variable values displayed in Figma in a format other than hexadecimal, #RRGGBB. If you know how, tell me in the comments! We will be using the HSL values.
Use the values in Omniverse Extension
If you haven’t already, create a new extension in Omniverse where you will apply the styles from Figma.
I use file structure below which mimics the collections of primitives and token variables in Figma.
The styles.py
file is where the tokens are assembled into the style object that we can apply to our Omniverse controls. For web developers, you may think of this style object as a .CSS file
Custom Styles Extension Preview
Now with your style object created, apply it to some top-level component such as a Window
or Frame
and play around to ensure it behaves as you expect.
Other Notable Techniques
There are few other techniques that are related to styling which I thought may be helpful to call out.
Using Debug Color
The quality of Nvidia documentation is poor and there are many markdown errors which don’t render preview images of their code snippets. This makes it hard to know what effect a certain code snippet has.
As far as I know, there is no element inspector tools such as those found Developer Tools of common browsers, like Edge or Chrome.
There is one technique they mention which is a special use case of rendering a Debug Color. This may help you visualize widget or component overlap and boundaries. Given they don’t show a preview I thought I would.
Add this entry for debug_color
to your style object. The extra 55
values are for transparency.
"debug_color": cl("#FF000055")
Discovering Widget Structure by inspecting default Styles
One way I have found to learn about styling Widgets in Omniverse is to inspect the default style object. You can import the style object and inspect it when debugging, learn the syntax of the desired selector and use it in your own styles.
from omni.ui.style_utils import style
Notable items are Button, CheckBox
, RadioButton
, etc
Future Ideas
- I thought it would be cool to develop an extension for Figma that automatically generates this Omniverse style object. Instead of manually constructing all the selectors which risks typos or missing an element causing incomplete transfer, it could be a simple as copy paste. (I would attempt although you now have to pay/subscribe to use Developer mode, and I have not explored this yet)
References
Documentation
Resources from Article
Conclusion
I hope this method of using Figma to quickly design and transfer the system of primitives and tokens to Omniverse will help accelerate and improve your extension development.
As always, let me know what you think in the comments!