1 By Example
Tearnote edited this page 2026-09-05 00:09:03 +01:00

Playnote > Theming > By example

Glad you decided to give it a go! Playnote theming can become quite extensive, but very little is needed to make a small change to the game's existing look. These examples are complete child themes that change one or two things at a time, so you can see both what is possible and how it is done.

Make your first theme

To get started, we'll change Playnote's accent colour. Once this theme is working, the later examples can be made by copying its folder and changing its files.

Start Playnote once so that it creates its configuration directory and installs the default theme. Then create a new folder named sunset inside the themes directory:

  • Linux: ~/.config/playnote/themes/sunset/
  • Windows and portable mode: [executable folder]/config/themes/sunset/

The folder name is the theme's ID, so it must match the ID in theme.kdl. Create theme.kdl inside the new folder:

theme "sunset" format=1 {
    name "Sunset"
    description "A warm accent-color remix of the default theme."
    creator "Your name"

    extends "default"
    styles "style.pncss"
}

The extends entry makes the theme inherit all the basics, so that we can specify just the changes. Now create style.pncss:

@const palette {
    accent: rgb(0.95 0.42 0.24);
    selection: rgb(0.22 0.13 0.11);
}

These entries use the same names as ones already in default, and default uses them all around the place to color game elements. By overriding them with other values, the rest of default now refers to our new values.

Finally, open config.toml in Playnote's configuration directory and set the theme in the [ui] section:

theme = "sunset"

The new accent colour should appear in the library and gameplay screens. (Even if the game was already open!) If nothing happened, check the logs for error messages.

If the load was successful, the theme is now enabled for hot reload. Try going back to style.pncss and editing the color values; the results should be visible instantly the moment you save the file.

Make the song wheel more compact

To try out this and any later examples, make a copy of the sunset folder, or edit it in-place. Remember that the theme ID (on the first line of theme.kdl) needs to match the folder name.

For this one, let's have the song select fit in more entries by compacting the list. Replace style.pncss with:

song-wheel {
    item-extent: 24;
}

text.song-wheel-entry {
    size: 16;
    inset: 0 6;
}

item-extent controls the size of each song entry, while the text rule makes the smaller entries fit comfortably inside it.

Use pill-shaped notes

The default playfield note uses a rectangle whose size is supplied by the playfield script, so that the various lane types (scratch, odd, even) can use just one note shape for all variants. Let's modify the note shape by keeping all the same hooks ($ values), but adding corner rounding:

@shape note {
    rect-tl {
        size: $size;
        rounding: inf; /* meaning "as far as the shorter edge allows" */
        color: $color;
    }
}

Notes can be changed to look like anything, but that would need a modification to the Playfield script to use hooks differently, so it's out of the scope of this page.

Remove a distracting element

To remove the gameplay statistics without leaving an empty region behind, add this rule:

list.play-stats {
    enabled: false;
}

The same technique can remove the note graph:

note-graph.gameplay-note-graph {
    enabled: false;
}

visible: false, or opacity: 0, would make an element invisible but would not remove it from the layout. enabled: false skips it during layout as well as drawing.

Rearrange the library

Views control the arrangement of widgets. For example, the default library uses a five-column grid, with chart information below the library and the song wheel on the right. To give the wheel a narrow column instead, add views "views.kdl" to the manifest and create that file:

view "library" {
    modular-grid columns=4 rows=2 {
        slot "chart-info" type="chart-info" column=0 row=0 column-width=3 row-height=2
        slot "song-wheel" type="song-wheel" column=3 row=0 row-height=2
    }
}

The grid that contains the library elements is now 4 columns wide, and the song wheel now has the default width of 1 column. As a result, the previous 60/40 width split now becomes 75/25, making the song wheel take up less space than before.

Important

When replacing a view, you need to keep all the slots, including their names and types. This is required because these elements might perform functions that the game requires to work. The previous example shows how to remove elements instead.

What's next

I hope these practical examples gave you a good taste of the theming system. If you want to know what else is possible to achieve, have a look at the detailed docs on the sidebar to the right. All of the game is built on this system, so if you're a more practical type, feel free to make a copy the entire default theme and play with it. If you get confused by anything you see, the reference pages will be waiting for you here.