Free Tutorial · Godot 4 Tweens

Godot 4 Tween Tutorial — Animate Anything
Without AnimationPlayer

SScriptSnap/March 2026/10 min read

AnimationPlayer is powerful — but for quick, code-driven animations, it's overkill. Need to fade a UI panel, bounce a coin pickup, or smooth-scroll a camera? Godot 4's Tween system lets you animate any property on any node with a single line of GDScript.

In this Godot 4 tween tutorial, you'll learn how to create tweens, chain multiple animations, pick the right easing functions, and add satisfying juice to your UI and gameplay. We'll cover 8+ real Godot tween examples you can paste straight into your project.

If you're used to Godot 3's Tween node, heads up — the API changed completely in Godot 4. Tweens are no longer nodes. They're lightweight objects you create on the fly and let the engine garbage-collect when done. Let's get into it.

Tutorial

Godot 4 Tweens: What Changed and Why

In Godot 3, you added a Tween node to the scene tree, configured it in the inspector, and called interpolate_property(). In Godot 4, tweens are RefCounted objects you create inline from any node. No scene tree clutter, no inspector setup.

The key differences:

  • No Tween node — call create_tween() from any script
  • Fluent API — chain .tween_property(), .tween_callback(), .tween_interval() together
  • Auto-cleanup — tweens are freed automatically when complete
  • Parallel & sequential — use .parallel() and .set_parallel() for complex sequences
  • New easing system — set_trans() and set_ease() on any tweener

This makes tweens perfect for quick GDScript tricks where you need a snappy animation in a few lines of code.

Creating Your First Tween

Every tween starts with create_tween(). This returns a Tween object you can chain methods onto. Here's the simplest possible example — fading a sprite's opacity from 1 to 0 over half a second:

fade_example.gd
extends Sprite2D

func fade_out():
    var tween = create_tween()
    tween.tween_property(self, "modulate:a", 0.0, 0.5)

That's it. Four arguments: target object, property path, final value, and duration in seconds. The tween interpolates from the current value to the final value over the given time. When it finishes, the engine frees the tween automatically.

You can animate any numeric property this way — position, scale, rotation, modulate, shader uniforms, even custom @export variables. If the engine can interpolate it, a tween can animate it.

Here's a more practical example — moving a platform between two points:

moving_platform.gd
extends AnimatableBody2D

@export var move_distance: float = 200.0
@export var duration: float = 2.0

func _ready():
    var tween = create_tween()
    tween.set_loops() # Loop forever
    tween.tween_property(self, "position:y", position.y + move_distance, duration)
    tween.tween_property(self, "position:y", position.y, duration)

The set_loops() call with no argument loops the tween forever. Pass a number to limit iterations. The two tween_property calls run sequentially by default — the platform moves down, then back up, then repeats.

Want to pair tweens with clean signal architecture? Our Mastering GDScript Signals course teaches you how to trigger animations from decoupled events.

View Course →
📧

Want more Godot tricks?

Get our free GDScript Cheat Sheet with 20+ copy-paste snippets for signals, exports, state machines & more.

GDSJoin 500+ Godot devs · No spam · Unsubscribe anytime

Chaining Tweens: Sequential & Parallel

The real power of Godot 4 tweens is chaining. By default, each call to tween_property(), tween_callback(), or tween_interval() is added to a sequential chain. Each step waits for the previous one to finish. To run animations simultaneously, use .parallel() or .set_parallel(true).

Sequential Chain Example

Here's a coin pickup sequence: scale up, fade out, then call a function:

coin_pickup.gd
extends Area2D

func collect():
    var tween = create_tween()
    # Step 1: Scale up
    tween.tween_property(self, "scale", Vector2(1.5, 1.5), 0.15)
    # Step 2: Fade out (waits for step 1)
    tween.tween_property(self, "modulate:a", 0.0, 0.2)
    # Step 3: Fire callback (waits for step 2)
    tween.tween_callback(queue_free)

Each step waits for the previous one. The coin scales up, then fades, then removes itself from the scene. Clean, readable, zero AnimationPlayer overhead.

Parallel Animations

To run scale and fade at the same time, use .parallel() before the second tweener:

parallel_example.gd
func pop_and_fade():
    var tween = create_tween()
    # These two run simultaneously
    tween.tween_property(self, "scale", Vector2(1.3, 1.3), 0.2)
    tween.parallel().tween_property(self, "modulate:a", 0.0, 0.2)
    # This callback runs after both finish
    tween.tween_callback(queue_free)

The .parallel() call merges the next tweener into the same time step. The callback after it still waits for both parallel animations to complete. This pattern is ideal for the kind of polished effects you see in visual shader tricks.

Easing Functions: Making Motion Feel Right

