Get started¶
Add the dependencies¶
Use Java 25+, Kotlin 2.4.20 and Compose Multiplatform 1.12.1 for the tested development setup. Add the repository to the consuming project's settings.gradle.kts:
dependencyResolutionManagement {
repositories {
maven {
url = uri("../byteink/build/repo")
content { includeGroup("com.vivenotes.byteink") }
}
google()
mavenCentral()
}
}
Publish the checkout locally once; its native build outputs must be present:
# In ByteInk; omit the native builds when their pinned outputs already exist.
native/build-linux.sh
native/build-windows.sh
./gradlew publishAllPublicationsToBuildRepository
In the consumer's JVM dependencies:
kotlin {
jvm()
sourceSets.jvmMain.dependencies {
implementation("com.vivenotes.byteink:byteink-compose:0.1.0-SNAPSHOT")
implementation("com.vivenotes.byteink:byteink-kit:0.1.0-SNAPSHOT")
implementation(compose.desktop.currentOs)
}
}
compose.desktop {
application {
mainClass = "your.package.MainKt"
jvmArgs += "--enable-native-access=ALL-UNNAMED"
}
}
Apply the Kotlin Compose compiler and Compose Multiplatform plugins in your application. The application supplies its OS-specific Compose/Skiko runtime. byteink-compose and byteink-kit bring in core, the pinned AndroidX modules and the native loader.
For a plain JVM project, put the same dependencies in dependencies { ... }. The example build uses a standalone JVM consumer.
Other repository choices¶
| Mode | Setup |
|---|---|
| Source/composite | Add includeBuild("../byteink") to settings; keep the normal dependency declarations. Native outputs are still required. |
| Maven local | Run ./gradlew publishToMavenLocal in ByteInk; configure mavenLocal { content { includeGroup("com.vivenotes.byteink") } }. |
| GitHub Packages | Use the registry below and a published version. A remote package must already exist. |
maven {
url = uri("https://maven.pkg.github.com/crownbyte0b/byteink")
content { includeGroup("com.vivenotes.byteink") }
credentials {
username = providers.environmentVariable("GITHUB_ACTOR").orNull
password = providers.environmentVariable("GITHUB_TOKEN").orNull
}
}
GitHub's Maven registry requires authentication, including for public packages. Use a classic token with read:packages; keep it outside source control. Registry documentation.
Avoid adding Google's androidx.ink:ink-nativeloader or ink-nativeloader-jvm separately: they conflict with ByteInk's loader. See troubleshooting.
Create, store and rebuild a stroke¶
This uses the same input/brush types as AndroidX Ink. elapsedTimeMillis starts at zero for each stroke.
package wiki
import androidx.ink.brush.InputToolType
import androidx.ink.strokes.MutableStrokeInputBatch
import androidx.ink.strokes.Stroke
import com.vivenotes.byteink.core.InkRuntime
import com.vivenotes.byteink.kit.AuthoredViveStroke
import com.vivenotes.byteink.kit.ViveBrushes
import com.vivenotes.byteink.kit.ViveInkTool
fun firstStroke(): AuthoredViveStroke {
InkRuntime.load()
val tool = ViveInkTool(
familyId = ViveBrushes.MARKER,
sizeDp = 6f,
colorArgb = 0xff202020.toInt(),
colorFollowsTheme = false,
)
val inputs = MutableStrokeInputBatch().apply {
add(type = InputToolType.MOUSE, x = 10f, y = 50f, elapsedTimeMillis = 0L)
add(type = InputToolType.MOUSE, x = 90f, y = 50f, elapsedTimeMillis = 80L)
}
return tool.complete(
stroke = Stroke(tool.brush, inputs),
id = "stroke-1",
pageId = "page-1",
seq = 1,
createdAt = 42L,
)
}
ViveInkTool.complete returns the finished stroke and a new stored row. canonicalStroke rebuilds that row through the codec, giving the geometry a reload will use. Persist row with a unique ID, correct page ID, and repository-allocated seq.
For live drawing, continue to the Compose surface. All tool parameters.