Skip to main content
Three.js Course · Visual Styling

Three.js Colors and Materials: Build a Pink Scene

Create a pink 3D world with a rotating red cube while learning scene backgrounds, color formats, MeshBasicMaterial, responsive rendering, and animated palettes.

Glossy red cube rotating in a luminous pink Three.js environment

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.

Starting point: If scenes, cameras, and renderers are new to you, begin with Your First Three.js Scene, then return here to style it.

The complete rendering flow

1ScenePink background
2CameraFrames the cube
3MaterialRed surface
4RendererDraws each frame

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:

index.html
<!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>
src/main.js
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:

Scene background
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:

Exact pink
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

0xff0000

CSS hex

'#ff0000'

Color name

'red'

HSL string

'hsl(0, 100%, 50%)'
Equivalent red colors
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.
Why this matters: Lighting and blending require linear working values, while displays and most design colors use sRGB. Three.js manages the common conversions so the same color can participate correctly in rendering.

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.

Camera and renderer
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.

Red cube
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 methods
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:

Update background
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.

Time-based animation
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

Resize handler
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.

+Y up-X left(0, 0, 0)+X right+Z toward 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

src/main.js
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

ExperimentCode to tryEffect
Dark backgroundscene.background.set(0x180018)More dramatic contrast
Green cubematerial.color.set(0x00ff66)Changes only the mesh surface
Wireframe cubematerial.wireframe = trueReveals geometry edges
Faster y rotationcube.rotation.y += delta * 2Doubles horizontal spin speed
Move camera backcamera.position.z = 8Makes the cube appear smaller

Animate hue over time

HSL is useful for smooth palette cycling because hue wraps around a color wheel:

Animated hue
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().

HTML
<label for="cube-color">Cube color</label>
<input id="cube-color" type="color" value="#ff0000" />
JavaScript
const colorPicker = document.querySelector('#cube-color')

colorPicker.addEventListener('input', (event) => {
  material.color.setStyle(event.currentTarget.value)
})

14. Common mistakes and fixes

ProblemFix
The background stays blackAssign a THREE.Color to scene.background and render the correct scene.
The material ignores lightsThis is expected for MeshBasicMaterial; use a light-reactive material when shading is required.
An RGB color is wrongUse component values from 0 to 1, or use a CSS RGB string.
A loaded color texture looks washed outConfirm that the color texture uses THREE.SRGBColorSpace.
Animation speed differs across devicesMultiply movement by elapsed delta time instead of adding a fixed value per frame.
Memory grows while changing colorReuse 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

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