Linear animation looks robotic. Easing functions control the acceleration curve of your tween — whether it starts fast and slows down, builds up speed gradually, or bounces at the end. Godot 4 gives you two controls: set_trans() (transition type) and set_ease() (ease direction).

Common transition types:

  • TRANS_SINE — smooth, natural acceleration (great for UI)
  • TRANS_QUAD — slightly sharper curve (buttons, popups)
  • TRANS_CUBIC — pronounced ease (camera moves, menus)
  • TRANS_BACK — overshoots then settles (bouncy popups)
  • TRANS_BOUNCE — literal bounce effect (damage numbers, pickups)
  • TRANS_ELASTIC — spring-like overshoot (satisfying game juice)

Ease directions control where the curve applies:

  • EASE_IN — starts slow, accelerates
  • EASE_OUT — starts fast, decelerates (most natural for UI)
  • EASE_IN_OUT — slow start and end (smooth camera transitions)
  • EASE_OUT_IN — fast middle, slow edges (less common)
easing_demo.gd
func smooth_popup(panel: Control):
    panel.scale = Vector2.ZERO
    panel.visible = true
    var tween = create_tween()
    tween.set_trans(Tween.TRANS_BACK)
    tween.set_ease(Tween.EASE_OUT)
    tween.tween_property(panel, "scale", Vector2.ONE, 0.35)

TRANS_BACK + EASE_OUT overshoots the target slightly, then settles back. This is the go-to combo for satisfying popup animations. Pair it with a signal bus to trigger popups from anywhere in your game.

Practical UI Animations with Tweens

Tweens are the fastest way to polish your game's UI. Here are three patterns you'll use constantly.

Animated Health Bar

Instead of snapping the health bar to its new value, tween it smoothly. This gives instant visual feedback that something happened:

ui/health_bar.gd
extends ProgressBar

var _tween: Tween

func update_health(new_value: float):
    # Kill previous tween if still running
    if _tween and _tween.is_running():
        _tween.kill()
    _tween = create_tween()
    _tween.set_trans(Tween.TRANS_SINE)
    _tween.set_ease(Tween.EASE_OUT)
    _tween.tween_property(self, "value", new_value, 0.3)

The .kill() pattern is critical. If the player takes rapid damage, you want each new tween to start from wherever the bar currently is — not queue up behind the old one. Always kill active tweens before creating replacements.

Slide-In Menu Panel

A common UI pattern is sliding a panel in from the side when the player opens a menu. Tweens make it trivial:

ui/slide_menu.gd
extends Panel

var _is_open: bool = false

func toggle():
    _is_open = !_is_open
    var target_x = 0.0 if _is_open else -size.x
    var tween = create_tween()
    tween.set_trans(Tween.TRANS_CUBIC)
    tween.set_ease(Tween.EASE_OUT)
    tween.tween_property(self, "position:x", target_x, 0.4)

Connect this to a button press and you have a polished slide-in/out menu in six lines. If you want to learn more about managing UI state transitions cleanly, check out our State Machines in GDScript course.

Ready to level up your GDScript? Grab the free cheat sheet with 20+ copy-paste snippets for tweens, signals, and more.

Get Cheat Sheet →

Gameplay Juice: Tweens for Game Feel

“Juice” is the industry term for those small, satisfying animations that make games feel good. Screen shakes, damage flashes, pickup effects — tweens handle all of it.

Hit Flash Effect

Flash a sprite white when the enemy takes damage, then return to normal. This is one of the most common juice effects in 2D games:

effects/hit_flash.gd
func flash_white(sprite: Sprite2D):
    sprite.modulate = Color.WHITE * 3.0
    var tween = create_tween()
    tween.tween_property(sprite, "modulate", Color.WHITE, 0.15)

By setting the modulate to a super-bright white first, then tweening back to normal, you get a crisp flash. For pixel art games, pair this with a white-override shader for cleaner results.

Camera Shake

A quick camera shake on impact makes hits feel powerful. Use tween_method() to drive a custom shake function:

camera/screen_shake.gd
extends Camera2D

func shake(intensity: float = 10.0, duration: float = 0.3):
    var tween = create_tween()
    tween.set_trans(Tween.TRANS_SINE)
    tween.set_ease(Tween.EASE_OUT)
    tween.tween_method(_apply_shake.bind(intensity), 1.0, 0.0, duration)

func _apply_shake(strength: float, progress: float):
    offset = Vector2(
        randf_range(-strength, strength) * progress,
        randf_range(-strength, strength) * progress
    )

The tween_method() call interpolates a float from 1.0 to 0.0, passing it to _apply_shake() every frame. The shake intensity fades out naturally as the tween progresses. Trigger it from a signal bus event to keep your camera fully decoupled.

Floating Damage Numbers

Spawn a label, tween it upward and fade it out — classic RPG juice:

