Instead of tweening the positions, you can tween the quaternions.
A rough concept. I’m using the tweening library from the Three.js distributive, not from GSAP. https://jsfiddle.net/prisoner849/b0u25h7c/

var radius = 1;
var sphere = new THREE.Mesh(new THREE.SphereGeometry(radius, 32, 24), new THREE.MeshBasicMaterial({color: "gray", wireframe: true}));
scene.add(sphere);
var item = new THREE.Mesh(new THREE.BoxGeometry(0.0625, 0.0625, 0.5), new THREE.MeshBasicMaterial({color: "red", wireframe: true}));
item.geometry.translate(0, 0, 0.25 + radius);
scene.add(item);
var startVector = new THREE.Vector3(0, 0, 1);
var endVector = new THREE.Vector3(
THREE.Math.randFloat(-1, 1),
THREE.Math.randFloat(-1, 1),
THREE.Math.randFloat(-1, 1)
);
var q = new THREE.Quaternion();
function setInitials(){
q.setFromUnitVectors(startVector.normalize(), endVector.normalize());
startVector = endVector;
endVector = new THREE.Vector3(
THREE.Math.randFloat(-1, 1),
THREE.Math.randFloat(-1, 1),
THREE.Math.randFloat(-1, 1)
);
}
setInitials();
btnMove.addEventListener("click", function(){
var tween = new TWEEN.Tween(item.quaternion).to(q, 1000).delay(500).onComplete(setInitials);
tween.chain(tween);
tween.start();
}, false);

The other approach is to use the THREE.Spherical() object and .setFromSpherical() method of THREE.Vector3() object to set start and end points on the sphere, then find the normal of the triangle (start, center, end) and the angle between the start and end vectors, then rotate the start vector around the normal, whilst tweening the angle.

var radius = 1;
var segmentsWidth = 16;
var segmentsHeight = 12;
var sphere = new THREE.Mesh(new THREE.SphereGeometry(radius, segmentsWidth, segmentsHeight), new THREE.MeshBasicMaterial({color: 0x404040, wireframe: true}));
scene.add(sphere);
var item = new THREE.Mesh(new THREE.BoxGeometry(0.0625, 0.0625, 0.5), new THREE.MeshBasicMaterial({color: "aqua", wireframe: true}));
item.geometry.translate(0, 0, 0.25);
scene.add(item);
var sphericalStart = new THREE.Spherical();
var sphericalEnd = new THREE.Spherical(radius, Math.PI * 0.5, 0);
var center = new THREE.Vector3();
var vectorStart = new THREE.Vector3();
var vectorEnd = new THREE.Vector3();
var angle = {value : 0};
var angleEnd = {value: 0};
var normal = new THREE.Vector3();
var lookAt = new THREE.Vector3();
function setInitials(){
sphericalStart.copy(sphericalEnd);
sphericalEnd.set(radius,THREE.Math.randFloat(0, Math.PI), THREE.Math.randFloat(0, Math.PI * 2));
vectorStart.setFromSpherical(sphericalStart);
vectorEnd.setFromSpherical(sphericalEnd);
normal.copy(vectorStart).cross(vectorEnd).normalize();
angle.value = 0;
angleEnd.value = vectorStart.angleTo(vectorEnd);
}
setInitials();
btnMove.addEventListener("click", function(){
var tween = new TWEEN.Tween(angle).to(angleEnd, 1000).delay(500).onUpdate(
function(){
item.position.copy(vectorStart).applyAxisAngle(normal, angle.value);
item.lookAt(lookAt.copy(item.position).normalize().multiplyScalar(radius + 1));
}
).onComplete(setInitials);
tween.chain(tween);
tween.start();
}, false);

However… In my code base… I have a bunch of items that need to move to a specific location. I’m struggling to work out what my start/end vectors should be.

I’ve tried using the current items position and the target position… but alas no joy.

const { x, y, z } = point.position
const { x: x2, y: y2, z: z2 } = this.latLngCords[index]
let startVector = new THREE.Vector3(x, y, z)
let endVector = new THREE.Vector3(x2, y2, z2)
const q = new THREE.Quaternion()
q.setFromUnitVectors(startVector.normalize(), endVector.normalize())
TweenMax.to(point.quaternion, 5.5, {
...q,
onComplete: () => {
q.setFromUnitVectors(startVector.normalize(), endVector.normalize())
}
})

Any thoughts…

I’ve not had a proper play with your other suggestion… Run out of time today, so i’ll take a look again tomorrow… The first solution certainly looks easier.

I would prefer to use the second approach. It looks more complicated than the frist one, but actually it’s not like that

The first one is just a very rough concept which uses quaternions for geometries whose centers conicide with the center of the sphere (notice, I translate vertices of the box geometry at the value of radius). In your case, centers of boxes don’t coincide with the center of the sphere, they are on the surface of the sphere.

The second one, from my point of view, has correct movement of the object on the sphere. Straight from one point to another, along the surface of the sphere.

Using the second approach, your animation will be like that:

this.local = points.map((point, index) => {
const { x, y, z } = point.position;
const { x: x2, y: y2, z: z2 } = this.latLngCords[index];
let startVector = new THREE.Vector3(x, y, z);
let endVector = new THREE.Vector3(x2, y2, z2);
let angle = { value: 0 };
let angleEnd = startVector.angleTo(endVector);
let normal = startVector.clone().cross(endVector).normalize();
TweenMax.to(angle, 5.5, {
value: angleEnd,
onUpdate: () => {
point.position.copy(startVector).applyAxisAngle(normal, angle.value);
point.lookAt(this.center);
}
});
});

A very good book for all 3D Math related stuff is:

I’ve read the first and second edition and still use it as a reference book. Many concepts elaborated in this thread are not three.js related. For example THREE.Spherical's are just spherical/polar coordinates. Topics like that are discussed in the book from scratch.

BTW: I’ve used the following fiddle for a recent stackoverflow post. It’s based on your version of THREE.Spherical but avoids some unnecessary calculations.

Just thought about the approach with tweening of spherical coordinates. It has confusing behaviour when theta changes, for examples, from 355 to 5 degrees. In this case an object moves along not the shortest path (as a user would expect) and makes almost a full turn: https://jsfiddle.net/prisoner849/6ery1qct/

Whereas the approach with tweening the angle around a triangle’s normal makes an object to move along the shortest path (most expectable behaviour): https://jsfiddle.net/prisoner849/zcv81gL5/