An unofficial Kotlin Multiplatform port of DiceBear, the avatar library. This project is not affiliated with or endorsed by DiceBear or its author. It turns any seed (a username, an email address, …) into an SVG avatar in one of 63 styles. Everything runs offline: no HTTP API, no WebView, no JavaScript engine.
Note
This project is 100% vibe coded: an AI agent (Claude Code) wrote it, porting DiceBear's reference implementation. It is checked against DiceBear's official cross-language test suite and the official JavaScript output for every bundled style, on every target. Still, review it before you rely on it.
- Targets: Android, iOS (arm64, simulator arm64, x64), JVM, JS and Wasm (browser and Node).
- Byte-identical output: the same seed and options produce exactly the SVG the official JavaScript, PHP, Python, Rust, Go, Dart and C# implementations produce. This is checked on every target (see Testing).
- No dependencies: the engine ships its own JSON parser and JSON Schema validator.
| Module | Contents |
|---|---|
dicebear-core |
The engine: Style, Avatar, OptionsDescriptor, validation errors. |
dicebear-styles |
All 63 official style definitions as DiceBearStyles.<name> (depends on core). |
This project has its own version numbers. Version 0.1.0 ports @dicebear/core 11.0.0-rc.2
and bundles the styles of @dicebear/styles 11.0.0-rc.3.
The library is on Maven Central:
repositories {
mavenCentral()
}
kotlin {
sourceSets {
commonMain.dependencies {
implementation("xyz.felixb.dicebear:dicebear-styles:0.1.0") // includes dicebear-core
}
}
}On the JVM or Android without Kotlin Multiplatform, the same coordinates work in a plain
dependencies { implementation(…) } block; Gradle picks the right variant.
Use dicebear-core alone if you bring your own style definitions (JSON) and don't want the
bundled ones.
import xyz.felixb.dicebear.Avatar
import xyz.felixb.dicebear.styles.DiceBearStyles
import xyz.felixb.dicebear.styles.lorelei
val avatar = Avatar(DiceBearStyles.lorelei) {
seed = "Felix"
size = 128
backgroundColor = listOf("b6e3f4", "c0aede", "d1d4f9")
}
avatar.svg // "<svg xmlns=…>…</svg>"
avatar.toDataUri() // "data:image/svg+xml;charset=utf-8,%3Csvg…" (e.g. for <img src>)
avatar.toJson() // {"svg": …, "options": …}, like JSON.stringify(avatar) in JS
avatar.resolvedOptions // what was picked: eyesVariant, backgroundColor, rotate, …Options use the names from the DiceBear docs. Every option can also be passed as a map, including the style-specific ones:
val avatar = Avatar(
DiceBearStyles.adventurer,
mapOf(
"seed" to "Aneka",
"flip" to "horizontal",
"rotate" to listOf(-10, 10), // a range: picked deterministically from the seed
"eyesVariant" to listOf("variant01", "variant02"),
"glassesProbability" to 100,
"backgroundColorFill" to "linear",
),
)
// The builder has `set` for the same purpose: Avatar(style) { this["eyesVariant"] = "variant01" }Styles by name, for example from user settings:
DiceBearStyles.names // ["adventurer", "adventurer-neutral", "avataaars", …]
DiceBearStyles["pixel-art"] // Style?
DiceBearStyles.definition("pixel-art") // raw JSONCustom styles (format):
val style = Style.parse(jsonText) // throws StyleValidationError when invalidOptionsDescriptor(style).toMap() lists every option a style accepts (types, ranges, variant
names). That is enough to build an avatar editor UI without reading the definition yourself.
The library returns SVG markup; drawing it is up to the platform:
- Compose Multiplatform / Android: e.g. Coil 3 with its SVG
decoder (
coil-svg): passavatar.svg.encodeToByteArray()as the model. - iOS:
WKWebView.loadHTMLString, or an SVG library such as SVGKit. - Web (JS/Wasm): set
innerHTML, or usetoDataUri()as an<img>source.
./gradlew :dicebear-styles:assembleDiceBearXCFramework
# → dicebear-styles/build/XCFrameworks/release/DiceBear.xcframeworkimport DiceBear
let avatar = try Avatar(style: DiceBearStyles.shared.lorelei, options: [
"seed": "Felix",
"size": 128,
"backgroundColor": ["b6e3f4", "c0aede"],
])
print(avatar.svg)Invalid options and styles throw Swift errors (ValidationError subclasses).
| Exception | When |
|---|---|
OptionsValidationError |
The options violate the DiceBear options schema. |
StyleValidationError |
A style definition is invalid. |
CircularColorReferenceError |
A style's colors reference each other in a cycle. |
Both validation errors extend ValidationError (an IllegalArgumentException) and list every
failure in details.
The engine is MIT licensed (see LICENSE; it is a port of DiceBear by Florian Körner). The avatar
styles have their own licenses: 44 are CC0 1.0, 14 are CC BY 4.0 (attribution required), 4 are
"free for personal and commercial use" and 1 is MIT.
See dicebear-styles/LICENSE.md and the KDoc of each DiceBearStyles.<name> accessor.
Style.meta gives you the creator, source and license at runtime. Every rendered SVG also embeds
this information in its <metadata> element.
The published jars carry these notices in META-INF/ (LICENSE, and LICENSE-STYLES.md for
dicebear-styles), and the POMs list the licenses per module. If you show avatars of a CC BY 4.0
style, you have to credit its creator as well.
./gradlew jvmTest jsNodeTest wasmJsNodeTest iosSimulatorArm64Test testAndroidHostTestEvery target runs:
- The DiceBear parity suite (
dicebear-core/parity, copied fromtests/fixtures/parity): FNV-1a, Mulberry32, PRNG, number formatting, initials, colors, schema validation, option descriptors and full avatars. The SVGs must match byte for byte. - The reference avatars (
dicebear-core/reference/avatars.json): all 63 bundled styles × 3 seeds × 2 option sets, rendered by the official@dicebear/core. They must be byte-identical, and the resolved options must match. Regenerate withscripts/generate-reference.mjswhen updating the styles.
./gradlew :dicebear-styles:jvmTest also writes example galleries to
dicebear-styles/build/gallery/ (index.html: every style; moods.html: 100 × moods).
Releases go to Maven Central (namespace xyz.felixb) through the
vanniktech maven-publish plugin.
The secrets live in ~/.gradle/gradle.properties, never in this repository:
mavenCentralUsername=<Central Portal user token: username>
mavenCentralPassword=<Central Portal user token: password>
signingInMemoryKey=<ASCII-armored private GPG key, newlines as \n>
signingInMemoryKeyPassword=<passphrase of that key>Run the release on a Mac, since the iOS artifacts can only be built on macOS:
./gradlew publishToMavenCentral # upload only, review and release in the portal
./gradlew publishAndReleaseToMavenCentral # upload and releaseBump version in build.gradle.kts first: a released version can never be replaced.
- Styles: replace
dicebear-styles/definitions/*.jsonwith thedist/*.min.jsonfiles of a new@dicebear/stylesrelease (drop the.min), then regenerate the reference avatars. - Engine: port changes from the reference implementation (the Dart port in
src/dart/coreis the closest to Kotlin). Copy the new parity fixtures todicebear-core/parityand the schemas of@dicebear/schematodicebear-core/schema.
build-logic/ EmbedJsonTask: turns JSON files into Kotlin sources (styles, schemas, fixtures)
dicebear-core/ engine (commonMain) + parity/reference tests (commonTest)
schema/ draft-07 JSON Schemas from @dicebear/schema
parity/ cross-language parity fixtures
reference/ official JS output for every bundled style
dicebear-styles/ bundled styles + XCFramework
definitions/ style definitions from @dicebear/styles
scripts/ reference fixture generator (Node)