# Design

SF's UI is a terminal application built on the Pi TUI framework (`@mariozechner/pi-tui`). These are the binding constraints any UI work must respect.

## The Cardinal Rule: Line Width

**Every line returned from `render(width)` must not exceed `width` in visible characters.** Exceeding it causes terminal line-wrapping, cursor misposition, and visual corruption the framework cannot fix.

Use the Pi TUI utilities — never raw `string.length`:

```typescript
import { visibleWidth, truncateToWidth, wrapTextWithAnsi } from "@mariozechner/pi-tui";

visibleWidth("\x1b[32mHello\x1b[0m");          // 5, not 14
truncateToWidth("Very long text here", 10);    // "Very lo..."
wrapTextWithAnsi("\x1b[32mlong green\x1b[0m", 15); // preserves ANSI per line
```

`visibleWidth` strips ANSI escape codes before measuring. `truncateToWidth` preserves ANSI codes in the truncated output. Use these everywhere a line's display length matters.

## Render Pattern

```typescript
render(width: number): string[] {
  const lines: string[] = [];
  lines.push(truncateToWidth(`  ${prefix}${content}`, width));

  const labelWidth = visibleWidth(label);
  const available = width - labelWidth - 4; // padding
  lines.push(`  ${label}: ${truncateToWidth(value, available)}`);

  return lines;
}
```

## Overlays and Modals

Floating panels use the Pi TUI overlay pattern: they render at a fixed position within the terminal bounds and must still respect the outer `width` constraint. An overlay that overflows its bounds causes the same wrapping corruption as any other component.

Use `ctx.ui.dialog()` for modal user input. Use `ctx.ui.notify()` for transient non-blocking notices. Persistent notification state goes through `notification-store.ts` → `notification-overlay.ts`.

## Theming

Colors and styles come from the Pi TUI theme system, not from hardcoded ANSI codes. Access the active theme via the `ExtensionContext`. Respect theme changes: components must re-render when the theme changes (implement `onThemeChange` if caching rendered output).

## IME and Focus

Interactive input components must implement the `Focusable` interface to receive keyboard events correctly, especially for IME (input method editor) support on non-ASCII keyboards. Components that handle key input but do not implement `Focusable` will silently swallow events.

## Performance

Cache rendered output when the underlying data hasn't changed. Invalidate the cache on data change or theme change. Do not re-render on every tick. The TUI framework calls `render()` frequently; rendering must be cheap.

## Reference

Full TUI documentation: [`docs/dev/pi-ui-tui/`](./dev/pi-ui-tui/README.md)
