# 3d terrain with Three.js

**URL:** <https://phaser.discourse.group/t/3d-terrain-with-three-js/15293>\
**Category:** Examples\
**Created:** [April 18, 2025, 4:32pm UTC](https://phaser.discourse.group/t/3d-terrain-with-three-js/15293 "2025-04-18T16:32:02Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![samme](https://yyz2.discourse-cdn.com/free1/user_avatar/phaser.discourse.group/samme/32/5275_2.png) [@samme](https://phaser.discourse.group/u/samme)\
**Post date:** [April 18, 2025, 4:32pm UTC](https://phaser.discourse.group/t/3d-terrain-with-three-js/15293/1 "2025-04-18T16:32:02Z")

</div>

![phaser and threejs](https://global.discourse-cdn.com/free1/uploads/phaser1/original/2X/8/8a1046e2a6621c9f27fe3be641b1d9f876a320f2.png)

> **[3d terrain ⛰ Phaser Sandbox Entry](https://phaser.io/sandbox/5otK61Ci)**
>
> W, A, S, D, R, F, left click, right click

---

<div class="post-metadata">

**Author:** ![samme](https://yyz2.discourse-cdn.com/free1/user_avatar/phaser.discourse.group/samme/32/5275_2.png) [@samme](https://phaser.discourse.group/u/samme)\
**Post date:** [April 18, 2025, 7:01pm UTC](https://phaser.discourse.group/t/3d-terrain-with-three-js/15293/2 "2025-04-18T19:01:42Z")

</div>

I started from [WebGL geometry terrain](https://threejs.org/examples/#webgl_geometry_terrain) and [examples/v3.85.0/game-objects/extern/view/threejs-cube](https://phaser.io/examples/v3.85.0/game-objects/extern/view/threejs-cube).

I used [three.js r149](https://github.com/mrdoob/three.js/releases/tag/r149).

I removed all of THREE’s resizing and used only

```js
renderer.setViewport(game.scale.width, game.scale.height);

```

Phaser is already scaling the game canvas and you want THREE to use the unscaled context size.

 ![terrain](https://global.discourse-cdn.com/free1/uploads/phaser1/original/2X/4/48902cddbd934ee349047e923175c873dd648e4a.png)

I used Phaser’s [CanvasTexture](https://docs.phaser.io/api-documentation/class/textures-canvastexture) in the terrain generation.

I removed THREE’s `Clock` and `renderer.setAnimationLoop()` and used instead

```js
const view = this.add.extern();

view.preUpdate = function (time, delta) {
  controls.update(delta / 1000);
};

view.render = function () {
  renderer.resetState();
  renderer.render(scene, camera);
};

```

This works because Extern Game Objects have a `preUpdate()` method and are on the scene Update List, like Sprites.

The `FirstPersonControls` class could be converted to a Phaser class, using the scene’s input events for mouse and keyboard.
