From 936368fb2f834dac7e55ba7d7f1b6f63d04c86aa Mon Sep 17 00:00:00 2001 From: ethanlchristensen Date: Sat, 2 Nov 2024 02:13:07 -0500 Subject: [PATCH] version bump --- bruhanimate/__init__.py | 12 +- bruhanimate/bruheffect/__init__.py | 4 + bruhanimate/bruheffect/firework_effect.py | 450 +++++++++++++++++++++ bruhanimate/bruhrenderer/base_renderer.py | 2 + bruhanimate/bruhrenderer/focus_renderer.py | 21 +- bruhanimate/bruhutil/bruhtypes.py | 9 +- bruhanimate/demos/firework_demo.py | 39 ++ setup.py | 2 +- 8 files changed, 524 insertions(+), 15 deletions(-) create mode 100644 bruhanimate/bruheffect/firework_effect.py create mode 100644 bruhanimate/demos/firework_demo.py diff --git a/bruhanimate/__init__.py b/bruhanimate/__init__.py index 72db465..045107b 100644 --- a/bruhanimate/__init__.py +++ b/bruhanimate/__init__.py @@ -75,22 +75,26 @@ offset_demo, static_demo, chatbot_demo, + firework_demo, ) -__version__ = "0.2.72" +__version__ = "0.2.73" __valid_demos__ = [ "static_demo", "offset_demo", "matrix_demo", "gol_demo", "rain_demo", - "chatbot_demo" "line_demo", + "chatbot_demo", + "line_demo", "plasma_demo", "snow_demo", "stars_demo", "twinkle_demo", - "noise_demo" "holiday", + "noise_demo", + "holiday", + "firework_demo" ] if sys.platform == "win32": @@ -162,6 +166,7 @@ "text_to_image", "TwinkleEffect", "TWINKLE_SPEC", + "firework_demo", ] else: __all__ = [ @@ -229,5 +234,6 @@ "text_to_image", "TwinkleEffect", "TWINKLE_SPEC", + "firework_demo", ] diff --git a/bruhanimate/bruheffect/__init__.py b/bruhanimate/bruheffect/__init__.py index 8a6876a..a92cbb6 100644 --- a/bruhanimate/bruheffect/__init__.py +++ b/bruhanimate/bruheffect/__init__.py @@ -12,6 +12,7 @@ from .offset_effect import OffsetEffect from .rain_effect import RainEffect from .noise_effect import NoiseEffect +from .firework_effect import FireworkEffect, Firework, Particle if sys.platform == "win32": @@ -37,6 +38,9 @@ "Key", "Line", "TWINKLE_SPEC", + "FireworkEffect", + "Firework", + "Particle" ] else: __all__ = [ diff --git a/bruhanimate/bruheffect/firework_effect.py b/bruhanimate/bruheffect/firework_effect.py new file mode 100644 index 0000000..6c71e82 --- /dev/null +++ b/bruhanimate/bruheffect/firework_effect.py @@ -0,0 +1,450 @@ +""" +Copyright 2023 Ethan Christensen + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +import math +import random +from bruhcolor import bruhcolored as bc +from .base_effect import BaseEffect +from ..bruhutil.bruhffer import Buffer +from ..bruhutil.bruhtypes import ( + FireworkType, + valid_firework_types, + FireworkColorType, + valid_firework_color_types, + two_tone_colors, +) + + +class Particle: + def __init__(self, x, y, dx, dy, width, height, symbol="*", life: int = None): + self.x = x + self.y = y + self.previous_x = x + self.previous_y = y + self.dx = dx + self.dy = dy + self.width = width + self.height = height + self.life = life if life else random.randint(8, 15) # Random lifespan for particle + self.symbol = symbol + + def update(self): + # Update position + self.previous_x = self.x + self.previous_y = self.y + self.x += self.dx + self.y += self.dy + # Apply gravity to simulate a slight downward motion + self.dy += 0.05 + # Decrease life + self.life -= 1 + # Flicker effect + if random.random() > 0.5: + self.symbol = "*" if self.symbol == "." else "." + + def is_alive(self): + # Particle is alive if it has life left and is within bounds + return ( + self.life > 0 + and 0 <= int(self.x) < self.width + and 0 <= int(self.y) < self.height + ) + + +class Firework: + def __init__(self, firework_type: FireworkType, height, width, firework_color_type: str = None, color_enabled: bool = False): + self.width = width + self.height = height + self.x = random.randint(0, self.width - 1) + self.y = height - 1 + self.previous_x = self.x + self.previous_y = self.y + self.peak = random.randint(5, self.height // 2) + self.exploded = False + self.particles = [] + self.explosion_type = ( + firework_type + if (firework_type != "random" and firework_type in valid_firework_types) + else random.choice(valid_firework_types) + ) + self.clear_particles = [] + self.caught_last_trail = False + self.speed = random.randint(1, 3) + self.firework_color_type = firework_color_type + self.colors = self.get_colors() + self.color_enabled = color_enabled + + def update(self): + if not self.exploded: + # Move firework up + self.previous_y = self.y + self.y -= self.speed + if self.y <= self.peak: + # Explode when it reaches the peak + self.exploded = True + self.create_particles() + else: + # Update particles + for particle in self.particles: + particle.update() + # Remove dead particles + for p in self.particles: + if not p.is_alive(): + self.clear_particles.append(p) + + self.particles = [p for p in self.particles if p.is_alive()] + + def create_particles(self): + if self.explosion_type == 'circular': + self.circular_explosion() + elif self.explosion_type == 'ring': + self.ring_explosion() + elif self.explosion_type == 'starburst': + self.starburst_explosion() + elif self.explosion_type == 'cone': + self.cone_explosion() + elif self.explosion_type == 'spiral': + self.spiral_explosion() + elif self.explosion_type == 'wave': + self.wave_explosion() + elif self.explosion_type == 'burst': + self.burst_explosion() + elif self.explosion_type == 'cross': + self.cross_explosion() + elif self.explosion_type == "flower": + self.flower_explosion() + elif self.explosion_type == "doublering": + self.double_ring_explosion() + elif self.explosion_type == "heart": + self.heart_explosion() + elif self.explosion_type == "star": + self.star_explosion() + elif self.explosion_type == "fireball": + self.fireball_explosion() + elif self.explosion_type == "diamond": + self.diamond_explosion() + elif self.explosion_type == "shockwave": + self.burst_with_shockwave_explosion() + elif self.explosion_type == "snowflake": + self.snowflake_explosion() + elif self.explosion_type == "cluster": + self.cluster_explosion() + elif self.explosion_type == "comet": + self.comet_tail_explosion() + + def circular_explosion(self): + for _ in range(30): + angle = random.uniform(0, 2 * math.pi) + speed = random.uniform(0.5, 1.5) + dx = math.cos(angle) * speed + dy = math.sin(angle) * speed + self.particles.append(Particle(self.x, self.y, dx, dy, self.width, self.height)) + + def ring_explosion(self): + for angle in range(0, 360, 12): # Ring pattern with evenly spaced particles + rad = math.radians(angle) + dx = math.cos(rad) + dy = math.sin(rad) + self.particles.append(Particle(self.x, self.y, dx, dy, self.width, self.height)) + + def starburst_explosion(self): + for angle in range( + 0, 360, 45 + ): # Starburst with particles in specific directions + rad = math.radians(angle) + speed = random.uniform(1, 1.5) + dx = math.cos(rad) * speed + dy = math.sin(rad) * speed + self.particles.append(Particle(self.x, self.y, dx, dy, self.width, self.height)) + + def cone_explosion(self): + for _ in range(20): + angle = random.uniform( + -math.pi / 6, math.pi / 6 + ) # Narrow range for cone shape + speed = random.uniform(0.5, 1.5) + dx = math.cos(angle) * speed + dy = -abs(math.sin(angle) * speed) # Force particles upward + self.particles.append(Particle(self.x, self.y, dx, dy, self.width, self.height)) + + def spiral_explosion(self): + for i in range(20): + angle = i * 0.3 # Gradually increasing angle for spiral effect + speed = 0.1 * i # Particles spread out as the spiral grows + dx = math.cos(angle) * speed + dy = math.sin(angle) * speed + self.particles.append(Particle(self.x, self.y, dx, dy, self.width, self.height)) + + def wave_explosion(self): + for i in range(30): + angle = i * 0.2 # Slightly increase angle for wave effect + speed = random.uniform(0.5, 1.0) + dx = math.cos(angle) * speed + dy = math.sin(angle) * speed * 0.5 # Particles move slower upward + self.particles.append(Particle(self.x, self.y, dx, dy, self.width, self.height)) + + def burst_explosion(self): + for _ in range(20): + angle = random.uniform(0, 2 * math.pi) # Random angles for burst + speed = random.uniform(0.5, 1.5) + dx = math.cos(angle) * speed + dy = math.sin(angle) * speed + self.particles.append(Particle(self.x, self.y, dx, dy, self.width, self.height)) + # Particles gradually fall downward after a burst + for particle in self.particles: + particle.dy += 0.5 # Increase downward velocity + + def cross_explosion(self): + for angle in [0, 90, 180, 270]: # Particles in cross directions + rad = math.radians(angle) + speed = random.uniform(0.5, 1.5) + dx = math.cos(rad) * speed + dy = math.sin(rad) * speed + self.particles.append(Particle(self.x, self.y, dx, dy, self.width, self.height)) + + def flower_explosion(self): + for angle in range(0, 360, 30): + rad = math.radians(angle) + speed = random.uniform(0.5, 1.0) + dx = math.cos(rad) * speed + dy = math.sin(rad) * speed + self.particles.append(Particle(self.x, self.y, dx, dy, self.width, self.height)) + # Add smaller "petal" particles around each main particle + for petal_angle in [-0.1, 0.1]: + dx_petal = math.cos(rad + petal_angle) * (speed * 0.7) + dy_petal = math.sin(rad + petal_angle) * (speed * 0.7) + self.particles.append(Particle(self.x, self.y, dx_petal, dy_petal, self.width, self.height)) + + def double_ring_explosion(self): + for radius_multiplier in [0.8, 1.2]: # Two rings at slightly different radii + for angle in range(0, 360, 15): + rad = math.radians(angle) + speed = 1.0 * radius_multiplier + dx = math.cos(rad) * speed + dy = math.sin(rad) * speed + self.particles.append(Particle(self.x, self.y, dx, dy, self.width, self.height)) + + def heart_explosion(self): + for t in range(0, 360, 10): # Parametric heart shape + rad = math.radians(t) + dx = 16 * math.sin(rad) ** 3 * 0.1 + dy = -(13 * math.cos(rad) - 5 * math.cos(2 * rad) - 2 * math.cos(3 * rad) - math.cos(4 * rad)) * 0.05 + self.particles.append(Particle(self.x, self.y, dx, dy, self.width, self.height)) + + def star_explosion(self): + for i in range(5): # 5-point star + angle = i * 2 * math.pi / 5 + dx = math.cos(angle) * 1.5 + dy = math.sin(angle) * 1.5 + self.particles.append(Particle(self.x, self.y, dx, dy, self.width, self.height)) + # Add particles in opposite direction for a sharper effect + self.particles.append(Particle(self.x, self.y, -dx, -dy, self.width, self.height)) + + def fireball_explosion(self): + for _ in range(50): # Dense number of particles + angle = random.uniform(0, 2 * math.pi) + speed = random.uniform(0.2, 1.5) + dx = math.cos(angle) * speed + dy = math.sin(angle) * speed + self.particles.append(Particle(self.x, self.y, dx, dy, self.width, self.height)) + + def diamond_explosion(self): + for angle in [45, 135, 225, 315]: # Four main directions for diamond points + rad = math.radians(angle) + dx = math.cos(rad) * 1.5 + dy = math.sin(rad) * 1.5 + self.particles.append(Particle(self.x, self.y, dx, dy, self.width, self.height)) + # Add smaller particles near each main point for a thicker diamond shape + for offset in [-0.1, 0.1]: + dx_offset = math.cos(rad + offset) * 1.2 + dy_offset = math.sin(rad + offset) * 1.2 + self.particles.append(Particle(self.x, self.y, dx_offset, dy_offset, self.width, self.height)) + + def burst_with_shockwave_explosion(self): + # Main burst particles + for angle in range(0, 360, 20): + rad = math.radians(angle) + speed = random.uniform(0.8, 1.2) + dx = math.cos(rad) * speed + dy = math.sin(rad) * speed + self.particles.append(Particle(self.x, self.y, dx, dy, self.width, self.height)) + + # Shockwave particles in a ring around the burst + for angle in range(0, 360, 5): + rad = math.radians(angle) + dx = math.cos(rad) * 1.5 + dy = math.sin(rad) * 1.5 + self.particles.append(Particle(self.x, self.y, dx * 0.5, dy * 0.5, self.width, self.height, life=5)) # Short lifespan for shockwave + + def snowflake_explosion(self): + for angle in range(0, 360, 60): # Six main directions + rad = math.radians(angle) + speed = random.uniform(0.8, 1.0) + dx = math.cos(rad) * speed + dy = math.sin(rad) * speed + self.particles.append(Particle(self.x, self.y, dx, dy, self.width, self.height)) + + # Small branches off each main point for the snowflake effect + for branch_angle in [-15, 15]: # Offset angles for branches + rad_branch = rad + math.radians(branch_angle) + dx_branch = math.cos(rad_branch) * (speed * 0.6) + dy_branch = math.sin(rad_branch) * (speed * 0.6) + self.particles.append(Particle(self.x, self.y, dx_branch, dy_branch, self.width, self.height)) + + def cluster_explosion(self): + for angle in range(0, 360, 30): + rad = math.radians(angle) + speed = 1.2 + dx = math.cos(rad) * speed + dy = math.sin(rad) * speed + main_particle = Particle(self.x, self.y, dx, dy, self.width, self.height) + self.particles.append(main_particle) + + # Surround each main particle with smaller "cluster" particles + for _ in range(6): + offset_dx = dx + random.uniform(-0.2, 0.2) + offset_dy = dy + random.uniform(-0.2, 0.2) + self.particles.append(Particle(self.x + offset_dx, self.y + offset_dy, offset_dx * 0.5, offset_dy * 0.5, self.width, self.height)) + + def comet_tail_explosion(self): + # Main comet direction + comet_angle = random.choice([45, 135, 225, 315]) # Random diagonal angle for comet + rad = math.radians(comet_angle) + speed = 1.5 + main_dx = math.cos(rad) * speed + main_dy = math.sin(rad) * speed + + for i in range(8): # Comet particles along the main direction + trail_dx = main_dx * (1 - i * 0.1) + trail_dy = main_dy * (1 - i * 0.1) + self.particles.append(Particle(self.x, self.y, trail_dx, trail_dy, self.width, self.height)) + + # Small trailing particles + for i in range(1, 5): + trail_dx = main_dx * 0.3 + trail_dy = main_dy * 0.3 + self.particles.append(Particle(self.x - trail_dx * i, self.y - trail_dy * i, trail_dx * 0.5, trail_dy * 0.5, self.width, self.height)) + + def is_active(self): + # Firework is active if it has not exploded or if particles are still alive + return not self.exploded or len(self.particles) > 0 + + def get_colors(self): + if self.firework_color_type == "solid": + return [random.randint(0, 255)] + elif self.firework_color_type == "twotone": + return random.choice(two_tone_colors) + elif self.firework_color_type == "random": + return [ + random.randint(0, 255), + random.randint(0, 255), + random.randint(0, 255), + random.randint(0, 255), + random.randint(0, 255), + random.randint(0, 255), + ] + elif self.firework_color_type == "rainbow": + return [ + 196, 208, 190, 46, 27, 92 + ] + + def render(self, buffer: Buffer): + # Draw firework trail or particles in the buffer + if not self.exploded: + if 0 <= self.x < self.width and 0 <= self.y < self.height: + buffer.put_char(int(self.x), int(self.y), val="|") + buffer.put_char(int(self.previous_x), int(self.previous_y), val=" ") + else: + if not self.caught_last_trail: + self.caught_last_trail = True + buffer.put_char(int(self.previous_x), int(self.previous_y), val=" ") + + for particle in self.particles: + px, py = int(particle.x), int(particle.y) + if 0 <= px < self.width and 0 <= py < self.height: + if self.color_enabled: + color = random.choice(self.colors) + buffer.put_char(px, py, val=bc(particle.symbol, color=color).colored) + else: + buffer.put_char(px, py, val=particle.symbol) + buffer.put_char(int(particle.previous_x), int(particle.previous_y), val=" ") + for particle in self.clear_particles: + buffer.put_char(int(particle.previous_x), int(particle.previous_y), val=" ") + + +class FireworkEffect(BaseEffect): + """ + Class for generating fireworks + """ + + def __init__(self, buffer: Buffer, background: str): + super(FireworkEffect, self).__init__(buffer, background) + self.firework_type: FireworkType = "circular" + self.firework_color_type: FireworkColorType = "solid" + self.color_enabled: bool = False + self.fireworks: list[Firework] = [] + self.firework_rate: float = 0.05 + + def set_firework_type(self, firework_type: FireworkType): + """ + Function to set the firework type of the effect + """ + if firework_type in valid_firework_types or firework_type == "random": + self.firework_type = firework_type + + def set_firework_color_enabled(self, color_enabled: bool): + """ + Function to set whether or not fireworks should have color + """ + self.color_enabled = color_enabled + + def set_firework_color_type(self, firework_color_type: FireworkColorType): + """ + Function to set the firework color type of the effect + """ + if firework_color_type in valid_firework_color_types: + self.firework_color_type = firework_color_type + + def set_firework_rate(self, firework_rate: float): + """ + Function to set the rate at which fireworks should be launched + """ + if firework_rate > 0.0 and firework_rate <= 1.0: + self.firework_rate = firework_rate + + def render_frame(self, frame_number): + """ + Renders the background to the screen + """ + + if random.random() < self.firework_rate: + self.fireworks.append( + Firework( + firework_type=self.firework_type, + height=self.buffer.height(), + width=self.buffer.width(), + firework_color_type=self.firework_color_type, + color_enabled=self.color_enabled + ) + ) + + for firework in self.fireworks: + firework.update() + firework.render(self.buffer) + + self.fireworks = [ + firework for firework in self.fireworks if firework.is_active() + ] diff --git a/bruhanimate/bruhrenderer/base_renderer.py b/bruhanimate/bruhrenderer/base_renderer.py index 7b5eefb..9fc4aa9 100644 --- a/bruhanimate/bruhrenderer/base_renderer.py +++ b/bruhanimate/bruhrenderer/base_renderer.py @@ -104,6 +104,8 @@ def create_effect(self, effect_type: EffectType): return AudioEffect(self.create_buffer(), self.background) elif effect_type == "chat": return ChatbotEffect(self.screen, self.create_buffer(), self.create_buffer(), self.background) + elif effect_type == "firework": + return FireworkEffect(self.create_buffer(), self.background) def create_buffer(self) -> Buffer: return Buffer(height=self.screen.height, width=self.screen.width) diff --git a/bruhanimate/bruhrenderer/focus_renderer.py b/bruhanimate/bruhrenderer/focus_renderer.py index 78eaf95..243d51e 100644 --- a/bruhanimate/bruhrenderer/focus_renderer.py +++ b/bruhanimate/bruhrenderer/focus_renderer.py @@ -39,7 +39,7 @@ def __init__( start_frame: int = 0, reverse: bool = False, start_reverse: int = None, - loop: bool = True + loop: bool = True, ): super(FocusRenderer, self).__init__( screen, frames, frame_time, effect_type, background, transparent, collision @@ -112,12 +112,16 @@ def _set_img_attributes(self): self.direction_board = [ [ [ - -1 - if (self.end_board[y][x][0] - self.current_board[y][x][0]) < 0 - else 1, - -1 - if (self.end_board[y][x][1] - self.current_board[y][x][1]) < 0 - else 1, + ( + -1 + if (self.end_board[y][x][0] - self.current_board[y][x][0]) < 0 + else 1 + ), + ( + -1 + if (self.end_board[y][x][1] - self.current_board[y][x][1]) < 0 + else 1 + ), ] for x in range(self.img_width) ] @@ -173,7 +177,7 @@ def solved(self, end_state): def render_img_frame(self, frame_number): """ Renders the next image frame into the image buffer - """ + """ if self.reverse and frame_number >= self.start_reverse: if not self.solved(end_state="start"): for y in range(len(self.current_board)): @@ -222,4 +226,3 @@ def render_img_frame(self, frame_number): self.image_buffer.put_char( value[0], value[1], value[2], transparent=self.transparent ) - diff --git a/bruhanimate/bruhutil/bruhtypes.py b/bruhanimate/bruhutil/bruhtypes.py index d79fdcf..1469d62 100644 --- a/bruhanimate/bruhutil/bruhtypes.py +++ b/bruhanimate/bruhutil/bruhtypes.py @@ -19,7 +19,12 @@ Font = Literal["1943____","1row","3-d","3d-ascii","3d_diagonal","3x5","4max","4x4_offr","5lineoblique","5x7","5x8","64f1____","6x10","6x9","acrobatic","advenger","alligator","alligator2","alpha","alphabet","amc_3_line","amc_3_liv1","amc_aaa01","amc_neko","amc_razor","amc_razor2","amc_slash","amc_slider","amc_thin","amc_tubes","amc_untitled","ansi_regular","ansi_shadow","aquaplan","arrows","ascii_new_roman","ascii___","asc_____","assalt_m","asslt__m","atc_gran","atc_____","avatar","a_zooloo","b1ff","banner","banner3-D","banner3","banner4","barbwire","basic","battlesh","battle_s","baz__bil","bear","beer_pub","bell","benjamin","big","bigchief","bigfig","big_money-ne","big_money-nw","big_money-se","big_money-sw","binary","block","blocks","blocky","bloody","bolger","braced","bright","brite","briteb","britebi","britei","broadway","broadway_kb","bubble","bubble_b","bubble__","bulbhead","b_m__200","c1______","c2______","calgphy2","caligraphy","calvin_s","cards","catwalk","caus_in_","char1___","char2___","char3___","char4___","charact1","charact2","charact3","charact4","charact5","charact6","characte","charset_","chartr","chartri","chiseled","chunky","clb6x10","clb8x10","clb8x8","cli8x8","clr4x6","clr5x10","clr5x6","clr5x8","clr6x10","clr6x6","clr6x8","clr7x10","clr7x8","clr8x10","clr8x8","coil_cop","coinstak","cola","colossal","computer","com_sen_","contessa","contrast","convoy__","cosmic","cosmike","cour","courb","courbi","couri","crawford","crawford2","crazy","cricket","cursive","cyberlarge","cybermedium","cybersmall","cygnet","c_ascii_","c_consen","danc4","dancing_font","dcs_bfmo","decimal","deep_str","defleppard","def_leppard","delta_corps_priest_1","demo_1__","demo_2__","demo_m__","devilish","diamond","diet_cola","digital","doh","doom","dos_rebel","dotmatrix","double","double_shorts","drpepper","druid___","dwhistled","d_dragon","ebbs_1__","ebbs_2__","eca_____","eftichess","eftifont","eftipiti","eftirobot","eftitalic","eftiwall","eftiwater","efti_robot","electronic","elite","epic","etcrvs__","e__fist_","f15_____","faces_of","fairligh","fair_mea","fantasy_","fbr12___","fbr1____","fbr2____","fbr_stri","fbr_tilt","fender","filter","finalass","fireing_","fire_font-k","fire_font-s","flipped","flower_power","flyn_sh","fourtops","fp1_____","fp2_____","fraktur","funky_dr","fun_face","fun_faces","future_1","future_2","future_3","future_4","future_5","future_6","future_7","future_8","fuzzy","gauntlet","georgi16","georgia11","ghost","ghost_bo","ghoulish","glenyn","goofy","gothic","gothic__","graceful","gradient","graffiti","grand_pr","greek","green_be","hades___","heart_left","heart_right","heavy_me","helv","helvb","helvbi","helvi","henry_3d","heroboti","hex","hieroglyphs","high_noo","hills___","hollywood","home_pak","horizontal_left","horizontal_right","house_of","hypa_bal","hyper___","icl-1900","impossible","inc_raw_","invita","isometric1","isometric2","isometric3","isometric4","italic","italics_","ivrit","jacky","jazmine","jerusalem","joust___","js_block_letters","js_bracket_letters","js_capital_curves","js_cursive","js_stick_letters","katakana","kban","keyboard","kgames_i","kik_star","knob","konto","konto_slant","krak_out","larry3d","lazy_jon","lcd","lean","letters","letterw3","letter_w","lexible_","lil_devil","line_blocks","linux","lockergnome","madrid","mad_nurs","magic_ma","marquee","master_o","maxfour","mayhem_d","mcg_____","merlin1","merlin2","mig_ally","mike","mini","mirror","mnemonic","modern__","modular","morse","morse2","moscow","mshebrew210","muzzle","nancyj-fancy","nancyj-improved","nancyj-underlined","nancyj","new_asci","nfi1____","nipples","notie_ca","npn_____","nscript","ntgreek","nvscript","o8","octal","odel_lak","ogre","ok_beer_","old_banner","os2","outrun__","pacos_pe","panther_","patorjk's_cheese","patorjk-hex","pawn_ins","pawp","peaks","pebbles","pepper","phonix__","platoon2","platoon_","pod_____","poison","puffy","puzzle","pyramid","p_skateb","p_s_h_m_","r2-d2___","radical_","rad_phan","rad_____","rainbow_","rally_s2","rally_sp","rammstein","rampage_","rastan__","raw_recu","rci_____","rectangles","red_phoenix","relief","relief2","rev","ripper!_","road_rai","rockbox_","rok_____","roman","roman___","rot13","rotated","rounded","rowancap","rozzo","runic","runyc","sans","sansb","sansbi","sansi","santa_clara","sblood","sbook","sbookb","sbookbi","sbooki","script","script__","serifcap","shadow","shimrod","short","skateord","skateroc","skate_ro","sketch_s","slant","slant_relief","slide","slscript","sl_script","small","small_caps","small_poison","small_shadow","small_slant","smisome1","smkeyboard","smscript","smshadow","smslant","smtengwar","sm______","soft","space_op","spc_demo","speed","spliff","stacey","stampate","stampatello","standard","starwars","star_strips","star_war","stealth_","stellar","stencil1","stencil2","stforek","stick_letters","stop","straight","street_s","stronger_than_all","sub-zero","subteran","super_te","swamp_land","swan","sweet","tanja","tav1____","taxi____","tec1____","tecrvs__","tec_7000","tengwar","term","test1","the_edge","thick","thin","this","thorned","threepoint","ticks","ticksslant","tiles","times","timesofl","tinker-toy","ti_pan__","tomahawk","tombstone","top_duck","train","trashman","trek","triad_st","ts1_____","tsalagi","tsm_____","tsn_base","tty","ttyb","tubular","twin_cob","twisted","twopoint","type_set","t__of_ap","ucf_fan_","ugalympi","unarmed_","univers","usaflag","usa_pq__","usa_____","utopia","utopiab","utopiabi","utopiai","varsity","vortron_","war_of_w","wavy","weird","wet_letter","whimsy","wow","xbrite","xbriteb","xbritebi","xbritei","xchartr","xchartri","xcour","xcourb","xcourbi","xcouri","xhelv","xhelvb","xhelvbi","xhelvi","xsans","xsansb","xsansbi","xsansi","xsbook","xsbookb","xsbookbi","xsbooki","xtimes","xtty","xttyb","yie-ar__","yie_ar_k","z-pilot_","zig_zag_","zone7___"] Image = Literal["bruh","bruh_empty","bruh_computer","computer", "hey","twopoint","christmas"] -EffectType = Literal["static","offset","noise","stars","plasma","gol","rain","matrix","drawlines","snow","twinkle","audio","chat"] -valid_effect_types = {"static","offset","noise","stars","plasma","gol","rain","matrix","drawlines","snow","twinkle","audio","chat"} +EffectType = Literal["static","offset","noise","stars","plasma","gol","rain","matrix","drawlines","snow","twinkle","audio","chat","firework"] +valid_effect_types = {"static","offset","noise","stars","plasma","gol","rain","matrix","drawlines","snow","twinkle","audio","chat","firework"} PanRendererDirection = Literal["horizontal", "vertical"] valid_pan_renderer_directions = {"horizontal", "vertical"} +FireworkType = Literal["circular","ring","starburst","cone","spiral","cross","burst","wave","flower","doublering","heart","start","fireball","diamond","shockwave","snowflake","cluster","comet","random"] +valid_firework_types = ["circular","ring","starburst","cone","spiral","cross","burst","wave","flower","doublering","heart","start","fireball","diamond","shockwave","snowflake","cluster","comet"] +FireworkColorType = Literal["solid", "twotone", "rainbow", "random"] +valid_firework_color_types = ["solid", "twotone", "rainbow", "random"] +two_tone_colors = [[12, 134], [124, 255], [220, 129]] \ No newline at end of file diff --git a/bruhanimate/demos/firework_demo.py b/bruhanimate/demos/firework_demo.py new file mode 100644 index 0000000..83f477b --- /dev/null +++ b/bruhanimate/demos/firework_demo.py @@ -0,0 +1,39 @@ +""" +Copyright 2023 Ethan Christensen + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +from ..bruhrenderer import CenterRenderer +from ..bruhutil import Screen, text_to_image, get_image + +def main(screen: Screen): + renderer = CenterRenderer( + screen=screen, + img=text_to_image("FIREWORKS!"), + frames=float("inf"), + frame_time=0.05, + effect_type="firework", + background=" ", + transparent=False + ) + + renderer.effect.set_firework_rate(firework_rate=0.1) + renderer.effect.set_firework_color_enabled(True) + renderer.effect.set_firework_color_type("solid") + renderer.effect.set_firework_type("random") + + renderer.run() + +if __name__ == "__main__": + Screen.show(main) diff --git a/setup.py b/setup.py index 120cc29..5ee4427 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ with codecs.open(os.path.join(here, "README.md"), encoding="utf-8") as fh: long_description = "\n" + fh.read() -VERSION = "0.2.72" +VERSION = "0.2.73" DESCRIPTION = 'ASCII Terminal Animation Package' LONG_DESCRIPTION = 'A package that allows for various animations in the terminal'