@mks2508/mks-ui
Blocks

Terminal

Full-featured terminal UI block with xterm.js and restty GPU renderers, ANSI log parsing, multi-session panels, and glassmorphism chrome.

Terminal Block

A production-grade terminal UI block with dual renderer support (xterm.js + restty GPU), log parsing engine, multi-session management, and premium glassmorphism panel chrome.

Blocks are high-level, ready-to-use components that compose primitives, UI components, and hooks into complete features — similar to Shadcn Blocks.

Import

import {
  TerminalPanel,
  TerminalLogsPanel,
  TerminalInteractivePanel,
  LogParserService,
  useTerminalWebSocket,
  useTerminalSettings,
  SYNTHWAVE_TERMINAL_THEME,
} from '@mks2508/mks-ui/react/blocks/Terminal';

Installation

The Terminal block requires optional peer dependencies depending on which renderer you use:

For xterm.js renderer

pnpm i @xterm/xterm @xterm/addon-fit @xterm/addon-web-links @xterm/addon-search @xterm/addon-unicode11

For restty GPU renderer

pnpm i restty

For log viewer (React mode)

pnpm i @tanstack/react-virtual shiki

Browser-Only

The Terminal block uses xterm.js and restty which require browser globals (window, self). You must load it client-side only:

// Next.js
import dynamic from 'next/dynamic';

const TerminalPanel = dynamic(
  () => import('@mks2508/mks-ui/react/blocks/Terminal').then(m => m.TerminalPanel),
  { ssr: false }
);

Basic Usage

Simple Terminal Panel

import { TerminalPanel } from '@mks2508/mks-ui/react/blocks/Terminal';

function App() {
  return (
    <TerminalPanel
      mode="interactive"
      wsUrl="ws://localhost:3100/api/terminal/session-1"
      title="Dev Server"
      onData={(data) => console.log('Input:', data)}
    />
  );
}

Log Viewer Panel

import {
  TerminalLogsPanel,
  TerminalPanelChrome,
} from '@mks2508/mks-ui/react/blocks/Terminal';

function LogViewer({ logs }) {
  return (
    <TerminalPanelChrome>
      <TerminalLogsPanel
        entries={logs}
        followCursor
        showLineNumbers
      />
    </TerminalPanelChrome>
  );
}

Interactive Terminal with xterm.js

import {
  TerminalInteractivePanel,
  useTerminalWebSocket,
} from '@mks2508/mks-ui/react/blocks/Terminal';

function InteractiveTerminal() {
  const { status, sendInput, sendResize } = useTerminalWebSocket({
    url: 'ws://localhost:3100/api/terminal/session-1',
    onOutput: (data) => terminalRef.current?.write(data),
  });

  return (
    <TerminalInteractivePanel
      session={{ id: '1', name: 'dev', isActive: true }}
      isConnected={status === 'connected'}
    />
  );
}

Restty GPU Terminal

import { TerminalRestty } from '@mks2508/mks-ui/react/blocks/Terminal';

function GPUTerminal() {
  return (
    <TerminalRestty
      wsUrl="ws://localhost:3100/api/terminal/session-1"
      fontSize={14}
      gpuRenderer="auto"
      onReady={(restty) => console.log('GPU terminal ready')}
      onResize={(cols, rows) => console.log(`${cols}x${rows}`)}
    />
  );
}

Custom PTY Transport

For custom WebSocket protocols, inject a transport factory:

import { TerminalRestty } from '@mks2508/mks-ui/react/blocks/Terminal';
import type { IPtyTransportFactory } from '@mks2508/mks-ui/react/blocks/Terminal';

// Your custom transport that bridges your WebSocket protocol
const createMyTransport: IPtyTransportFactory = () => ({
  connect: (options) => { /* ... */ },
  disconnect: () => { /* ... */ },
  sendInput: (data) => { /* ... */ return true; },
  resize: (cols, rows) => { /* ... */ return true; },
  isConnected: () => true,
  destroy: () => { /* ... */ },
});

<TerminalRestty
  createPtyTransport={createMyTransport}
  wsUrl="ws://localhost:3100/terminal"
/>

Log Parsing Engine

The Terminal block includes a framework-agnostic log parsing engine:

import {
  LogParserService,
  AnsiParser,
  LogLevelDetector,
  PersistentLogBuffer,
} from '@mks2508/mks-ui/react/blocks/Terminal';

// Parse a log line
const parser = new LogParserService();
const entry = parser.parseLine('[2024-01-15 10:30:00] INFO: Server started on port 3000');
// { level: 'info', message: 'Server started on port 3000', timestamp: '2024-01-15 10:30:00' }

