from engine.effects.types import EffectConfig, EffectContext, EffectPlugin class BorderEffect(EffectPlugin): """Simple border effect for terminal display. Draws a border around the buffer and optionally displays performance metrics in the border corners. Internally crops to display dimensions to ensure border fits. """ name = "border" config = EffectConfig(enabled=True, intensity=1.0) def process(self, buf: list[str], ctx: EffectContext) -> list[str]: if not buf: return buf # Get actual display dimensions from context display_w = ctx.terminal_width display_h = ctx.terminal_height # If dimensions are reasonable, crop first - use slightly smaller to ensure fit if display_w >= 10 and display_h >= 3: # Subtract 2 for border characters (left and right) crop_w = display_w - 2 crop_h = display_h - 2 buf = self._crop_to_size(buf, crop_w, crop_h) w = display_w h = display_h else: # Use buffer dimensions h = len(buf) w = max(len(line) for line in buf) if buf else 0 if w < 3 or h < 3: return buf inner_w = w - 2 # Get metrics from context fps = 0.0 frame_time = 0.0 metrics = ctx.get_state("metrics") if metrics: avg_ms = metrics.get("avg_ms") frame_count = metrics.get("frame_count", 0) if avg_ms and frame_count > 0: fps = 1000.0 / avg_ms frame_time = avg_ms # Build borders # Top border: ┌────────────────────┐ or with FPS if fps > 0: fps_str = f" FPS:{fps:.0f}" if len(fps_str) < inner_w: right_len = inner_w - len(fps_str) top_border = "┌" + "─" * right_len + fps_str + "┐" else: top_border = "┌" + "─" * inner_w + "┐" else: top_border = "┌" + "─" * inner_w + "┐" # Bottom border: └────────────────────┘ or with frame time if frame_time > 0: ft_str = f" {frame_time:.1f}ms" if len(ft_str) < inner_w: right_len = inner_w - len(ft_str) bottom_border = "└" + "─" * right_len + ft_str + "┘" else: bottom_border = "└" + "─" * inner_w + "┘" else: bottom_border = "└" + "─" * inner_w + "┘" # Build result with left/right borders result = [top_border] for line in buf[: h - 2]: if len(line) >= inner_w: result.append("│" + line[:inner_w] + "│") else: result.append("│" + line + " " * (inner_w - len(line)) + "│") result.append(bottom_border) return result def _crop_to_size(self, buf: list[str], w: int, h: int) -> list[str]: """Crop buffer to fit within w x h.""" result = [] for i in range(min(h, len(buf))): line = buf[i] if len(line) > w: result.append(line[:w]) else: result.append(line + " " * (w - len(line))) # Pad with empty lines if needed (for border) while len(result) < h: result.append(" " * w) return result def configure(self, config: EffectConfig) -> None: self.config = config