The final base post covers the territory that "barely existed" when the prior posts' patterns were stabilising and is now front-of-mind: AI-generated 3D assets (text-to-3D and image-to-3D in seconds), NavMesh + pathfinding for AI-driven characters, Gaussian Splatting for photoreal scanned environments, and the procedural generation techniques (noise, L-systems, wave-function collapse) that complement or replace authored assets. None of these are exclusive to Three.js, but they all show up in production Three.js pipelines today.

Series map: 00 Foundations → 01 Geometry & Materials → 02 Cameras & Controls → 03 Lighting & Shadows → 04 Textures & PBR → 05 Asset Pipeline → 06 Animation → 07 Instancing & Batching → 08 Low-End Perf → 09 Shaders → 10 Post-Processing → 11 Physics → 12 R3F → 13 AI 3D + NavMesh + Procedural (this post — final in the base series).


Learning Outcome

  • Use AI tools (Meshy, Tripo, Luma Genie, TripoSR, Hunyuan3D, CSM) to generate 3D models from text or images.
  • Clean up + optimise AI-generated meshes for production.
  • Generate a NavMesh from your scene with recast-navigation-js.
  • Pathfind across a NavMesh with Detour.
  • Display Gaussian Splatting captures in Three.js.
  • Generate procedural terrain with Perlin / Simplex noise.
  • Recognise where each technique fits in a pipeline.

Chapter 1 — Text-to-3D + image-to-3D (the 2026 landscape)

In 2026, a usable 3D model from a text prompt or single reference image takes about a minute and costs a few cents. None of these tools fully replace a 3D artist for hero work, but they're production-ready for backgrounds, props, prototypes, and indie / mid-tier projects.

Tool Inputs Outputs Notes
Meshy text, image textured glTF / FBX / USDZ; auto-rig; 500+ animation presets most-complete pipeline; web + API
Tripo text, image textured glTF fast; web + API; cheaper than Meshy
Luma Genie text glTF strong geometric reasoning; web
TripoSR single image mesh in < 0.5 s on an A100 open-source (Stability AI + Tripo); self-hostable
Hunyuan3D (Tencent) text, image high-quality textured mesh open-source, top-tier quality
CSM (Common Sense Machines) concept art / character sheet proportion-faithful character mesh designer-friendly
Spline AI text scenes within Spline (Three.js compatible export) designer tool with AI assist
Rodin text high quality newer, gaining traction

Workflow for AI-generated mesh → Three.js

  1. Generate at the tool's UI. Iterate on prompt + reference images until happy.
  2. Download glTF.
  3. Clean up in Blender — fix the inevitable issues:
    • Floating / disconnected geometry → merge by distance.
    • Hyper-dense topology → decimate.
    • Wrong scale / orientation → fix root transform.
    • Inverted normals → recalculate.
    • Texture seams or bake noise → repaint patches.
  4. Optimise with gltf-transform optimize (Post 05).
  5. Drop into your Three.js scene with GLTFLoader.

Trick: AI-generated meshes look right at "hero camera" angles and wrong from close-up. Always test from your actual camera. For backgrounds it doesn't matter; for player-inspected props, plan to clean up.

Production readiness in 2026

  • Prototype quality is trivial — minutes from prompt to scene.
  • Production quality still needs human review for: hero characters, branded assets, anything inspected closely, manufacturing geometry, anything with text on it (still flaky in 2026).
  • Round-trip test always — export from AI tool, import into your engine, render at production camera, before committing.

Chapter 2 — API integration

