Skip to content

Arelav-git/godot-gif-studio

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Gif studio

If you want to rebuild the extension source code yourself, please refer to the official Godot GDExtension documentation..

Gif Studio for Godot

Gif Studio is GDExtension for Godot Engine that allows you to load, edit, play, and export GIF animations.
Supported platforms:
Windows x64 ✅
Windows arm64 ⚠️ (not tested)
Linux x64 ✅
Android arm64 ✅

Features

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.

⚡ Performance

Decodes a 90MB GIF in just ~240ms.
GifPlayer2D ~7% faster than AnimatedSprite2D.

🛡 Protection

Full crash protection is implemented when attempting to load corrupted or invalid GIF files.

⚠️ Known Issues

Currently, there is no support for Interlaced GIF.

Installation

  1. Download the latest release archive from the Releases page of this repository.
  2. Extract the archive and move the addons directory into the root folder of your Godot project.
  3. Done! Since this plugin is built using GDExtension, it activates automatically and does not require manual enabling in the project settings.

How it works

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

Usage Recommendations

Store the original .gif in the project and load it once using the load_gif_from_path(res://my_gif.gif) method.

Custom Player Example (GDScript)

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_frame

GifPlayerData

Inherits: 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.

Description

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.

Editor buttons

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.

Properties

type name
Mode mode
ImageCompressMode bake_compress
BakeMode bake_mode
Vector2i full_size
Color background_color
Array[ImageTexture] baked_image
Array[ImageTexture] source_image
PackedVector2Array position
Array[Color] transparent_color
Array[bool] transparent_color_flag
PackedByteArray disposal
PackedInt32Array delta

Methods

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

Signals

source_image_changed()

rebaked()

Enumerations

enum ImageCompressMode

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.

enum Mode

Mode Source = 0

Mode Baker = 1

enum BakeMode

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.

Property Descriptions

PackedInt32Array 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

  • void set_mode(value: Mode)
  • Mode get_mode()

Dynamically hides or shows properties relevant to the selected mode.

ImageCompressMode 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

An array storing the position for frame.

Array[bool] transparent_color_flag

  • void set_transparent_color_flag(value: Array[bool])
  • Array[bool] get_transparent_color_flag()

Is frame has transparent_color.

Array[Color] transparent_color

Transparent color for frame.

Color background_color

  • void set_background_color(value: Color)
  • Color get_background_color()

The background color of the GIF.

PackedByteArray 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

The array of textures generated by the bake_images method.

Array[ImageTexture] source_image

The array of original frames, loaded directly from the GIF file.

Method Descriptions

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.

void bake_images()

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.

GifPlayer2D

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.

Description

GifPlayer2D is the visual component for GIF integration.

Properties

type name
bool play
int frame
float speed_scale
bool centered
Vector2 offset
GifPlayerData gif_player_data

Signals

frame_changed()

  • Emitted when frame changes.

Property Descriptions

bool play

  • void set_play(value : bool)
  • bool get_play()

If true, the animation is playing.

int frame

  • void set_frame(frame : int)
  • int get_frame()

Index of the currently displayed animation frame.

float speed_scale

  • void set_speed_scale(speed_scale : float)
  • float get_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

  • void set_centered(value : bool)
  • bool get_centered()

If true, texture will be centered.

Vector2 offset

The texture's drawing offset.

GifPlayerData gif_player_data

GifPlayerData.

Bad & good

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.

About

Gif Studio is GDExtension for Godot Engine that allows you to load, edit, play, and export GIF animations.

Topics

Resources

License

Stars

1 star

Watchers

0 watching

Forks

Packages

 
 
 

Contributors

Languages