Guides
Ink Migration
Move an existing Ink application into a tuil runtime incrementally.
1. Keep the component tree
tuil uses Ink, so begin by wrapping the existing root without rewriting its children:
const app = createApp({ id: "existing-cli", component: ExistingApp });
render(<ExistingApp />, { app });2. Replace global input
Move overlay-specific handlers to TerminalInputLayer, application shortcuts
to HotkeyManager, and traversal to focusable semantic components. This
prevents multiple useInput hooks from competing.
3. Introduce ownership boundaries
Move global singletons into services, teardown into lifecycle disposers, and cross-feature messages into declared events.
4. Adopt components selectively
Registry components are source-owned, so install only the primitives or blocks you need:
npx @mwillbanks/tuil add button field text-input dialog5. Convert tests
Keep frame assertions for visual regressions, then add semantic queries for behavior. Semantic assertions survive spacing, color, and viewport changes.