How to animate a button/controller?

I may be asking a stupid question, but I just tried to animate the width of a button, and I couldn’t, because the width seemed to be stored as a string (e.g. “80%”). Same problem with position (top, left).

Am I missing something?

I did try to animate widthInPixel, but it is read-only…

Actually it works like html:
https://www.babylonjs-playground.com/#XCPP9Y#1064

Because of the unit, you have to animate a value on the side and then rebuild the property

Thank you very much for your quick reply. Looks like you are answering all the problems :slight_smile:

So, yeah, your solution works, but I don’t think it is a good one; and I am not willing to use it.

BabylonJS has an animation system, that allows to easily make tweens (see below). I think it will be beneficial to the engine if the GUI can be animated with the animation system.

Basically, I believe that we should be able to use the below on any properties of any target object in BabylonJS:

private static createAnimation (target : any, targetProperty:string, startValue:any, endValue:any, 
            duration:number, loopMode:number, easingFunction?:BABYLON.EasingFunction, easingMode:number=BABYLON.EasingFunction.EASINGMODE_EASEIN) : BABYLON.Animation {
        
        if(startValue.constructor !== endValue.constructor){
            throw new Error("Tween: start and end values should be of the same type! type of: " + startValue.constructor + ", " + endValue.constructor);
        }
        let animation_type = this.inferAnimationType(startValue);
        if(animation_type === null)
            throw new Error("Tween: the value type (endValue/startValue) is not supported!")

        let totalFrame = this.frameRate*duration;
        let animation = new BABYLON.Animation("Tween." + target.name + "." + targetProperty, 
                                                targetProperty, this.frameRate, 
                                                animation_type, loopMode);

        let keyFrames = []; 

        keyFrames.push({
            frame: 0,
            value: startValue,
        });

        keyFrames.push({
            frame: totalFrame,
            value: endValue,
        });

        animation.setKeys(keyFrames);
        
        if(easingFunction){
            easingFunction.setEasingMode(easingMode);
            animation.setEasingFunction(easingFunction);
        }

        return animation
    }

I noticed that now, the GUI controller/container’s size (width, height) and position (top, let) have the type ValueAndUnit. Would it be possible to make this ValueAndUnit type compatible with the animation system? If not, could we add a Vector2 property position which would overwrite top and left if used? A little bit as it is done with rotation and quaternion?

It seems to me that it would be a very good improvement for managing complex menu animation.

@Nodragem
@Deltakosh

How about a setter function for xInPixels ?
https://www.babylonjs-playground.com/#XCPP9Y#1066

you can then directly animate e.g. button.widthInPixels as a float / number

I’m OK if you guys want to do a PR for that setter (but for 4.1)

1 Like

Actually I was on it so I will do it

2 Likes

Would it be possible to have a Vector2 position that controls both leftInPixel and topInPixel? that way the GUI objects are consistent with 3D objects? and that also reduces the number of animations to create (Vector2 can be animated with one animation, while two floats require two animations).

Same idea for width and height?

I do not want to bloat the engine too much. Your idea is fine but animating two floats or one vector2 is kind of the same performance wise

I would like that we agree that usability is also important, as it facilitates the creativity of your users. If your engine is aimed at small teams and indie developers, then it is likely that the persons who code are also involved in the creative process. Hence, less code to do one thing equals more time for creativity. One paradigm (e.g. animation system) that applies consistently to everything (e.g. 3D objects, TransformNodes, Camera, controllers, containers) equals less time fiddling and more time for creativity.

To be honest, I felt a bit annoyed when I first discovered how BABYLON.GUI was organised differently than BABYLON and that I could not animate 2D objects as easily as 3D objects ^^.
When you think of it, BABYLON.GUI could have been a 2D mirror of BABYLON. Now I understand that it also makes sense for BABYLON.GUI to be a mirror of CSS.

However, I believe that BABYLON.GUI should still be easy to use with BABYLON core paradigms (e.g. with the animation system). In the above messages, we spoke about positions and sizes, but really, all properties of controllers and containers (e.g. alpha, color, border, cornerRadius, rotation, etc) should be animable with the animation system of BABYLON (and some already are).

I may repeat myself a little bit but I think my point is important: when you develop a game or an app with 3D content, you want to focus on the creative process. That means that a good engine would provide very intuitive usability that facilitate creativity, while making sure that performance isn’t a worry either. That is why some times ago I was defending that refactorying and breaking compatibility for major releases was a good thing, if it is aiming at improving usability (for the end users and the engine developers).

Now, I would like to highlight that BabylonJS is already doing a good job at being usable and in terms of performance, and I enjoy using it. But nothing is ever perfect and I’m giving my opinion on what could be improved :smiley:

At least :smiley:

I’m not opposed to also add properties to simply the use. But it requires documentation and maintenance and ultimately it will end up on me :slight_smile:
Everything in GUI is animatable as long as it is not a ValueOrUnit property.

I guess that was exactly what I was trying to point out in this thread :slight_smile: either the animation system needs to be tweaked so that it can deal with ValueOrUnit or the ValueOrUnit need to consistently have a setter usable with the animation system (either Vector2 or Float).

I never really understood if BabylonJS was a one man API made in your free time or if there is a dedicated team behind or if there was a strong support from Microsoft and big company that uses it? BabylonJS definitely deserves love and support :slight_smile: no patreon or donation system? Krita, Blender, Godot, all these opensource projects have their way to get some money in a sustainable way to get part-time or full-time developers.

Anyway, need to get some rest :slight_smile: I see you later!

Microsoft pays an entire team (including me) to support babylon.js :slight_smile:
But I’m the one working on both animation and GUI

I’m also the keeper of the framework and I try to keep it to get too bloated while staying stable, fast and backward compatible :smiley:

and easy to use :slight_smile: and consistent :smiley: and well-designed :smile:

My Top 5 priority list would be:

  1. Stable
  2. Consistent/Flexible/Well-designed API
  3. Easy to Use/Extent (for the engine devs, and game devs, which results from 2))
  4. Fast
  5. Backward compatible

Backward compatibility is last because no one can make the perfect API design (2) at once, hence major releases would allow for breaking backward compatibility and improve on the API design (and usability). Breaking compatibility allows to replace or prune parts of the API; while if you never allow to break the compatibility, then your only option is to add new properties/functions and depreciate the old one, which ultimately confuse people and, as you said, bloat the engine (as Unity likes to do it seems).

To not allow for breaking the backward compatibility and at the same time being very worry about bloating the engine means that you are giving yourself no margins for mistakes in the API design. You only have one chance to write it right :slight_smile: aren’t there any parts of the engine you wish you would have designed differently? :smiley:

We have all the alpha and beta period of a release to make it right. Once it is public and people use it we do not change it anymore (unless performance reason). So basically we have 6 months to make sure users like the new API

And once again, here we are just talking about creating two animations instead of one (which can be done by user code as both animations would be the same but the target)

But anyway, as width/height would not be animatable for performance reasons (the animation engine cannot test for it on every tick) what about having something like:

  • TopLeftInPixels as vector2 (or any better name)
  • WidthHeightInPixels as vector2 as well
  • PaddingTopLeftInPixels as vector2

Sound great. But widthInPixels and other inPixels variables are read-only if I remember well?

No there are writeonly following our previous discussion!
This is why I told you it is not a big deal: you can animate widthInPixels and all other inPixels now as they are read/write now