What is the best way to achieve a seamless transition between keyframes?

Currently, I am working on developing an animation system for my three.js project which involves utilizing a JSON file. While I have successfully implemented the animation playback, I am facing an issue where objects immediately move to their designated locations instead of smoothly transitioning over time. The JSON file contains data specifying where a particular object should be located at specific intervals. For instance:

JSON File:

{
"right": {
    "position": {
        "0.0": [0, 0, 0],
        "0.25": [0, 1, 0],
        "0.5": [1, 1, 0]
    }
}

The JSON file denotes the position of the object, timing of the changes in position, and the corresponding coordinates.

Code:

for (const [key, value] of Object.entries(json.position.right)) 
  if(seconds === json.position.right[key]) {
    obj.position.x = json.right.position[key][0];
    obj.position.y = json.right.position[key][1];
    obj.position.z = json.right.position[key][2];
  }
}

In this code snippet, I iterate through the JSON file's right cube position (which signifies when the position changes occur). If the seconds match the specified keyframe, the object is moved to that location.

My main query pertains to achieving smooth movement between keyframes for the object.

Check out this example:

Access all the code here:

I leveraged Blockbench to export models as .OBJ files, materials as .MTL files, and animations as .JSON files.

If my explanation seems convoluted, I apologize and would greatly appreciate any assistance.

Answer №1

When working with Three.js, you have access to a convenient method called MathUtils.lerp() which allows for smooth interpolation between two points based on a specified value ranging from 0 to 1. This can be particularly useful for creating animations that transition smoothly between different positions, as illustrated in the example below:

const holder = document.getElementById("holder");
const circle = document.getElementById("circle");

// Define initial positions
let circlePosX = 0;
let circlePosY = 0;

// Specify target positions
let targetX = 0;
let targetY = 0;

// Update target positions upon user interaction
function onMove(event) {
  targetX = event.layerX;
  targetY = event.layerY;
}

function updateAnimation() {
  // Interpolate current position towards targets
  circlePosX = THREE.MathUtils.lerp(circlePosX, targetX, 0.1);
  circlePosY = THREE.MathUtils.lerp(circlePosY, targetY, 0.1);
  
  // Apply calculated positions to the object
  circle.style.left = circlePosX + "px";
  circle.style.top = circlePosY + "px";
  requestAnimationFrame(updateAnimation);
}

holder.addEventListener("mousemove", onMove);
updateAnimation();
#holder {
  width: 300px;
  height: 300px;
  background: #ddd;
}

#circle {
  width: 10px;
  height: 10px;
  position: absolute;
  top: 0;
  left: 0;
  background: #f90;
  border-radius: 10px;
  margin-top: -5px;
  margin-left: -5px;
}
<div id="holder">
  <div id="circle"></div>
</div>

<script src="https://threejs.org/build/three.js"></script>

Additional Info:

If you want to create a linear timeline with keyframes, you can leverage gsap.to() along with keyframes parameter to define all the positions sequentially. For more details and examples, refer to the official documentation mentioned here under "keyframes". Check out the provided code demo below to see this technique in action. Feel free to customize it by iterating through your JSON data and incorporating it into GSAP. Best of luck!

// Initialize position vector
const circlePos = {x: 0, y: 0};
const positionsMap = {
    "0.0": [0, 0],
    "0.25": [0, 100],
    "0.5": [100, 100],
    "0.75": [100, 0],
    "1.0": [0, 0],
}
const animationTimeline = gsap.to(circlePos, {keyframes: [
  {x: positionsMap["0.0"][0], y: positionsMap["0.0"][1], duration: 0.0},
  {x: positionsMap["0.25"][0], y: positionsMap["0.25"][1], duration: 0.25},
  {x: positionsMap["0.5"][0], y: positionsMap["0.5"][1], duration: 0.25},
  {x: positionsMap["0.75"][0], y: positionsMap["0.75"][1], duration: 0.25},
  {x: positionsMap["1.0"][0], y: positionsMap["1.0"][1], duration: 0.25},
]});

const container = document.getElementById("holder");
const circle = document.getElementById("circle");


let currentProgressTime = 0;
function updateAnimationFrames() {
  currentProgressTime += 0.001;
  currentProgressTime %= 1;
  animationTimeline.seek(currentProgressTime);

  // Apply current position to our object
  circle.style.left = circlePos.x + "px";
  circle.style.top = circlePos.y + "px";
  requestAnimationFrame(updateAnimationFrames);
}

updateAnimationFrames();
#holder {
  width: 300px;
  height: 300px;
  background: #ddd;
}

#circle {
  width: 10px;
  height: 10px;
  position: absolute;
  top: 0;
  left: 0;
  background: #f90;
  border-radius: 10px;
  margin-top: -5px;
  margin-left: -5px;
}
<div id="holder">
  <div id="circle"></div>
</div>

<script src="https://threejs.org/build/three.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.7.1/gsap.min.js"></script>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

How can you merge webSDK with jQuery within a Vue Component?

I am currently working on incorporating the webSDK found at into our Vue application. My goal is to load jquery only within a single component. Below is the code I have written, however, when I click the button, it does not seem to function as expected. ...

