Sometimes you only need a simple positional transform to occur over time. An easing library works very well, but it could be over engineering if you don't actually need all the features that it offers.
If you only want to move an object from A to B and, and nothing else then you can use the Vector3.lerp and .lerpVectors methods.
Calling .lerpVectors is useful if you want to slide an object along an arbitrary line depending on the alpha value. Amongst other things.
Set alpha to low number such as 0.1, and the vector will appear to lerp more slowly, slowing down as it gets closer to the target vector.
Set alpha to 1.0, and the easing will happen instantly in one render cycle.
Double-click on the floor in the example to see a slower lerp. Then experiment with the alphas to see a faster lerp and slide a second cube along a line between the first cube and the starting position.
import*asTHREEfrom'three'import{OrbitControls}from'three/examples/jsm/controls/OrbitControls'importStatsfrom'three/examples/jsm/libs/stats.module'import{GUI}from'dat.gui'constscene=newTHREE.Scene()constcamera=newTHREE.PerspectiveCamera(75,window.innerWidth/window.innerHeight,0.1,1000)camera.position.set(1,2,5)constrenderer=newTHREE.WebGLRenderer()renderer.setSize(window.innerWidth,window.innerHeight)document.body.appendChild(renderer.domElement)constcontrols=newOrbitControls(camera,renderer.domElement)constfloor=newTHREE.Mesh(newTHREE.PlaneGeometry(20,20,10,10),newTHREE.MeshBasicMaterial({color:0xaec6cf,wireframe:true}))floor.rotateX(-Math.PI/2)scene.add(floor)constgeometry=newTHREE.BoxGeometry()//the cube used for .lerpconstcube1=newTHREE.Mesh(geometry,newTHREE.MeshBasicMaterial({color:0x00ff00,wireframe:true}))cube1.position.y=0.5scene.add(cube1)//the cube used for .lerpVectorsconstcube2=newTHREE.Mesh(geometry,newTHREE.MeshBasicMaterial({color:0xff0000,wireframe:true}))cube2.position.y=0.5scene.add(cube2)window.addEventListener('resize',onWindowResize,false)functiononWindowResize(){camera.aspect=window.innerWidth/window.innerHeightcamera.updateProjectionMatrix()renderer.setSize(window.innerWidth,window.innerHeight)render()}constraycaster=newTHREE.Raycaster()letv1=newTHREE.Vector3(2,0.5,2)letv2=newTHREE.Vector3(0,0.5,0)constmouse=newTHREE.Vector2()functiononDoubleClick(event:THREE.Event){mouse.set((event.clientX/renderer.domElement.clientWidth)*2-1,-(event.clientY/renderer.domElement.clientHeight)*2+1)raycaster.setFromCamera(mouse,camera)constintersects=raycaster.intersectObject(floor,false)if(intersects.length>0){v1=intersects[0].pointv1.y+=0.5//raise it so it appears to sit on grid//console.log(v1)}}renderer.domElement.addEventListener('dblclick',onDoubleClick,false)conststats=newStats()document.body.appendChild(stats.dom)constdata={lerpAlpha:0.1,lerpVectorsAlpha:1.0,}constgui=newGUI()constlerpFolder=gui.addFolder('.lerp')lerpFolder.add(data,'lerpAlpha',0,1.0,0.01)lerpFolder.open()constlerpVectorsFolder=gui.addFolder('.lerpVectors')lerpVectorsFolder.add(data,'lerpVectorsAlpha',0,1.0,0.01)lerpVectorsFolder.open()functionanimate(){requestAnimationFrame(animate)controls.update()cube1.position.lerp(v1,data.lerpAlpha)cube2.position.lerpVectors(v1,v2,data.lerpVectorsAlpha)controls.target.copy(cube1.position)render()stats.update()}functionrender(){renderer.render(scene,camera)}animate()