Creating Custom Templates

To this point, we have explored how to extend and customize the template applications and extensions provided by the kit-app-template repository. In this section, we will explore how to create a custom template using the provided tooling. This process will allow you to create a new application or extension template that can be used as a starting point for new projects withing your team or organization.


Template Configuration

The repo template uses the templates/templates.toml configuration file to define the available templates and their properties. The templates.toml file is structured as follows:

[templates."template_name"]
class = "ApplicationTemplate" or "ExtensionTemplate"
name = "Template Display Name"
url = "location of template, '.' for local"
subpath = "path/to/the/template/at/specified/url"
variables.first_variable = "the first variable to be queried from the user"
variables.second_variable = "the second variable to be queried from the user"
...
variables.nth_variable = "the nth variable to be queried from the user"

[templates."template_name".extensions]
template = "ExtensionTemplate"
type = "extension type"

Configuration Examples

The following examples demonstrate how to configure a custom application and extension template using the templates.toml configuration file. In the examples below we show the configuration for the kit_service application template and the corresponding kit_service_setup setup extension template.

Application Template Configuration

[templates."kit_service"]
class = "ApplicationTemplate"
name = "Kit Service"
url = "."
subpath = "apps/kit_service/kit_service.kit"
variables.application_name = "my_company.my_service"
variables.application_display_name = "My Service"
variables.version = "0.1.0"

[[templates."kit_service".extensions]]
template = "kit_service_setup"
type = "setup"

Extension Template Configuration

[templates."kit_service_setup"]
class = "SetupExtensionTemplate"
name = "Service Setup"
url = "."
subpath = "extensions/service.setup/template"
variables.extension_name = "my_company.my_service_setup_extension"
variables.extension_display_name = "My Service Setup Extension"
variables.version = "0.1.0"

Default Behaviors

There are some default behaviors that are applied to all templates. These behaviors include:

  • application_name and extension_name: These variables are required for all templates and will always be the first variables queried from the user. It is recommended that the default value for these variables is set as the first variable listed in the templates.toml configuration for a given template.

  • Variables in Order: The variables are queried from the user in the order they are listed in the templates.toml configuration file. It is recommended that the application_name and extension_name variables are listed first.

  • Found Variables: While it is recommended to set all critical defaults using the variables listed in the templates.toml configuration file, users will be prompted for all variables that are found in the template files themselves in the order they are found. Variables set within the template files can be set with the pattern {{variable_name}} and will be replaced with the user input. If you wish to set a default value within the template file, you can use the pattern {{variable_name|default('default_value')}}.

  • Multiple Application Extensions: In the above example we show how to configure a single setup extension for the kit_service. If you wish to add multiple extensions to an application, you can add additional [[templates."app_name".extensions]] entries to the templates.toml configuration file along with the relevant extension template configuration. Each entry should specify the template and type of the extension. Note that each extension that is required to be added to the .kit file will require an entry of the form "{{ extension-type_extension_name }}" = {} in the .kit file.

  • Multiple Application Extensions (Dependencies): For extensions that depend on one another, it is recommended to list them in the templates.toml file in the order from least dependent to most dependent (e.g. if extension A depends on extension B, list extension B first). This will limit the number of times the user is prompted for variables. An example of this can be seen with the omni_usd_viewer application template. Note that when one extension depends on another, only the top level extension needs to be added to the .kit file.

  • Application Template Layering: Application templates can depend on each other. When configuring template layers using the templates.toml file, the ApplicationLayerTemplate class is used. This approach is particularly useful when you want to inherit the behavior of a base application and extend it with additional functionality, such as streaming.

Hands-on Exploration

In this section we will create a template extension that builds upon the Python UI extension template. Our goal will be to create a simple UI element that launches a Warp kernel. Warp is a Python framework for writing high-performance simulation and graphics code. Warp takes regular Python functions and JIT compiles them to efficient kernel code that can run on the CPU or GPU. Our new template will allow our users to quickly setup a new Warp kernel and launch it from within the Omniverse Kit UI.

1. Create a New Template Extension

  1. Within the templates/extensions directory, create a new directory called warp_kernel_ui for the new template extension.

  2. From within the templates/extensions/python_ui directory, copy the entire template directory to the new warp_kernel_ui directory.

    Our new directory within the templates/extensions directory should look like this:

     warp_kernel_ui/
     ├── template/
    
  3. Update the [dependencies] section of the extension.toml file within the templates/extensions/warp_kernel_ui/template/config directory to the following :

     [dependencies]
     "omni.kit.uiapp" = {}
     "omni.warp" = {} # Warp support
    
  4. Update the python code contained within templates/extensions/warp_kernel_ui/template/{{python_module_path}}/extension.py to the following code:

