Navigate
Search topics across all sections
Coordinate System
Every object in your 3D scene has an address — a position in 3D space. Understanding how this addressing system works is the key to placing objects exactly where you want them.
You place a cube at position [0, 0, 5] expecting it to float above the ground. Instead, it flies straight toward the camera and fills the entire screen. You try [0, 5, 0] and now it's up in the sky. The axes aren't what you expected.
Object appears at wrong position. Expected 'up' but got 'toward camera'.
Real-world
Imagine you're looking at a city map. Every building has an address based on three things:
X = East/West streets — Positive X is to the right (East), negative is left (West).
Y = Altitude — How high something is. Positive Y is up (a skyscraper), negative is underground (a subway).
Z = North/South avenues — Positive Z comes toward you (South), negative goes away from you (North).
The origin (0, 0, 0) is city center. Every object in your scene has an address in this city.
X Axis
Left / Right
Y Axis
Up / Down
Z Axis
Toward / Away
Origin
(0, 0, 0) = Center
Hands-On: Placing Objects in 3D Space
Let's place some objects and see how the coordinate system works in practice. Remember: X is left/right, Y is up/down, Z is toward/away.
Step 1: Place an object using its address
<mesh position={[2, 1, 0]}>
<boxGeometry />
<meshStandardMaterial color="coral" />
</mesh>This places a cube 2 units to the right and 1 unit up from the center. The position prop takes an array of [x, y, z]. Think of it as a street address: 2 blocks east, 1 floor up, ground level.
Step 2: Rotate and scale
<mesh
position={[0, 0, 0]}
rotation={[0, Math.PI / 4, 0]}
scale={[1, 2, 1]}
>
<boxGeometry />
<meshStandardMaterial color="skyblue" />
</mesh>Rotation is in radians (Math.PI / 4 = 45 degrees). Scale stretches the cube — here it's twice as tall on Y. Notice the order: Three.js applies Scale first, then Rotation, then Position.
Step 3: Group objects together
<group position={[3, 0, 0]}>
<mesh position={[0, 1, 0]}>
<sphereGeometry args={[0.5]} />
<meshStandardMaterial color="gold" />
</mesh>
<mesh>
<boxGeometry />
<meshStandardMaterial color="teal" />
</mesh>
</group>Groups are like neighborhoods. The group is at [3, 0, 0], and the sphere inside is at [0, 1, 0] relative to the group — so its real-world address is [3, 1, 0]. Move the group, and everything inside moves together.
What you just learned
Three.js uses a Y-up coordinate system: X = left/right, Y = up/down, Z = toward/away from the viewer.
The origin (0, 0, 0) is the center of the world. Every object has a position relative to this center.
Rotation is measured in radians, not degrees. Math.PI = 180 degrees, Math.PI / 2 = 90 degrees.
Groups let you create local coordinate systems — children are positioned relative to their parent.
Question
If a child mesh is at position [0, 2, 0] inside a group at [5, 0, 0], where is the child in world space? What happens to the child if you rotate the group 90 degrees around the Y axis?
Think about it...
You set a mesh's rotation to [0, 90, 0]. Instead of rotating 90 degrees, the object spins wildly. What went wrong?
Hint: Remember, Three.js doesn't use degrees...
Try These Challenges
Put what you learned into practice. Try each challenge in the demo above using the Leva controls, then check the solution.
Try This!
Beginner
Move the cube to [2, 0, -3] — where does it go?
Try This!
Beginner
Rotate by Math.PI/4 — what angle is that?
Try This!
Beginner
Scale to [2, 0.5, 1] — what shape do you get?
These are the patterns that trip up developers most often. Switch between Wrong and Fixed to compare the code side by side.
// Coming from Blender (Z-up) and assuming Z is up
<mesh position={[0, 0, 5]}>
{/* Thinks this moves up — actually moves TOWARD the camera! */}// WRONG: rotation uses radians, not degrees!
<mesh rotation={[0, 45, 0]}>
{/* 45 radians = about 7 full spins! */}// WRONG: Replacing the vector entirely in useFrame
useFrame(() => {
ref.current.position = new Vector3(1, 2, 3);
// Breaks the internal matrix update link!
});Best Practices
Use AxesHelper During Development
Add an axesHelper to your scene while building. The color coding (Red=X, Green=Y, Blue=Z) makes it immediately obvious which direction is which.
Use Groups for Hierarchies
Group related objects together. Moving or rotating the group transforms all children — perfect for things like robot arms, solar systems, or UI panels.
1 Unit = 1 Meter Convention
Stick to the convention that 1 unit equals 1 meter. This keeps physics, lighting, shadows, and VR/AR experiences working correctly without constant scaling headaches.
Prefer degToRad for Readability
When you think in degrees, use MathUtils.degToRad(45) instead of doing the math yourself. Your future self (and teammates) will thank you for the clarity.