singularity-forge/docs/DESIGN.md

57 lines
2.6 KiB
Markdown
Raw Permalink Normal View History

# 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)