Fixed Animation GDExtension
Summary
| Latest Version | Unknown |
|---|---|
| License | Unknown |
| CI Status | Failing |
| Stars | 2 |
| Forks | 0 |
| Open Issues | 0 |
| Last Commit | 2026-06-30 |
| Downloads | 0 |
| Last Indexed | 2026-07-22 05:35 |
Tags
Installation
nimble install Fixed Animation GDExtension
choosenim install Fixed Animation GDExtension
git clone https://gitlab.com/night-apparatus/fixed-animation-gdextension
OS Compatibility
| Platform | Linux | macOS | Windows | FreeBSD | OpenBSD | NetBSD | Android | iOS | WASM | Embedded |
|---|---|---|---|---|---|---|---|---|---|---|
| Fixed Animation GDExtension | ✓ | ✓ | ✓ | - | - | - | - | - | - | - |
Source
| Repository | https://gitlab.com/night-apparatus/fixed-animation-gdextension |
|---|---|
| Homepage | https://gitlab.com/night-apparatus/fixed-animation-gdextension |
| Registry Source | gitlab |
README
Fixed Animation
This GDExtension is not production ready and is missing features. You have been warned.
Available for Godot 4.2+
The Animation Player in Godot is pretty good, but it is based on time, and more importantly, floats. Because of its usage of floats, it is not deterministic and should not be used to animate anything that affects the game's state such as hitboxes if determinism is required for your game. Determinism is required for Rollback Netcode and a few other niche cases. If you don't know what determinism is or why you might need it for your game, then you probably don't need this extension and can use the Godot Animation Player.
This GDExtension reimplements the Godot Animation Player, but uses fixed point math instead of floats in order to be fully deterministic. It also comes with an animation player for Delta Rollback and comes with some features to make function calling from animations more rollback friendly. If you want to use this extension with different rollback netcode than Delta Rollback, you can easily make your own rollback player by extending the base Fixed Animation Player. Check out the Delta Rollback Fixed Animation Player for tips on how to do that.
Development Status
It's a work in progress. Features for 3D projects will have a very low priority since the project that we are making this extension for is 2D. If you want them, you might want to implement them yourself.
Supported Track Types
- [x] Property Track
- [ ] 3D Position Track
- [ ] 3D Rotation Track
- [ ] 3D Scale Track
- [ ] Blend Shape Track
- [x] Call Method Track
- [ ] Bezier Curve Track
- [x] Audio Playback Track
- [ ] Animation Playback Track
Implemented Features
- [x] Animation Autoplay
- [x] Animation Linear Looping
- [ ] Animation Ping-Pong Looping
- [x] Animation Play
- [x] Animation Pause
- [x] Animation Stop
- [x] Animation Seek
- [x] Animation Queue
- [x] Animation Set Next
- [x] Animation Speed Scale
- [x] Animation Reset
- [ ] Track Keyframe Easing
- [ ] Track Capture Update Mode
- [ ] Track Linear Interpolation
- [ ] Track Cubic Interpolation
- [ ] Track Linear Angle Interpolation
- [ ] Track Cubic Angle Interpolation
- [ ] Track Clamp Loop Interpolation
- [ ] Track Wrap Loop Interpolation
- [x] 2D Position Root Motion
- [x] 2D Rotation Root Motion
- [x] 2D Scale Root Motion
- [ ] 3D Position Root Motion
- [ ] 3D Rotation Root Motion
- [ ] 3D Scale Root Motion
- [ ] Animation Library Support
Implemented Rollback Animation Players
Since we are using Delta Rollback for our project, supporting any other rollback system will have a very low priority. You might want to implement the custom animation player yourself; it shouldn't be too hard.
- [x] Delta Rollback Fixed Animation Player
- [ ] Godot Rollback Netcode (GRN) Fixed Animation Player
- Due to differences between how Delta and GRN call functions like network_process() on nodes, the implemented Delta Animation Player can not be used for GRN. It should be easy to modify it to work though.
Differences with Godot's Animation Player
The Fixed Animation Player is designed to be as close to Godot's Animation Player as possible without creating an inferior product. As such, most of the functions and properties of Godot's Animation Player are replicated in Fixed Animation Player with the same names and parameters whenever possible.
Fixed Point Numbers
The Fixed Animation Player uses fixed-point numbers instead of floats for things such as the animation position, speed scale, etc. Specifically, it uses 64-bit signed integers, with the first 16 bits reserved for the fractional part. This is the same as SG Physics 2D, for anyone that is using that too. Basically, 1.0 is equivalent to 65536 and 0.5 is 65536/2 (32768). When using the Fixed Animation Player's functions and methods, keep this in mind.
Frame-Based Animation Position
Unlike Godot's Animation Player which uses time, the Fixed Animation Player uses frames. The frequency of the frames is based on the project's Physics Ticks Per Second setting, which is 60 by default. So, for example, the seek() function expects an animation frame number for its parameter instead of a number representing the time. To seek to half a second into the animation, you would use seek(30) if your FPS is 60.
There are a couple of reasons for this difference, but the main one is that there aren't any powers of 2 that are divisible by 60. In our extension, as mentioned above, we are using the first 16 bits for the fractional part, which means that:
$$ 1.0 = 2^{16} = 65,536 $$
If we want to use seconds instead of frames, then on every tick we need to add a fraction to the current animation time that corresponds to the project's tick rate. 60 ticks per second is the most common, and it's what we're using for our project, so let's use that:
$$ 1.0/60 = 65,536/60 = 1,092.2\overline{6} \to 1,092 $$
This means that after 60 ticks, the animation position would be $1,092*60 = 65,520$ instead of $65,536$. The animation position would lag behind the place where it should be, and play slightly slower as a result. Our solution is to use animation frame numbers instead of seconds so that it will work no matter the tick rate.
Additionally, using frames can be useful for games where events happening on specific animation frames is important. The main examples for this would be fighting games, which are also the main use-cases for rollback netcode.
Missing Features
The following features of Godot's Animation Player will most likely never be supported by the Fixed Animation Player:
- Animation Blending
- Animation Tree Compatibility
- In order to get the Fixed Animation Player to work with Animation Trees, we would most likely have to create our own custom Animation Tree. This is out of the scope of this project.
Installing
Install the addon by putting the "addons" folder from the demo into the root of your project. It comes with an Editor Plugin, so you will have to enable it in Project Settings > Plugins. You might need to restart Godot. It's weird sometimes.
Usage
Creating and Editing Animations
To use the Fixed Animation Player, you will need to have a regular Godot Animation Player for every Fixed Animation Player in your scenes. They should also be at the same place in the scene hierarchy.

