├── requirements.txt ├── docs ├── assets │ ├── wave.gif │ ├── Scrame.gif │ ├── glitch.gif │ └── typee.gif └── examples.md ├── textfx ├── __init__.py ├── textfx.py ├── untextfx.py └── loading.py ├── tests └── test_textfx.py ├── .github ├── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md └── workflows │ └── python-package.yml ├── LICENSE ├── examples └── example.py └── README.md /requirements.txt: -------------------------------------------------------------------------------- 1 | termcolor>=3.0.0 2 | -------------------------------------------------------------------------------- /docs/assets/wave.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iliakarimi/textfx/HEAD/docs/assets/wave.gif -------------------------------------------------------------------------------- /docs/assets/Scrame.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iliakarimi/textfx/HEAD/docs/assets/Scrame.gif -------------------------------------------------------------------------------- /docs/assets/glitch.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iliakarimi/textfx/HEAD/docs/assets/glitch.gif -------------------------------------------------------------------------------- /docs/assets/typee.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iliakarimi/textfx/HEAD/docs/assets/typee.gif -------------------------------------------------------------------------------- /textfx/__init__.py: -------------------------------------------------------------------------------- 1 | from .textfx import typeeffect, scrameffect, wavetext 2 | from .untextfx import untypeeffect, unscrameffect, unwavetext 3 | from .loading import SpinnerLoading, ProgressBarLoading, GlitchLoading 4 | -------------------------------------------------------------------------------- /tests/test_textfx.py: -------------------------------------------------------------------------------- 1 | import io 2 | import sys 3 | import pytest 4 | from textfx import * 5 | 6 | def capture_output(func, *args, **kwargs): 7 | captured = io.StringIO() 8 | sys.stdout = captured 9 | func(*args, **kwargs) 10 | sys.stdout = sys.__stdout__ 11 | return captured.getvalue() 12 | 13 | def test_basic_effect(): 14 | text = "Hello, TextFX!" 15 | output = capture_output(typeeffect, text) 16 | assert "Hello" in output 17 | 18 | def test_scramble_effect(): 19 | text = "Testing" 20 | output = capture_output(scrameffect, text) 21 | assert len(output.strip()) > 0 22 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. ubuntu] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Additional context** 32 | Add any other context about the problem here. 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Ilia Karimi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.github/workflows/python-package.yml: -------------------------------------------------------------------------------- 1 | name: Python package 2 | 3 | on: 4 | schedule: 5 | - cron: "0 */48 * * *" 6 | push: 7 | branches: [ "main" ] 8 | pull_request: 9 | branches: [ "main" ] 10 | 11 | 12 | jobs: 13 | build: 14 | runs-on: ubuntu-latest 15 | 16 | strategy: 17 | fail-fast: false 18 | matrix: 19 | python-version: ["3.10", "3.11", "3.12", "3.13"] 20 | 21 | steps: 22 | - uses: actions/checkout@v4 23 | 24 | - name: Set up Python ${{ matrix.python-version }} 25 | uses: actions/setup-python@v3 26 | with: 27 | python-version: ${{ matrix.python-version }} 28 | 29 | - name: Install dependencies 30 | run: | 31 | python -m pip install --upgrade pip 32 | python -m pip install flake8 pytest 33 | if [ -f requirements.txt ]; then pip install -r requirements.txt; fi 34 | pip install textfx 35 | 36 | - name: Lint with flake8 37 | run: | 38 | flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics 39 | flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics 40 | 41 | - name: Test with pytest 42 | run: pytest 43 | -------------------------------------------------------------------------------- /textfx/textfx.py: -------------------------------------------------------------------------------- 1 | import string 2 | import random 3 | from time import sleep 4 | from termcolor import colored 5 | 6 | 7 | 8 | 9 | 10 | def typeeffect(text, color=None, delay=0.1): 11 | """"" 12 | This type of effect prints text character by character with a specific delay. 13 | 14 | This effect is commonly used to simulate manual typing. 15 | """"" 16 | for tp in text: 17 | sleep(delay) 18 | print(colored(tp, color), end='', flush=True) 19 | 20 | 21 | def scrameffect(text, color=None, delay=0.1): 22 | 23 | """"" 24 | The characters are first displayed randomly 25 | 26 | (such as irrelevant letters or symbols) and gradually transform into actual text. 27 | """"" 28 | scrambled = list(''.join(random.choices(string.ascii_letters + string.punctuation, k=len(text)))) 29 | for i in range(len(text) + 1): 30 | scrambled[:i] = text[:i] 31 | print("\r" + colored(''.join(scrambled), color), end='', flush=True) 32 | sleep(delay) 33 | 34 | 35 | def wavetext(text, color=None, delay=0.1): 36 | 37 | """"" 38 | The text moves in a wave-like manner, as if the characters are jumping up and down. 39 | """"" 40 | for i in range(len(text)): 41 | wave = ''.join([char.upper() if idx == i else char.lower() for idx, char in enumerate(text)]) 42 | print("\r" + colored(wave, color), end='', flush=True) 43 | sleep(delay) 44 | -------------------------------------------------------------------------------- /examples/example.py: -------------------------------------------------------------------------------- 1 | from textfx import typeeffect, scrameffect, wavetext, untypeeffect, unscrameffect, unwavetext, SpinnerLoading, GlitchLoading, ProgressBarLoading 2 | from time import sleep 3 | import time 4 | 5 | 6 | 7 | def run_examples(): 8 | print("Typing Effect:") 9 | typeeffect("Hello, world!", color="cyan", delay=0.1) 10 | time.sleep(1) 11 | 12 | print("\nScramble Effect:") 13 | scrameffect("Scrambled Text", delay=0.1) 14 | time.sleep(1) 15 | 16 | print("\nWave Text:") 17 | wavetext("Wave Text", delay=0.1) 18 | time.sleep(1) 19 | 20 | print("\nUntyping Effect:") 21 | untypeeffect("Erasing Text", delay=0.1) 22 | time.sleep(1) 23 | 24 | print("\nUnscramble Effect:") 25 | unscrameffect("Glitching Away", delay=0.1) 26 | time.sleep(1) 27 | 28 | print("\nUnwave Text:") 29 | unwavetext("Steadying Waves", delay=0.1) 30 | time.sleep(1) 31 | 32 | if __name__ == "__main__": 33 | run_examples() 34 | 35 | 36 | with SpinnerLoading(message="Loading ", animation="⠋⠙⠸⠴⠦⠇", message_color="red", animation_color="blue", delay=0.1): 37 | sleep(5) 38 | 39 | with ProgressBarLoading(message="Loading", barline='-', animation='#', length=20, message_color="yellow", animation_color=None, barline_color="green", delay=0.1): 40 | sleep(4) 41 | 42 | with GlitchLoading(message="Loading...", delay=0.1, charset="#$%&*@!?", color="blue"): 43 | sleep(3) -------------------------------------------------------------------------------- /textfx/untextfx.py: -------------------------------------------------------------------------------- 1 | import string 2 | import random 3 | from time import sleep 4 | from termcolor import colored 5 | 6 | 7 | 8 | 9 | 10 | def untypeeffect(text, color=None, delay=0.1): 11 | """ 12 | This effect gradually erases text character by character with a specific delay. 13 | 14 | It simulates the process of manual text deletion, making it useful for interactive 15 | terminal applications, chatbots, or animations. 16 | """ 17 | print(colored(text , color), end='', flush=True) 18 | sleep(1) 19 | for _ in text: 20 | print("\b \b", end='', flush=True) # Removes characters one by one 21 | sleep(delay) 22 | 23 | 24 | def unscrameffect(text, color=None, delay=0.1): 25 | """ 26 | The actual text gradually scrambles into random characters until it disappears. 27 | 28 | This effect creates a glitch-like transition where letters are replaced with 29 | random symbols before vanishing completely. 30 | """ 31 | scrambled = list(text) 32 | for i in range(len(text) + 1): 33 | if i < len(text): 34 | scrambled[i:] = random.choices(string.ascii_letters + string.punctuation + ' ', k=len(text) - i) 35 | print("\r" +colored(''.join(scrambled), color), end='', flush=True) 36 | sleep(delay) 37 | 38 | print("\r" + " " * len(text), end='', flush=True) 39 | 40 | 41 | def unwavetext(text, color=None, delay=0.1): 42 | """ 43 | The text starts in a wave-like pattern and gradually stabilizes into normal text. 44 | 45 | This effect gives the illusion of motion calming down over time. 46 | """ 47 | for i in range(len(text), -1, -1): 48 | wave = ''.join([char.upper() if idx == i else char.lower() for idx, char in enumerate(text)]) 49 | print("\r" + colored(wave, color), end='', flush=True) 50 | sleep(delay) 51 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Textfx 2 | 3 | [![PyPI Downloads](https://static.pepy.tech/personalized-badge/textfx?period=monthly&units=INTERNATIONAL_SYSTEM&left_color=BLACK&right_color=GREEN&left_text=Monthly+downloads)](https://pepy.tech/projects/textfx) 4 | [![PyPI Downloads](https://static.pepy.tech/personalized-badge/textfx?period=total&units=INTERNATIONAL_SYSTEM&left_color=BLACK&right_color=BLUE&left_text=Total+downloads)](https://pepy.tech/projects/textfx) 5 | ![Python](https://img.shields.io/badge/python-3.9%2B-blue) 6 | [![License](https://img.shields.io/github/license/iliakarimi/textfx)](https://github.com/iliakarimi/textfx/blob/main/LICENSE) 7 | [![Repo Size](https://img.shields.io/github/repo-size/iliakarimi/textfx)](https://github.com/iliakarimi/textfx) 8 | 9 | Textfx is a lightweight Python library for creating dynamic, visually engaging console text effects and Loading Animation. 10 | 11 | ## 📦 Installation 12 | 13 | ```bash 14 | pip install textfx 15 | ``` 16 | 17 | Or clone & install dependencies: 18 | 19 | ```bash 20 | git clone https://github.com/iliakarimi/textfx.git 21 | cd textfx 22 | pip install -r requirements.txt 23 | ``` 24 | 25 | ## 🎨 Features 26 | 27 | 1. **Typing Effect** 28 | 2. **Scramble Effect** 29 | 3. **Wave Text** 30 | 4. **Untyping Effect** 31 | 5. **Unscramble Effect** 32 | 6. **Unwave Text** 33 | 7. **Loading Animations** 34 | 8. **Color Support** via `termcolor` 35 | 36 | ## 🚀 Usage 37 | 38 | Import the desired effects and loaders: 39 | 40 | ```python 41 | from textfx import ( 42 | typeeffect, scrameffect, wavetext, 43 | untypeeffect, unscrameffect, unwavetext, 44 | SpinnerLoading, ProgressBarLoading, GlitchLoading 45 | ) 46 | ``` 47 | 48 | 49 | ### Loading Animations 50 | 51 | All loader classes share these parameters: 52 | 53 | * `message` (str): Prefix text displayed before the animation. 54 | * `end_message` (str): Text displayed after the loader stops. 55 | * `delay` (float): Seconds between animation frames. 56 | 57 | #### 1. SpinnerLoading 58 | 59 | Classic spinner cursor: 60 | 61 | ```python 62 | with SpinnerLoading( 63 | message="Processing...", 64 | animation="⠋⠙⠸⠴⠦⠇", 65 | delay=0.1 66 | ): 67 | do_work() 68 | ``` 69 | 70 | #### 2. ProgressBarLoading 71 | 72 | Animated bar moving back and forth: 73 | 74 | ```python 75 | with ProgressBarLoading( 76 | barline='-', animation='█', length=30, 77 | message="Loading", delay=0.05 78 | ): 79 | do_work() 80 | ``` 81 | 82 | #### 3. GlitchLoading 83 | 84 | Random-character glitch effect: 85 | 86 | ```python 87 | with ProgressBarLoading(message="Compiling Code", barline=".", animation="⚙", length=40, message_color="cyan", animation_color="yellow", barline_color="white", delay=0.07): 88 | time.sleep(5) 89 | ``` 90 | 91 | For detailed examples, see [`Documention`](docs/examples.md). 92 | 93 | 94 | ## 🎨 Color Options 95 | 96 | All effects support an optional `color` parameter (via `termcolor`): 97 | 98 | 99 | `black` 100 | `red` 101 | `green` 102 | `yellow` 103 | `blue` 104 | `magenta` 105 | `cyan` 106 | `white` 107 | 108 | `light_grey` 109 | `dark_grey` 110 | `light_red` 111 | `light_green` 112 | `light_yellow` 113 | `light_blue` 114 | `light_magenta` 115 | `light_cyan` 116 | 117 | 118 | > *Ensure your terminal supports ANSI colors for `termcolor` outputs.* 119 | 120 | ## 📋 Dependencies 121 | 122 | * Python **3.9+** 123 | * [`termcolor`](https://pypi.org/project/termcolor/) 124 | 125 | Install dependencies: 126 | 127 | ```bash 128 | pip install -r requirements.txt 129 | ``` 130 | 131 | ## 🏗️ Contributing 132 | 133 | Pull requests are welcome! For more examples and details, refer to `docs/examples.md`. 134 | 135 | ## 📄 License 136 | 137 | MIT License — see [LICENSE](LICENSE). 138 | 139 | --- 140 | 141 | Enjoy using Textfx! 142 | -------------------------------------------------------------------------------- /docs/examples.md: -------------------------------------------------------------------------------- 1 | # Textfx Examples 2 | 3 | This file contains detailed usage examples for all available Textfx effects and loader classes. 4 | 5 | --- 6 | 7 | ## 1. Typing Effect (`typeeffect`) 8 | 9 | ```python 10 | from textfx import typeeffect 11 | 12 | # Basic typing 13 | typeeffect("Hello, world!", delay=0.1) 14 | 15 | # With color 16 | typeeffect("Colored typing...", color="cyan", delay=0.05) 17 | ``` 18 | ![Alt text](assets/typee.gif) 19 | --- 20 | 21 | ## 2. Scramble Effect (`scrameffect`) 22 | 23 | ```python 24 | from textfx import scrameffect 25 | 26 | # Scramble to real text 27 | scrameffect("Scrambled Text", delay=0.1) 28 | 29 | # With color and faster speed 30 | scrameffect("Fast & Green", color="green", delay=0.03) 31 | ``` 32 | ![Alt text](assets/Scrame.gif) 33 | --- 34 | 35 | ## 3. Wave Text (`wavetext`) 36 | 37 | ```python 38 | from textfx import wavetext 39 | 40 | # Basic wave pattern 41 | wavetext("Wave Text Demo", delay=0.1) 42 | 43 | # Colored wave 44 | wavetext("Rainbow Waves", color="magenta", delay=0.08) 45 | ``` 46 | ![Alt text](assets/wave.gif) 47 | --- 48 | 49 | ## 4. Untyping Effect (`untypeeffect`) 50 | 51 | ```python 52 | from textfx import untypeeffect 53 | 54 | # Erase character by character 55 | untypeeffect("Erasing this line...", delay=0.1) 56 | ``` 57 | 58 | --- 59 | 60 | ## 5. Unscramble Effect (`unscrameffect`) 61 | 62 | ```python 63 | from textfx import unscrameffect 64 | 65 | # Glitch into nothing 66 | unscrameffect("Glitching Away", delay=0.1) 67 | ``` 68 | 69 | --- 70 | 71 | ## 6. Unwave Text (`unwavetext`) 72 | 73 | ```python 74 | from textfx import unwavetext 75 | 76 | # Start wavy then settle 77 | unwavetext("Settling Waves", delay=0.1) 78 | ``` 79 | 80 | --- 81 | 82 | ## 7. Loading Animations 83 | 84 | All loader classes use `with` context manager. 85 | 86 | ### 7.1 SpinnerLoading 87 | 88 | ```python 89 | import time 90 | from textfx import SpinnerLoading 91 | 92 | with SpinnerLoading( 93 | message="Processing...", 94 | animation="⠋⠙⠸⠴⠦⠇", 95 | delay=0.1 96 | ): 97 | time.sleep(3) 98 | ``` 99 | 100 | ### 7.2 ProgressBarLoading 101 | 102 | ```python 103 | import time 104 | from textfx import ProgressBarLoading 105 | 106 | with ProgressBarLoading( 107 | barline="-", animation="█", length=30, 108 | message="Loading", delay=0.05 109 | ): 110 | time.sleep(4) 111 | ``` 112 | 113 | ### 7.3 GlitchLoading 114 | 115 | ```python 116 | import time 117 | from textfx import GlitchLoading 118 | 119 | with GlitchLoading( 120 | text="Decrypting...", 121 | delay=0.1 122 | ): 123 | time.sleep(5) 124 | ``` 125 | ![Alt text](assets/glitch.gif) 126 | --- 127 | 128 | ## 8. Color Examples 129 | 130 | 131 | ```python 132 | from textfx import typeeffect, scrameffect 133 | 134 | typeeffect("This is red text!", color="red", delay=0.1) 135 | scrameffect("Yellow scramble", color="yellow", delay=0.1) 136 | ``` 137 | --- 138 | 139 | 140 | ## 9. Loading Examples with Loading Animation 141 | 142 | 143 | 144 | ```python 145 | from textfx import SpinnerLoading, ProgressBarLoading, GlitchLoading 146 | from time import sleep 147 | 148 | with SpinnerLoading(message="Loading ", animation="⠋⠙⠸⠴⠦⠇", message_color="red", animation_color="blue", delay=0.1): 149 | sleep(5) 150 | 151 | with ProgressBarLoading(message="Loading", barline='-', animation='#', length=20, message_color="yellow", animation_color=None, barline_color="green", delay=0.1): 152 | sleep(4) 153 | 154 | with GlitchLoading(message="Loading...", delay=0.1, charset="#$%&*@!?", color="blue"): 155 | sleep(3) 156 | 157 | with ProgressBarLoading(message="Compiling Code", barline=".", animation="⚙", length=40, message_color="cyan", animation_color="yellow", barline_color="white", delay=0.07): 158 | time.sleep(5) 159 | 160 | 161 | ``` 162 | --- 163 | 164 | Enjoy experimenting with Textfx! 165 | -------------------------------------------------------------------------------- /textfx/loading.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import random 3 | import itertools 4 | import threading 5 | from time import sleep 6 | from termcolor import colored 7 | 8 | 9 | 10 | 11 | 12 | class SpinnerLoading(): 13 | """ 14 | A simple and lightweight spinner loading class that uses text animations to display the waiting state. 15 | 16 | This loading runs in a separate Thread and can be easily used using the context manager (`with`). 17 | 18 | Features: 19 | - Display a message with the spinner animation 20 | - Ability to customize the animation characters (with any string of characters) 21 | - Auto-end and display the final message after the `with` block is finished 22 | - Suitable for CLI tasks and applications that need live feedback while waiting 23 | 24 | Parameters: 25 | - message (str): Message to display at the beginning of the loading (before the spinner) 26 | - animation (str): String of characters to create the spinning effect (displayed in a loop) 27 | - delay (float): Delay time between displaying each frame of the animation 28 | """ 29 | def __init__(self, message="Loading ", animation="⠋⠙⠸⠴⠦⠇", message_color=None, animation_color=None, delay=0.1): 30 | self.message = message 31 | self.animation = animation 32 | self.message_color = message_color 33 | self.animation_color = animation_color 34 | self.delay = delay 35 | self._done = False 36 | self._thread = None 37 | 38 | def _animate(self): 39 | for frame in itertools.cycle(self.animation): 40 | if self._done: 41 | break 42 | sys.stdout.write(f"\r{colored(self.message, self.message_color)}{colored(frame, self.animation_color)}") 43 | sys.stdout.flush() 44 | sleep(self.delay) 45 | 46 | 47 | def __enter__(self): 48 | self._done = False 49 | self._thread = threading.Thread(target=self._animate, daemon=True) 50 | self._thread.start() 51 | return self 52 | 53 | def __exit__(self, exc_type, exc_val, exc_tb): 54 | self._done = True 55 | self._thread.join() 56 | 57 | 58 | class ProgressBarLoading(): 59 | """ 60 | A class for a reciprocating bar loading where a symbol (like # or ░) moves back and forth within the bar 61 | and creates a sense of dynamism and active loading. 62 | 63 | This loading can be used with the `with` statement and runs live in a separate Thread 64 | during the execution of the block. 65 | 66 | Features: 67 | - An animated bar where the animated character moves back and forth between the lines of the bar. 68 | - Fully customizable: animation type, bar background character, start and end message. 69 | - Non-blocking execution with Thread. 70 | - Suitable for CLI and text applications. 71 | 72 | Parameters: 73 | - barline (str): fixed bar character (default: '-') 74 | - animation (str): animated symbol (default: '#') 75 | - length (int): bar length (number of characters) 76 | - message (str): message when loading starts 77 | - delay (float): Delay time between animation frames (seconds) 78 | """ 79 | def __init__(self, message="Loading", barline='-', animation='#', length=20, message_color=None, animation_color=None, barline_color=None, delay=0.1): 80 | self.length = length 81 | self.message = message 82 | self.animation = animation 83 | self.message_color = message_color 84 | self.animation_color = animation_color 85 | self.barline_color = barline_color 86 | self.barline = barline 87 | self.delay = delay 88 | self._done = False 89 | self._thread = None 90 | self._pos = 0 91 | self._dir = 1 92 | 93 | def _animate(self): 94 | while not self._done: 95 | bar = [colored(self.barline, self.barline_color)] * self.length 96 | bar[self._pos] = colored(self.animation, self.animation_color) 97 | sys.stdout.write(f"\r{colored(self.message, self.message_color)}: [{''.join(bar)}]") 98 | sys.stdout.flush() 99 | sleep(self.delay) 100 | 101 | if self._pos == self.length - 1: 102 | self._dir = -1 103 | elif self._pos == 0: 104 | self._dir = 1 105 | self._pos += self._dir 106 | 107 | 108 | def __enter__(self): 109 | self._done = False 110 | self._pos = 0 111 | self._dir = 1 112 | self._thread = threading.Thread(target=self._animate, daemon=True) 113 | self._thread.start() 114 | return self 115 | 116 | def __exit__(self, exc_type, exc_val, exc_tb): 117 | self._done = True 118 | self._thread.join() 119 | 120 | 121 | class GlitchLoading(): 122 | """ 123 | A typographic loading with a 'glitch' effect that creates a sense of encryption or hacking by randomly replacing some letters 124 | in the displayed text. 125 | 126 | This class also supports context manager and is very suitable for loading in a fantasy or artistic style. 127 | 128 | Features: 129 | - Dynamic and random change of part of the characters of the main text 130 | - A sense of encryption, hacking, or mysterious loading 131 | - Completely non-blocking (in a separate thread) 132 | - Ability to customize charset, speed, and end message 133 | 134 | Parameters: 135 | - text (str): The text to which the glitch effect will be applied 136 | - delay (float): The delay between frames (lower value = faster effect) 137 | - charset (str): The characters used for the glitch effect 138 | """ 139 | def __init__(self, message="Loading...", delay=0.1, charset="#$%&*@!?", color=None): 140 | self.message = message 141 | self.delay = delay 142 | self.charset = charset 143 | self.color = color 144 | self._done = False 145 | self._thread = None 146 | 147 | def _animate(self): 148 | while not self._done: 149 | glitched = ''.join( 150 | char if random.random() > 0.2 else random.choice(self.charset) 151 | for char in self.message 152 | ) 153 | sys.stdout.write(f"\r{colored(glitched, self.color)}") 154 | sys.stdout.flush() 155 | sleep(self.delay) 156 | 157 | 158 | def __enter__(self): 159 | self._done = False 160 | self._thread = threading.Thread(target=self._animate, daemon=True) 161 | self._thread.start() 162 | return self 163 | 164 | def __exit__(self, exc_type, exc_val, exc_tb): 165 | self._done = True 166 | self._thread.join() 167 | --------------------------------------------------------------------------------