def main(): app = App(framerate=float("inf")) colors = [Color.rgb(r,g,b) for r in (0, 1) for g in (0, 1) for b in (0, 1)] pixels = [PixelData(char="▄", fg=col1, bg=col2) for col1 in colors for col2 in colors] t0 = perf_counter() n_frames = 0 n_updates = 0 update_time = 0 @app.on("frame") def on_frame(): nonlocal n_frames, n_updates, update_time for x in range(app.screen.w): for y in range(app.screen.h): app.screen[x,y].set(choice(pixels)) app.screen.update() n_frames += 1 n_updates += app.screen._update_count update_time += app.screen._update_duration app.run() updates_per_ms = n_updates / update_time / 1000 updates_per_ms_real = n_updates / (perf_counter() - t0) / 1000 print("Updates per ms (updating): {:.2f}".format(updates_per_ms)) print("Updates per ms (real time): {:.2f}".format(updates_per_ms_real)) print("Average update time ms: {:.2f}".format(update_time / n_frames * 1000)) print("Average potential FPS: {:.2f}".format(n_frames / update_time))
def main(): app = App(mouse=True, framerate=120) buf = Buffer(0, 0) dirty = True dragging = False drag_start = None mouse_pos = None def do_box(buffer): if drag_start is None or mouse_pos is None: return x, y, w, h = corners_to_box(*drag_start, *mouse_pos) # draw_box(buffer, x, y, w, h, chars=BOX_CHARS_DOUBLE, fg=Color.hsl(perf_counter(), 1.0, 0.5)) draw_frame(buffer, x, y, w, h, chars=FRAME_CHARS_DOUBLE, fg=Color.hsl(perf_counter(), 1.0, 0.5)) @app.on("start") @app.on("resize") def on_resize(): buf.resize(app.screen.w, app.screen.h) for x in range(buf.w): for y in range(buf.h): col = Color.rgb(0, 0, 0) if (x + y) % 2 else Color.rgb( 0.1, 0.1, 0.1) buf.put_char(" ", x, y, bg=col) @app.on("mouse") def on_mouse(mouse): nonlocal dirty, dragging, drag_start, mouse_pos if mouse.left: if mouse.down: dragging = True drag_start = (mouse.x, mouse.y) if mouse.up: do_box(buf) dragging = False dirty = True mouse_pos = (mouse.x, mouse.y) else: dragging = False @app.on("frame") def on_frame(): app.screen.clear() app.screen.blit(buf) if dragging: do_box(app.screen) app.screen.update() app.run()
def main(): app = App(framerate=float("inf")) app.t0 = perf_counter() app.frames = 0 app.pos = 0 @app.on("frame") def on_frame(): app.pos = (app.pos + 1) % (app.screen.w * app.screen.h) x = app.pos % app.screen.w y = app.pos // app.screen.w app.screen.clear() app.screen.print(" " * 5, x, y, bg=AQUA) app.screen.update() app.frames += 1 app.t1 = perf_counter() @app.on("after_stop") def on_after_stop(): tpf = (app.t1 - app.t0) / app.frames print("Terminal: {} ({}x{})\n".format(app.backend.terminal_name, app.screen.w, app.screen.h)) print("Avg time per frame: {:.4f}\n".format(tpf)) print("Avg framerate: {:.2f}\n".format(1 / tpf)) app.start() app.await_stop()
def main(): app = App(mouse=True, framerate=60) app.mouse_x = 0 app.mouse_y = 0 app.mouse_px = 0 app.mouse_py = 0 app.particles = [] @app.on("mouse") def on_mouse(m): app.mouse_x = m.x app.mouse_y = m.y * 2 @app.on("frame") def on_frame(): w = app.screen.w h = app.screen.h colormap = [Color.rgb(0,0,0) for x in range(w) for y in range(h * 2)] dx = app.mouse_x - app.mouse_px dy = app.mouse_y - app.mouse_py l = math.sqrt(dx ** 2 + dy ** 2) d = math.atan2(dy, dx) j = min(25, int(l)) * 6 for i in range(j): f = i / j ll = l* random.uniform(0.25, 0.5) dd = d + random.uniform(-0.25, 0.25) vx = ll * math.cos(dd) vy = ll * math.sin(dd) app.particles.append(Particle(app.mouse_px + dx * f, app.mouse_py + dy * f, vx, vy)) app.screen.clear() for i, p in enumerate(app.particles): col = Color.hsl(i/len(app.particles), 1.0, 0.5) steps = math.hypot(p.vx, p.vy) for step in range(int(steps + 1)): f = step / steps px = int(p.x - p.vx * f) py = int(p.y - p.vy * f) if px >= 0 and py >= 0 and px < w and py < h * 2: colormap[py * w + px] += RED p.update() if p.x < 0 or p.y < 0 or p.x >= w or p.y >= h * 2: app.particles.remove(p) draw_colormap_2x(app.screen, colormap, 0, 0, w=w, h=h * 2) app.screen.update() app.mouse_px = app.mouse_x app.mouse_py = app.mouse_y app.run()
def main(): app = App(mouse=True) x = 0 y = 0 left = False middle = False right = False scroll_total = 0 @app.on("mouse") def mouse(mouse: Mouse): nonlocal x, y, left, middle, right, scroll_total if mouse.scrollup: scroll_total += 1 elif mouse.scrolldown: scroll_total -= 1 if mouse.down: if mouse.left: left = True if mouse.middle: middle = True if mouse.right: right = True elif mouse.up: if mouse.left: left = False if mouse.middle: middle = False if mouse.right: right = False x = mouse.x y = mouse.y @app.on("frame") def frame(): app.screen.clear() app.screen.print( "".join("#" if b else "_" for b in [left, middle, right]), 1, 1) app.screen.print("LMR", 1, 2) app.screen.print(f"scroll: {scroll_total}", 7, 2) app.screen.show_cursor = True app.screen.cursor_pos = (x, y) app.screen.update() app.run()
def main(): app = App(mouse=True) @app.on("start") def on_start(): app.mouse = None app.key = None app.dirty = False redraw(app) @app.on("resize") def on_resize(): redraw(app) @app.on("key") def on_key(k): app.key = k app.dirty = True @app.on("mouse") def on_mouse(m): app.mouse = m app.dirty = True @app.on("frame") def on_frame(): if app.dirty: redraw(app) app.dirty = False app.start() app.await_stop()
def main(): app = App() @app.on("frame") # run this function every frame def on_frame(): app.screen.clear() # remove everything from the screen text = "Hello world, from termpixels!" for i, c in enumerate(text): f = i / len(text) color = Color.hsl(f + time(), 1, 0.5) # create a color from a hue value x = app.screen.w // 2 - len( text) // 2 # horizontally center the text offset = sin(time() * 3 + f * 5) * 2 # some arbitrary math y = round(app.screen.h / 2 + offset) # vertical center with an offset app.screen.print(c, x + i, y, fg=color) # draw the text to the screen buffer app.screen.update() # commit the changes to the screen app.run() # block here until the app exits (press Escape!)
def main(): app = App(mouse=True) frame_num = 0 size_text = "" @app.on("start") def start(): app.screen.show_cursor = True app.screen.print("App start, waiting 1 second.", 0, 0) app.screen.update() sleep(1) @app.on("frame") def frame(): nonlocal frame_num app.screen.clear() app.screen.print(f"Frame: {frame_num}", 0, 0) app.screen.print("Press 'q' to quit.", 0, 1) app.screen.print(size_text, 0, 2) app.screen.update() frame_num += 1 @app.on("resize") def resize(): nonlocal size_text size_text = f"Resized to {app.screen.w}x{app.screen.h}" @app.on("key") def key(k): if k == "q": app.stop() @app.on("mouse") def mouse(m): app.screen.cursor_pos = (m.x, m.y) @app.on("before_stop") def before_stop(): # Terminal is not reset; we can use the screen. app.screen.clear() app.screen.print("Before stop", 0, 0) app.screen.update() sleep(0.5) @app.on("after_stop") def after_stop(): # Terminal is reset; we can print normally. print("After stop") # the following two method calls are equivalent to calling app.run() app.start() # this does not block # you could run code concurrently with the App here, but you should not # interact with its attributes outside of event listeners due to potential # concurrency issues. app.await_stop() # this blocks print("Exited")
def main(): app = App() @app.on("key") def on_key(k): app.screen.clear() app.screen.print(repr(k), 1, 1) app.screen.update() app.start() app.await_stop()
def main(): app = App() @app.on("frame") def on_frame(): app.screen.print("Goodbye", 0, 0) # this should be overwritten completely app.screen.print("こんにちは世界", 0, 0) # double-width characters app.screen.print( " (Hello World)") # this should follow the previous printout app.screen.update() app.start() app.await_stop()
def main(): app = App() @app.on("frame") def on_frame(): clock_time = time.strftime("%H:%M:%S", time.gmtime()) app.screen.print("Clock: " + clock_time, 1, 1) try: app.backend.window_title = clock_time except: app.screen.print("Terminal does not support setting window title", 1, 2, fg=Color.rgb(1,0,0)) app.screen.update() app.start() app.await_stop()
def main(): app = App() run_count = 0 @app.on("start") def start(): nonlocal run_count run_count += 1 app.screen.print("Run {}".format(run_count), 0, 0) app.screen.print("Press any key to restart...", 0, 1) app.screen.update() @app.on("key") def key(k): app.stop() app.run() app.run() app.run()
def main(): app = App(mouse=True) in_buffer = [] @app.input.on("raw_input") def on_raw(data): in_buffer.append(data) def print_escape(line, x, y): app.screen.print_pos = (x, y) for ch in line: fg = COL_FG bg = None cat = category(ch) if "C" in cat: fg = COL_CTRL elif "N" in cat: fg = COL_NUM elif "P" in cat: fg = COL_PUNC elif "Z" in cat: bg = COL_SEP app.screen.print(repr(ch).lstrip("'").rstrip("'"), fg=fg, bg=bg) @app.on("frame") @app.on("resize") def update(): max_lines = app.screen.h n_lines = min(max_lines, len(in_buffer)) lines = in_buffer[-n_lines:] app.screen.clear() for i, line in enumerate(lines): print_escape(line, 0, i) app.screen.update() app.start() app.await_stop()
def main(): app = App() @app.on("start") def on_start(): app.screen.print("Resize the terminal.", 1, 1, fg=Color.rgb(0, 1, 0)) app.screen.update() @app.on("resize") def on_resize(): app.screen.clear() app.screen.fill(0, 0, app.screen.w, app.screen.h, bg=Color(0, 255, 0)) app.screen.fill(1, 1, app.screen.w - 2, app.screen.h - 2, bg=Color(0, 0, 0)) app.screen.print("{} x {}".format(app.screen.w, app.screen.h), 2, 2) app.screen.update() app.start() app.await_stop()
def main(): app = App(framerate=60) @app.on("start") def on_start(): app.buffer = Buffer(16, 4) app.buffer.clear(bg=Color.rgb(0.2, 0, 0), fg=Color.rgb(1, 0.5, 0.5)) app.buffer.print("Hello world") @app.on("frame") def on_frame(): t = time() app.screen.clear() app.screen.blit( app.buffer, round(app.screen.w / 2 + sin(t * 3) * 16) - app.buffer.w // 2, round(app.screen.h / 2 + cos(t * 1) * 4) - app.buffer.h // 2) app.screen.print( "Update time: {:.2f}ms".format(app.screen._update_duration * 1000), 0, 0) app.screen.update() app.start() app.await_stop()
def main(): backend = App().backend backend.enter_alt_buffer() colors = [ Color.rgb(1, 0, 0), Color.rgb(1, 1, 0), Color.rgb(0, 1, 0), Color.rgb(0, 1, 1), Color.rgb(0, 0, 1), Color.rgb(1, 0, 1) ] t0 = perf_counter() frames = 0 pos = 0 while frames < 10000: backend.bg = colors[frames % len(colors)] backend.write(" ") backend.flush() frames += 1 t1 = perf_counter() backend.exit_alt_buffer() backend.flush() tpf = (t1 - t0) / frames print("Terminal: {}\n".format(backend.terminal_name)) print("Avg time per frame: {:.4f}\n".format(tpf)) print("Avg framerate: {:.2f}\n".format(1 / tpf))
from datetime import datetime from time import time from termpixels import App, Color, SparseBuffer from termpixels.util import splitlines_print a = App() b = SparseBuffer(0, 0) b.extend_to(10, 10) scroll_y = 0 autoscroll = False def log(s): global scroll_y for line in splitlines_print(s): b.print(line, fg=Color.hsl(time() * 0.2, 0.5, 0.4)) b.print_pos = (0, b.print_pos[1] + 1) b.extend_to(0, b.print_pos[1] + 1) if autoscroll: scroll_y = b.print_pos[1] - a.screen.h @a.on("start") @a.on("resize") def resize(): b.resize(a.screen.w, b.h) log("Use up/down arrow keys to scroll!") @a.on("key")
from termpixels import App, Color if __name__ == "__main__": # it's possible to not "start" an App and just use its terminal backend. term = App().backend term.fg = Color.rgb(1, 0, 1) term.write("Hello world\n") term.flush() term.fg = Color.rgb(1, 1, 0) term.flush() print("print() works too; just flush first.")
def main(): app = App() inner_buffer = Buffer(0, 0) outer_pad = 1 inner_w = 0 inner_h = 0 @app.on("start") @app.on("resize") @app.on("frame") def update(): nonlocal inner_w, inner_h app.screen.clear() inner_buffer.clear() # compute inner dimensions of box inner_w = app.screen.w - outer_pad * 2 - 2 inner_h = app.screen.h - outer_pad * 2 - 2 inner_buffer.resize(inner_w, inner_h) # draw a box with a title draw_box(app.screen, outer_pad, outer_pad, inner_w + 2, inner_h + 2, chars=BOX_CHARS_LIGHT_DOUBLE_TOP) title = "Hello drawing" app.screen.print(title, app.screen.w // 2 - len(title) // 2, outer_pad) # draw spinners inner_buffer.print("Inner header ", 0, 0) draw_spinner(inner_buffer, *inner_buffer.print_pos, freq=2, fg=GREEN) inner_buffer.print(" ") draw_spinner(inner_buffer, *inner_buffer.print_pos, freq=2, fg=GREY, frames=SPINNER_PIPE) inner_buffer.print(" ") draw_spinner(inner_buffer, *inner_buffer.print_pos, freq=2, fg=GREY, frames=SPINNER_CLOCK) inner_buffer.print(" ") draw_spinner(inner_buffer, *inner_buffer.print_pos, freq=2, t=math.sin(time.perf_counter()), fg=YELLOW, frames=SPINNER_MOON) inner_buffer.print(" ") draw_spinner(inner_buffer, *inner_buffer.print_pos, freq=1, fg=WHITE, frames=SPINNER_DOTS) # draw a horizontal line along x=2 within the box draw_hline(inner_buffer, 2, fg=GREY) # print some word-wrapped text inside the box inner_buffer.print(wrap_text(LIPSUM, inner_w), 0, 3, fg=YELLOW) # progress bar draw_progress(inner_buffer, 0, inner_buffer.print_pos[1] + 2, w=inner_buffer.w // 3, progress=math.sin(time.perf_counter()) * 0.5 + 0.5, fg=BRIGHT_YELLOW, bg=GREY, **PROGRESS_SMOOTH) # draw a color bitmap at 2x vertical resolution draw_colormap_2x(inner_buffer, SMILEY, 2, inner_buffer.h - 3 - 2, w=7, h=7) # copy box contents to screen app.screen.blit(inner_buffer, outer_pad + 1, outer_pad + 1) app.screen.update() app.start() app.await_stop()
from termpixels import App, Color, Buffer, SparseBuffer a = App() b = Buffer(16, 8) sb = SparseBuffer(16, 8) b.clear(bg=Color.rgb(0.5, 0, 0)) b.print("Hello Buffer!") sb.clear(bg=Color.rgb(0, 0.5, 0)) sb.print("Hello Sparse!") @a.on("frame") def frame(): a.screen.clear() a.screen.blit(b, 1, 1) a.screen.blit(sb, 1 + b.w + 1, 1) a.screen.print_pos = (1, 1 + b.h + 1) a.screen.print(f"Pixels in buffer: {b.w * b.h}\n") a.screen.print(f"Pixels in sparse buffer: {sb._pixel_count}\n") a.screen.update() if __name__ == "__main__": a.run()
def main(): app = App(mouse=True, framerate=60) app.mouse_x = 0 app.mouse_y = 0 app.mouse_px = 0 app.mouse_py = 0 app.particles = [] @app.on("mouse") def on_mouse(m): app.mouse_x = m.x app.mouse_y = m.y @app.on("frame") def on_frame(): dx = app.mouse_x - app.mouse_px dy = app.mouse_y - app.mouse_py l = math.sqrt(dx**2 + dy**2) d = math.atan2(dy, dx) j = min(45, int(l)) * 2 for i in range(j): f = i / j ll = l * random.uniform(0.25, 0.5) dd = d + random.uniform(-0.2, 0.2) vx = ll * math.cos(dd) vy = ll * math.sin(dd) app.particles.append( Particle(app.mouse_px + dx * f, app.mouse_py + dy * f, vx, vy)) app.screen.clear() for i, p in enumerate(app.particles): col = Color.hsl(i / len(app.particles), 1.0, 0.5) app.screen.print(" ", int(p.x), int(p.y), bg=col) p.update() if p.x < 0 or p.y < 0 or p.x >= app.screen.w or p.y >= app.screen.h: app.particles.remove(p) app.screen.update() app.mouse_px = app.mouse_x app.mouse_py = app.mouse_y app.start() app.await_stop()
def main(): app = App(mouse=True, framerate=60) app.screen.show_cursor = True w = 0 h = 0 buf = None c_x = 0 c_y = 0 show_help = True @app.on("start") @app.on("resize") def make_buffers(): nonlocal w, h, buf w = app.screen.w h = app.screen.h * 2 buf = [P(**props["air"]) for y in range(w) for x in range(h)] @app.on("frame") def on_frame(): app.screen.clear() app.screen.cursor_pos = (c_x, c_y) P.update(buf, w, h) P.draw(app.screen, buf, w, h) if show_help: app.screen.print(helptext, 1, 1, fg=Color.rgb(1, 1, 1)) app.screen.update() def interact(place): nonlocal show_help show_help = False x = c_x y = c_y * 2 if x >= 0 and x < w and y >= 0 and y < h: if place: buf[y * w + x] = P(color=Color.hsl(perf_counter() * 0.25, 1, 0.5), **props["sand"]) else: buf[y * w + x] = P(**props["air"]) @app.on("mouse") def on_mouse(m): nonlocal c_x, c_y c_x = m.x c_y = m.y if m.left: interact(True) if m.right: interact(False) @app.on("key") def on_key(k): nonlocal c_x, c_y if k == "left": c_x = max(0, c_x - 1) if k == "right": c_x = min(w - 1, c_x + 1) if k == "up": c_y = max(0, c_y - 1) if k == "down": c_y = min(w - 1, c_y + 1) if k == "z": interact(True) if k == "x": interact(False) app.start() app.await_stop()
SPEED_MIN = 0.5 SPEED_MAX = 1.5 LENGTH_MIN = 3 LENGTH_MAX = 8 HUE = 0.3 * 360 class Particle: def __init__(self): self.pos = 0 self.speed = uniform(SPEED_MIN, SPEED_MAX) self.length = uniform(LENGTH_MIN, LENGTH_MAX) a = App() cols = [] @a.on("start") @a.on("resize") def start(): global cols cols = [Particle() for x in range(a.screen.w)] a.screen.clear(fg=Color.rgb(0, 0, 0)) @a.on("frame") def on_frame(): for x, p in enumerate(cols): # update colors
def main(): app = App(framerate=20) ui_height = 3 game_buffer = Buffer(0,0) score = 0 hiscore = load_hiscore() mode = None worm = None food_x = 0 food_y = 0 control_x = 0 control_y = 0 def move_food(): nonlocal food_x, food_y w = game_buffer.w // 2 h = game_buffer.h positions = [(x,y) for x in range(w) for y in range(h) if not worm.intersecting(x, y)] food_x, food_y = choice(positions) @app.on("start") def start(): nonlocal score, mode, worm score = 0 worm = Worm(randint(0, app.screen.w - 1), randint(0, app.screen.h - 1)) mode = MODE_GAME @app.on("start") @app.on("resize") def resize(): game_buffer.resize(app.screen.w, app.screen.h - ui_height) move_food() @app.on("key") def key(k): nonlocal control_x, control_y if mode == MODE_GAME: if k == K_UP: control_y = -1 if k == K_DOWN: control_y = 1 if k == K_LEFT: control_x = -1 if k == K_RIGHT: control_x = 1 elif mode == MODE_GAMEOVER: if k == "\n": app.emit("start") def frame_game(): nonlocal control_x, control_y nonlocal score, hiscore nonlocal mode # handle input if control_x != 0 and not worm.intersecting(worm.x + control_x, worm.y): worm.vx = control_x worm.vy = 0 control_x = 0 if control_y != 0 and not worm.intersecting(worm.x, worm.y + control_y): worm.vy = control_y worm.vx = 0 control_y = 0 if worm.intersecting(food_x, food_y): score += 1 worm.length += 1 hiscore = max(hiscore, score) save_hiscore(hiscore) move_food() game_buffer.clear() game_buffer.print("░░", food_x * 2, food_y) try: worm.update(game_buffer) except GameOver: mode = MODE_GAMEOVER multiply_buffer(game_buffer, 0.4) return # draw app.screen.clear() app.screen.print("~TermWorm~", 0, 0) app.screen.print("Score: {}".format(score), 0, 1, fg=Color.rgb(.7,.7,.7)) app.screen.print(" Hi: {}".format(hiscore), fg=Color.rgb(.7,.7,0)) draw_box(app.screen, 0, 2, app.screen.w, 1, chars=BOX_CHARS_DOUBLE) app.screen.blit(game_buffer, 0, ui_height) app.screen.update() def frame_gameover(): dark = Color.rgb(0.2,0.2,0.2) app.screen.clear() app.screen.blit(game_buffer, 0, ui_height) print_hcenter(app.screen, "Game over!", y=3, fg=Color.rgb(1,1,0), bg=dark) print_hcenter(app.screen, "Press enter to restart", y=4, fg=Color.rgb(0.75,0.75,0.75), bg=dark) print_hcenter(app.screen, "Press escape to exit", y=5, fg=Color.rgb(0.75,0.75,0.75), bg=dark) app.screen.update() @app.on("frame") def frame(): if mode == "game": frame_game() elif mode == "gameover": frame_gameover() else: raise Exception("Invalid mode: {}".format(mode)) @app.on("after_stop") def after_stop(): print("Thanks for playing TermWorm!") app.run()