What are some solutions for dealing with NodeJS heap memory errors?

I am currently working with a NodeJS connected database that is 723.1 MB in size, and I am running into memory size issues. To make my database available as an API for use in my VueJS application, I have successfully rendered all the necessary data from a ...

An embedded object is encountering an error due to an undefined value in the field of 'Math'

My approach involves using AJAX to dynamically load a YouTube video when the page is loaded. $(document).ready(function(){ $.ajax({ url : '/myurl', type:"post", data:{"d": $('#d_id').val()}, ...

Destroying the entire HTML content results in the invalidation of both the HEAD and BODY tags post-

Upon clicking a button, I execute a script that sends the entire HTML content of a webpage (everything within the <html> tags) to a CGI script for processing. However, when I attempt to replace the existing content with the manipulated result, I enc ...

What is the best way to create a fading footer effect on scroll using jQuery?

Why is my footer not fading in after 1000px like I want it to? Instead, it appears immediately on the screen. I attempted using fadeIn() in jQuery but had no luck. I also tried to make it disappear with fadeOut(), again with no success. Am I missing someth ...

Loading texts with the same color code via ajax will reveal there are differences among them

I am currently designing a webshop with green as the primary color scheme. Everything is functioning perfectly, but I have noticed that the text within an ajax loaded div appears brighter than it should be. The text that loads traditionally is noticeably d ...

Utilize Node.js to simultaneously connect with several APIs

Consider a scenario where multiple APIs need to be called in parallel using promise.all(). The issue arises when promise.all() rejects if any API fails. In this case, instead of giving up on failed APIs, I want to retry them until they succeed. However, ...

Place the div's scrollbar at the beginning of its content

Recently, I put together a custom CSS modal that includes a scrollable div (without the modal itself being scrollable). Interestingly enough, when I initially open the modal, the scrollbar of the div starts at the top as anticipated. However, if I scroll d ...

Enhancing Element Generation and Data Association through jQuery

Currently, I am seeking a more streamlined approach to generate DOM alterations and update the object within .data(). At the moment, data is being supplied in an array of objects. I construct strings piecemeal, appending them to the table body, and affixi ...

Displaying HTML elements in a specific order using ng-repeat

Upon receiving the json message, my goal is to display it in HTML in a specific order. Within the json message, the position value indicates the desired order of elements, with 0 representing the first element in the array. At times, the json message may ...

Contrast between the act of passing arguments and using apply with arguments

I have an important backbone collection that utilizes a save mixin to perform Bulk save operations (as Backbone does not natively support this feature). // Example usage of Cars collection define([ 'Car', 'BulkSave' ], function(Car ...

What steps should be followed to set up Selenium WebDriver to accept command line options using Node.js?

I'm currently working with Selenium WebDriver through Node.js and I have a set of resources that I'm not sure how to interpret for my specific objective (here and here). At the moment, all my tests are running successfully as intended but now I w ...

Storing Form Input in Browser's Local Memory

I am currently working on a form section where individuals can input their email addresses. However, I have encountered a couple of issues: (1) After submitting an email address, the page refreshes. While I understand that this is inevitable without usin ...

Guide to displaying or concealing the header using PHP

Once the add button is clicked, the text should be hidden and the form should be displayed. Check out my code below: <h2 style="font-size: 2em; margin-bottom: 0.75em; margin-left: -1%;">Specify Co-Owners for self occupied property</h2> <div ...

Guide to positioning a div in the center while implementing animations through transition and transformation using scale

Creating a popup for my React app without relying on external libraries is my current project. I am experimenting with using transition and transform with scale to size the popup dynamically based on screen size and content, then center it on the screen. ...

404 error: API endpoint inexistent despite being present

I am encountering an issue while attempting to retrieve a product by its ID. Interestingly, when I tested this using Postman, everything worked flawlessly without any errors. However, when I tried to fetch the data using Angular, it kept returning a 404 no ...

Utilizing HTML properties in stenciljs for variable binding

I'm struggling to display a value with custom HTML inside an element. example: this.title = 'Hello <b> stencil </b>'; << response value from an API Binding: <h1>{this.title}</h1> I hope to achieve similar ...

Unable to assign the value 'hello' to an undefined property in TypeScript

I'm attempting to define a class in TypeScript, but I keep encountering the error shown below. Here is the execution log where the error occurs: [LOG]: "adding" [LOG]: undefined [ERR]: Cannot set property 'hello' of undefined class Cust ...

Using jQuery, effortlessly scroll a div to a specific vertical position of your choice

After referring to this previous question: Scrollpane on the bottom, css is hacky, javascript is hard I followed the same scrolling method as explained in the accepted answer. Now there's a new requirement to select a specific item (e.g., through a ...

What are the best practices for avoiding the need to restart my node server every time an error occurs?

Network.js const mysql = require("mysql"); var connectionDetails = mysql.createConnection({ host: "xxx.amazonaws.com", user: "admin", password: "xxx", database: "xxx", multipleStatements: true, } ...