Niji

Niji is an extensible theming framework that brings uniform, responsive and comfortable theming to the tinkerer's desktop. It currently comes with builtin support for gtk apps, sway, hyprland, kitty, and others, but it also allows you to easily add custom modules for anything you desire.

Refer to Getting Started for a quick guide on how to set niji up, or take a look at Configuration and Built-in Modules for a more in-depth reference of niji's capabilities.

Getting Started

Installation

AUR

Arch Linux users can install niji from the AUR using the niji-git package.

Manually

To install niji manually from source, do the following steps:

  1. Clone the git repository and enter the folder
  2. Install using cargo: cargo install --path ./crates/main
  3. Create the config directory: mkdir ~/.config/niji
  4. Install the builtin modules: cp ./assets/modules ~/.config/niji/modules
  5. Install the builtin themes: cp ./assets/themes ~/.config/niji/themes

Initial Configuration

Create the configuration file at ~/.config/niji/config.toml. The first step is to choose which modules to use. Take a look at Built-in Modules for a list of available modules. Simply set your desired modules using this syntax:

modules = ["hyprland", "waybar"]

Afterwards, you should set font_family, cursor_theme and cursor_size as basic preferences. Make sure you have the cursor theme installed that you select.

modules = ["hyprland", "waybar"]

[global]
font_family = "Fira Sans"
cursor_theme = "Adwaita"
cursor_size = 22

Lastly, be sure to refer to the documentation of each of your selected modules and check for available configuration options and additional necessary steps for activation.

You can now list avaliable themes using niji theme list, and preview them using niji theme show <name>. If you've picked one, apply it using niji theme set <name>.

Next Steps

After the initial setup, you may want to consider taking a look at Configuration for some advanced configuration options.

If you want to use a custom theme, refer to Custom Themes.

If you want to apply your theme to an application that isn't supported out of the box, you can take a look at Custom Modules.

Configuration

