Kotlin implementation of the Narrative format, a format for writing interactive stories.
Heavily inspired by Twine, Ren'Py and Cyberscript.
Before you start using this library, we would like to tell you a few words about the format benefits.
Unlike many other storytelling formats, Narrative does not depend on any environment.
You are taking all work on story display and control. Feel the true freedom of telling your ideas. On a web page, in the console, and in any more places.
Any story in Narrative is just a JSON file that can be loaded everywhere and edited by anyone.
And it still strictly maintains the format specification, so you can be sure that your stories will look the same under the hood.
The format itself providing a minimal set of building blocks for your needs. Text and actors, grouped into labels and followed by some interactive events ("jumps" and "signals").
As the format does not depend on any environment, you can add your own features to it. Just describe how you handle them in your code — most times it is as easy as adding a new class to your sources.
First, add the library to your project. We recommend using Gradle and will use it in all examples.
repositories {
// be sure to include the mavenCentral() repository
// if you for some reason don't have it already ಠ__ಠ
mavenCentral()
}
dependencies {
val version = "1.0.0" // replace it with the latest version if there is one
implementation("net.blusutils.narrative:narrative-foundation:$version")
}
If you want JSON serialization support, add the following plugin and dependency:
plugins {
// ...
kotlin("plugin.serialization") version "<kotlin version>"
}
// ...
dependencies {
// ...
implementation("net.blusutils.narrative:narrative-json:$version")
}
In some cases, you may need to add the extensions too (see extensions for more details):
dependencies {
// ...
implementation("net.blusutils.narrative:narrative-extensions:$version")
}
Note
When using extensions, you need to register serializers modules for classes provided by extensions. See extensions for more details.
It is very easy to write a story.
val story = buildStory {
meta {
name = "my_story"
}
labels {
main {
text("Hello, world!")
}
}
}
More details about the format can be found in the Building stories guide.
ToDo
var currentLabel = story.labels.find { it.id == "main" }
if (currentLabel == null) {
for (element in label.elements) {
when (element) {
is LabelText -> println(element.text)
else -> {}
}
}
}
Detailed guides can be found in the Rendering stories.
The documentation is available here.
Licensed under Apache License 2.0.
Copyright 2025 EgorBron
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.