The reason for this is that we use the default Animation Editor to create animations and then convert them from float and time based animations to fixed-point integer and frame based animations for the Fixed Animation Player to use. This way, we don't have to implement a custom animation editor and will get updates to the editor when Godot releases them.
Assign the Godot Animation Player to the "Animation Source Node" property of the Fixed Animation Player so that it knows which Animation Player to pull animations from.

Create animations in the Godot Animation Player like normal. When animations are converted, keyframes will be snapped to match the project's Physics Ticks Per Second setting, which is 60 by default. For best results, in the Animation Editor: enable Snap, change the Snap Mode to 'FPS', and set the FPS to something that corresponds to your project's Physics Ticks Per Second.

To take advantage of optimizations in the Fixed Animation Player, keyframes should be placed equidistant from each other. To make this easy, you can set the Snapping FPS to a divisor, or factor, of the total FPS. So, for example, if your Physics Ticks Per Second is 60: | Animate on | Snapping FPS | | :-: | - | | 1s | 60 | | 2s | 30 | | 3s | 20 | | 4s | 15 |
This isn't a requirement; it will just help to avoid creating unnecessary duplicate keyframes when baking. If you want a track to animate on 2s most of the time, but use 1s when extra smooth animation is needed, that's fine. This optimization is *per track*. So, you can have one track that has keyframes on 1s, another track on 2s and yet another track on 4s and still take full advantage of it.
When you're done creating or editing your animation(s), make sure that the Fixed Animation Player that is tied to the Animation Player you are editing is the most recently selected Fixed Animation Player and press the "Bake All Animations" button that should be at the bottom of the inspector. If the button isn't there, then the plugin hasn't detected a Fixed Animation Player that has a valid Animation Source Node set and has been selected in the scene tree recently. This button will bake and convert all animations in the Animation Source Node and add them to the Fixed Animation Player.

