bug: Color animation happens instantly
Bug Description
I'm trying to create a hover effect by animating my colour to a different value:
let c = add([
circle(50),
pos(200, 300),
color("#53eafd"),
animate(),
area(),
]);
c.onHover(() => {
c.animate("color", [Color.fromHex("#f4a8ff")], {
duration: 0.5,
loops: 1,
direction: "end"
})
})
c.onHoverEnd(() => {
c.color = Color.RED;
})
The problem is that the colour instantly changes to the new colour.
Am I missing something on how this is supposed to work? Or is this a bug?
Is animate okay to use here, or should I use tween or lerp?
Next, the assignment of c.color = Color.RED does not work when an animation is used.
Is this also to be expected? How should this work?
Version
master
Playground Link
No response
Extra information
I was expecting this to be similar to how I would do it in the browser:
const square = document.createElement("div");
square.style = "background: yellow; width: 50px; height: 50px; position: fixed; right: 50px; top: 50px; z-index: 1000; transition: background 500ms;";
square.addEventListener("mouseenter", () => {
square.style.background = "#FF0000";
})
square.addEventListener("mouseleave", () => {
square.style.background = "yellow";
})
document.documentElement.lastChild.appendChild(square)
Summary
- [ ] Fixed in v4000
- [ ] Fixed in v3001
Animate does not use the current color, position, angle or any other property. You need to pass several keyframes to animate and it will interpolate between them.
So correct would be c.animate("color", [c.color, Color.fromHex("#f4a8ff")], ...)
https://play.kaplayjs.com/?code=eJyNkMFqwzAMhu95CuFdHDCuty5QWlooW6Hn7Vh6ELY8Qh07OOm6Mfbuc5x0hZ0mDJY%2BydIvz2bw2mPsO0DwdIE3bKg4Yevwk5eronDUg4Y1oDH8UEAyXUftiFeqFDluQ8cflBIwV1ekgwuRs7tqTmgNmyj6usGe%2BDWMhIN%2FHMZoGfw%2BvFPkvIT1Br7GPvLsp1db5wY9Ix1ZHbzsiE5c%2FUkQZ1kBE3DQMrsCnoZL2hiaPX0kbfYRF9ay8iimYYOZc8x9l6BkJX6xC6HtlnB%2FI6aOpMdKZkO8YDQsJ7%2FLIp3bPjtv%2FrVSVpn%2BeZT5sntepT4%2FZRlwmg%3D%3D&version=master
Can you explain this a bit?
Why do I need to call c.animation.seek(0);?
Seems like that is fixing some internal state that was wrong.
This is unintuitive after reading the guide
The animate component has an internal clock which starts the moment it is added to an object. So by the time you animate a property for 0.5ms, the internal clock may already be many seconds ahead. So when you want to play an animation not at creation time, you need to seek to 0, which sets the internal clock to 0. The other mistake is to not clear existing animations. Animations don't disappear on their own, you need to clear them when finished with them.
Thanks, this is super insightful! That explains
c.onAnimateChannelFinished(name => {
if (name === "color") {
console.log("color ended")
c.unanimate("color");
}
})
better as well.
Would you accept a PR with some more API documentation for this?
Sure. Originally animate was meant to build or load (it can export and load animations too) a complex animation, and play it. That's why the internal clock starts immediately. However now it is often used as a more advanced replacement for the old tween, so maybe some API changes are in order.
Thanks, will try and prepare something in the next days.