Home / Guides / Cozy walking game in three.js

How to make a cozy walking game in three.js with AI

Short answer: set up a Vite project with three.js, let an AI coding agent (Claude Code, Codex or Cursor) write the code one feature at a time, build a little meadow from free CC0 models (Kenney, Quaternius, Poly Haven), give your character a free walk and idle animation from Mixamo, add a follow camera and a calm ambient loop, then upload the build to itch.io as an HTML game. Everything here is free except, possibly, the coding agent. Checked Oct 26, 2026.

What you will build

A tiny cozy walking game: one character, one pretty place, no enemies and no way to lose. The player walks around a meadow with trees and rocks, the camera follows gently, soft music plays, and maybe there are a few lanterns to find. It is small on purpose. A walking game skips the hardest parts of game design, so your first 3D game actually gets finished.

New to three.js? Read How to make a browser game with three.js and AI first. It covers picking an agent, the general Vite setup and hosting options. This guide is the next step: a complete little game that ties together free models, AI 3D tools, Mixamo animation and publishing.

What you need (all free)

three.js

Free, open source (MIT) JavaScript 3D library for WebGL and WebGPU that runs games and scenes directly in the browser.

Pricing: Free. Beginner rating: 3/5. A code library, not an editor, but AI coding agents write three.js well and you test in any browser.

Free, runs in any modern browser, and AI agents write it well.

Step 1: Set up the project and agent notes

Install Node.js, then run these commands from the Vite guide and the three.js installation manual:

npm create vite@latest cozy-walk -- --template vanilla
cd cozy-walk
npm install
npm install three
npm run dev

Add a vite.config.js so asset paths stay relative. itch.io serves your game from a subfolder, and paths that start with / break there:

// vite.config.js
import { defineConfig } from 'vite';

export default defineConfig({
  base: './', // relative paths so the build works on itch.io
});

Then give your agent a short notes file. Claude Code reads CLAUDE.md, Codex reads AGENTS.md, and Cursor supports project rules. The notes keep the agent on the right three.js version and stop it from adding random frameworks:

# Cozy walking game: project notes

- Stack: Vite (vanilla JavaScript) + three.js (npm "three" 0.186.1, release r186).
- Import addons from 'three/addons/...'. Use THREE.Timer, not THREE.Clock (deprecated since r183).
- Game code lives in src/main.js. Models in public/models/, sounds in public/sounds/.
- Load assets with relative paths like './models/player.glb' (the game ships to itch.io).
- player.glb has two animation clips named "Idle" and "Walk".
- Mood: calm and cozy. No enemies, no timer, no game over.
- One feature per change. Do not add frameworks or npm packages without asking.
- Run: npm run dev. Build: npm run build (outputs dist/).

Step 2: Build the world from free CC0 models

Free model kits give you a matching art style in minutes. We checked each license on the official site on Oct 26, 2026:

Copy the files you want into public/models/, then ask the agent to place them. A good first prompt:

Load trees and rocks from public/models with GLTFLoader and scatter about 40 of them randomly on the ground plane, at least 3 units from the center so the player starts in a clearing. Use a fixed random seed so the layout is the same every time. Keep the total under 60 models.

Kenney

Thousands of free 2D and 3D game assets, UI and audio packs. Kenney states all assets on its asset pages are public domain (CC0), commercial use allowed, attribution not required.

Pricing: Free. Beginner rating: 5/5. Consistent style, no sign up, and the CC0 license means nothing to track.

CC0 kits with ready GLB files and a consistent, cozy low poly style.

Quaternius

Free low poly 3D model packs, many rigged and animated. Quaternius says its assets are CC0, usable in commercial projects without credit and modifiable in any way.

Pricing: Free. Beginner rating: 5/5. Ready made themed packs with a matching style and no license strings.

CC0 low poly nature packs and animated characters.

More libraries are in free game assets for beginners. For a sky, our skybox and game level guide covers free CC0 HDRIs.

Step 3 (optional): Add a few AI generated props

Want one special object no kit has, like a mossy shrine or a crooked mailbox? Generate it with an AI 3D tool, but read the free plan rules first. From each official pricing page, checked Oct 26, 2026:

AI models are often heavy and oddly scaled. Ask your agent: Log the bounding box size of each loaded model and scale it so trees are about 4 units tall and props about 1 unit. If a model has far too many triangles, Blender's Decimate modifier reduces them. Full comparison: Best free AI 3D model generators for game assets and Meshy vs Tripo.

Step 4: Give your character a walk and idle animation