If you have only changed one animation, you can select "Bake Current Animation" instead. Keep in mind, the RESET animation counts as an animation and is used by the Fixed Animation Player, so if you have changed the RESET animation, perhaps by adding tracks to it, then you should make sure to either Bake All or Bake Current with the RESET animation selected. Unless you have a lot of animations with a lot of tracks in the Animation Player, the conversion should be very fast, so I would recommend always using "Bake All" instead of "Bake Current" in order to avoid headaches.
Now that you have the animations in the Fixed Animation Player, you can use it mostly the same way that you would use an Animation Player. Make sure to check out the differences between the Fixed Animation Player and Godot's Animation Player.
Don't try to reference or use the Source Animation Player in game, because the Fixed Animation Player will destroy it on ready.
Using a Fixed Animation Player with Rollback Netcode
Rollback Animation Player
If you are using the Fixed Animation Player with rollback netcode, you will need to use an Animation Player that extends the Fixed Animation Player and implements rollback mechanics for your specific rollback system. There is an Animation Player provided for Delta Rollback called Delta Fixed Animation Player.

Using Call Method Tracks
Calling methods in Call Method animation tracks typically have an issue when used with rollback netcode: there is no way for the rollback system to know what the function that got called did. Additionally, it probably doesn't even know that a function was called in the first place. So, if the game rolls back to a tick before the function is called, it doesn't know how to roll back the changes that the function made. The solution to this is typically:
- Save all variables that are modified in called functions to the game's rollback state buffer
This is generally a good solution, but you need to store more variables to state and it's not very versatile. The Fixed Animation Player offers another option:
- Implement a "reset" function Note: This feature does not currently work fully with rollback and you will get state mismatch errors.
To use this feature, implement a second function with the same name as the function that you are calling in the method call track, but with a prefix and/or suffix defined in the project setting Addons > Fixed Animation > Reset Method Naming. The default setting is "*_reset". If you want to change this project setting, here's how it works:
- Anything before the '*' is a prefix, and anything after it is a suffix.
With the default setting of "*_reset", the Fixed Animation Player will look for functions that have the same name as the one called in the call method track, but with "_reset" at the end. So, for example:
#This function is called in the method call track
func enable_hitboxes(count : int):
#Do something
#This function will be called to roll back the changes of enable_hitboxes() when needed
func enable_hitboxes_reset(count : int):
#Undo whatever we did in enable_hitboxes
There are a couple of things you should know about using this feature.
- Reset functions must have the same number and type of parameters as the functions that they are undoing.
- When they are called, they will receive the same parameters as when called from the method call track.
- The reset function for a reset function is the original function.
- In the previous example, if you made a keyframe that calls "enable_hitboxes_reset", then "enable_hitboxes" will be called if it needs to roll back the call to "enable_hitboxes_reset".
- Because of this, it might be better in this example to use "enable_hitboxes_reset" instead of making a "disable_hitboxes" function. It depends on what the functions are doing though.
- Reset functions are automatically called when changing animations or calling stop() if their corresponding function has been called by the animation player.
- You don't need to use this feature, and you don't need to enable anything to use it.
- This isn't witchcraft. You might still run into cases where you can't write a function that actually rolls back another function, especially if the function is complex.
Compiling from source
If you'd like to build this extension from the source yourself, you can follow these steps:
-
Download this repository and extract it.
-
If you used Git, make sure that all the Git submodule are checked out too:
bash git submodule update --init --recursive -
Build both the debug and release version for your platform:
scons target=template_debug
scons target=template_release
Running the Demos
There are some demo scenes located in the demo folder of this repo that test various aspects of the extension. More will be added as new features are added.
The "RollbackDemoDelta" demo requires the Delta Rollback and SG Physics 2D addons. They are not included in this repo, so you will have to install them yourself if you want to run it.
Discord Server
If you have any questions about the extension or want to contribute, you can join the Night Apparatus Community Discord Server.
Credits
Thanks to all of the people that have made things that have helped us make this extension.
Godot Developers
Most of the code in the FixedAnimationPlayer is based off of the code for Godot's AnimationPlayer.
Demos
Godot Rollback Netcode/Delta Rollback demo
The demo we use for testing Delta Rollback was modified from the Delta Rollback demo, which was modified from the Godot Rollback Netcode demo. Thanks to David Snopek and David Dehaene (@BimDav) for their extensions and the demo.
Demo Assets
Godette sprite animations Count Ouf
Footstep sound effects Kyle Carpio
Bomb Explosion sprite animations Sentient Dream Games