Color is one of the fastest ways to give a Three.js scene a clear mood. A scene background establishes the environment, a material color identifies the subject, and carefully chosen contrast helps the viewer understand shape and movement.
This tutorial turns the supplied pink-and-red lesson into a focused guide to THREE.Color and THREE.MeshBasicMaterial. You will build a responsive scene, learn the supported color formats, animate a red cube, and add safe controls for experimenting with palettes.
The complete rendering flow
1. Set up the canvas and import Three.js
This article assumes an npm and Vite project with Three.js installed. Your page needs one canvas and one module entry point:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Pink Three.js Scene</title>
</head>
<body>
<canvas class="world" aria-label="Rotating red 3D cube"></canvas>
<script type="module" src="/src/main.js"></script>
</body>
</html>import * as THREE from 'three'
import './style.css'
const canvas = document.querySelector('.world')2. Create a scene with a pink background
scene.background accepts a color, texture, or cube texture. For a solid background, assign a THREE.Color instance:
const scene = new THREE.Scene()
scene.background = new THREE.Color('pink')A named color is easy to read, but an exact hexadecimal value gives stronger design control:
scene.background = new THREE.Color(0xffb6c1)The background is not a mesh and does not need geometry, a camera-facing plane, or lighting. The renderer clears the canvas with this color before drawing the scene.
3. Understand Three.js color formats
THREE.Color supports several input styles. Hexadecimal triplets are the standard form used throughout the official documentation, while CSS-style strings can be convenient for design systems and browser color pickers.
Hexadecimal
0xff0000CSS hex
'#ff0000'Color name
'red'HSL string
'hsl(0, 100%, 50%)'const redFromHex = new THREE.Color(0xff0000)
const redFromCSS = new THREE.Color('#ff0000')
const redFromName = new THREE.Color('red')
const redFromRGB = new THREE.Color(1, 0, 0)
const redFromHSL = new THREE.Color('hsl(0, 100%, 50%)')Separate RGB components use values from 0 to 1, not 0 to 255. For colors copied from CSS or design software, a hexadecimal number or CSS string is usually the least surprising input.
4. A practical color-management mental model
Modern Three.js uses Linear-sRGB as its working color space. Common hexadecimal and CSS-style color inputs are treated as sRGB and converted automatically when color management is enabled, which it is by default.
- Use ordinary hexadecimal or CSS colors for material and light inputs.
- Do not manually convert every color unless you know its source color space.
- Mark ordinary color textures such as PNG and JPEG base-color maps with
texture.colorSpace = THREE.SRGBColorSpace. - Leave non-color data textures such as normal and roughness maps without an sRGB color-space assignment.
- When a whole scene looks too light or dark, inspect output, post-processing, textures, and tone mapping before changing every color.
5. Add the camera and renderer
A perspective camera gives the cube realistic depth. Position it away from the origin so it is not inside the cube.
const camera = new THREE.PerspectiveCamera(
60,
window.innerWidth / window.innerHeight,
0.1,
100
)
camera.position.z = 5
const renderer = new THREE.WebGLRenderer({
canvas,
antialias: true
})
renderer.setSize(window.innerWidth, window.innerHeight)
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))For more detail about FOV, aspect ratio, clipping, and positioning, continue with the PerspectiveCamera guide.
6. Create a red cube with MeshBasicMaterial
Geometry defines the cube's shape. Material defines the surface. A mesh combines both into an object that the scene can render.
const geometry = new THREE.BoxGeometry(1.6, 1.6, 1.6)
const material = new THREE.MeshBasicMaterial({
color: 0xff0000
})
const cube = new THREE.Mesh(geometry, material)
scene.add(cube)Geometry
The cube's vertices, edges, and triangles.
Material
The red surface drawn across the geometry.
Mesh
The complete object placed in the scene.
MeshBasicMaterial is not affected by lights. That makes its color clear and predictable for a starter lesson, flat graphics, helpers, and debugging. To show light and shadow, use a physically based material such as MeshStandardMaterial and add suitable lights or an environment.
7. Change colors after creation
A material owns a reusable Color object. Update that object instead of allocating a new material every time a visitor picks a color.
material.color.set(0xff0000)
material.color.setHex(0xe11d48)
material.color.setStyle('#be123c')
material.color.setRGB(1, 0, 0)
material.color.setHSL(0.98, 0.85, 0.5)The same approach works for the background, although scene.background must already contain a Color:
scene.background.setStyle('#f9a8d4')8. Animate the cube with frame-independent motion
Adding 0.01 every frame is easy to understand, but it makes the speed depend on the display frame rate. A clock provides elapsed time between frames so animation speed remains more consistent.
const clock = new THREE.Clock()
function animate() {
const delta = Math.min(clock.getDelta(), 0.1)
cube.rotation.x += delta * 0.7
cube.rotation.y += delta * 1.0
renderer.render(scene, camera)
}
renderer.setAnimationLoop(animate)The delta clamp avoids an unusually large jump if the tab was inactive or the device paused. The multipliers represent rotation speed in radians per second rather than per frame.
9. Keep the colored scene responsive
function resizeScene() {
const width = window.innerWidth
const height = window.innerHeight
camera.aspect = width / height
camera.updateProjectionMatrix()
renderer.setSize(width, height)
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
}
window.addEventListener('resize', resizeScene)
resizeScene()This prevents the cube from stretching when the browser changes shape and limits unnecessary rendering cost on high-density displays.
10. Understand the coordinate system
Three.js uses x, y, and z axes. A new object begins at the origin, (0, 0, 0). In a typical starter setup, positive x points right, positive y points up, and positive z points toward the viewer.
The cube starts at the origin and the camera starts at (0, 0, 5), looking down its default direction toward the center. Rotations are measured in radians around these same axes.
11. Complete pink-and-red scene
import * as THREE from 'three'
import './style.css'
const canvas = document.querySelector('.world')
const scene = new THREE.Scene()
scene.background = new THREE.Color(0xffb6c1)
const camera = new THREE.PerspectiveCamera(
60,
window.innerWidth / window.innerHeight,
0.1,
100
)
camera.position.z = 5
const renderer = new THREE.WebGLRenderer({ canvas, antialias: true })
const geometry = new THREE.BoxGeometry(1.6, 1.6, 1.6)
const material = new THREE.MeshBasicMaterial({ color: 0xff0000 })
const cube = new THREE.Mesh(geometry, material)
scene.add(cube)
function resizeScene() {
const width = window.innerWidth
const height = window.innerHeight
camera.aspect = width / height
camera.updateProjectionMatrix()
renderer.setSize(width, height)
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
}
window.addEventListener('resize', resizeScene)
resizeScene()
const clock = new THREE.Clock()
renderer.setAnimationLoop(() => {
const delta = Math.min(clock.getDelta(), 0.1)
cube.rotation.x += delta * 0.7
cube.rotation.y += delta
renderer.render(scene, camera)
})12. Color and motion experiments
| Experiment | Code to try | Effect |
|---|---|---|
| Dark background | scene.background.set(0x180018) | More dramatic contrast |
| Green cube | material.color.set(0x00ff66) | Changes only the mesh surface |
| Wireframe cube | material.wireframe = true | Reveals geometry edges |
| Faster y rotation | cube.rotation.y += delta * 2 | Doubles horizontal spin speed |
| Move camera back | camera.position.z = 8 | Makes the cube appear smaller |
Animate hue over time
HSL is useful for smooth palette cycling because hue wraps around a color wheel:
renderer.setAnimationLoop((time) => {
const hue = (time * 0.00005) % 1
material.color.setHSL(hue, 0.85, 0.5)
cube.rotation.y = time * 0.001
renderer.render(scene, camera)
})13. Connect an accessible color picker
An HTML color input returns a CSS hexadecimal string, which can be passed directly to material.color.setStyle().
<label for="cube-color">Cube color</label>
<input id="cube-color" type="color" value="#ff0000" />const colorPicker = document.querySelector('#cube-color')
colorPicker.addEventListener('input', (event) => {
material.color.setStyle(event.currentTarget.value)
})14. Common mistakes and fixes
| Problem | Fix |
|---|---|
| The background stays black | Assign a THREE.Color to scene.background and render the correct scene. |
| The material ignores lights | This is expected for MeshBasicMaterial; use a light-reactive material when shading is required. |
| An RGB color is wrong | Use component values from 0 to 1, or use a CSS RGB string. |
| A loaded color texture looks washed out | Confirm that the color texture uses THREE.SRGBColorSpace. |
| Animation speed differs across devices | Multiply movement by elapsed delta time instead of adding a fixed value per frame. |
| Memory grows while changing color | Reuse material.color instead of repeatedly creating new materials. |
Frequently asked questions
Which color formats can Three.js use?
THREE.Color accepts hexadecimal triplets, CSS-style color strings, another Color instance, or separate RGB component values. Hexadecimal values are the standard style used throughout the Three.js documentation.
How do I change the scene background color?
Assign a THREE.Color instance to scene.background, for example scene.background = new THREE.Color(0xffb6c1).
Why is MeshBasicMaterial visible without lights?
MeshBasicMaterial is not affected by scene lights. It displays a flat base color, map, or wireframe and is useful for simple graphics and debugging.
Can I change a material color after creating the mesh?
Yes. Update material.color with set, setHex, setStyle, setRGB, or setHSL. A normal color change does not require recreating the material.
Why does a Three.js color look different than expected?
Unexpected brightness can come from lighting, tone mapping, texture color-space settings, post-processing, or incorrect manual color conversions. Current Three.js color management converts common hexadecimal and CSS color inputs automatically.
Official references
- THREE.Color documentation
- MeshBasicMaterial documentation
- Three.js color management guide
- Three.js backgrounds guide
Use color as part of the 3D system
A polished scene does more than assign two attractive colors. The background creates context, the material communicates the subject, color management keeps inputs and output consistent, and time-based animation preserves the intended motion across devices. With those pieces understood, you can replace this playful pink-and-red palette with any visual identity your project needs.
Need a distinctive interactive website?
NavTech Solution combines modern JavaScript, Three.js, animation, and thoughtful visual systems to create memorable digital experiences.
Discuss your project