For automated pipelines (user-generated content sites, game asset farms, procedural batches):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Meshy API example (text-to-3D)
const r = await fetch('https://api.meshy.ai/v2/text-to-3d', {
method: 'POST',
headers: { 'Authorization': `Bearer ${MESHY_API_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify({
mode: 'preview',
prompt: 'a low-poly mushroom, vibrant colours',
art_style: 'cartoon',
})
});
const { result: taskId } = await r.json();

// poll until ready
const model = await pollUntilReady(taskId);
const glbUrl = model.model_urls.glb;

// load into Three.js
const gltf = await new GLTFLoader().loadAsync(glbUrl);
scene.add(gltf.scene);

Tripo, Luma, Hunyuan have similar REST + polling APIs. TripoSR runs entirely on your own GPU — no external API.

Self-hosting TripoSR

1
2
3
4
5
git clone https://github.com/VAST-AI-Research/TripoSR.git
cd TripoSR
pip install -r requirements.txt
python run.py --input image.png --output out/

Requires a CUDA GPU (A100 ideal, RTX 3060 / 4070 viable). ~0.5-3 seconds per mesh. Self-host when you need privacy, batch volume, or zero per-call cost.


Chapter 3 — NavMesh + pathfinding

For AI-driven characters that need to walk around obstacles, NavMesh (Navigation Mesh) is the standard. A NavMesh is a polygon graph of the walkable surface; pathfinding queries return a sequence of polygons + a straight path inside them.

NavMesh pathfinding in three steps: scene meshes, the NavMesh, and a path around a wall, plus walking to the next waypoint

The canonical library for JS is recast-navigation-js — a WASM port of the C++ Recast (NavMesh construction) + Detour (pathfinding) libraries used in Unreal, Unity, and most game engines.

Install

1
2
npm install recast-navigation @recast-navigation/three

Generate a NavMesh from a Three.js scene

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import { init, threeToSoloNavMesh } from '@recast-navigation/three';

await init(); // load WASM

// gather meshes that the NavMesh should consider as ground / obstacles
const sources = [];
scene.traverse((c) => { if (c.isMesh && c.userData.walkable) sources.push(c); });

const { navMesh, success } = threeToSoloNavMesh(sources, {
cs: 0.2, // cell size (smaller = more detail, slower build)
ch: 0.2, // cell height
walkableSlopeAngle: 60,
walkableHeight: 2,
walkableClimb: 0.9,
walkableRadius: 0.6,
maxEdgeLen: 12,
maxSimplificationError: 1.3,
minRegionArea: 8,
mergeRegionArea: 20,
});

if (!success) throw new Error('NavMesh build failed');

Pathfind

1
2
3
4
5
6
7
8
9
10
import { NavMeshQuery } from 'recast-navigation';

const query = new NavMeshQuery({ navMesh });

const start = { x: 0, y: 0, z: 0 };
const goal = { x: 10, y: 0, z: 8 };

const { path, success } = query.computePath(start, goal);
// path = array of waypoints

Visualise the path:

1
2
3
4
const geo = new THREE.BufferGeometry().setFromPoints(path.map(p => new THREE.Vector3(p.x, p.y, p.z)));
const line = new THREE.Line(geo, new THREE.LineBasicMaterial({ color: 0xff00ff }));
scene.add(line);

Move a character along the path

Each frame, advance toward the next waypoint at walking speed; pop the waypoint when reached.

1
2
3
4
5
6
7
8
9
10
11
12
13
let pathIdx = 0;
const speed = 3;

useFrame ((s, dt) => {
if (pathIdx >= path.length) return;
const target = new THREE.Vector3(path[pathIdx].x, path[pathIdx].y, path[pathIdx].z);
const dir = target.clone().sub(character.position);
const d = dir.length();
if (d < 0.1) { pathIdx++; return; }
character.position.add(dir.normalize().multiplyScalar(speed * dt));
character.lookAt(target);
});

Crowds

For many AI characters, Detour Crowd handles avoidance between them:

1
2
3
4
5
6
7
8
9
10
11
12
13
import { Crowd } from 'recast-navigation';

const crowd = new Crowd({ maxAgents: 200, maxAgentRadius: 0.6, navMesh });
const agent = crowd.addAgent({ x: 0, y: 0, z: 0 }, {
radius: 0.6, height: 2, maxAcceleration: 8, maxSpeed: 4,
});
agent.requestMoveTarget({ x: 10, y: 0, z: 0 });

useFrame((s, dt) => {
crowd.update(dt);
character.position.copy(agent.position());
});

For dynamic scenes (rebuild NavMesh as the world changes), use tiled NavMesh via threeToTiledNavMesh — only rebuild affected tiles.


Chapter 4 — Procedural generation

When you can't or don't want to author every prop, generate procedurally.

Perlin / Simplex noise (the workhorse)

1
2
npm install simplex-noise
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import { createNoise2D } from 'simplex-noise';

const noise2D = createNoise2D();

const SIZE = 100;
const SEG = 200;
const geo = new THREE.PlaneGeometry(SIZE, SIZE, SEG, SEG);

const pos = geo.attributes.position;
for (let i = 0; i < pos.count; i++) {
const x = pos.getX(i);
const y = pos.getY(i);
const h = noise2D(x * 0.05, y * 0.05) * 5
+ noise2D(x * 0.2, y * 0.2) * 1
+ noise2D(x * 1.0, y * 1.0) * 0.25;
pos.setZ(i, h);
}
geo.computeVertexNormals();

const mesh = new THREE.Mesh(geo, new THREE.MeshStandardMaterial({ color: 0x668866, flatShading: true }));
mesh.rotation.x = -Math.PI / 2;
scene.add(mesh);

Layering noise at multiple frequencies + amplitudes (fractal Brownian motion) gives natural-looking terrain.

L-systems for plants / fractals

1
2
3
4
5
6
7
// L-system rules (very simplified)
let s = 'F';
for (let i = 0; i < 4; i++) {
s = s.replaceAll('F', 'FF+[+F-F-F]-[-F+F+F]');
}
// interpret s as turtle commands → draw cylinders/branches in 3D

Useful for plants, branches, trees.

Wave Function Collapse (WFC)

Generate tile-based maps from a small example. Libraries: wavefunctioncollapse (npm). Use for dungeons, city blocks, decorative patterns.

Voronoi / Delaunay

Cell partitioning — useful for procedural ground textures, cracked surfaces, cell-shaded foliage clumps. Library: d3-delaunay.

Marching cubes

Convert a 3D scalar field (e.g., from noise) into a triangle mesh — generates caves, blob shapes, organic terrain. Three.js has MarchingCubes in addons.

Trick: "looks too perfect / too repetitive" is the procedural-generation tell. Layer multiple techniques (noise + WFC + hand-placed accents). Add small artist-authored variation on top to break uniformity.


Chapter 5 — Gaussian Splatting (3DGS)

Gaussian Splatting (2023) is a new way to represent and render 3D scenes — a cloud of millions of view-dependent ellipsoids ("splats") rather than a triangle mesh. Captured from photos with tools like Luma AI, Polycam, PostShot. Renders extremely fast even on mobile.

Status in 2026:

  • Three.js doesn't yet ship a built-in 3DGS renderer.
  • Use @mkkellogg/gaussian-splats-3d or luma-web to render .splat / .ply files in a Three.js scene.
1
2
npm install @mkkellogg/gaussian-splats-3d
1
2
3
4
5
6
7
8
9
10
import { Viewer as SplatViewer } from '@mkkellogg/gaussian-splats-3d';

const viewer = new SplatViewer({
cameraUp: [0, 1, 0],
initialCameraPosition: [0, 1, 5],
initialCameraLookAt: [0, 0, 0],
});
await viewer.addSplatScene('/scans/livingroom.splat');
viewer.start();

Use cases: virtual scans of real places, e-commerce showroom captures, AR scene reconstruction. Limitations: editing is hard (no triangle mesh to nudge); animation harder still.


Chapter 6 — Pipeline integration

Putting it all together — a realistic mixed pipeline for a game / interactive experience:

1
2
3
4
5
6
7
8
9
10
11
1. Concept       — designer sketches, mood boards.
2. Hero assets — human-authored in Blender (player character, key items).
3. Background — AI-generated (Meshy/Tripo) + light human cleanup.
4. Terrain — procedural noise + hand-painted layers.
5. Environment — Gaussian Splat of a real location (for hero scenes).
6. Materials — PBR maps, KTX2-compressed.
7. NavMesh — recast-navigation-js, built once on level load.
8. AI characters — pathfind on the NavMesh, animate with mixed authored + procedural motion.
9. Optimise — gltf-transform, LOD, instancing.
10. Ship — adaptive quality on mobile.

Three.js (or R3F) sits in the middle, integrating all of it through GLTFLoader, custom loaders, NavMesh queries, and the patterns from posts 00-12.


Chapter 7 — Ethical + legal notes

AI-generated 3D models:

  • Licensing of training data is contested. Most commercial tools (Meshy, Tripo, Luma) claim model output is yours to use; check current ToS.
  • Open-source models (TripoSR, Hunyuan3D) have permissive licences for output but may have non-commercial training-data caveats.
  • Brand / IP prompts ("a Star Wars X-wing") will produce IP-infringing outputs; you carry the legal risk, not the tool.
  • Disclose AI-generated content where required by platform rules (App Store, Steam, etc.).
  • Workflow auditability — log prompts + tool + version per asset for future review.

NavMesh + procedural generation aren't ethically loaded; standard library licensing applies (most are MIT / Apache-2.0).

Gaussian Splat captures of real places — same as photography: respect private property, get model releases for people, follow GDPR / local rules for identifiable people.


Practice Exercises

Exercise 1 — Generate + import

Generate a model on Meshy (free tier) of "a stylised mushroom". Download glTF. Load into a Three.js scene. Add Environment + OrbitControls. Note quality and what you'd need to fix.

Exercise 2 — Optimise the AI mesh

Run gltf-transform inspect then optimize. Compare file size + draw calls + visual quality.

Exercise 3 — NavMesh on a room

Build a simple "room" scene: floor + several walls + a couple of obstacles. Generate a NavMesh via recast-navigation-js. Visualise it (the NavMesh has a .getDebugTriangles() method or similar).

Exercise 4 — Click-to-walk

Click anywhere on the floor → pathfind from character position to click target → move character along the path.

Exercise 5 — Procedural terrain

Generate a 100×100 terrain with layered Simplex noise. Add an LOD swap for distant chunks. Tile with a grass texture (Post 04).

Exercise 6 — Gaussian Splat viewer

Find a free .splat file on luma.com/featured or download one. Display it in a Three.js scene via @mkkellogg/gaussian-splats-3d. Add OrbitControls.

Exercise 7 — Full mini-pipeline

Build a 30-second prototype scene: AI-generated mushroom forest (5 species via Meshy/Tripo), procedural noise terrain, recast-navigation crowd of 20 agents wandering between waypoints, R3F + Drei + Rapier for the engine, deployed on Vercel. Note the friction at each step.


Cheat-sheet

What How
Text-to-3D Meshy, Tripo, Luma Genie, CSM, Spline AI, Rodin
Image-to-3D TripoSR (open-source), Meshy, Tripo
Open-source self-host TripoSR, Hunyuan3D
Round-trip test always render in your engine at your camera before committing
Cleanup after AI Blender: merge by distance, decimate, normals, scale
NavMesh library recast-navigation-js + @recast-navigation/three
Build NavMesh threeToSoloNavMesh(meshes, params)
Pathfind new NavMeshQuery({ navMesh }).computePath(start, goal)
Many agents + avoidance Crowd from recast-navigation
Dynamic world tiled NavMesh, rebuild affected tiles
Noise terrain simplex-noise layered as fBm
L-system / WFC for plants / tiled maps
Marching cubes scalar field → mesh (caves, blobs)
Gaussian Splat viewer @mkkellogg/gaussian-splats-3d
Legal check tool ToS; disclose AI; respect IP

Course base complete

This concludes the 14-post base series. You've covered:

  • Foundations (00).
  • Geometry + materials (01).
  • Cameras + controls (02).
  • Lighting + shadows (03).
  • Textures + PBR (04).
  • Asset pipeline + glTF (05).
  • Animation (06).
  • Instancing + batching (07).
  • Low-end performance (08).
  • Custom shaders (09).
  • Post-processing + colour (10).
  • Physics + interactivity (11).
  • React Three Fiber + Drei (12).
  • AI + NavMesh + procedural (13).

That covers ~95 % of what working Three.js engineers touch week-to-week.

Planned future extensions

# Topic Why follow
14 WebXR — VR + AR + handheld needed for immersive 3D
15 WebGPU compute deep dive particle sims, GPU pathfinding, ML
16 Networked 3D — Yjs / Colyseus / Hathora collaborative scenes
17 Cloth, soft body, fluid advanced physics
18 Audio-reactive scenes Web Audio API + Three.js
19 Theatre.js / cinematic cameras timeline-based animation
20 Three.js + Spline + Houdini integrations designer pipelines
21 Production-grade asset CI/CD gltf-transform in pipelines
22 Benchmarks + tuning case studies real-world performance investigations

References

Note: this post — and the base course — is in progress. Planned additions: full AI pipeline walkthrough; tiled NavMesh + dynamic obstacles; Gaussian Splat editing tooling; Houdini PDG → Three.js batch generation.