Skip to main content

Known Issues

Comparing strings with differently composed UTF-8 characters​

In UTF-8 characters can existing in multiple forms, e.g. decomposed and pre-composed. Visually they always appear as a single character and should compare equal.

Spacer size incorrect if applying modifiers to it​

A modifier applied to a Spacer in a stack can alter the Spacer size in unexpected ways. For a correct behavior of Spacer, avoid applying modifiers directly on it.

Large sprites rendered blurry​

Large sprites displayed with Image or NinePatchImage can appear blurry.

Images are uploaded to the GPU as-is. When an image exceeds the GPU's maximum texture size, the GPU stores a downscaled version of it, which is then upscaled again when rendering. This causes the image to appear blurry (low-res).

The maximum texture size depends on the platform and cannot be controlled by Kontakt. On desktop systems it is usually around 16000×16000 pixels, sometimes 32000×32000. Most images never get this big, but sprites with many frames might do, especially when all frames are stacked along one dimension.

To avoid the issue, keep images below 16000 pixels per dimension, ideally even below 8000. Since Kontakt 8.14, the frames of a sprite can be arranged in a grid of rows and columns, which keeps both dimensions small.

Font styles recognized as different families on Windows​

On Windows, some font files of the same family are recognized as different families, depending on their style. For example, Roboto-Regular.ttf and Roboto-Bold.ttf belong to the family Roboto, while Roboto-Medium.ttf belongs to a separate Roboto Medium family. Loading such files together in a single load_font call fails with an error, because the files must be of the same family.

To avoid the issue, load the styles in separate groups, one load_font call per weight with its bold and italic variants:

import { Text, VStack, load_font } from ui

var roboto = load_font([
"assets/Roboto-Regular.ttf",
"assets/Roboto-Bold.ttf",
"assets/Roboto-Italic.ttf",
"assets/Roboto-BoldItalic.ttf",
])

var roboto_medium = load_font([
"assets/Roboto-Medium.ttf",
"assets/Roboto-MediumItalic.ttf",
])

var roboto_black = load_font([
"assets/Roboto-Black.ttf",
"assets/Roboto-BlackItalic.ttf",
])

export var main = VStack {
Text("Regular", font_family: roboto)
Text("Medium", font_family: roboto_medium)
Text("Black", font_family: roboto_black)
}

This works on all platforms, so it's best to always group font files like this.

Enabling experimental features in Kontakt options can break existing content​

When the Experimental Features option is enabled in Kontakt, all Komplete UI instruments automatically use the latest Kontakt version as their Kontakt target version. This can cause errors in instruments that rely on an older API affected by breaking changes.

Using the iterated container inside the declarative for loop​

info

This was fixed in Kontakt 8.4

Using the same container that was used to iterated over in the declarative for loop can cause out of bounds errors, if elements are removed from the container.

import * from ui

var presets = ["A", "B", "C", "D"]

export component Main {
VStack {
Text("Remove") with {
TapGesture(fun (event) {
presets.remove(at: 0)
})
}

for i, preset in presets.enumerated() {
Text("\{i}: \{presets[i]}")
}
}
}

export var main = Main()

For now it's best to only access the iteration values and not the entire list:

import * from ui

var presets = ["A", "B", "C", "D"]

export component Main {
VStack {
Text("Remove") with {
TapGesture(fun (event) {
presets.remove(at: 0)
})
}

for i, preset in presets.enumerated() {
Text("\{i}: \{preset}")
}
}
}

export var main = Main()

Using the same state in the declarative for loop and its body can cause a "cycle" error​

info

This was fixed in Kontakt 8.4

In some cases using the same state to create the sequence to loop over inside the body of the loop can cause a "cycle detected" error.

import * from ui

var presets = ["A", "B", "C", "D"]

export component Main {
offset: Int = 0

VStack {
Text("Next") with {
TapGesture(fun (event) {
self.offset = (self.offset + 1) % presets.length
})
}

for i, preset in presets.subsequence(from: self.offset, length: 1).enumerated() {
Text("\{i + self.offset}: \{preset}")
}
}
}

export var main = Main()

Currently, the only workaround is to embed the total index (id) into the preset and avoid using the offset inside the body.

import * from ui

class Preset {
id: Int
name: String
}

var presets = [
Preset(id: 0, name: "A"),
Preset(id: 1, name: "B"),
Preset(id: 2, name: "C"),
Preset(id: 3, name: "D"),
]

export component Main {
offset: Int = 0

VStack {
Text("Next") with {
TapGesture(fun (event) {
self.offset = (self.offset + 1) % presets.length
})
}

for preset in presets.subsequence(from: self.offset, length: 1) {
Text("\{preset.id}: \{preset.name}")
}
}
}

export var main = Main()