Skip to main content

CTk Transitions Demo

Standalone CustomTkinter playground for animations and easings. Pick a curve, watch it run on buttons, cards, text, loaders, popups, and toasts, then click Generate code to export a self-contained Python module you can drop into any project.

Transitions Demo screenshot

Features

  • 6 tabs — Button presses, Text, Card, Loaders, Popups, Toasts
  • 25+ animations across the tabs
  • 9 built-in easings: linear, ease_in, ease_out, ease_in_out, ease_out_quint, back_out, elastic_out, spring, bounce_out
  • Generate code exports imports + easings + Tween engine + helpers + animation function + a runnable __main__ block — paste-anywhere
  • Single file, single dependency: customtkinter

Quick start

Install from PyPI:

pip install ctk-transitions
ctk-transitions          # launches the GUI
# or
python -m ctk_transitions

Or run from a clone:

git clone https://github.com/kandelucky/ctk-transitions-code-generator.git
cd ctk-transitions-code-generator
pip install customtkinter
python -m ctk_transitions

Demo gallery

Button presses

Button presses

Text

Text animations

Card

Card animations

Loaders

Loading indicators

Popups

Popup dialogs

Toasts

Toast notifications

Example generated code

Picking Button → Grow with back_out easing and 0.5s duration and clicking Generate code produces this self-contained module. Drop it next to any project, import attach_press_effect, and wrap a button:

Click to expand the generated module (annotated)
"""Button press effect — generated by Transitions Demo.

Settings:
  Effect:   Grow
  Easing:   back_out
  Duration: 0.5s

Usage:
  attach_press_effect(my_button, base_w=160, base_h=44)
"""
import time

import customtkinter as ctk


# --- easings ---
# Each easing(t) maps t in [0, 1] (linear time) to a curve in [0, ~1].
# Pick the one that matches the feel you want — back_out overshoots
# slightly and then settles, giving a tactile "snap back" finish.

def back_out(t):
    if t >= 1:
        return 1.0
    s = 1.70158
    u = t - 1
    return 1 + (s + 1) * u ** 3 + s * u ** 2


def ease_out(t):  # used for the press-in (smooth deceleration)
    return 1 - (1 - t) ** 3


# --- tween engine ---
# Time-based, ~60 fps via Tk's after(16ms). Re-uses the host widget's
# event loop, so no threads, no extra dependencies.

class Tween:
    FRAME_MS = 16

    def __init__(self, widget, duration, easing, step, on_done=None):
        self.widget = widget
        self.duration = max(duration, 0.001)
        self.easing = easing
        self.step = step          # called every frame with eased t
        self.on_done = on_done    # called once after the final frame
        self._start = None
        self._running = False

    def start(self):
        self._start = time.perf_counter()
        self._running = True
        self._tick()
        return self

    def _tick(self):
        if not self._running:
            return
        # Linear progress 0 → 1, clamped at the end.
        t = min((time.perf_counter() - self._start) / self.duration, 1.0)
        self.step(self.easing(t))   # eased value handed to the step fn
        if t < 1.0:
            self.widget.after(self.FRAME_MS, self._tick)
        else:
            self._running = False
            if self.on_done:
                self.on_done()


# Linear interpolation between two scalars.
def lerp(a, b, t):
    return a + (b - a) * t


# --- attach press effect ---
# Wraps a button so its existing command still fires, but alongside an
# animation that grows it to 108% and snaps back with back_out.

def attach_press_effect(button, base_w=160, base_h=44, duration=0.5):
    """Wrap button command with a "Grow" press animation."""
    original = button.cget('command') or (lambda: None)

    PEAK_W = max(1, int(base_w * 1.08))
    PEAK_H = max(1, int(base_h * 1.08))

    # Phase 1: smooth grow to peak (120 ms).
    def to_peak(t):
        button.configure(
            width=int(lerp(base_w, PEAK_W, t)),
            height=int(lerp(base_h, PEAK_H, t)),
        )

    # Phase 2: settle back to base size with the chosen easing.
    def to_base(t):
        button.configure(
            width=int(lerp(PEAK_W, base_w, t)),
            height=int(lerp(PEAK_H, base_h, t)),
        )

    def on_press():
        # Chain the two tweens — phase 2 starts when phase 1 finishes.
        Tween(
            button, 0.12, ease_out, to_peak,
            on_done=lambda: Tween(
                button, duration, back_out, to_base
            ).start(),
        ).start()
        original()  # still call whatever the button was originally bound to

    button.configure(command=on_press)


# --- runnable demo ---

if __name__ == "__main__":
    ctk.set_appearance_mode("dark")
    app = ctk.CTk()
    app.geometry("400x200")
    btn = ctk.CTkButton(
        app, text="Press me", width=160, height=44,
        command=lambda: print("clicked"),
    )
    btn.place(relx=0.5, rely=0.5, anchor="center")
    attach_press_effect(btn, base_w=160, base_h=44)
    app.mainloop()

Every other animation in the gallery exports the same shape — imports + easings + Tween + helpers + an animation function + a runnable __main__ block — so each output is self-contained and dependency-free beyond customtkinter.

Try it in a real GUI builder

This demo started life as a tool window inside CTkMaker — a drag-and-drop visual designer for CustomTkinter. In CTkMaker you build full applications on a canvas, attach behavior files, manage multi-page projects, and export runnable Python. The same playground ships under Tools → Transitions Demo, so you can audition any of these animations against the real widgets you have already laid out.

Support

If this is useful, you can support the work here: ☕ Buy me a coffee

License

MIT — see LICENSE.

Metadata

Release files for ctk-transitions 1.0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ctk-transitions 1.0.1
File Size Uploaded Provenance
ctk_transitions-1.0.1.tar.gz 28.2 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for ctk-transitions 1.0.1
File Interpreter ABI Platform
ctk_transitions-1.0.1-py3-none-any.whl Python 3 none any Details

Total release size: 54.3 kB

Release files / ctk_transitions-1.0.1.tar.gz

Download URL ctk_transitions-1.0.1.tar.gz
Size 28.2 kB
Tags Source
SHA-256 checksum
How to use checksums
bee2b1cdd3291e7fd7e50cfa27ddd84939c96601011b2fd53bcfa5378209a02c
BLAKE2b-256 checksum
How to use checksums
119472998e49cfba242bfe2ab96d502665e114bba7916c1fce605944a334ce9f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.4

Release files / ctk_transitions-1.0.1-py3-none-any.whl

Download URL ctk_transitions-1.0.1-py3-none-any.whl
Size 26.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1a22d4e99a6e14692a3729c6a2b1cd59be127a51336a2ad8cb825ecc688bbc43
BLAKE2b-256 checksum
How to use checksums
d82830f08438e2b22a03efa1c2f76f27dc96a77de34a03d987b13c09c7f2f502
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.4

Security for ctk-transitions 1.0.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

1.0.1 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page