Skip to content
Kunkun

Custom UI Command

Custom UI command is just a web app. You can use any front-end framework (React, Vue, Angular, Svelte, etc) to build arbitrarily complex UI, as long as it can be built into static files (e.g. SSG, CSR, but not SSR).

For example, you can create a transparent window with a 3D model floating on your screen.

Here is an example of KK’s git-skyline extension,

KK provides multiple scaffolding templates to help you get started with your extension development.

Supported templates:

  • React
  • Next.js
  • Vue
  • Nuxt.js
  • Svelte
  • SvelteKit

Installation

Terminal window
npm init kunkun@latest # choose a template

After creating a template project, you need to edit package.json.

You don’t have to use the template provided, you can always start from scratch with pnpm create vite.

You can also convert an existing web app into a KK extension by adding kunkun config to package.json.

Development

Change Dev Extension Path

Dev extensions are not installed together with the extensions installed from the extension store.

They can be anywhere on your file system, but you need to tell KK where to find them.

Go to Settings -> Developer -> Installation, there is a field to Set Dev Extension Path.

Choose the parent folder containing your extension project.

If you are using the KunkunExtensions repo, set it to KunkunExtensions/extensions.

  • DirectoryKunkunExtensions
    • Directoryextensions
      • Directoryext-qrcode
        • package.json
        • dist
      • Directoryext-jwt
        • package.json
        • dist

Now go back to the main search in home page, you should see the extension loaded. Dev extensions should have a DEV tag.

For now, you can only have one dev path. In the future, we may support multiple dev paths.

Edit Manifest

KK uses package.json to define an extension.

See Manifest for more details.

You need to edit the name, description, identifier and icon of your extension.

customUiCmds

Sample Config

package.json
"kunkun": {
...
"customUiCmds": [
{
"main": "/",
"dist": "build",
"devMain": "http://localhost:5173/dev-extensions/template-ext-sveltekit/build",
"name": "Sveltekit Template Home Page",
"cmds": []
},
{
"main": "about",
"dist": "build",
"devMain": "http://localhost:5173/dev-extensions/template-ext-sveltekit/build/about",
"name": "Sveltekit Template About Page",
"cmds": []
}
],
...
}
  • dist is the build output folder.
    • For Vite, it is dist.
    • For SvelteKit, it is build.
    • For Next.js, it is out.
  • devMain is the development server URL.
  • name is the name of the command.

Permissions

KK provides many APIs within @kksh/api package. See API Docs for more details.

Most of them requires adding corresponding permissions in package.json.

For example, if you want to read clipboard text, you need to add clipboard:read-text permission in package.json, under kunkun.permissions field.

See Extension Permissions for a full list of permissions, and API docs for each API to see how to add permissions.

Some permissions are just a single string, some are scoped permissions.

Configure Base Path

Unfortunately, due to a limitation of Tauri’s API, KK requires the base url for a web app to be set. The default base url ”/” won’t work. This may be solved in the future.

  1. Extension identifier in package.json must be the same as folder name
  2. dist is the build output folder, this should also be set in package.json for each custom ui command
  3. Base Url should be set to ${identifier}/${dist}

For example,

  • an react extension called my-react-ext, with build folder dist, the base url should be /my-react-ext/dist.
  • an sveltekit extension called my-sveltekit-ext, with build folder build, the base url should be /my-sveltekit-ext/build.

Here are some sample configurations:

The base url config for vite projects should be the same no matter what framework you choose. Here I use react as an example.

Vite Public Base Path Docs: https://vitejs.dev/guide/build#public-base-path

ext-react/vite.config.ts
import react from "@vitejs/plugin-react"
import { defineConfig } from "vite"
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
base: "/ext-react/dist"
})

Start Coding

It is recommended to use pnpm for development because when the extension is built in our CI, it is also built with pnpm.

Developing custom command is the same as developing a web app, HMR is supported.

Load Mode

Each custom UI command can have a devMain URL. This is the URL of the development server.

To enable dev mode, toggle setting: Settings -> General -> Dev Extension Load Mode to Development Mode.

When dev mode is enabled, you should see Live badge beside the extension commands in KK, and KK will load the devMain URL from your development server.

When mode is Production Mode, KK loads built extension from main field in package.json.

For example, given the config above, it loads build/index.html and build/about.html.

Helper Buttons

Custom command by default injects some buttons (back button, move button and refresh button) on top of your extension.

They are useful when your extension is not ready yet. Without these buttons, you may not be able to navigate back to the main menu or move the app window.

See Iframe UI API, for how to move or hide these buttons.

Theme

The scaffolded project uses @kksh/react or @kksh/vue or @kksh/svelte as the UI component library.

When these libraries, you can easily keep your extensions’ theme consistent with KK.

import { ui } from "@kksh/api/ui/iframe"
import { updateTheme } from "@kksh/vue"
// or
import { updateTheme } from "@kksh/react"
// or
import { updateTheme } from "@kksh/svelte"
ui.getTheme().then((theme) => {
updateTheme(theme)
})

Window Customization

Under uiCmds field, each UI command can have custom window style. All Tauri window styles are supported. You can read more in Tauri’s documentation. The attributes are passed to WebviewWindow class from Tauri to create a Window.

Go to Developer/Manifest Doc to see all avaialble window styles with intellisense in the code playground. In Sample Package JSON, in a UI Command, type double quote in a window object. Then intellisense will display all available window styles.

...
"customUiCmds": [
"window": {
"titleBarStyle": "overlay"
},
...
]
...

Advanced Usage

Although I previously mentioned that KK supports any SSG/CSR web apps as extensions, this doesn’t mean you can’t run a web server in the extension.

If you request shell permission in the manifest file, you can run a web server process in the extension (e.g. with Node, Bun, Deno runtime if installed locally, read more about runtime) and communicate with the frontend. You can then implement pretty much anything you want.

Verify

To verify the extension, you need to build it and run the verification command.

To make sure the build environment is consistent, docker is required to run the build command.

Terminal window
npx @kksh/cli build # requires docker
npx @kksh/cli verify --publish

These commands verify whether the extension can be loaded and published to the extension store.

To verify the functionality in production build,

  1. Set Dev Extension Load Mode to Production Mode in settings, general tab.

  2. Run npm run build

  3. Try to load the dev extension in KK, i.e. Search for your dev extension and select it to see if the UI can be loaded.

  4. Make sure files field in package.json only includes necessary files. e.g. "files": ["dist"].

  5. Run npm pack to generate a tarball file.

    • Decompress the tarball file to see if only necessary files are included.
  6. Go to settings page, developer tab, drag and drop the tarball file to install the extension.

    • The tarball file is decompressed to the dev extension path.
    • You may want to change the dev extension path as the new extension will be installed in the dev extension path as well, where your dev project is. And 2 extensions with the same identifier will be loaded.
  7. Check to see if the extension UI can be loaded in KK.

Publish

For now, send a PR to KunkunExtensions. Add the source code in extensions/ folder of this repo.

To update the extension and republish, just update the version in package.json and send a PR again.

When the version is updated, CI will auto publish the extension to the extension store.