You need a humanoid character in a neutral pose (a T-pose or A-pose works best). Use one from a free CC0 kit, or generate one with an AI tool whose free plan allows your use. Then:

  1. Rig it in Mixamo. Adobe's Mixamo FAQ (checked Oct 26, 2026) says Mixamo is free with an Adobe ID, with no Creative Cloud subscription, and its characters and animations are royalty free for personal, commercial and non-profit projects, including video games. The auto rigger only works on bipedal humanoids, and Mixamo only keeps your last character, so save the rigged one to your computer.
  2. Download two clips. Pick an idle animation and a walk animation and download each one as FBX. For the walk, tick In Place if the clip offers it, so the character walks on the spot and your code does the moving. Download options are not listed on Adobe's help pages, so the option names here are unverified.
  3. Combine them in Blender. Import both FBX files (File, Import, FBX). Each clip comes in as an Action. Rename the actions Idle and Walk, make sure both belong to the same armature (push each one down to an NLA track or stash it, because Blender's glTF exporter only exports actions linked to an object), and delete the extra imported character.
  4. Export one GLB. File, Export, glTF 2.0, and choose glTF Binary (.glb). Save it as public/models/player.glb.

Stuck? How to animate a 3D character for free goes deeper on Mixamo, free AI motion capture and Blender, and Mixamo vs Cascadeur compares the two free animation tools.

Mixamo

Free Adobe service that auto rigs characters and applies ready made animations.

Pricing: Free. Beginner rating: 5/5. Free, drag and drop rigging and animations.

Free auto rigging and a big animation library for humanoids, royalty free in games.

Step 5: Movement, animation and a third person camera

This is the whole game loop in one file. Put it in src/main.js, and replace the template's index.html body with just <script type="module" src="/src/main.js"></script>. It loads player.glb, plays Idle or Walk depending on whether you are moving, turns the character to face where it walks, eases the camera behind it, and loops an ambient track after your first click or key press.

import * as THREE from 'three';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';

// Scene: soft sky color, fog and warm light for a cozy look
const scene = new THREE.Scene();
scene.background = new THREE.Color(0xbfd8e8);
scene.fog = new THREE.Fog(0xbfd8e8, 15, 60);
const camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 0.1, 200);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
scene.add(new THREE.HemisphereLight(0xfff4e0, 0x6b8f5a, 2));
const sun = new THREE.DirectionalLight(0xffe2b0, 2);
sun.position.set(10, 20, 5);
scene.add(sun);
const ground = new THREE.Mesh(new THREE.PlaneGeometry(200, 200), new THREE.MeshStandardMaterial({ color: 0x8fbf6a }));
ground.rotation.x = -Math.PI / 2;
scene.add(ground);

// Player: a GLB with "Idle" and "Walk" clips (see Step 4)
const player = new THREE.Group();
scene.add(player);
let mixer, idle, walk, current;
new GLTFLoader().load('./models/player.glb', (gltf) => {
  player.add(gltf.scene);
  mixer = new THREE.AnimationMixer(gltf.scene);
  console.log('Clips:', gltf.animations.map((c) => c.name));
  idle = mixer.clipAction(THREE.AnimationClip.findByName(gltf.animations, 'Idle'));
  walk = mixer.clipAction(THREE.AnimationClip.findByName(gltf.animations, 'Walk'));
  current = idle;
  idle.play();
}, undefined, (err) => console.error('Model failed to load', err));

function playClip(next) {
  if (!next || next === current) return;
  next.reset().play();
  current.crossFadeTo(next, 0.25, false);
  current = next;
}

// Input: WASD or arrow keys
const keys = {};
addEventListener('keydown', (e) => { keys[e.code] = true; startMusic(); });
addEventListener('keyup', (e) => { keys[e.code] = false; });

// Ambient loop: browsers only allow sound after the player clicks or presses a key
const listener = new THREE.AudioListener();
camera.add(listener);
const music = new THREE.Audio(listener);
new THREE.AudioLoader().load('./sounds/ambient.mp3', (buffer) => {
  music.setBuffer(buffer);
  music.setLoop(true);
  music.setVolume(0.4);
});
function startMusic() {
  if (music.buffer && !music.isPlaying) music.play();
}
addEventListener('pointerdown', startMusic);

// Third person camera: sits behind and above the player and eases toward that spot
const camOffset = new THREE.Vector3(0, 3, -6);
const camTarget = new THREE.Vector3();
const move = new THREE.Vector3();
const timer = new THREE.Timer();
timer.connect(document);

renderer.setAnimationLoop((time) => {
  timer.update(time);
  const dt = Math.min(timer.getDelta(), 0.1);
  move.set(0, 0, 0);
  if (keys.KeyW || keys.ArrowUp) move.z += 1;
  if (keys.KeyS || keys.ArrowDown) move.z -= 1;
  if (keys.KeyA || keys.ArrowLeft) move.x += 1;
  if (keys.KeyD || keys.ArrowRight) move.x -= 1;
  if (move.lengthSq() > 0) {
    move.normalize().multiplyScalar(3 * dt); // walking speed: 3 units per second
    player.position.add(move);
    player.rotation.y = Math.atan2(move.x, move.z); // face the way you walk
    playClip(walk);
  } else {
    playClip(idle);
  }
  if (mixer) mixer.update(dt);
  camTarget.copy(player.position).add(camOffset);
  camera.position.lerp(camTarget, 1 - Math.exp(-5 * dt));
  camera.lookAt(player.position.x, player.position.y + 1, player.position.z);
  renderer.render(scene, camera);
});

