If you want to rebuild the extension source code yourself, please refer to the official Godot GDExtension documentation..
Gif Studio is GDExtension for Godot Engine that allows you to load, edit, play, and export GIF animations.
Supported platforms:
Windows x64 ✅
Windows arm64
Linux x64 ✅
Android arm64 ✅
Load & Play: Easily import GIF files and play them in your scenes.
In-Engine Editing: Modify your GIFs using Godot UI.
High Performance: Built as a GDExtension for optimal speed and efficiency.
Export Ready: Save your creations or modified frames back to GIF format.
Decodes a 90MB GIF in just ~240ms.
GifPlayer2D ~7% faster than AnimatedSprite2D.
Full crash protection is implemented when attempting to load corrupted or invalid GIF files.
Currently, there is no support for Interlaced GIF.
- Download the latest release archive from the Releases page of this repository.
- Extract the archive and move the addons directory into the root folder of your Godot project.
- Done! Since this plugin is built using GDExtension, it activates automatically and does not require manual enabling in the project settings.
Gif Studio uses two main components to handle animations:
GifPlayerData : The core engine. Use this to load, edit, and export GIF files. It acts as a data container for your animation.
GifPlayer2D : The visual component. It features a GifPlayerData property - simply plug your resource into the node to play and display the GIF in your scene.
Getting Started (Video Tutorial)
2026-05-14.04-47-30.mp4
Store the original .gif in the project and load it once using the load_gif_from_path(res://my_gif.gif) method.
If you need a custom implementation (e.g., for UI or specific logic), you can easily use GifPlayerData manually. Here is a basic example of how to draw and animate a GIF using _draw():
extends Node2D
@export var frame : int = 0 : set = set_frame
@export var data : GifPlayerData
var time : float = 0
func set_frame(new_frame : int) -> void :
frame = new_frame
queue_redraw()
func _draw() -> void:
if !data : return
var texture : ImageTexture = data.get_active_image(frame)
if !texture : return
draw_texture(texture,Vector2.ZERO)
func _process(delta: float) -> void:
if !data : return
time += delta
var gif_delta : float = data.get_frame_delta_float(frame)
if time < gif_delta : return
var local_frame : int = frame
while time >= gif_delta:
time -= gif_delta
local_frame += 1
local_frame = data.wrapi_valid_frame(local_frame)
gif_delta = data.get_frame_delta_float(local_frame)
frame = local_frameInherits: Resource<RefCounted<Object
A specialized resource for managing, processing, and exporting GIF animations. GifPlayerData handles the low-level logic of GIF decoding and encoding, providing frame manipulation and baking frames.
GifPlayerData is the central component for GIF operations within the engine. It handles all GIF data,supports fast decoding (e.g., 90MB in ~240ms), frame-by-frame editing via the Godot Inspector, and exporting animations back to the .gif format.
| name | description |
|---|---|
| Load | Call load_gif_from_path method with popup EditorFileDialog. |
| Save as .gif | Call save_as_gif method with popup EditorFileDialog. |
| Rebake | Call bake_images method. |
| return type | method |
|---|---|
| void | load_gif_from_buffer(buffer: PackedByteArray, compress_mode: ImageCompressMode = 2) |
| void | load_gif_from_path(path: String, compress_mode: ImageCompressMode = 2) |
| void | bake_images() |
| void | save_as_gif(full_path : String = "res://MyGif.gif") |
| ImageTexture | get_active_image(frame_index: int) const |
| int | get_frames_count() const |
| int | wrapi_valid_frame(frame: int) const |
| int | get_frame_delta(delta_index: int) const |
| float | get_frame_delta_float(delta_index: int) const |
| int | get_frame_disposal(disposal_index: int) const |
| Vector2 | get_frame_position(position_index: int) const |
| Color | get_frame_transparent_color(transparent_color_index: int) const |
| bool | get_frame_transparent_color_flag(transparent_color_flag_index: int) const |
| ImageTexture | get_frame_source(source_index: int) const |
| ImageTexture | get_frame_baked(image_index: int) const |
source_image_changed()
- Emitted when the source_image changes.
rebaked()
- Emitted after bake_images method.
ImageCompressMode None = 0
Not use compression.
ImageCompressMode S3TC = 1
Use S3TC compression.
ImageCompressMode ETC = 2
Use ETC compression.
ImageCompressMode ETC2 = 3
Use ETC2 compression.
ImageCompressMode BPTC = 4
Use BPTC compression.
ImageCompressMode ASTC_4X4 = 5
Use ASTC_4X4 compression.
ImageCompressMode ASTC_8X8 = 6
Use ASTC_8X8 compression.
Mode Source = 0
Mode Baker = 1
BakeMode Save = 0
baked_image saved within the resource file.
NOTE: In current versions of Godot this may cause performance issues when working with large files (a 90 MB GIF can weigh ~1 GB when decoded), this option is added for the future.
BakeMode GenerateOnStart = 1
Reduces the resource file size on disk by not storing the baked data.
PackedInt32Array delta
- void set_delta(value: PackedInt32Array)
- PackedInt32Array get_delta()
An array containing the delay time for each individual frame.
Values are stored in GIF delay units, where 100 units = 1 second .
Mode mode
Dynamically hides or shows properties relevant to the selected mode.
ImageCompressMode bake_compress
- void set_bake_compress(value: ImageCompressMode)
- ImageCompressMode get_bake_compress()
Determines the compression algorithm applied to the generated images during the bake_images() process.
BakeMode bake_mode
Determines the lifecycle of the baked textures.
Vector2i full_size
The logical canvas size of the GIF.
PackedVector2Array position
- void set_position(value: PackedVector2Array)
- PackedVector2Array get_position()
An array storing the position for frame.
Array[bool] transparent_color_flag
Is frame has transparent_color.
Array[Color] transparent_color
Transparent color for frame.
Color background_color
The background color of the GIF.
PackedByteArray disposal
- void set_disposal(value: PackedByteArray)
- PackedByteArray get_disposal()
Disposal is frame cleaning method.
0 - Disposal method not specified.
1 - draw the next image on top of the current one.
2 - canvas should be restored to the background_color.
3 - should restore the canvas to its previous state before the current image was drawn.
Array[ImageTexture] baked_image
- void set_baked_image(value: Array[ImageTexture])
- Array[ImageTexture] get_baked_image()
The array of textures generated by the bake_images method.
Array[ImageTexture] source_image
- void set_source_image(value: Array[ImageTexture])
if mode is Baker and bake_mode is GenerateOnStart and baked_image is empty call bake_images method. - Array[ImageTexture] get_source_image()
The array of original frames, loaded directly from the GIF file.
void load_gif_from_buffer(buffer: PackedByteArray, compress_mode: ImageCompressMode = 2)
Decode .gif into current GifPlayerData resource fields.
Array Optimization:
To save memory, arrays disposal, position,transparent_color, transparent_color_flag, delta are truncated. If trailing elements are identical, they are removed. If an index is out of bounds during playback, the last available element in the array is used for all subsequent frames.
Example: [0, 2, 0, 0, 0, 0] becomes [0, 2, 0].
void load_gif_from_path(path: String, compress_mode: ImageCompressMode = 2)
Prepare buffer than call load_gif_from_buffer.
void save_as_gif(full_path : String = "res://MyGif.gif")
Encode and saves a GifPlayerData resource to disk to the given path as .gif file.Reduce the palette to 255 colors per frame for accurate color reproduction.During the process using source_image or baked_image,full_size, position, disposal, background_color, transparent_color, transparent_color_flag,mode.
Note: Even if a property is not currently visible in the editor, its values are still used during process to ensure the resulting file maintains correct frame behavior.
Important compatibility note: Support for the disposal and delta depends on the specific viewer.
In particular, the mobile version of Telegram (unlike the desktop version) has specific processing algorithms: it can ignore the dynamic delay between frames and incorrectly overlay delta changes, leading to visual bugs.
General compatibility recommendations: use disposal = 0 and delta = 10 when encoding.
Generates an ImageTexture array for baked_image by processing the raw source_image frames.During the process using source_image,full_size, position, disposal, background_color, transparent_color, transparent_color_flag.
int wrapi_valid_frame(int: frame) const
Wraps the frame value between 0 and the array size (exclusive). The array size depend on the current mode.
int get_frames_count() const
Returns the count from source_image or baked_image depending on the current mode.
ImageTexture get_active_image(int: image_index) const
Returns the ImageTexture from source_image if mode is Source otherwise from baked_image.The image_index is clamped to the array size.Returns null if the array is empty.
ImageTexture get_frame_source(int: source_index) const
Returns the ImageTexture from source_image at the given source_index.The source_index is clamped to the array size.Returns null if source_image is empty .
ImageTexture get_frame_baked(int: baked_index) const
Returns the ImageTexture from baked_image at the given baked_index.The baked_index is clamped to the array size.Returns null if baked_image is empty .
int get_frame_delta(delta_index : int) const
Returns frame duration from delta at the given delta_index in Gifs units (100 units = 1 second).If delta is empty or frame duration is 0 returns 10.
float get_frame_delta_float(delta_index : int) const
Returns Godot-friendly frame duration from delta at the given delta_index.Optimized for direct use in Godot (seconds).If delta is empty or frame duration < 0.01 returns 0.01.
int get_frame_diposal(disposal_index : int) const
Returns frame clean-up method from disposal.If disposal is emty returns 0.
Vector2 get_frame_position(position_index : Vector2) const
Returns frame position from position.If position is emty returns Vector2.ZERO.
Color get_frame_transparent_color(transparent_color_index : Vector2) const
Returns frame transparent color from frame_transparent_color.If frame_transparent_color is emty returns Color(0,0,0,0).
bool get_frame_transparent_color_flag(transparent_color_flag_index : Vector2) const
Returns frame transparent flag from frame_transparent_color_flag.If frame_transparent_color_flag is emty returns false.
Inherits: Node2D<CanvasItem<Node<Object
A specialized node for displaying and controlling GIF animations in a 2D environment. GifPlayer2D acts as the visual component for GifPlayerData.
GifPlayer2D is the visual component for GIF integration.
| type | name |
|---|---|
| bool | play |
| int | frame |
| float | speed_scale |
| bool | centered |
| Vector2 | offset |
| GifPlayerData | gif_player_data |
frame_changed()
- Emitted when frame changes.
bool play
If true, the animation is playing.
int frame
Index of the currently displayed animation frame.
float speed_scale
The speed multiplier for animation playback. A value of 1.0 is normal speed,negative values cause the animation to play in reverse.
bool centered
If true, texture will be centered.
Vector2 offset
The texture's drawing offset.
GifPlayerData gif_player_data
- void set_gif_player_data(new_gif_player_data : GifPlayerData)
- GifPlayerData get_gif_player_data()
very bad:
var my_var : Vector2 = position[my_index]bad:
var my_var : Vector2 = position[ clamp(my_index, 0, position.size() - 1) ]ok but bad:
var my_var : Vector2 = Vector2.ZERO
if position.size() > 0:
my_var = position[ clamp(my_index, 0, position.size() - 1) ]good:
var my_var : Vector2 = get_frame_position(my_index)the same applies to arrays delta, position, disposal, transparent_color, transparent_color_flag.