Metadata-Version: 2.4
Name: ctk-transitions
Version: 1.0.1
Summary: Standalone CustomTkinter playground for animations and easings — pick a curve, watch it run on buttons / cards / text / loaders / popups / toasts, then export self-contained Python code.
Author-email: Lasha Kandelaki <kandelucky.dev@gmail.com>
License: MIT License
        
        Copyright (c) 2026 Lasha Kandelaki
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
        
Project-URL: Homepage, https://github.com/kandelucky/ctk-transitions-code-generator
Project-URL: Repository, https://github.com/kandelucky/ctk-transitions-code-generator
Project-URL: Issues, https://github.com/kandelucky/ctk-transitions-code-generator/issues
Project-URL: CTkMaker (full visual builder), https://github.com/kandelucky/ctk_maker
Project-URL: Buy Me a Coffee, https://buymeacoffee.com/kandelucky_dev
Keywords: customtkinter,tkinter,animation,easing,tween,ui,gui,transitions
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: X11 Applications
Classifier: Environment :: Win32 (MS Windows)
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Software Development :: User Interfaces
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: customtkinter>=5.2.0
Dynamic: license-file

# 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](https://raw.githubusercontent.com/kandelucky/ctk-transitions-code-generator/main/assets/screenshot.png)

## 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:

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

Or run from a clone:

```bash
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](https://raw.githubusercontent.com/kandelucky/ctk-transitions-code-generator/main/assets/buttons.gif)

### Text

![Text animations](https://raw.githubusercontent.com/kandelucky/ctk-transitions-code-generator/main/assets/text.gif)

### Card

![Card animations](https://raw.githubusercontent.com/kandelucky/ctk-transitions-code-generator/main/assets/card.gif)

### Loaders

![Loading indicators](https://raw.githubusercontent.com/kandelucky/ctk-transitions-code-generator/main/assets/loaders.gif)

### Popups

![Popup dialogs](https://raw.githubusercontent.com/kandelucky/ctk-transitions-code-generator/main/assets/popups.gif)

### Toasts

![Toast notifications](https://raw.githubusercontent.com/kandelucky/ctk-transitions-code-generator/main/assets/toasts.gif)

## 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:

<details>
<summary>Click to expand the generated module (annotated)</summary>

```python
"""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()
```

</details>

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](https://github.com/kandelucky/ctk_maker)** — 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.

- [CTkMaker repo](https://github.com/kandelucky/ctk_maker)
- [Component library hub](https://kandelucky.github.io/ctkmaker-hub/library.html)

## Support

If this is useful, you can support the work here:
[☕ Buy me a coffee](https://buymeacoffee.com/kandelucky_dev)

## License

MIT — see [LICENSE](LICENSE).