addEventListener('resize', () => {
  camera.aspect = innerWidth / innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(innerWidth, innerHeight);
});

Tested: we built this exact file with Vite 8.3.5 and three 0.186.1 on Oct 26, 2026, ran the build in headless Chromium, and held W and A. The test model (a placeholder box with clips named Idle and Walk) turned, walked and switched clips, the camera followed, and the page threw no errors. We did not listen to the audio in the test, and we did not test it with a real Mixamo export.

How it works, briefly:

Step 6: Ambient sound

Sound does most of the cozy work. Put a looping track (birds, wind, soft music) in public/sounds/ambient.mp3. The sample uses three.js's AudioListener and Audio, and starts playback on the first click or key press because browsers block sound until the player interacts with the page. For sounds that get louder as you walk closer, like a stream or a campfire, ask for PositionalAudio attached to an object.

Where to get sounds for free: Kenney's CC0 audio packs, or AI music and sound tools. Check each tool's free plan for commercial use in Best free AI tools for game sound effects and music.

Step 7: Cozy polish, one prompt at a time

Ask for one change, play it, keep it or undo it. Prompts that work well for this kind of game:

When something breaks, open the browser console (F12), copy the red error and paste it to the agent with what you were doing. That one habit fixes most problems.

Step 8: Publish free on itch.io

  1. Run npm run build. Check it with npm run preview.
  2. Zip the contents of dist/, so index.html sits inside the ZIP. File names are case sensitive on itch.io, so Player.glb and player.glb are different files.
  3. On itch.io, click Create new game, pick HTML Game as the kind of game, upload the ZIP, set a viewport size, and fill in the Generative AI disclosure if any art, sound or code came from AI.
  4. Preview the private page, play it there, then set it to Public.

Our step by step guide How to publish your first game on itch.io covers the page, pricing and AI disclosure in detail. Put your credits (Meshy, any CC-BY Poly Pizza models) in the page description.

Common pitfalls

What we could not verify

Sources (checked Oct 26, 2026)

FAQ

What is a cozy walking game?

A small, calm game where the fun is moving through a pretty place: no enemies, no timer, no way to lose. You walk, look around, maybe find a few things. It is a great first 3D project because the hard parts of game design (balance, difficulty, combat) mostly disappear, and you can finish it in a weekend or two.

Can I make this with no money?

Yes. three.js, Vite, Node.js, Blender, Mixamo (with a free Adobe ID), the Kenney, Quaternius and Poly Haven libraries and an itch.io page are all free. The only part that can cost money is the AI coding agent. Cursor has a limited free plan and ChatGPT Free includes limited Codex access, while Claude Code needs a paid Claude plan (Pro is $20/mo, checked Oct 25, 2026).

Can I use free AI generated models in a game on itch.io?

It depends on the tool. Meshy's pricing page (checked Oct 26, 2026) says free plan outputs are CC BY 4.0, so you can use them, even commercially, if you credit Meshy. Tripo's pricing page lists its free plan as public models and non-commercial use, so do not use free Tripo models in a game you sell or take donations for. Fill in itch.io's Generative AI disclosure either way.

How do I get a Mixamo animation into three.js?

Rig your humanoid character in Mixamo, download an idle clip and a walk clip, import both FBX files into Blender, give the actions clear names like Idle and Walk, and export one glTF Binary (.glb) file. three.js loads it with GLTFLoader and plays each clip through an AnimationMixer. three.js also has an FBXLoader if you want to skip Blender, but one GLB is simpler to manage.

Why does my character slide or walk away from the camera on its own?

The walk clip probably moves the character forward by itself (root motion) while your code also moves it. If Mixamo offers an In Place option for the walk clip, tick it before downloading, so the character walks on the spot and only your code moves it. Adobe's help pages do not document Mixamo's download options, so treat this as unverified.

Why is there no sound when my game starts?

Browsers block audio until the player interacts with the page. Start your ambient loop on the first click or key press, as the code sample on this page does.

How is this different from your other three.js guide?

Our guide How to make a browser game with three.js and AI covers the general setup: Vite, picking an agent, loading a single GLB and hosting. This guide builds one specific game on top of that: a world made from free CC0 kits, an animated character from Mixamo, a third person camera and ambient sound, then publishing on itch.io.

Related

Get the free browser game + AI starter pack

Our AI tools kit with a browser games section, plus a 7-step first game path, free art and sound picks with license notes, and a printable checklist. Plus one short tool tip a week. No spam, unsubscribe any time.

No spam. Unsubscribe in 1 click. Privacy See past issues

Preview of the First Game Starter Pack: the README, the AI Tools Kit and the first game checklist