Files
vue-tui/packages/runtime
Yunfei He 51cca1cf05 docs(divergences)+refactor(scheduler): prune mis-scoped idioms, fix throttle figure, drop dead constant (#133)
Audit of the "byte-identical reconciler/runtime mechanics" subsection, each entry
verified against vue-tui + Ink v7.0.4 source.

Doc:
- Rewrite the TuiComment/Transform entry cause-first (Vue materializes a comment
  placeholder where React renders nothing -> vue makes it inert) for clarity.
- Fix the commit-throttle figure: it is `ceil(1000/maxFps)` = 34ms at the default
  maxFps=30, not "~32ms". The 32 was vue's own dead fallback constant, never the
  production value; Ink has no 32 either.
- Drop the keyed-lists (LIS) entry: it restated the section header and guarded no
  vue-authored code (patchKeyedChildren is upstream Vue).
- Drop the wrapText-truncate and animation-scheduler entries: both are vue-tui
  implementation choices, not Vue-vs-React framework differences, and both are
  already explained by their in-code comments.

Code (no behavior change; verified by `vp run ready`):
- Remove the dead `DEFAULT_THROTTLE_MS = 32` fallback in scheduler.ts. Production
  always passes throttleMs (render.ts derives it from maxFps) and the immediate
  path never reads it, so the 32 fallback never gated a frame. Make throttleMs
  required; render.ts always passes it (0 when unthrottled).
- Tighten the animation-scheduler ceil comment (drop the "busy-loop" overstatement;
  the fractional-delay truncation it describes is real and keeps the Math.ceil).

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 13:58:52 +08:00
..

@vue-tui/runtime

Early stage — under active development. Bug reports welcome, but not recommended for production use yet.

Vue 3 terminal renderer with Yoga flexbox layout — build rich TUI apps with the same component model you use on the web.

npm version npm downloads

Why

  • Vue SFC & JSX — <template>, TSX, or render functions — your choice
  • Yoga flexbox — the same layout engine behind React Native, not a CSS-subset hack
  • Built-in input system — keyboard handling, focus management, Tab navigation
  • Terminal-native — renders directly to stdout, purpose-built for CLI tools and AI agent interfaces

@vue-tui/runtime is a terminal platform renderer parallel to @vue/runtime-dom, comparable to React Ink but adapted for Vue's reactivity model.

Install

npm install @vue-tui/runtime vue

Quick Start

// src/main.ts
import { createApp } from "@vue-tui/runtime";
import App from "./App.vue";

createApp(App).mount();
<!-- src/App.vue -->
<script setup lang="ts">
import { shallowRef } from "vue";
import { Box, Text, useInput } from "@vue-tui/runtime";

const count = shallowRef(0);

useInput((input) => {
  if (input === "+") count.value++;
  if (input === "-") count.value--;
});
</script>

<template>
  <Box>
    <Text>Count: </Text>
    <Text bold color="green">{{ count }}</Text>
    <Text dimColor> (+/- to change)</Text>
  </Box>
</template>

Components

Component Description
<Box> Flexbox container — direction, wrap, align, justify, gap, padding, margin, borders, background
<Text> Styled text — color, bold, italic, underline, strikethrough, dimColor, wrap/truncate modes
<Spacer> Expands to fill available space (flex-grow: 1)
<Newline> Inserts line breaks (configurable count)
<Static> Renders a list of items once, above the redrawn region
<Transform> Applies a string transform function to each rendered line

Composables

Composable Description
useInput(handler, opts?) Keyboard input — (input, key) with modifier and arrow key detection
useFocus(opts?) Component-level focus — returns { isFocused, focus }
useFocusManager() App-level focus — focusNext(), focusPrevious(), focus(id)
useApp() App lifecycle — { exit(error?), waitUntilRenderFlush() }
useTerminalSize() Reactive terminal dimensions — { columns, rows }
useAnimation(opts?) Frame-based animation loop — returns { frame, time, delta, reset }
useBoxMetrics(ref) Reactive layout metrics — { width, height, left, top, hasMeasured }
measureElement(node) Imperative read of computed { width, height } from a yoga node
useCursor() Control terminal cursor visibility
usePaste(handler, opts?) Handle clipboard paste events
useStdin() Access stdin stream and raw mode control
useStdout() Write directly to stdout
useStderr() Write directly to stderr

App Lifecycle

import { createApp } from "@vue-tui/runtime";

// Fire and forget (most common):
createApp(App).mount();

// Wait for the app to exit:
const app = createApp(App);
app.mount();
await app.waitUntilExit();

// Custom streams (for testing):
createApp(App).mount({ stdout, stdin, stderr });

License

MIT