ui/damage_number.gd
extends Label

func _ready():
    pivot_offset = size / 2.0
    var tween = create_tween()
    tween.set_parallel(true)
    # Float upward
    tween.tween_property(self, "position:y", position.y - 60, 0.8)
    # Fade out
    tween.tween_property(self, "modulate:a", 0.0, 0.8)
    # Pop scale
    tween.tween_property(self, "scale", Vector2(0.5, 0.5), 0.8)
    # Cleanup
    tween.set_parallel(false)
    tween.tween_callback(queue_free)

Using set_parallel(true) makes all three property tweens run at once. Then we flip back to sequential mode for the cleanup callback. The number floats up, fades out, and shrinks simultaneously before removing itself.

Get all our Godot courses in one pack — signals, shaders, state machines, and more. Save 50%+ with the bundle.

Grab the Bundle →

Advanced Tween Patterns

Awaiting Tweens with async/await

Godot 4 tweens emit a finished signal when complete. Combined with GDScript's await keyword, you can write cinematic sequences like synchronous code:

cutscene/intro.gd
func play_intro():
    # Fade in from black
    var t1 = create_tween()
    t1.tween_property($BlackOverlay, "modulate:a", 0.0, 1.5)
    await t1.finished

    # Slide title in
    var t2 = create_tween()
    t2.set_trans(Tween.TRANS_CUBIC)
    t2.set_ease(Tween.EASE_OUT)
    t2.tween_property($Title, "position:y", 300.0, 0.8)
    await t2.finished

    # Continue to gameplay
    start_game()

The await tween.finished pattern is incredibly useful for cutscenes, dialog systems, and any scenario where you need step-by-step animation sequences. It's one of those GDScript tricks that makes Godot's async model feel magical.

Custom Tween Intervals and Delays

Use tween_interval() to insert pauses between steps. This is great for staggered animations:

ui/staggered_list.gd
func reveal_items(items: Array[Control]):
    var tween = create_tween()
    for item in items:
        item.modulate.a = 0.0
        item.position.y += 20.0
        tween.tween_property(item, "modulate:a", 1.0, 0.2)
        tween.parallel().tween_property(item, "position:y", item.position.y - 20.0, 0.2)
        tween.tween_interval(0.05) # Stagger delay

Each item fades in and slides up, with a 50ms stagger between them. This creates a cascading reveal effect that feels polished and intentional — perfect for inventory screens, level-select UIs, or leaderboards.

Tween Best Practices

After building dozens of Godot projects with tweens, here are the patterns that keep your code clean and bug-free:

  • Always .kill() active tweens before creating replacements — prevents overlapping animations
  • Store tween references in class variables when you need to cancel or check status later
  • Use set_trans() + set_ease() on every tween — TRANS_LINEAR is almost never what you want
  • Prefer EASE_OUT for UI animations — things arrive fast and settle smoothly
  • Use TRANS_BACK for playful popups and TRANS_ELASTIC for game juice
  • Keep durations between 0.15s-0.5s for UI — longer feels sluggish, shorter feels invisible
  • Use tween_callback(queue_free) at the end of one-shot effects to prevent memory leaks
  • Await tween.finished to chain complex sequences without callback spaghetti

For projects that need more complex animation state management — like transitioning between idle, walk, and attack animations — tweens pair beautifully with state machines. Each state can own its enter/exit tweens for a clean, modular system.

When to Use Tweens vs. AnimationPlayer

Tweens and AnimationPlayer aren't competitors — they solve different problems:

  • Use Tweens for runtime, code-driven animations — UI transitions, juice effects, dynamic values
  • Use AnimationPlayer for complex, designer-authored sequences — sprite frame animations, cutscenes with multiple tracks
  • Use Tweens when the end value is calculated at runtime (e.g., move to player's current position)
  • Use AnimationPlayer when artists need to scrub through timelines and preview keyframes visually

In practice, most indie games use both. AnimationPlayer handles sprite animations and authored cutscenes, while tweens handle everything runtime — UI polish, gameplay juice, and procedural effects.

Start experimenting with the examples in this tutorial. Even adding a simple TRANS_BACK ease to a popup or a 0.3s health bar tween will make your game feel significantly more polished. Tweens are the quickest path from “functional prototype” to “feels like a real game.”

EOF
Free download
+ weekly tips

Get the Free GDScript Cheat Sheet + Weekly Godot Tips

Join indie devs getting our GDScript Cheat Sheet with 20+ copy-paste snippets for signals, exports, state machines, and more — plus weekly Godot tips and architecture tricks straight to your inbox.

20+ GDScript snippets
Weekly Godot tips
Zero spam, cancel anytime
>
GDSJoin 500+ Godot devs. Unsubscribe in one click.