Skip to content

Your first window

Describe an app with the app { } DSL, give it a render plan, and open it in a desktop window with the Vulkan backend.

Vulkan Desktop

This page uses awake-engine-bootstrap and awake-asset-shader-pack in commonMain, and awake-backend-vulkan in desktopMain. See Installation.

Describe the app

In commonMain, the app { } DSL describes the window and the hooks the engine calls. render runs once per frame.

commonMain/kotlin/Game.kt
import com.awakekt.awake.asset.shaderpack.PackShaderSets
import com.awakekt.awake.asset.shaders.RenderPlan
import com.awakekt.awake.asset.shaders.ScenePipeline
import com.awakekt.awake.core.geometry.VertexFormat
import com.awakekt.awake.engine.bootstrap.dsl.app
import com.awakekt.awake.engine.platform.lifecycle.AwakeAppLifecycle
import com.awakekt.awake.render.pipeline.GroupBindings
import com.awakekt.awake.render.pipeline.PipelineKey

/** The app: one window, and a hook that runs every frame. */
fun firstWindow(): AwakeAppLifecycle = app {
    window {
        title = "Hello AwakeKt"
        size(1280, 720)
    }
    render { frame ->
        // frame.delta is the seconds since the last frame.
    }
}

The app does not name a backend, so the same app runs on Vulkan here and on WebGPU in Run in the browser.

Choose what it draws with

A RenderPlan lists the shaders the app renders with. Every app needs a primary pipeline: meshes draw through it unless their vertex format asks for another. This plan uses the lit shader from the shader pack, and turns on the depth pre-pass it samples for shadows. Add it to the same file:

commonMain/kotlin/Game.kt
/** What the app draws with: the lit, shadowed shader that ships in the shader pack. */
val GameRenderPlan = RenderPlan(
    primary = ScenePipeline(
        key = PipelineKey.Primary,
        shaders = PackShaderSets.LitShadow,
        vertexFormat = VertexFormat.PositionNormalColor,
        materialBindings = GroupBindings.UniformOnlyMaterial,
    ),
    depthPrePassShaderSet = PackShaderSets.ShadowDepth,
)

The plan lives in commonMain so that every backend reads the same one. A backend that cannot run part of a plan leaves that part out and reports it, rather than failing.

Open the window

In desktopMain, hand the app and the plan to runVulkanDesktopGame:

desktopMain/kotlin/Main.kt
import com.awakekt.awake.vulkan.application.runVulkanDesktopGame

fun main() = runVulkanDesktopGame(firstWindow(), GameRenderPlan)

Run main. A 1280 × 720 window titled "Hello AwakeKt" opens. Nothing has been added to draw yet, so it shows only the clear colour. Closing the window ends the loop and disposes the app.

macOS needs -XstartOnFirstThread

GLFW only opens windows from the process's first thread on macOS. Add -XstartOnFirstThread to the JVM options of whatever runs main, such as your IDE run configuration or Gradle JavaExec task.

Window settings

Everything inside window { }:

Property Type Default What it does
title String "Awake" The window title.
size(width, height) function 800 × 600 The window size, in pixels.
backend vulkan() · webGpu() · default() default() Which backend the app asks for. runVulkanDesktopGame accepts vulkan() or default().
frameRateMode FrameRateMode FrameRateMode.Auto Auto follows the display, Capped(fps) limits it, Unlimited never waits.
presentMode PresentMode PresentMode.Auto How finished frames reach the display. A request: the surface may pick another.
throttleCpuWhenNotForeground Boolean true Drops to backgroundFrameRate while the window is not focused.
backgroundFrameRate Int 15 The frame rate used while throttled.

Besides render, the app DSL has ready, resize, pause, resume, and dispose hooks.

Next

Your first scene puts a camera, a light, and a spinning cube in this window.