diff --git a/engine/scroll.py b/engine/scroll.py deleted file mode 100644 index 65a2a23..0000000 --- a/engine/scroll.py +++ /dev/null @@ -1,156 +0,0 @@ -""" -Render engine — ticker content, scroll motion, message panel, and firehose overlay. -Orchestrates viewport, frame timing, and layers. - -.. deprecated:: - This module contains legacy rendering/orchestration code. New pipeline code should - use the Stage-based pipeline architecture instead. This module is - maintained for backwards compatibility with the demo mode. -""" - -import random -import time - -from engine import config -from engine.camera import Camera -from engine.display import ( - Display, - TerminalDisplay, -) -from engine.display import ( - get_monitor as _get_display_monitor, -) -from engine.frame import calculate_scroll_step -from engine.layers import ( - apply_glitch, - process_effects, - render_firehose, - render_message_overlay, - render_ticker_zone, -) -from engine.viewport import th, tw - -USE_EFFECT_CHAIN = True - - -def stream( - items, - ntfy_poller, - mic_monitor, - display: Display | None = None, - camera: Camera | None = None, -): - """Main render loop with four layers: message, ticker, scroll motion, firehose.""" - if display is None: - display = TerminalDisplay() - if camera is None: - camera = Camera.vertical() - - random.shuffle(items) - pool = list(items) - seen = set() - queued = 0 - - time.sleep(0.5) - w, h = tw(), th() - display.init(w, h) - display.clear() - fh = config.FIREHOSE_H if config.FIREHOSE else 0 - ticker_view_h = h - fh - GAP = 3 - scroll_step_interval = calculate_scroll_step(config.SCROLL_DUR, ticker_view_h) - - active = [] - ticker_next_y = ticker_view_h - noise_cache = {} - scroll_motion_accum = 0.0 - msg_cache = (None, None) - frame_number = 0 - - while True: - if queued >= config.HEADLINE_LIMIT and not active: - break - - t0 = time.monotonic() - w, h = tw(), th() - fh = config.FIREHOSE_H if config.FIREHOSE else 0 - ticker_view_h = h - fh - scroll_step_interval = calculate_scroll_step(config.SCROLL_DUR, ticker_view_h) - - msg = ntfy_poller.get_active_message() - msg_overlay, msg_cache = render_message_overlay(msg, w, h, msg_cache) - - buf = [] - ticker_h = ticker_view_h - - scroll_motion_accum += config.FRAME_DT - while scroll_motion_accum >= scroll_step_interval: - scroll_motion_accum -= scroll_step_interval - camera.update(config.FRAME_DT) - - while ( - ticker_next_y < camera.y + ticker_view_h + 10 - and queued < config.HEADLINE_LIMIT - ): - from engine.effects import next_headline - from engine.render import make_block - - t, src, ts = next_headline(pool, items, seen) - ticker_content, hc, midx = make_block(t, src, ts, w) - active.append((ticker_content, hc, ticker_next_y, midx)) - ticker_next_y += len(ticker_content) + GAP - queued += 1 - - active = [ - (c, hc, by, mi) for c, hc, by, mi in active if by + len(c) > camera.y - ] - for k in list(noise_cache): - if k < camera.y: - del noise_cache[k] - - grad_offset = (time.monotonic() * config.GRAD_SPEED) % 1.0 - ticker_buf_start = len(buf) - - ticker_buf, noise_cache = render_ticker_zone( - active, camera.y, camera.x, ticker_h, w, noise_cache, grad_offset - ) - buf.extend(ticker_buf) - - mic_excess = mic_monitor.excess - render_start = time.perf_counter() - - if USE_EFFECT_CHAIN: - buf = process_effects( - buf, - w, - h, - camera.y, - ticker_h, - camera.x, - mic_excess, - grad_offset, - frame_number, - msg is not None, - items, - ) - else: - buf = apply_glitch(buf, ticker_buf_start, mic_excess, w) - firehose_buf = render_firehose(items, w, fh, h) - buf.extend(firehose_buf) - - if msg_overlay: - buf.extend(msg_overlay) - - render_elapsed = (time.perf_counter() - render_start) * 1000 - monitor = _get_display_monitor() - if monitor: - chars = sum(len(line) for line in buf) - monitor.record_effect("render", render_elapsed, chars, chars) - - display.show(buf) - - elapsed = time.monotonic() - t0 - time.sleep(max(0, config.FRAME_DT - elapsed)) - frame_number += 1 - - display.cleanup()