LittleKt Documentation

repository·master·Indexed 17 days ago

https://github.com/littlektframework/littlekt

A Kotlin multiplatform 2D game development framework based on WebGPU, designed to combine libGDX's flexibility with idiomatic Kotlin features. It supports Desktop (JVM) via the Java FFM API and Web (JS), with planned support for Android and iOS. Key features include a scene-graph module, GLTF model loading with customizable material strategies, an AnimationBuilder DSL for sprite animations, a CPU-based particle system with lifecycle hooks, and a ShapeRenderer for high-performance 2D shape drawing.

Tokens
9K
Snippets
30
Records
37
Agent score
63%

What's inside LittleKt

  1. Supported Platforms and Targets

    master

    LittleKt is a Kotlin multiplatform 2D game framework based on WebGPU. Current support status:

    • Desktop (JVM): ✅ Supported via wgpu-native using the Java FFM API.
    • Web (JS): ✅ Supported via webgpu.
    • Android: 🚧 In Progress (Planned: wgpu-native via JNI).
    • iOS / Native: 📅 Planned (wgpu-native).

    Note: An OpenGL version exists on a separate branch but is deprecated.

  2. Install LittleKt Snapshots

    master

    If you want to use the bleeding-edge version of LittleKt, you can pull from the Sonatype snapshot repository. Snapshot versions follow the pattern x.x.x.hash-SNAPSHOT (e.g., 0.2.1.080b1ad-SNAPSHOT).

    Warning: Snapshot versions are subject to breaking changes.

    repositories {
        maven(url = "https://central.sonatype.com/repository/maven-snapshots/")
    }
    
    kotlin {
        compilerOptions {
            jvmTarget = JvmTarget.JVM_25
        }
    }
    
    val littleKtVersion = "0.11.0.131d453-SNAPSHOT"
    val kotlinCoroutinesVersion = "1.9.0"
    
    sourceSets {
        val commonMain by getting {
            dependencies {
                implementation("com.littlekt:core:$littleKtVersion")
                implementation("com.littlekt:scene-graph:$littleKtVersion")
                implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinCoroutinesVersion")
            }
        }
    }
  3. Install LittleKt via Maven Central

    master

    To use LittleKt in your Kotlin Multiplatform project, add mavenCentral() to your repositories and include the com.littlekt:core dependency. You must also include org.jetbrains.kotlinx:kotlinx-coroutines-core as LittleKt requires coroutines on the classpath.

    Important Requirements:

    • JDK 22+ is required because LittleKt uses the Java Foreign Function & Memory (FFM) API.
    • Set your jvmTarget to JvmTarget.JVM_25 (or the appropriate version for your setup) in your build.gradle.kts.
    repositories {
        mavenCentral()
    }
    
    kotlin {
        jvm {
            compilerOptions {
                jvmTarget = JvmTarget.JVM_25
            }
        }
    }
    
    val littleKtVersion = "0.11.0"
    val kotlinCoroutinesVersion = "1.9.0"
    
    sourceSets {
        val commonMain by getting {
            dependencies {
                implementation("com.littlekt:core:$littleKtVersion")
                implementation("com.littlekt:scene-graph:$littleKtVersion") // optional scene-graph module
                implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinCoroutinesVersion")
            }
        }
    }
  4. Configure Particle lifecycle and user data

    master

    The Particle class includes several lifecycle hooks and user-defined data fields to facilitate complex particle behaviors.

    Lifecycle Hooks:

    • onStart: (() -> Unit)?: Invoked when the particle is first initialized.
    • onUpdate: ((Particle) -> Unit)?: Invoked every frame while the particle is alive.
    • onKill: (() -> Unit)?: Invoked when the particle is killed.

    User Data Fields: data0 through data7 are Float fields used to mark or denote events within the lifecycle hooks. These fields are reset to 0f whenever the particle is reallocated.

    Example of using onUpdate and data0 to trigger an event once a condition is met:

    particle.onUpdate = {
        if (particle.data0 == 1f) {
            // do something once
        } else if (particle.x >= 50f) {
            particle.data0 = 1f
        }
    }
    particle.onUpdate = {
       if(particle.data0 == 1f) {
          // do something
       } else if(particle.x >= 50f) {
          particle.data0 = 1f
       }
    }
  5. Use ModelBatch for efficient 3D rendering

    master

    The ModelBatch class is a rendering helper designed to handle pipeline caching and bind group caching for drawing 3D meshes. It optimizes rendering by grouping primitives by their MaterialPipeline, reducing state changes during the flush process.

    To use it, you must provide a Device and register MaterialPipelineProviders for the material types you intend to use. You then queue objects for rendering using render() and execute the actual draw calls by calling flush() with a RenderPassEncoder.

    // Initialize the batch
    val modelBatch = ModelBatch(device)
    
    // Register providers for your materials
    modelBatch.addPipelineProvider(MyMaterialPipelineProvider())
    
    // In your render loop:
    // 1. Queue nodes/primitives
    modelBatch.render(myNode3D, environment)
    
    // 2. Execute draw calls
    modelBatch.flush(renderPassEncoder, camera, deltaTime)
  6. Implement custom material strategies for GLTF

    master

    You can extend the GLTF loading process by providing custom implementations of GltfModelMaterialStrategy or GltfModelFallbackMaterialStrategy.

    GltfModelMaterialStrategy

    Used to create a Material when a GLTF primitive contains material data. The createMaterial method provides access to the Device (GPU context), the preferredFormat for textures, the GltfMaterial data, and the full GltfData file.

    Available built-in strategies:

    • PBRMaterialStrategy: Creates a PBRMaterial using metallic-roughness data from the GLTF file.
    • UnlitMaterialStrategy: Creates an UnlitMaterial using base color data.

    GltfModelFallbackMaterialStrategy

    Used to create a Material when a GLTF primitive does not have material data. The createMaterial method provides the GltfModelConfig and the Device.

    Available built-in strategy:

    • UnlitMaterialFallbackStrategy: Creates an UnlitMaterial that defaults to a white texture.
  7. Configure GLTF model loading with GltfLoaderConfig

    master

    To load GLTF models, you must provide a GltfLoaderConfig. This configuration determines how the model's physical properties (like shadows and skinning) are handled and defines the strategies used to create materials both when GLTF material data is present and when it is missing.

    GltfLoaderConfig is composed of:

    • modelConfig: A GltfModelConfig defining castShadows and skinned properties.
    • materialStrategy: A GltfModelMaterialStrategy used when a primitive has GLTF material data.
    • fallbackMaterialStrategy: A GltfModelFallbackMaterialStrategy used when a primitive lacks GLTF material data.

    Convenience functions are provided for common use cases:

    • GltfLoaderPbrConfig(): Configures the loader for Physically Based Rendering (PBR) using PBRMaterialStrategy and an UnlitMaterialFallbackStrategy.
    • GltfLoaderUnlitConfig(): Configures the loader for unlit materials using UnlitMaterialStrategy and an UnlitMaterialFallbackStrategy.
    // Example: Creating a PBR configuration for a skinned model that casts shadows
    val config = GltfLoaderPbrConfig(
        modelConfig = GltfModelConfig(castShadows = true, skinned = true)
    )
  8. Configure ShapeRenderer properties

    master

    You can configure several properties on a ShapeRenderer instance to affect all subsequent draw calls:

    • snap: A Boolean that, when true, snaps line endpoints to the center of pixels. Defaults to false.
    • thickness: A Float representing the default thickness in world units for lines and outlines. Defaults to 1f.
    • sideEstimator: An implementation of SideEstimator used to calculate the number of sides required for smooth curves (circles/ellipses). Defaults to DefaultSideEstimator().
    • color: The current Color used for drawing. Setting this updates the underlying BatchManager.
    • pixelSize: A read-only Float representing the current pixel size in world units. This is updated via updatePixelSize(width: Int).
  9. Create a Logger instance

    master

    You can obtain a Logger instance by invoking the Logger class with a name or by using a class reference. If a logger with that name already exists, the existing instance is returned; otherwise, a new one is created and registered.

    • Use Logger("name") to create a logger with a specific name.
    • Use Logger<MyClass>() to create a logger named after the simple name of the provided class.
    // By name
    val logger = Logger("MySystem")
    
    // By class type
    val logger = Logger<MyComponent>()
  10. Use Scaler to calculate viewport dimensions

    master

    The Scaler class and its implementations provide different strategies for calculating how a source dimension (e.g., game resolution) should be scaled to fit a target dimension (e.g., screen size).

    To use a scaler, call the apply method with the source and target dimensions. The method returns a Vec2f representing the new calculated size.

    Available scaling strategies:

    • Fit: Maintains aspect ratio while fitting as much content as possible onto the screen.
    • Fill: Maintains aspect ratio while ensuring the entire target area is covered (may crop content).
    • FillX: Stretches to fit the target width while maintaining the source aspect ratio.
    • FillY: Stretches to fit the target height while maintaining the source aspect ratio.
    • Stretch: Stretches the content to match the target width and height exactly (ignores aspect ratio).
    • StretchX: Stretches to the target width but keeps the source height.
    • StretchY: Stretches to the target height but keeps the source width.
    • None: Performs no scaling and returns the original source dimensions.
    import com.littlekt.util.Scaler
    
    val scaler = Scaler.Fit()
    val newSize = scaler.apply(
        sourceWidth = 1920,
        sourceHeight = 1080,
        targetWidth = 1280,
        targetHeight = 720
    )
    
    println("New Width: ${newSize.x}, New Height: ${newSize.y}")
  11. Pre-warm pipelines with preparePipeline()

    master

    To prevent frame drops caused by shader or pipeline compilation during gameplay, you can use preparePipeline to generate the necessary pipelines and bind groups on a separate thread or during a loading screen. This method does nothing if the pipeline is already prepared via render or preparePipeline.

    // Prepare an entire Node3D tree
    modelBatch.preparePipeline(node, environment)
    
    // Prepare a specific MeshPrimitive
    modelBatch.preparePipeline(meshPrimitive, environment)