Skip to content

3D · TypeScript · Free download

Babylon.js game starter

A complete 3D engine with rendering, cameras, animation, and game development tools.

Build locally with your preferred editor or AI coding agent. You keep the source and choose where to publish.

No account needed. Extract into a new folder to keep your existing projects safe.

Babylon.js starter illustration

What you can build

Interactive 3D browser worlds. The starter includes a minimal movement and collection scene so you can verify the runtime before adding your own rules, artwork and levels.

Included in this kit

  • Babylon.js for 3D rendering
  • Plain movement without a separate physics integration
  • HTML/CSS interface, keyboard input and editable game logic
  • Vite development server, TypeScript, linting and Vitest checks

Browser games are the supported target. Native desktop and mobile packaging are not included.

Run your game

Requires Node.js >=24.0.0 and pnpm@12.10.1.

  1. Download and extract the kit into a new folder.
  2. Open that folder in your editor and run pnpm install.
  3. Run pnpm dev and open the address shown in your terminal.

The local HTTPS setup may ask you to trust its development certificate. See the included README for setup and troubleshooting.

Run pnpm build to prepare a release. Explore hosting when you are ready to share it.

Preview the generated project

These 32 files and commands come from the same configuration used by the download.

Project files
  • dev-domains.config.mjs
  • scripts/local-environment.mjs
  • scripts/local-environment.d.mts
  • .gitignore
  • .npmrc
  • pnpm-workspace.yaml
  • tsconfig.json
  • .oxlintrc.json
  • .oxfmtrc.json
  • src/score.ts
  • src/input.ts
  • vite.config.ts
  • spawnkit/config.ts
  • spawnkit/vite.ts
  • src/style.css
  • src/main.ts
  • src/simulation.ts
  • vitest.config.ts
  • src/score.test.ts
  • src/simulation.test.ts
  • src/ui.ts
  • src/input.test.ts
  • src/main.test.ts
  • src/ui.test.ts
  • package.json
  • game.config.json
  • spawnkit.config.ts
  • public/spawnkit-listing.schema.json
  • public/media/cover.svg
  • index.html
  • README.md
  • .spawn/state.json
Available commands
pnpm dev
dev-domains run app
pnpm build
tsc --noEmit && vite build
pnpm preview
vite preview
pnpm lint
oxlint --no-ignore src vite.config.ts
pnpm test
vitest run --coverage
Entry point: src/main.ts
import { createUI } from "./ui"
import { ArcRotateCamera } from "@babylonjs/core/Cameras/arcRotateCamera"
import { Engine } from "@babylonjs/core/Engines/engine"
import { HemisphericLight } from "@babylonjs/core/Lights/hemisphericLight"
import { StandardMaterial } from "@babylonjs/core/Materials/standardMaterial"
import { Color3, Color4 } from "@babylonjs/core/Maths/math.color"
import { Vector3 } from "@babylonjs/core/Maths/math.vector"
import { CreateBox } from "@babylonjs/core/Meshes/Builders/boxBuilder"
import { CreateGround } from "@babylonjs/core/Meshes/Builders/groundBuilder"
import { CreateSphere } from "@babylonjs/core/Meshes/Builders/sphereBuilder"
import { Scene } from "@babylonjs/core/scene"
import "./style.css"
import { advanceScore } from "./score"
import { createSimulation } from "./simulation"
import { createInput } from "./input"

const simulation = createSimulation({ x: 0, y: 0, speed: 5, minX: -7.5, maxX: 7.5, minY: -5.5, maxY: 5.5 })

const canvas = document.createElement("canvas")
canvas.setAttribute("aria-label", "3D game. Use arrow keys to collect gold.")
canvas.tabIndex = 0
document.querySelector("#game")?.append(canvas)
const controls = createInput(canvas)
const engine = new Engine(canvas, true)
const scene = new Scene(engine)
scene.clearColor = new Color4(0.04, 0.08, 0.12, 1)
new ArcRotateCamera("camera", -Math.PI / 2, Math.PI / 3, 18, Vector3.Zero(), scene)
new HemisphericLight("light", new Vector3(0, 1, 0), scene)
const ground = CreateGround("ground", { width: 16, height: 12 }, scene)
const groundMaterial = new StandardMaterial("ground-material", scene)
groundMaterial.diffuseColor = new Color3(0.1, 0.2, 0.25)
ground.material = groundMaterial
const player = CreateBox("player", { size: 0.7 }, scene)
player.position.y = 0.35
const playerMaterial = new StandardMaterial("player-material", scene)
playerMaterial.diffuseColor = new Color3(0.7, 0.96, 0.42)
player.material = playerMaterial
const collectible = CreateSphere("collectible", { diameter: 0.55 }, scene)
collectible.position.set(3, 0.5, 0)
const gold = new StandardMaterial("gold", scene)
gold.diffuseColor = new Color3(1, 0.7, 0.3)
collectible.material = gold
const ui = createUI()
window.addEventListener("pagehide", () => ui.dispose(), { once: true })
let score = 0
scene.onBeforeRenderObservable.add(() => {
  scene.physicsEnabled = !ui.isPaused()
  if (ui.isPaused()) return
  const position = simulation.step(controls.read(), engine.getDeltaTime() / 1000)
  player.position.x = position.x
  player.position.z = -position.y
  if (Vector3.Distance(player.position, collectible.position) < 0.8) {
    score = advanceScore(score)
    const label = document.querySelector("#score")
    if (label) label.textContent = "Collected: " + score
    collectible.position.set(Math.random() * 14 - 7, 0.5, Math.random() * 10 - 5)
  }
})
engine.runRenderLoop(() => scene.render())
window.addEventListener("resize", () => engine.resize())

window.addEventListener("pagehide", () => { scene.dispose(); engine.dispose() }, { once: true })

Explore other engines