Dat GUI

Video Lecture

Dat GUI Dat GUI Dat GUI Dat GUI

Description

The Dat GUI is another very useful tool that we can use to learn about Three.js as it allows us to quickly add a very basic user interface which allows us to interact with our 3d scene and the objects within it.

The Three.js install includes a copy of dat.gui.module.js so we will use that.

However, the version of Three.js at the time of writing this lesson, doesn't include a type definition file for dat.gui.module.js by default.

Manually install the type definition file.

1
npm install @types/dat.gui

The installed type definition file will not auto link with the dat.gui.module.js in the Three.js library folder just yet. See the section below at ./src/client/tsconfig.json

Final Scripts

./src/client/client.ts

Add the Dat.GUI import and usage to the ./src/client/client.ts

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
import * as THREE from '/build/three.module.js'
import { OrbitControls } from '/jsm/controls/OrbitControls'
import Stats from '/jsm/libs/stats.module'
import { GUI } from '/jsm/libs/dat.gui.module'

const scene: THREE.Scene = new THREE.Scene()
var axesHelper = new THREE.AxesHelper( 5 );
scene.add( axesHelper );

const camera: THREE.PerspectiveCamera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000)

const renderer: THREE.WebGLRenderer = new THREE.WebGLRenderer()
renderer.setSize(window.innerWidth, window.innerHeight)
document.body.appendChild(renderer.domElement)

const controls = new OrbitControls(camera, renderer.domElement)
//controls.addEventListener('change', render) 

const geometry: THREE.BoxGeometry = new THREE.BoxGeometry()
const material: THREE.MeshBasicMaterial = new THREE.MeshBasicMaterial({ color: 0x00ff00, wireframe: true })

const cube: THREE.Mesh = new THREE.Mesh(geometry, material)
scene.add(cube)

camera.position.z = 2

window.addEventListener('resize', onWindowResize, false)
function onWindowResize() {
    camera.aspect = window.innerWidth / window.innerHeight
    camera.updateProjectionMatrix()
    renderer.setSize(window.innerWidth, window.innerHeight)
    render()
}

const stats = Stats()
document.body.appendChild(stats.dom)

const gui = new GUI()
const cubeFolder = gui.addFolder("Cube")
cubeFolder.add(cube.rotation, "x", 0, Math.PI * 2, 0.01)
cubeFolder.add(cube.rotation, "y", 0, Math.PI * 2, 0.01)
cubeFolder.add(cube.rotation, "z", 0, Math.PI * 2, 0.01)
cubeFolder.open()
const cameraFolder = gui.addFolder("Camera")
cameraFolder.add(camera.position, "z", 0, 10, 0.01)
cameraFolder.open()

var animate = function () {
    requestAnimationFrame(animate)

    //cube.rotation.x += 0.01;
    //cube.rotation.y += 0.01;

    render()

    stats.update()
};

function render() {
    renderer.render(scene, camera)
}
//render()
animate();

./src/server/server.ts

Add the static route to the NodeJS Express server so that it knows which file to return to it when it is asked for it by the client,

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import http from "http"
import path from "path"
import express from "express"

const port: number = 3000

class App {
    private server: http.Server
    private port: number

    constructor(port: number) {
        this.port = port
        const app = express()
        app.use(express.static(path.join(__dirname, '../client')))
        app.use('/build/three.module.js', express.static(path.join(__dirname, '../../node_modules/three/build/three.module.js')))
        app.use('/jsm/controls/OrbitControls', express.static(path.join(__dirname, '../../node_modules/three/examples/jsm/controls/OrbitControls.js')))
        app.use('/jsm/libs/stats.module', express.static(path.join(__dirname, '../../node_modules/three/examples/jsm/libs/stats.module.js')))
        app.use('/jsm/libs/dat.gui.module', express.static(path.join(__dirname, '../../node_modules/three/examples/jsm/libs/dat.gui.module.js')))
        this.server = new http.Server(app);
    }

    public Start() {
        this.server.listen(this.port, () => {
            console.log(`Server listening on Port ${this.port}.`)
        })
    }
}

new App(port).Start()

./src/client/tsconfig.json

You have several options here to correct the missing type definition reference.

One option is to manually copy the file index.d.ts from the node_modules/@types/dat.gui folder into the node_modules/three/examples/jsm/libs folder and rename it to dat.gui.module.d.ts.

or

add a path to the ./src/client/tsconfig.json that indicates to the VSCode IDE and TypeScript compiler which type definition to use when it sees the import to /jsm/libs/dat.gui.module

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
{
    "compilerOptions": {
        "target": "ES6",
        "module": "ES6",
        "outDir": "../../dist/client",
        "baseUrl": ".",
        "paths": {
            "/build/three.module.js": ["../../node_modules/three/src/Three"],
            "/jsm/*": ["../../node_modules/three/examples/jsm/*"],
            "/jsm/libs/dat.gui.module": ["../../node_modules/@types/dat.gui"]
        },
        "moduleResolution": "node",
        "strict": true
    },
    "include": [
        "**/*.ts"
    ]
}