Niji is configured via its config file, which lies at ~/.config/niji/config.toml (Assuming you don't have a custom $XDG_CONFIG_HOME set). The config file uses TOML syntax.

Base Configuration

The base configuration configures the behavior of the niji framework itself. These options go at the top level of config.toml. Currently, the following options are available:

# A list of module names to activate.
# This value is required.
modules = []

# A list of module names that shouldn't be automatically reloaded.
# This is useful if the reloading behavior of that module interferes with your
# specific configuration.
disable_reloads = []

Module Configuration

Configuration options for modules appear after a header containing their name. The one exception is the special [global] header, which applies to all modules.

All module configuration options are optional, but if you want consistency across different theming targets, it is a good idea to set the available global options that make sense for your setup, since default behaviors may differ from module to module.

Global Options

The available global module configuration options are as follows, shown here with example values:

[global]

# The font family to use for UI
font_family = "Fira Sans"

# A scaling factor for text.
# Use this if you want larger text for better visibility, or smaller text for
# a more compact UI.
font_scale = 1.0

# The cursor theme to use
cursor_theme = "Adwaita"

# The cursor size to use
cursor_size = 22

You can also override any of these options individually for each module, simply by adding to the corresponding section. For example, you could configure the waybar module to use a different font like this:

[waybar]
font_family = "Fira Code"

Setting Wallpapers per Theme

If you have a module that supports setting wallpapers, such as hyprpaper, you can set a global wallpaper map, that specifies which wallpaper to use for each theme. You can do this by adding a [global.wallpaper] heading to your config, with keys corresponding to the theme names, and values corresponding to the path to the wallpaper. You can also add a default key as a fallback.

An example configuration might look like this:

[global.wallpaper]
default = "./wallpapers/wp1.png"
tokyonight = "./wallpapers/wp2.png"
dracula = "./wallpapers/wp3.png"

If you just want to use a single wallpaper for every theme, you can also just set the wallpaper option like this:

[global]
wallpaper = "./wallpaper/my-wallpaper.png"

Module-Specific Options

Module-specific options come after a header with the name of the corresponding module. An example configuration for the waybar module might look like this:

[waybar]
icon_font = "Material Design Icons"
show_shadow = false
module_margin = 8

What specific options are available differs from module to module. If you are using a builtin module, you can find their respective documentation in Built-In Modules.

Command Line Interface

To get help with the CLI you can always use niji help or niji help <command>.

Usage: niji [OPTIONS]

Global Options

These options are available for all commands.

NameDescription
-q, --quietDisable log output
-v, --verbosePrint debug messages
-b, --no-colorDisable colored output
-h, --helpPrint help
-V, --versionPrint version number

Commands

niji apply [OPTIONS]

Applies (or re-applies) the current theme and configuration to all active modules, or to the selcted modules if --module is used.

Options

NameDescription
-M, --module <modules>Apply the specified modules rather than the active ones. Can be set multiple times.
-k, --no-reloadDon't reload the affected modules

niji theme get

Return the name of the currently active theme

niji theme show [name]

Print a preview of the theme with name [name], or the active theme if [name] is omitted.

niji theme set [name]

Set the active theme to [name]. By default, this command also applies the theme to all active modules (can be disabled using --no-apply), and reloads them (can be disabled using --no-reload).

Options

NameDescription
-n, --no-applyDon't apply the theme after setting it
-k --no-reloadDon't reload the affected modules

niji theme list

List the names of all installed themes

niji theme unset

Unsets the currently set theme. Does not apply or reload any modules.

Built-in Themes

Niji includes a number of built-in themes. You can preview them using the niji theme show <name> command, and select them using niji theme set <name>. For more information, refer to Command Line Interface.

The built-in themes currently included with niji are:

  • catpuccin-frappe
  • catpuccin-latte
  • dracula
  • gruvbox
  • gruvbox-light
  • tokyonight

To list these themes, along with any custom or separately installed themes, use the niji theme list command.

If there is something missing from this list that you'd like to have, take a look at Custom Themes.

Built-in Modules

Niji includes a number of modules already built-in. You can simply activate them by adding their names to the "modules" list in your config.toml. For more details, see Configuration, and the documentation of the respective module.

The built-in modules currently included with niji are:

  • gtk: Theming GTK3 and GTK4 applications
  • hyprland: Theming hyprland window decorations
  • hyprpaper: Wallpaper setting support for hyprpaper
  • kitty: Theming kitty window and terminal colors
  • mako: Theming mako notifications
  • sway: Theming sway window decorations and setting swaybg wallpapers
  • swaylock: Theming your swaylock lock screen
  • waybar: A fully managed waybar theme

If there is something missing from this list that you'd like to have, take a look at Custom Modules.

Module gtk

The gtk module allows you to theme GTK3 and GTK4 applications. Note that other targets for GTK themes, such as GTK2, qt6gtk2, gnome-shell, etc. are currently not supported.

The niji theme is a modified version of the amazing Colloid theme by vinceliuice.

Activating

To activate the module, add it to your config.toml:

modules = ["gtk"]

This will export a GTK theme called "niji" to your system. If you have reloads enabled for this module (which they are by default), niji will also automatically set the system GTK theme when applying. If you don't want this behavior, you can disable it by adding "gtk" to your disable_reloads list (see Configuration).

libadwaita

Apps that use libadwaita, such as nautilus, are quite stubborn when it comes to convincing them to use a gtk theme other than Adwaita. The easiest way to fix this is to globally set the environent variable GTK_THEME to niji, which works.

If you are using Arch Linux, you can also use libadwaita-without-adwaita-git for an arguably cleaner solution; this patched version of libadwaita properly respects your system gtk theme, and makes apps like nautilus work properly with niji, nwg-look, and other tools, out of the box.

Configuration

The following global configuration options are relevant to this module:

  • cursor_theme
  • cursor_size
  • font_family
  • font_scale

See Configuration for a detailed explanation. Note that these options do not work if reloads are disabled for this module.

Additionaly, these module-specific configuration options can be added to config.toml (shown here with their default values):

[gtk]

# Set to true to use a more compact layout in gtk apps
compact = false

# Set to "normal" for less flashy window buttons
window_button = "mac"

Module hyprland

The hyprland module allows you to theme the window decoration of the Hyprland wayland compositor.

The configuration produced by this module is intentionally minimal, and does not interfere with your existing hyprland config.

See also the hyprpaper module.

Activating

To activate the module, add it to your config.toml:

modules = ["hyprland"]

Niji will now output a hyprland configuration file to ~/.local/share/niji/hyprland/theme.conf. To enable it, add the following line to the bottom of your hyprland.conf:

source = ~/.local/share/niji/hyprland/theme.conf

You can, of course, override as much of the generated configuration as you like, simply by adding configuration after the source statement.

Configuration

The following global configuration options are relevant to this module:

  • cursor_theme
  • cursor_size

See Configuration for a detailed explanation.

Additionally, these module-specific configuration options can be added to config.toml (shown here with their default values):

[hyprland]

# Can be either "background", "surface", "primary" or "secondary".
# This value determines which theme color is used for focused window borders.
focused_color = "surface"

Module hyprpaper

The hyprpaper module allows you to automatically reconfigure hyprpaper to use a specific wallpaper for each theme.

See also the hyprland module.

Activating

To activate the module, add it to your config.toml:

modules = ["hyprpaper"]

This will cause niji to take control of your .config/hypr/hyprpaper.conf file.

Configuration

In order for this module to do anything, you have to have a wallpaper map configured. See Setting Wallpapers per Theme for information on how to do that.

Beyond that, these module-specific configuration options can be added to config.toml (shown here with their default values):

[hyprpaper]

# Set to true to show the hyprland splash text on the wallpaper
splash = false

# The command to be used to start hyprpaper when restarting it
hyprpaper_command = "hyprpaper > /dev/null"

Module kitty

The kitty module allows you to set the window and terminal colors for the kitty terminal emulator.

Activating

Th activate the module, add it to your config.toml:

modules = ["kitty"]

This will create a kitty theme called "niji". If you have reloads enabled for this module (which they are by default), niji will also automatically apply this theme. If you do not want this behaviour, you can disable it by adding "kitty" to your disable_reloads list (see Configuration).

Module mako

The mako module allows you to theme notifications produced by the mako notification daemon.

Activating

To activate the module, add it to your config.toml:

modules = ["mako"]

This will cause niji to take control of your .config/mako/config file.

Configuration

The following global configuration options are relevant to this module:

  • font_family
  • font_scale

See Configuration for a detailed explanation.

Additionally, these module-specific configuration options can be added to config.toml (shown here with their default values):

[mako]

# The border width around notifications
border_width = 2

# The border radius of notifications
border_radius = 10

# The background transparency of the popup
popup_alpha = 1.0

# Set to a path string to set more configuration options
custom_config_file = false

Since niji needs to take control of .config/mako/config, if you want to set any of mako's numerous additional configuration options that have nothing to do with theming, you'll have to create a separate configuration file in your .config/niji directory, and link to it in config.toml. For example, if you wanted to set the default timeout of notifications, you might do something like this:

~/.config/niji/config.toml

# ...

[mako]
custom_config_file = "./custom/mako_config"

~/.config/niji/custom/mako_config

default-timeout=10000

Module sway

The sway module allows you to theme sway window decorations, as well as setting your swaybg wallpaper per theme.

Activating

To activate the module, add it to your config.toml:

modules = ["sway"]

Niji will now output a sway configuration file to ~/.local/share/niji/sway/theme. To enable it, add the following line to the bottom of your sway config:

include ~/.local/share/niji/sway/theme

If you want to override any of the settings exported by niji, you can simply add more configuration after the include statement.

Configuration

The following global configuration options are relevant to this module:

  • font_family
  • font_scale
  • cursor_theme
  • cursor_size
  • wallpaper

See Configuration for a detailed explanantion. In particular, see Setting Wallpapers per Theme for information on the wallpaper setting.

Additionally, these module-specific configuration options can be added to config.toml (shown here with their default values):

[sway]

# Can be either "background", "surface", or "primary".
# This value determines which theme color is used for focused window borders.
focused_color = "surface"

# Can be either "background", "surface", "primary" or "secondary".
# This value determines which theme color is used for the indicator bar.
# Set to the same value as `focused_color` to hide the indicator entirely.
indicator_color = "surface"

Module swaylock

The swaylock module allows you to theme your swaylock lock screen.

Activating

To activate the module, add it to your config.toml:

modules = ["swaylock"]

This will cause niji to take control of your .config/swaylock.config file.

Configuration

The following global configuration options are relevant for this module:

  • font_family
  • font_scale

See Configuration for a detailed explanation.

Additionally, these module-specific configuration options can be added to config.toml (shown here with their default values):

[swaylock]

# Set to a path string to set additional configuration options
custom_config_file = false

This module is only concerned with setting colors. Any additional configuration of swaylock, particularly if you are using something like swaylock-effects, needs to be done in a separate custom configuration file. An example configuration might look like this:

~/.config/niji/config.toml

# ...

[swaylock]
custom_config_file = "./custom/swaylock_config"

~/.config/niji/custom/swaylock_config

clock
indicator
grace=3
fade-in=1

Module waybar

The waybar module provides a fully managed waybar theme in line with your system's niji theme.

Activating

To activate the module, add it to your config.toml:

modules = ["waybar"]

This will cause niji to take control of your .config/waybar/style.css file.

Configuration

The following global configuration options are relevant for this module:

  • font_family
  • font_scale

See Configuration for a detailed explanation.

Additionally, these module-specific configuration options can be added to config.toml (shown here with their default values):

[waybar]

# Set to the ids of custom modules that you use (e.g. "custom-gpu"),
# in order for them to be styled properly.
custom_modules = []

# Set to a string to specify a font to use for icons,
# such as FontAwesome or Material Desing icons
icon_font = false

# Set to false to disable shadows behind waybar elements
show_shadow = true

# The opacity of waybar when in a hidden state
hidden_opacity = 0.0

# The padding in pixels of waybar elements in the x direction.
padding_x = 12

# The padding in pixels of waybar elements in the y direction.
padding_y = 4

# The margin between workspace buttons in pixels
workspace_button_margin = 6

# Set to the path to a css file to include arbitrary custom styles
custom_style_file = false

Note, in particular, the custom_modules option. If you use custom modules, you have to add them to the list, otherwise they won't be styled properly.

More Customization

Since waybar is, by its nature, highly customizable, this module is not going to fit many people's use cases. You can try to fiddle around with the custom_style_file configuration option, but if you already have a highly customized waybar theme, I recommend you check out Creating Custom Modules.

Module wob

The mako module allows you to theme wob bars.

Activating

To activate the module, add it to your config.toml:

modules = ["wob"]

This will cause niji to take control of your .config/wob/wob.ini file.

Note that if you want live reloading to work, you will likely need to configure a wob_command. See the following for details.

Configuration

These module-specific configuration options can be added to config.toml (shown here with their default values):

[mako]
# The command used to start wob when reloading
wob_command = "tail -f $XDG_RUNTIME_DIR/wob.sock | wob"

# Set to a path string to specify custom values for wob.ini
custom_config_file = false

Due to the nature of how wob functions, it is likely necessary to customize the wob_command option to get live reloading to function correctly. Simply set it to the same command that you use to start wob initially.

Since niji needs to take control of .config/wob/wob.ini, if you want to set any of wobs's additional configuration options, or override a value set by niji, you'll have to create a separate configuration file in your .config/niji directory, and link to it in config.toml. For example, if you wanted to show the bar at the top of the screen, you might do somethin like this:

~/.config/niji/config.toml

# ...

[wob]
custom_config_file = "./custom/wob.ini"

~/.config/niji/custom/wob.ini

anchor = top

Custom Themes

If you build a custom theme, consider contributing it! Just make sure you have the proper license for the color scheme you're using, as color schemes may be subject to copyright.

Custom niji themes are defined using TOML files placed into the ~/.config/niji/themes directory, with the filename (without the extension) matching the theme name.

The file is split into two sections: [ui] for GUI colors, and [terminal] for terminal colors. All colors are defined using #RRGGBB or #RRGGBBAA syntax.

[ui]

The [ui] section defines colors for graphical interfaces. It also contains the option color_scheme, which should be either "light" or "dark" to tell GUI toolkits whether the theme should be considered a light or a dark theme.

The section contains the following options:

OptionDescription
color_schemeWhether the theme should be considered light or dark. Takes only the values "light" and "dark".
backgroundThe main background color
text_backgroundThe color of text appearing on background
surfaceThe background color of surfaces that appear on top of background (such as panels or cards)
text_surfaceThe color of text appearing on surface
primaryThe primary accent color of the UI
text_primaryThe color of text appearing on primary
secondaryThe secondary accent color of the UI
borderThe color of borders around certain elements. May be set to transparent (#00000000) to remove borders.
shadowThe color of drop shadow around certain elements. May be set to transparent (#00000000) to remove drop shadows.
successThe color indicating a successful action. Usually a shade of green.
text_successThe color of text appearing on success
infoThe color used for informative user feedback. May be set to the same as surface to remove the distinction.
text_infoThe color of text appearing on info. May be set to the same as text_surface to remove the distinction.
warningThe color used for warning messages. Usually a shade of yellow or orange.
text_warningThe color of text appearing on warning
errorThe color used for error messages and states. Usually a shade of red.
text_errorThe color of text appearing on error

[terminal]

The [terminal] section contains color definitions corresponding to the standard 16 ANSI colors:

  • black
  • red
  • green
  • yellow
  • blue
  • magenta
  • cyan
  • white
  • bright_black
  • bright_red
  • bright_green
  • bright_yellow
  • bright_blue
  • bright_magenta
  • bright_cyan
  • bright_white

Example

The following is an example for a theme definition for the built-in tokyonight theme:

[ui]
color_scheme = "dark"
background = "#1a1b26"
text_background = "#c0caf5"
surface = "#414868"
text_surface = "#c0caf5"
primary = "#a9b1d6"
text_primary = "#1a1b26"
secondary = "#73daca"
border = "#1a1b26"
shadow = "#10101080"

success = "#73daca"
text_success = "#e0af68"
info = "#7aa2f7"
text_info = "#1a1b26"
warning = "#e0af68"
text_warning = "#1a1b26"
error = "#f7768e"
text_error = "#1a1b26"

[terminal]
black = "#15161e"
red = "#f7768e"
green = "#9ece6a"
yellow = "#e0af68"
blue = "#7aa2f7"
magenta = "#bb9af7"
cyan = "#7dcfff"
white = "#a9b1d6"
bright_black = "#414868"
bright_red = "#f7768e"
bright_green = "#73daca"
bright_yellow = "#e0af68"
bright_blue = "#7aa2f7"
bright_magenta = "#bb9af7"
bright_cyan = "#7dcfff"
bright_white = "#c0caf5"

Custom Modules

If you build a custom module, consider contributing it! PRs are always welcome :)

Custom modules are located in the directory ~/.config/niji/modules. Each module is a folder in that directory; the name of the folder is the module name.

The heart of a niji module is a lua module in the module folder called module.lua. It has this general structure:

local M = {}

function M.apply(config, theme)
    -- Apply the theme here
end

function M.reload(config)
    -- Reload the application here.
end

return M

The module defines two handlers, apply and reload.

The apply handler receives the module config and the theme as parameters. It is responsible for taking the theme, transforming its contents and writing them to where they need to go for the theming target to use them.

THe reload handler is optional. It is responsible for reloading the theming target to apply the new config. The reason why these two are separate is so that niji can more easily tell which modules support live reloading, and so that users can selectively disable live reloading for certain modules.

The exact semantics of the two handlers are different depending on the nature of the theming target, but in general, apply should apply the theme and config in the least invasive way possible, while reload does whatever is necessary to live-reload the theming target.

Module Config

The module config, which is passed as the first parameter to both the apply and the reload handlers, is a table with string keys and arbitrary values. It comes from combining the module-specific configuration for your module with the global module configuration, both of which are defined in config.toml. See Configuration for more information.

Simple modules for personal use probably won't use this feature much, but it is recommended that modules which are used by multiple users and may be merged to be builtin modules use the config feature to provide options to users, and conform to certain global configuration options like font_scale.

Theme

The theme is a table that corresponds directly to the theme format documented in Custom Themes. All color values in the theme table are passed as a niji.Color instance.

Lua API

Niji provides its own Lua API for building modules. It is fully documented in the section Lua API Reference.

Templates

A very common thing that modules need to do is inserting some values from the theme into a pre-made config file template. niji provides a builtin system to do this, which is documented in the section Templating Reference, and can be used via the niji.Template class from the Lua API.

Lua API Reference

niji's Lua API resides in the global niji namespace. There is no need to import it. The niji namespace contains several sub-namespaces and classes for different purposes, which are listed in this document.

In addution, you can always use the Lua standard library which is fully supported. If one of the functions in the niji API fits what you want to do however, you should always prefer using the niji API, as it provides better integration and safety features.

Modules are always executed with their working directory inside of their module folder, so you can easily reference bundled assets like template files using relative paths.

Contents:

Class niji.Color

The class niji.Color represents an RGBA color. it can be used to perform certain manipulations on colors. All color manipulations use the Oklab perceptual color space, so while some results may appear unexpected through an RGB lens, they should look good.

All color fields in the theme parameter of the module application handler are also instances of niji.Color.

All functions that accept colors also accept strings of the format "#RRGGBB" and "#RRGGBBAA".

Property niji.Color.r

The red channel of the color as an integer between 0 and 255

Property niji.Color.g

The green channel of the color as an integer between 0 and 255

Property niji.Color.b

The blue channel of the color as an integer between 0 and 255

Property niji.Color.a

The alpha channel of the color as an integer between 0 and 255

Static niji.Color:new(color_string)

Constructs a new niji.Color object.

  • color_string: A string representing the desired color (string)
  • returns: The resulting color (niji.Color)
local my_color = niji.Color:new("#ab38a3ff")

-- Prints "#ab3aa3ff"
niji.console.debug(my_color)

Static niji.Color:blend(color_1, color_2, t)

Interpolates between two colors.

  • color_1: The first of the two colors to interpolate between (string or niji.Color)
  • color_2: The second of the two colors to interpolate between (string or niji.Color)
  • t: A number between 0 and 1 that controls the interpolation (float)
  • returns: The resulting color (niji.Color)
local my_color = niji.Color:blend("#ff0000", "#00ff00", 0.3)

-- Prints "#ff6300ff"
niji.console.debug(my_color)

Static niji.Color:mix(color_1, color_2)

Mixes two colors together evenly. Equivalent to calling niji.Color:blend with a t of 0.5.

  • color_1: The first of the two colors to mix together (string or niji.Color)
  • color_2: The second of the two colors to mix together (string or niji.Color)
local my_color = niji.Color:mix("#ff0000", "#00ff00")

-- Prints "#f99500ff"
niji.console.debug(my_color)

niji.Color:lighten(amount)

Lightens the color by the given amount. "Amount" here refers to relative perceived lightness, which means that the change in lightness for a given amount parameter should look the same for any base color, unless the resulting color would fall outside the RGB color gamut.

  • amount: The desired relative perceived lightness, ranging between -1 and 1 (float)
local base_color = niji.Color:new("#123faa")
local lightened_color = base_color:lighten(0.2)

-- Prints "#4a7eeeff"
niji.console.debug(lightened_color)

niji.Color:darken(amount)

Darkens the color by the given amount. Equivalent to calling niji.Color:lighten with -amount.

  • amount: The desired relative perceived lightness, ranging between -1 and 1 (float)
local base_color = niji.Color:new("#c670f9")
local lightened_color = base_color:darken(0.2)

-- Prints "#872eb5ff"
niji.console.debug(lightened_color)

niji.Color:shade(lightness)

Selects a shade of the color that has the provided absolute perceived lightness. As with other operations, if that color falls outside the RGB gamut, it gets gamut-clipped.

  • lightness: The desired perceived lightness, ranging between 0 and 1 (float)
local base_color = niji.Color:new("#cb9174")
local shade = base_color:shade(0.4)

-- Prints "#6c3a1fff"
niji.console.debug(shade)

niji.Color:with_alpha(alpha)

Returns the same color with the provided alpha value.

  • alpha: The desired alpha value, ranging between 0 and 1 (float)
local base_color = niji.Color:new("#abcdef")
local transparent_color = base_color:with_alpha(0.5)

-- Prints "#abcdef80"
niji.console.debug(transparent_color)

Class niji.Template

The class niji.Template is the lua API for niji's builtin templating system. It can be used to load, parse and render templates.

Static niji.Template:parse(template)

Parses the provided string template as a template.

  • template: The template string (string)
  • returns: The parsed template object (niji.Template)
local my_template = niji.Template:parse("Hello {{name}}!")

Static niji.Template:load(path)

A utility method that loads a template from a file.

  • path: The path to the template file to load (string)
  • returns: The parsed template object (niji.Template)
local my_template = niji.Template:load("my_template.mustache")

niji.Template:render(value)

Render the template to a string using a given input value. This is most commonly a table of keys and values used in the template.

  • value: The value to use as an input in the template (any type)
  • returns: The rendered string (string)
local my_template = niji.Template:parse("Hello {{name}}!")
local rendered = my_template:render({ name = "World" })

-- prints "Hello World!"
niji.console.debug(rendered)

niji.Template:set_format(type_name, format_string)

Set the custom format for the specified type. See the template system reference for more information.

  • type_name: The name of the type for which to set the format (string)
  • format_string: The format string to use for the given type

Namespace niji.console

The niji.console namespace provides niji-flavored functions for interacting with the console.

niji.console.debug(message)

Sends a debug message to the console. Note that these messages are only visible if --verbose is passed as an argument to niji.

  • message: The message to send (any type)

niji.console.info(message)

Sends an info message to the console.

  • message: The message to send (any type)

niji.console.warn(message)

Sends a warning message to the console.

  • message: The message to send (any type)

niji.console.error(message)

Sends an error message to the console.

  • message: The message to send (any type)

niji.console.prompt(message, default)

Sends a confirmation prompt to the user. If default is not nil, pressing enter without entering a response will return that value. If default is nil, pressing enter without entering a response will trigger a reprompt.

  • prompt: The message to show in the prompt (any type)
  • default: The default value for the prompt (bool or nil)
  • returns: The response from the user (bool)
if niji.console.prompt("Do the thing?", true) then
    doTheThing()
end

Namespace niji.fs

The namespace niji.fs contains functions for interacting with the file system. While it is much more restrictive than the filesystem API built into lua, it is strongly recommended to use niji.fs functions over raw lua functions whenever possible, because they have a lot of extra safety features, such as automatically checking for conflicts with preexisting files.

niji.fs.write(path, content)

This function should be used when you have to write to a file that might already exist on the system, and which you might not want to silently overwrite if it does; the major example for this is configuration files which don't support including files from other locations.

If you just want to output a file that can then be included/imported by another program, consider using niji.fs.output. This is often a better approach, because it is a lot less invasive.

Calling niji.fs.write will cause niji to check if the file already exists, and contains data that wasn't written to it by niji. If that is the case, niji will inform the user via a prompt, and create a backup of the previous version if necessary. Ultimately, it writes content to file at the given path.

  • path: The path of the file to write to (string). You can use "~" to refer to the current user's home directory.
  • content: The string to write to the file (string)
  • returns: The absolute, canonical path of the file written to (string)

niji.fs.write_config(path, content)

A version of niji.fs.write that takes paths relative to ~/.config.

  • path: The relative path to the config file to write to (string)
  • content: The content to write to the file (string)
  • returns: The absolute, canonical path of the file written to (string)

niji.fs.write_state(path, content)

A version of niji.fs.write that takes paths relative to ~/.local/state.

  • path: The relative path of the state file to write to (string)
  • content: The content to write to the file (string)
  • returns: The absolute, canonical path of the file written to (string)

niji.fs.write_data(path, content)

A version of niji.fs.write that takes path relative to ~/.local/share.

  • path: The relative path of the data file to write to (string)
  • content: The content to write to the file (string)
  • returns: The absolute, canonical path of the file written to (string)

niji.fs.output(path, content)

This function should be used if you want to output a file that is then actively imported/included by another program. An example for this is the hyprland module, which outputs a partial hyprland config file which you can then include in your config. In many cases, this is the recommended approach over niji.fs.write, because it is less invasive and makes it easier to manage separate config options. Which approach fits each module better is up to the disgression of the module author however.

The path argument for this functions is relative to your module's output folder, which, by default, is located at ~/.local/share/niji/<module name>.

  • path: The relative path of the output file within the output folde (string)
  • content: The content to write to the file (string)
  • returns: The absolute path of the file that was written to (string)

niji.fs.read_config_asset(path)

Reads a file with a path relative to .config/niji. This is often used for things like supplementary configuration files that get inserted into the generated config of a module, as used in the mako module for example.

  • path: The relative path of the asset file within the config folder (string)
  • returns: The contents of the file (string)

niji.fs.read_config(path)

Reads a file with a path relative to ~/.config.

  • path: The relative path of the config file (string)
  • returns: The contents of the file (string)

niji.fs.read_state(path)

Reads a file with a path relative to ~/.local/state.

  • path: The relative path of the state file (string)
  • returns: The contents of the file (string)

niji.fs.read_data(path)

Reads a file with a path relative to ~/.local/share.

  • path: The relative path of the state file (string)
  • returns: The contents of the file (string)

Namespace niji.mod

The namespace niji.mod can be used to obtain metadata about the current module.

niji.mod.name

The name of the current module (string)

niji.mod.path

The absolute path to the module folder of the current module (string)

Namespace niji.os

The namespace niji.os contains supplementary functions to the "os" functionality in lua.

niji.os.exec_detached(command)

Behaves like the builtin os.exec function in lua, except it detaches the command from the parent process, allowing it to keep running in the background after niji has completed execution.

You should use this method if you want to restart a background process with updated configuration, for example.

  • command: The command to execute in the background (string)

Namespace niji.util

The namespace niji.util implements functions for a couple of common, specific operations.

niji.util.font_size(config, default)

This function allows modules to easily handle the global font_scale option. If you output a font size to somewhere, simply pass it through this function to allow the user to scale their system font to their liking.

  • config: The module configuration passed to the module handlers
  • default: The font size to use if the scale is 1.0 (int)
  • returns: The properly scaled font size (int)
function M.apply(config, theme)
    local my_font_size = niji.util.font_size(config, 12)

    -- ...
end

niji.util.by_theme(theme, value)

This function makes it easy to allow a config option to optionally be set for each theme individually. The archetypical use case is modules with wallpaper support handling the global wallpaper config option.

The logic itself is fairly simple; if value is a table, return value[<theme name>], or value.default if that is not set. Otherwise, just return value itself.

  • theme: The theme passed to the apply handler
  • value: The config value to handle
function M.apply(config, theme)
    local selected_wallpaper = niji.util.by_theme(theme, config.wallpaper)

    -- ...
end

Namespace niji.xdg

The namespace niji.xdg provides bindings to the configured locations for the xdg base directories standard.

niji.xdg.config_home

$XDG_CONFIG_HOME, or $HOME/.config by default. (string)

niji.xdg.data_home

$XDG_DATA_HOME, or $HOME/.local/share by default. (string)

niji.xdg.state_home

$XDG_STATE_HOME, or $HOME/.local/state by default. (string)

niji.xdg.cache_home

$XDG_CACHE_HOME, or $HOME/.cache by default. (string)

niji.xdg.runtime_dir

The value of $XDG_RUNTIME_DIR. (string)

niji.xdg_data_dirs

The paths contained in $XDG_DATA_DIRS, or { "/usr/local/share", "/usr/share" } by default. (string[])

niji.xdg_config.dirs

The paths contained in $XDG_CONFIG_DIRS, { "/etc/xdg" } by default. (string[])

Templating reference

niji has builtin support for templating using its niji.Template API.

The templating language used for this is niji's own dialect of mustache. You can look at the mustache documentation for general information on how it works, it mostly applies to niji's dialect as well.

One major difference from the mustache specification is that triple mustaches ({{{name}}}), which are normally used to disable escaping of HTML characters, are not supported. Instead, niji templates just never escape HTML characters.

Custom Formats

The one extension that niji makes to the base mustache specification is custom formats for complex types. niji's mustache dialect provides special syntax for displaying formattable types using format strings. This feature is necessary because the vast array of targets niji supports may expect vastly different formats for different data types, and it is impractial to split those datatypes up into more atomic parts.

For example, you can render a color using a custom format like this:

{{my_color : "🔴{r}🟢{g}🔵{b}"}}

The result of rendering this with my_color = "#abcdefff" would be 🔴171🟢205🔵239.

Often times, you will want to use a specific format for the entirety of a template. You can do this by adding a format specification for the type name at the top of your file like this:

{{% "color" : "rgba({r}, {g}, {b}, {a})" %}}

.some-class {
    background-color: {{my_color}}
}

The general format for format strings is exactly the same as that which is used by Rust's standard library, and you can insert any of the properties defined for the type you're working with. A list can be found in the following section.

Formattable Types

For now, the only formattable type is niji.Color. It exposes the following properties:

NameDescription
rThe red component as an integer between 0 and 255
gThe green component as an integer between 0 and 255
bThe blue component as an integer between 0 and 255
aThe alpha component as an integer between 0 and 255
rxThe red component as two hexadecimal digits
gxThe green component as two hexadecimal digits
bxThe blue component as two hexadecimal digits
axThe alpha component as two hexadecimal digits
rfThe red component as a float between 0 and 1
gfThe green component as a float between 0 and 1
bfThe blue component as a float between 0 and 1
afThe alpha component as a float between 0 and 1