EasyTransition is a lightweight screen transition addon for Godot 4 that lets you create smooth, stylized scene changes with a single call. Works as an autoloaded singleton: no setup per scene, no boilerplate.
- β 16 ready-to-use transition animations
- β Customizable transition color
- β Pixel-perfect dithering on the edge of every animation
- β Support for custom mask textures
- β
Simple API with native
await - β Parameters adjustable in real time from the editor Inspector
- Global access from any script via the
EasyTransitionsingleton - 16 animations β wipe, radial, diagonal, circular, blur, spiral, curtain, and more
- Mask textures to create transitions with fully custom shapes
- Ordered dithering (Bayer 4Γ4) with pixel-perfect edges on the transition border
- Per-call transition color configuration
- Manual mode (
cover/uncover) for controlled loading screens - Editor preview: open the autoload scene and tweak shader parameters in the Inspector to see animations in real time
Make sure your project contains this structure:
res://addons/easytransition/
plugin.cfg
plugin.gd
easytransition.tscn
easytransition.gd
transition.gdshader
If you cloned the repository, copy or keep the files under
res://addons/easytransition/.
In Godot:
- Open Project β Project Settings...
- Go to the Plugins tab
- Find EasyTransition
- Click Enable
When enabled, the plugin automatically registers the autoload singleton:
- Name:
EasyTransition - Scene:
res://addons/easytransition/easytransition.tscn
From that point you can call EasyTransition from any script in the project.
# Black fade, 0.5 s total duration (0.25 s cover + 0.25 s uncover)
EasyTransition.transition_to("res://scenes/game.tscn")await EasyTransition.transition_to(
"res://scenes/menu.tscn", # path
0.8, # duration
EasyTransition.TransitionAnim.WIPE_RADIAL, # animation
Color.WHITE, # color
null, # mask_texture
true, # dither
0.7, # dither_intensity
3.0, # dither_scale
)Use
awaitif you need to run code after the transition completes.
Covers the screen, changes scene, then uncovers the screen.
EasyTransition.transition_to(
path: String,
duration: float = 0.5,
animation: TransitionAnim = TransitionAnim.FADE,
color: Color = Color.BLACK,
mask_texture: Texture2D = null,
dither: bool = false,
dither_intensity: float = 0.5,
dither_scale: float = 2.0,
) -> void| Parameter | Type | Default | Description |
|---|---|---|---|
path |
String |
β | Path to the destination scene (.tscn) |
duration |
float |
0.5 |
Total duration in seconds (cover + uncover) |
animation |
TransitionAnim |
FADE |
Animation type (see Animations section) |
color |
Color |
BLACK |
Screen color during the transition |
mask_texture |
Texture2D |
null |
Shape texture for TEXTURE_* animations (see below) |
dither |
bool |
false |
Enables pixel-perfect dithered edge |
dither_intensity |
float |
0.5 |
Dithered edge intensity (0β1) |
dither_scale |
float |
2.0 |
Size of each pattern cell in screen pixels (1β8) |
Covers the screen only (does not change scene). Useful for manual loading screens.
EasyTransition.cover(
duration: float = 0.3,
animation: TransitionAnim = TransitionAnim.FADE,
color: Color = Color.BLACK,
mask_texture: Texture2D = null,
dither: bool = false,
dither_intensity: float = 0.5,
dither_scale: float = 2.0,
) -> voidUncovers the screen. Always call this after cover().
EasyTransition.uncover(duration: float = 0.3) -> voidAdjusts a shader parameter at runtime (useful for animations like WAVE or SPIRAL).
EasyTransition.set_param(param: String, value: Variant) -> voidExamples:
EasyTransition.set_param("wave_frequency", 12.0)
EasyTransition.set_param("spiral_tightness", 3.5)
EasyTransition.set_param("wave_amplitude", 0.12)Read-only property. Returns true while a transition is active. New calls to transition_to() or cover() are ignored while it is true.
if not EasyTransition.is_transitioning:
EasyTransition.transition_to("res://scenes/game.tscn")All animations are selected via the EasyTransition.TransitionAnim enum.
| ID | Name | Description |
|---|---|---|
0 |
FADE |
Smooth alpha fade. With dither enabled it becomes an ordered dissolve (each pixel appears on its Bayer turn). |
1 |
WIPE_LINEAR |
Sweeps the screen left to right with a vertical edge. |
2 |
WIPE_RADIAL |
Clockwise angular sweep from the right, like clock hands. |
3 |
WIPE_DIAGONAL |
Sweeps from the top-left corner to the bottom-right. |
4 |
DUAL_WIPE_LINEAR |
Two vertical bars advance from both edges (left and right) and meet in the center. |
5 |
DUAL_WIPE_RADIAL |
Two circles grow from the left and right edge centers until they meet in the middle. |
6 |
DUAL_WIPE_DIAGONAL |
Top-left and bottom-right corners are covered simultaneously toward the anti-diagonal. |
7 |
BLUR |
The scene progressively blurs before fading into the transition color. Requires access to the screen texture. |
8 |
CIRCLE_CENTER_EXPAND |
A circle grows from the center of the screen toward the edges. |
9 |
CIRCLE_CENTER_COLLAPSE |
Screen edges are covered first and the circle closes toward the center (reverse iris effect). |
10 |
TEXTURE_CENTER_EXPAND |
Like Circle Expand but the shape is defined by the texture assigned to mask_texture. White areas of the texture are the last to be covered. |
11 |
TEXTURE_CENTER_COLLAPSE |
Inverse of TEXTURE_CENTER_EXPAND. White areas of the texture are covered first. |
12 |
CURTAIN |
The screen falls from above like a curtain. |
13 |
WAVE |
Like WIPE_LINEAR but with a vertically wavy edge. Configurable with wave_frequency and wave_amplitude. |
14 |
SPIRAL |
A multi-arm spiral expands from the center. Configurable with spiral_tightness. |
15 |
TEXTURE_LUMINANCE |
Uses any standard greyscale transition texture. Black areas are covered first; white areas last. The most flexible way to create custom transitions. |
The TEXTURE_CENTER_EXPAND, TEXTURE_CENTER_COLLAPSE, and TEXTURE_LUMINANCE animations use a greyscale texture to define the reveal order:
- Black (
0.0) β that pixel is covered at the start of the transition - White (
1.0) β that pixel is covered at the end of the transition - Mid-grey values create a gradient of coverage order
You can use any black-and-white image: radial gradients, noise, geometric shapes, etc. With dithering enabled, the edge between covered and uncovered areas takes on the characteristic pixel-art look.
var my_mask: Texture2D = preload("res://assets/transitions/star_mask.png")
EasyTransition.transition_to(
"res://scenes/level2.tscn", # path
0.5, # duration
EasyTransition.TransitionAnim.TEXTURE_LUMINANCE, # animation
Color.BLACK, # color
my_mask, # mask_texture
true, # dither
)Tip: enable Import β Filter on the mask texture for soft edges, or disable it for hard edges. With dithering active, filtering matters less.
The transition.gdshader shader exposes the following uniforms. You can adjust them from code with set_param() or directly from the Inspector in the editor (see the preview section).
| Uniform | Type | Range | Default | Description |
|---|---|---|---|---|
animation |
int |
0β15 | 0 |
Index of the active animation |
progress |
float |
0.0β1.0 | 0.0 |
Transition progress. 0 = transparent, 1 = screen fully covered |
transition_color |
vec4 |
β | (0,0,0,1) |
Screen color during the transition |
| Uniform | Type | Range | Default | Used by |
|---|---|---|---|---|
wave_frequency |
float |
1.0β20.0 | 8.0 |
WAVE β Number of waves along the vertical edge |
wave_amplitude |
float |
0.0β0.3 | 0.08 |
WAVE β Wave depth (higher = more curved edges) |
spiral_tightness |
float |
0.5β5.0 | 2.0 |
SPIRAL β Number of spiral arms (higher = denser) |
| Uniform | Type | Range | Default | Description |
|---|---|---|---|---|
dither_enabled |
bool |
β | false |
Enables the pixel-art dithered edge |
dither_intensity |
float |
0.0β1.0 | 0.5 |
Effect intensity. 0 = clean edge, 1 = fully pixelated edge |
dither_scale |
float |
1.0β8.0 | 2.0 |
Size of each Bayer pattern cell in screen pixels. Higher values produce a chunkier retro look |
The dithering uses a pixel-perfect Bayer 4Γ4 matrix to create a pixel-art style edge on every transition animation.
How it works:
Instead of a smooth anti-aliased edge, each Bayer pattern cell decides whether the pixel in the transition zone should appear covered or uncovered. This creates the characteristic pixelated border of retro games.
dither_scale |
Visual result |
|---|---|
1.0 |
Individual pixel-level pattern (subtle grain) |
2.0 |
2Γ2 px cells (balanced retro look) |
4.0 |
4Γ4 px cells (chunky, very blocky look) |
8.0 |
Very large cells, strong effect |
The system guarantees that:
- At
progress = 0.0β no pixel is covered, regardless of the pattern - At
progress = 1.0β every pixel is covered, with no residual gaps - Between
0and1β the pixelated edge progresses continuously without any abrupt jumps
You can test all animations and settings directly in the Godot editor without running the game:
- Open
res://addons/easytransition/easytransition.tscnin the editor - Select the ColorRect node in the scene tree
- In the Inspector, expand the ShaderMaterial β Shader Parameters section
- Adjust the
progressparameter to see the transition advance - Change
animationto try different types - Enable
dither_enabledand adjustdither_scaleto see the pixelated effect - Modify
wave_frequency,spiral_tightness, or other animation parameters in real time
This is especially useful for calibrating
dither_scale,wave_frequency, andspiral_tightnessbefore using them in your project.
EasyTransition.transition_to("res://scenes/game.tscn")EasyTransition.transition_to(
"res://scenes/level_2.tscn", # path
1.0, # duration
EasyTransition.TransitionAnim.WIPE_LINEAR, # animation
Color.WHITE, # color
null, # mask_texture
true, # dither
1.0, # dither_intensity
4.0, # dither_scale
)EasyTransition.set_param("spiral_tightness", 4.0)
await EasyTransition.transition_to(
"res://scenes/boss.tscn", # path
1.2, # duration
EasyTransition.TransitionAnim.SPIRAL, # animation
Color(0.1, 0.0, 0.05), # color
)# 1. Cover the screen
await EasyTransition.cover(
0.4,
EasyTransition.TransitionAnim.CIRCLE_CENTER_EXPAND,
Color.BLACK,
)
# 2. Load resources while the screen is covered
ResourceLoader.load_threaded_request("res://assets/world.tscn")
while ResourceLoader.load_threaded_get_status("res://assets/world.tscn") != ResourceLoader.THREAD_LOAD_LOADED:
await get_tree().process_frame
# 3. Switch to the new scene
get_tree().change_scene_to_packed(ResourceLoader.load_threaded_get("res://assets/world.tscn"))
# 4. Uncover the screen
await EasyTransition.uncover(0.4)var mask := preload("res://assets/masks/star.png") as Texture2D
await EasyTransition.transition_to(
"res://scenes/menu.tscn", # path
0.9, # duration
EasyTransition.TransitionAnim.TEXTURE_LUMINANCE, # animation
Color(0.05, 0.05, 0.1), # color
mask, # mask_texture
true, # dither
0.5, # dither_intensity
2.0, # dither_scale
)| File | Description |
|---|---|
plugin.gd |
Registers and removes the autoload when the plugin is enabled/disabled. On enable, verifies the scene has the shader assigned. |
easytransition.tscn |
Autoload scene. Contains a CanvasLayer (layer 128) with a fullscreen ColorRect. |
easytransition.gd |
Main logic: tween management, public API, and shader configuration. |
transition.gdshader |
canvas_item shader with 16 animations, mask texture support, and a Bayer 4Γ4 dithering system. |
- When
transition_to()is called, the singleton configures the shader parameters and starts a Tween that animatesprogressfrom0.0 β 1.0(cover phase). - When the Tween finishes,
get_tree().change_scene_to_file()is called. - A second Tween immediately animates
progressfrom1.0 β 0.0(uncover phase). - The
CanvasLayerat layer128ensures theColorRectrenders above every element in the active scene, including otherCanvasLayernodes. process_mode = PROCESS_MODE_ALWAYSensures the transition is not interrupted if the scene tree is paused.
- Designed for Godot 4.
- The singleton is named
EasyTransitionand is accessible from any script withoutpreload. - Multiple calls to
transition_to()orcover()whileis_transitioning == trueare automatically ignored. - For the
BLUReffect theColorRectsamples the screen buffer; make sure the node renders after the scene (theCanvasLayer 128guarantees this). - Mask textures for
TEXTURE_LUMINANCEshould be imported with Compress Mode: Lossless to preserve exact luminance values.
MIT License Β© 2026 IUX Games, Isaackiux.