docs / Native

Getting Started (Native)

Scaffold a native Android app with create-vesk-native, install the toolchain, write your first .vsk page, and build an APK.

`create-vesk-native` scaffolds a complete native project: gradle build files, a sample `.vsk` page tree, `veskconfig.ts`, and `package.json` scripts. No Android Studio project setup — the CLI owns every generated file.

Scaffold a project

terminal
									
										npx create-vesk-native my-app
cd my-app
npm install
npm run dev
									
								
  • `--template blank` — minimal single-page app.
  • `--template starter` — counter with a test notification button (default).
  • `--template demo` — full showcase: shop, blog, animations, media, device APIs.
  • `--app-id com.example.myapp` — override the Android application ID.
  • `--primary '#FF5722'` — set the theme primary color.
  • `-y` — non-interactive mode (uses defaults for all prompts).
terminal
									
										npx create-vesk-native my-app -y --template starter --app-id com.example.myapp
									
								

Toolchain setup

The CLI detects your OS, architecture, and whether you are on Termux, then resolves the Android SDK automatically. When the toolchain is missing it offers to install it:

  • JDK 17+ — detected via `JAVA_HOME` or `which java`.
  • Android SDK — detected via `ANDROID_HOME`, `ANDROID_SDK_ROOT`, the toolchain root, or Termux `$PREFIX`.
  • Gradle 9.7.0 — managed at the toolchain root; PATH gradle is used only if it is a supported version.
  • Install commands: `vesk setup` provisions everything under the toolchain root; `vesk update-tools` refreshes SDK packages and Gradle.

Termux users get native aapt2 proxy support — the CLI detects `$PREFIX` and syncs the aapt2 override automatically.

Project layout

my-app/
									
										app/
  layout.vsk              # root layout — wraps every route via {props.children}
  page.vsk                # / (home)
  about/page.vsk          # /about
  blog/page.vsk           # /blog
  blog/[slug]/page.vsk    # /blog/:slug
  shop/page.vsk           # /shop
  shop/[id]/page.vsk      # /shop/:id
veskconfig.ts             # app config (defineConfig)
libraries.json            # installed Kotlin libraries (committed)
package.json              # scripts: build, dev, dev:web, dev:desktop
app/
  build.gradle.kts        # generated — do not edit
  src/main/
    AndroidManifest.xml   # generated from device API usage
    java/com/.../
      MainActivity.kt     # generated
shared/
  build.gradle.kts        # generated KMP module
  commonMain/             # generated shared Kotlin
  androidMain/            # generated Android-specific Kotlin
									
								

First build

terminal
									
										npm run build

# Output:
# app/build/outputs/apk/debug/app-debug.apk
# shared/commonMain/src/.../
# shared/androidMain/src/.../
									
								
  • `build` regenerates all Kotlin sources from `.vsk` files, then runs `gradle assembleDebug`.
  • Every generated file is owned by vesk-native and regenerated on every build — never hand-edit generated files.
  • The debug APK is signed with the debug keystore automatically.

Scripts

Script What it does
npm run build Regenerate + gradle assembleDebug → debug APK
npm run dev On-device fast reload (requires adb + emulator/device)
npm run dev:web Browser preview on localhost:5173
npm run dev:desktop Desktop JVM preview with Compose Hot Reload

Key conventions

  • All configuration lives in `veskconfig.ts` — no XML, no Kotlin, no gradle edits.
  • All app code lives in `.vsk` component files — Tailwind classes become Compose Modifier chains.
  • Permissions, gradle deps, and runtime helpers are derived from what the app actually uses — never added 'just in case'.
  • Tracked state uses `track()` and `&[]` sugar — same as web. Reads auto-subscribe, writes schedule updates.
  • The `component` keyword, statement mode, and expression mode all work exactly as they do on the web.

CSS animation classes are unsupported in native — use motion.animate() instead. The compiler warns on unsupported web constructs and hard-errors on untranslatable constructs.