// Parse ANSI escape codes
const ansi = new AnsiParser();
const result = ansi.parse('\x1b[31mError:\x1b[0m Something failed');
// Extracts styled spans with foreground/background colors

// Detect log levels
const detector = new LogLevelDetector();
const level = detector.detect('WARN: Memory usage high');
// { level: 'warn', confidence: 0.95 }

Theme System

import {
  SYNTHWAVE_TERMINAL_THEME,
  getTerminalTheme,
  xtermThemeToGhostty,
} from '@mks2508/mks-ui/react/blocks/Terminal';

// Use default Synthwave Dark theme
const theme = SYNTHWAVE_TERMINAL_THEME;

// Customize theme
const customTheme = getTerminalTheme({
  background: '#1a1a2e',
  foreground: '#ffffff',
  cursor: '#ff0080',
});

// Convert xterm theme to restty/Ghostty format
const ghosttyTheme = xtermThemeToGhostty(customTheme);

Settings Hook

import { useTerminalSettings } from '@mks2508/mks-ui/react/blocks/Terminal';

function Settings() {
  const { settings, setRenderer, setFontSize, resetToDefaults } = useTerminalSettings();

  return (
    <div>
      <p>Renderer: {settings.renderer}</p>
      <p>Font size: {settings.fontSize}px</p>
      <button onClick={() => setRenderer('restty')}>Use GPU</button>
      <button onClick={() => setFontSize(16)}>Size 16</button>
      <button onClick={resetToDefaults}>Reset</button>
    </div>
  );
}

Architecture

blocks/Terminal/
├── index.ts                    # Barrel export
├── TerminalPanel.tsx           # Main orchestrating component
├── Terminal.types.ts           # All types + IPtyTransportFactory
├── Terminal.theme.ts           # Synthwave theme + getTerminalTheme()
├── Terminal.theme.restty.ts    # xterm ↔ Ghostty theme bridge
├── Terminal.adapter.ts         # Adapter factory
├── XTermAdapter.ts             # xterm.js adapter
├── ResttyAdapter.ts            # restty GPU adapter
├── TerminalXterm.tsx           # React wrapper for xterm.js
├── TerminalRestty.tsx          # React wrapper for restty
├── components/                 # UI sub-components
│   ├── LogLineBadges.tsx       # Level/timestamp/tag badges
│   ├── SyntaxHighlight.tsx     # Syntax highlighted text
│   ├── TerminalLogBadge.tsx    # Log level colored badge
│   └── SpecializedSyntaxHighlighter.tsx
├── panel/                      # Panel chrome and views
│   ├── TerminalPanelChrome.tsx # Glassmorphic wrapper
│   ├── TerminalLogsPanel.tsx   # Log viewer (React mode)
│   ├── TerminalInteractivePanel.tsx  # Interactive terminal
│   ├── TerminalSessionTabs.tsx # Multi-session tabs
│   ├── TerminalSettingsPopover.tsx
│   └── ...
├── parsing/                    # Log parsing engine
│   ├── LogParserService.ts     # Main parser
│   ├── AnsiParser.ts           # ANSI escape codes
│   ├── LogLevelDetector.ts     # Level detection
│   ├── PersistentLogBuffer.ts  # Searchable buffer
│   └── ...
└── hooks/
    ├── useTerminalWebSocket.ts # WebSocket lifecycle
    └── useTerminalSettings.ts  # localStorage settings

Exported Types

TypeDescription
ITerminalThemeTerminal color theme (16 ANSI colors + background/foreground/cursor)
ITerminalAdapterPluggable renderer interface
ITerminalAdapterCapabilitiesRuntime feature detection
IPtyTransportCustom PTY transport interface
IPtyTransportFactoryFactory for creating custom transports
ITerminalRendererType'xterm' | 'restty'
ITerminalMode'interactive' | 'readonly'
TLogLevel'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal' | 'unknown'
IParsedLogEntryParsed log line with level, timestamp, content type

Panel Components

ComponentDescription
TerminalPanelMain component with toolbar, terminal, and status
TerminalPanelChromeGlassmorphic wrapper with noise texture
TerminalPanelHeadermacOS-style header with traffic lights
TerminalLogsPanelVirtualized log viewer with filtering
TerminalInteractivePanelInteractive terminal (auto-selects renderer)
TerminalSettingsPopoverSettings gear menu
TerminalThemeSelectorSearchable theme dropdown (458 themes)
LogLinesViewerVirtualized log line renderer

Hooks

HookDescription
useTerminalWebSocketWebSocket lifecycle with auto-reconnect
useTerminalSettingsGlobal settings with localStorage persistence