import omni.ext
import omni.ui as ui
import warp as wp
import numpy as np


# Warp kernel to computes the lengths of 3D vectors
@wp.kernel
def length(points: wp.array(dtype=wp.vec3),
           lengths: wp.array(dtype=float)):

    # thread index
    tid = wp.tid()

    # compute distance of each point from origin
    lengths[tid] = wp.length(points[tid])


# Any class derived from `omni.ext.IExt` in the top level module (defined in `python.modules` of `extension.toml`) will
# be instantiated when the extension gets enabled, and `on_startup(ext_id)` will be called.
# Later when the extension gets disabled on_shutdown() is called.
class MyExtension(omni.ext.IExt):
    # ext_id is the current extension id. It can be used with the extension manager to query additional information,
    # like where this extension is located on the filesystem.
    def on_startup(self, ext_id):
        print("[{{ extension_name }}] Extension startup")

        wp.init()
        self._count = 0
        self._num_points = 1024

        self._window = ui.Window("{{ extension_display_name }}", width=300, height=300)
        with self._window.frame:
            with ui.VStack():
                label = ui.Label("")

                def on_click():
                    self._count += 1
                    label.text = f"# Runs: {self._count}"
                    # allocate an array of 3d points
                    points = wp.array(np.random.rand(self._num_points, 3), dtype=wp.vec3)
                    lengths = wp.zeros(self._num_points, dtype=float)

                    # launch kernel
                    wp.launch(kernel=length,
                            dim=len(points),
                            inputs=[points, lengths])

                    print(lengths)



                with ui.HStack():
                    ui.Button("Run Kernel", clicked_fn=on_click)

    def on_shutdown(self):
        print("[{{ extension_name }}] Extension shutdown")

2. Configure the New Template Extension

Add the following entry to the templates/templates.toml file to configure the new template extension:

[templates."warp_kernel_ui"]
class = "ExtensionTemplate"
name = "Warp Kernel UI"
url = "."
subpath = "extensions/warp_kernel_ui/template"
variables.extension_name = "my_company.warp_kernel_ui"
variables.extension_display_name = "Warp Kernel UI"
variables.version = "0.1.0"

3. Test the New Template Extension

To test the new template extension we will create a Base Editor application and include the new Warp Kernel UI extension.

  1. Create a new Base Editor application using the repo template new command:

    Linux:

    ./repo.sh template new
    

    Windows:

    .\repo.bat template new
    

    Follow the prompt instructions, choosing:

    • ? Select with arrow keys what you want to create: Application

    • ? Select with arrow keys your desired template: Kit Base Editor

    • ? Enter name of application .kit file [name-spaced, lowercase, alphanumeric]: my_company.my_editor

    • ? Enter application_display_name: My Editor

    • ? Enter version: 0.1.0

  2. Create a new Warp Kernel UI extension using the repo template new command:

    Linux:

    ./repo.sh template new
    

    Windows:

    .\repo.bat template new
    

    Follow the prompt instructions, choosing:

    • ? Select with arrow keys what you want to create: Extension

    • ? Select with arrow keys your desired template: Warp Kernel UI

    • ? Enter name of extension [name-spaced, lowercase, alphanumeric]: my_company.warp_kernel_ui

    • ? Enter extension_display_name: Warp Kernel UI

    • ? Enter version: 0.1.0

  3. Add the Warp Kernel UI extension to the .kit file for the Base Editor application. Within the source/apps/my_company.my_editor.kit file, add the following line to the dependencies section:

    "my_company.warp_kernel_ui" = {}
    
  4. Build and launch the Base Editor application:

    Linux:

    ./repo.sh build
    

    Windows:

    .\repo.bat build
    

    Linux:

    ./repo.sh launch
    

    Windows:

    .\repo.bat launch
    

    The launch tool will prompt you to select an application .kit file to launch. Select my_company.my_editor.kit

  5. Within the Base Editor application, you should see a new button labeled “Run Kernel”. Clicking this button will launch the Warp kernel and print the results to the console.

4. Cleanup

Before continuing to the next section, it is recommended to clean up the applications, extensions, and any other repository changes that were created during this exploration.

Either revert all changes made to the repository or delete the repository and clone it again before continuing.

Typical cleanup steps include:

  • Revert changes to top level premake5.lua file

  • Revert changes to repo.toml

  • Delete the source/ directory

  • Delete the _build/ directory, or run ./repo.sh build -c or .\repo.bat build -c


Additional Resources