Skip to content

Latest commit

 

History

History
1014 lines (761 loc) · 38.2 KB

File metadata and controls

1014 lines (761 loc) · 38.2 KB

Storm AI Widgets

15 components for AI agent terminal UIs: token streaming, approval workflows, cost tracking, and performance profiling.


Table of Contents

  1. ApprovalPrompt
  2. BlinkDot
  3. CommandBlock
  4. CommandDropdown
  5. ContextWindow
  6. CostTracker
  7. MessageBubble
  8. ModelBadge
  9. OperationTree
  10. PerformanceHUD
  11. ShimmerText
  12. StatusLine
  13. StreamingText
  14. SyntaxHighlight
  15. TokenStream

1. ApprovalPrompt

Tool execution approval dialog with risk levels, keyboard selection, and auto-deny timeout.

Renders a bordered prompt showing a tool name, risk level badge (colored by severity), optional parameter display, and a row of keyboard-selectable options. Supports countdown auto-deny when a timeout is set. Uses useInput for key handling.

Props

Name Type Default Description
tool string required Tool name displayed in the header.
risk string -- Risk level string (e.g. "high", "medium", "low"). Colors the border: red for high, amber for medium.
params Record<string, unknown> -- Tool parameters to display. Values are truncated at 60 characters.
options ApprovalOption[] [{key:"y", label:"approve"}, {key:"n", label:"deny"}, {key:"a", label:"always approve"}] Approval options with key, label, and color.
onSelect (key: string) => void required Called when the user presses an option key.
width number -- Terminal width hint (unused -- Divider auto-fills).
visible boolean true Whether the prompt captures keyboard input.
timeout number -- Auto-deny timeout in milliseconds. Displays a countdown and calls onSelect("n") when expired.
renderOption (option: ApprovalOption, index: number) => ReactNode -- Custom render for each approval option.
timeoutMessage (seconds: number) => string (s) => `Auto-deny in ${s}s` Custom countdown message formatter.

ApprovalOption

Name Type Description
key string Keyboard key to press.
label string Display text next to the key.
color string Color for the key character.

Usage

import { ApprovalPrompt } from "@orchetron/storm";

// Basic approval prompt
<ApprovalPrompt
  tool="execute_shell"
  risk="high"
  params={{ command: "rm -rf /tmp/cache", cwd: "/home/user" }}
  onSelect={(key) => {
    if (key === "y") runTool();
    else if (key === "a") alwaysApprove("execute_shell");
    else deny();
  }}
/>

// With auto-deny timeout
<ApprovalPrompt
  tool="file_write"
  risk="medium"
  timeout={30000}
  onSelect={handleApproval}
/>

// Custom options
<ApprovalPrompt
  tool="deploy"
  risk="high"
  options={[
    { key: "y", label: "deploy now", color: "#00FF00" },
    { key: "s", label: "stage first", color: "#FFAA00" },
    { key: "n", label: "cancel", color: "#FF0000" },
  ]}
  onSelect={handleDeploy}
/>

When to use

Any time an AI agent needs human confirmation before executing a tool -- file writes, shell commands, API calls, deployments. The risk level coloring provides instant visual severity assessment. The timeout auto-deny prevents blocking when running unattended.


2. BlinkDot

Status indicator dot that blinks based on operation state.

Renders a colored dot () whose behavior changes by state: blinks when running, stays solid for pending/streaming/completed/failed/cancelled. Uses imperative animation -- timer stops automatically for terminal states to avoid wasting CPU.

Props

Name Type Default Description
state DotState required Current state. One of: "pending", "running", "streaming", "completed", "failed", "cancelled".
interval number personality.animation.durationSlow Blink interval in milliseconds.
dotCharacter string "●" Character displayed when the dot is visible.
offCharacter string " " (space) Character displayed when the dot is hidden during blink.
renderDot (char: string, state: DotState) => ReactNode -- Custom render for the dot.

State Colors

State Color
pending colors.tool.pending
running colors.tool.running
streaming colors.tool.pending
completed colors.tool.completed
failed colors.tool.failed
cancelled colors.tool.cancelled

Usage

import { BlinkDot } from "@orchetron/storm";

// Running operation -- dot blinks
<BlinkDot state="running" />

// Completed -- solid green dot
<BlinkDot state="completed" />

// Custom character and speed
<BlinkDot state="running" dotCharacter="*" interval={300} />

When to use

Compact status indicator for individual operations, tool calls, or list items. Pairs well with OperationTree nodes or MessageBubble metadata. The automatic CPU optimization (timer stops for terminal states) makes it safe to render hundreds of these.


3. CommandBlock

Collapsible command output display with exit code badge and duration.

Renders a bordered block showing a command string (bold, with collapse toggle indicator), expandable output content, a colored exit code badge, and duration. Supports keyboard toggle (Enter/Space) and copy (c key) when focused.

Props

Name Type Default Description
command string required The command that was run.
output ReactNode -- Command output content.
exitCode number -- Exit code. 0 shows green checkmark, non-zero shows red X with code.
duration number -- Duration in milliseconds, displayed formatted (e.g. "1.2s").
collapsed boolean false Whether the output is collapsed.
onToggle () => void -- Toggle callback for collapse/expand.
isFocused boolean -- Whether this block receives keyboard input. Shows hint text when true.
onCopy (text: string) => void -- Called when user presses "c" while focused. Receives the output text.
ansiOutput boolean -- When true, passes output through without stripping ANSI codes.
renderHeader (command: string, exitCode?: number) => ReactNode -- Custom render for the command header row.
toggleIndicators { collapsed?: string; expanded?: string } { collapsed: "▸", expanded: "▾" } Override collapse/expand toggle characters.
exitCodeSymbols { success?: string; failure?: string } { success: "✓", failure: "✗" } Override exit code symbols.

Usage

import { CommandBlock } from "@orchetron/storm";

// Basic command block
<CommandBlock
  command="npm test"
  output="PASS src/index.test.ts\n42 tests passed"
  exitCode={0}
  duration={1234}
/>

// Collapsible with toggle
<CommandBlock
  command="git diff"
  output={diffOutput}
  collapsed={isCollapsed}
  onToggle={() => setCollapsed(!isCollapsed)}
  isFocused={true}
/>

// With ANSI color output
<CommandBlock
  command="ls --color"
  output={ansiColoredOutput}
  ansiOutput={true}
  exitCode={0}
/>

When to use

Displaying tool execution results in an AI chat interface. Each tool call that runs a command should wrap its output in a CommandBlock. The collapse feature keeps long outputs manageable, and the exit code badge provides instant pass/fail visibility.


4. CommandDropdown

Fuzzy-searchable command palette dropdown with keyboard navigation.

Renders a vertical list of items with a highlighted selection indicator. Features type-to-filter fuzzy matching (matched characters shown bold), scrollable window with overflow indicators, and full keyboard navigation (up/down/enter/escape/backspace).

Props

Name Type Default Description
items readonly CommandItem[] required Items to display. Each has name and description.
selectedIndex number 0 Currently selected index.
maxVisible number 6 Maximum visible items before scrolling. Shows ... overflow indicators.
highlightColor string colors.brand.primary Color for the selected item.
isFocused boolean -- Whether the dropdown captures keyboard input.
onSelect (item: CommandItem) => void -- Called when the user presses Enter on an item.
onSelectionChange (index: number) => void -- Called when keyboard navigation changes the selected index.
onClose () => void -- Called on second Escape press (first Escape clears filter).
selectionIndicator string "▸ " Override the selection indicator string.
renderItem (item: CommandItem, isSelected: boolean) => ReactNode -- Custom render for each dropdown item.

CommandItem

Name Type Description
name string Item name (searchable).
description string Description shown dim after the name.

Usage

import { CommandDropdown } from "@orchetron/storm";

const commands = [
  { name: "/help", description: "Show available commands" },
  { name: "/model", description: "Switch AI model" },
  { name: "/clear", description: "Clear conversation" },
  { name: "/export", description: "Export chat to file" },
];

<CommandDropdown
  items={commands}
  selectedIndex={selectedIdx}
  isFocused={true}
  onSelect={(item) => executeCommand(item.name)}
  onSelectionChange={(idx) => setSelectedIdx(idx)}
  onClose={() => hideDropdown()}
/>

When to use

Slash command palettes, autocomplete menus, or any searchable item picker in an AI agent interface. The fuzzy matching makes it fast to find commands without exact typing. Escape behavior (clear filter first, then close) follows standard UI conventions.


5. ContextWindow

Token/context usage visualization with segmented bar and optional sparkline history.

Renders a progress bar showing LLM context window usage. Supports a simple filled/empty bar or a segmented bar where each segment (system, user, tools, assistant) gets its own color. Includes percentage, token counts, remaining tokens, and an optional sparkline showing historical usage.

Props

Name Type Default Description
used number required Tokens currently used.
limit number required Maximum context window size.
breakdown Array<{ label: string; tokens: number; color?: string }> -- Segment breakdown for multi-color bar. Each segment gets its own color.
compact boolean -- When true, renders single-line bar only. When false with breakdown, shows bar + legend list.
barWidth number 24 Width of the bar in characters.
history number[] -- Historical token usage values. Renders a sparkline below the bar when provided.
renderBar (used: number, limit: number) => ReactNode -- Custom render for the entire context bar.
sparklineChars string[] ["▁","▂","▃","▄","▅","▆","▇","█"] Override sparkline block characters.

Color Behavior

The bar color changes based on fill level:

  • Green: usage <= 70%
  • Amber: usage 70-90%
  • Red: usage > 90%

Usage

import { ContextWindow } from "@orchetron/storm";

// Simple usage bar
<ContextWindow used={6000} limit={8192} />

// Segmented breakdown with legend
<ContextWindow
  used={6700}
  limit={8192}
  breakdown={[
    { label: "System", tokens: 1200 },
    { label: "User", tokens: 3400, color: "#4CAF50" },
    { label: "Assistant", tokens: 2100 },
  ]}
/>

// Compact with history sparkline
<ContextWindow
  used={4096}
  limit={8192}
  compact
  history={[1000, 2000, 3500, 4096, 3800, 4096]}
/>

When to use

Any AI chat interface where context window management matters. Shows users how much of the model's context is consumed, broken down by role. The sparkline history helps identify context growth patterns. Critical for long conversations approaching the token limit.


6. CostTracker

API cost tracking display with per-token pricing and color-coded spend levels.

Calculates and displays running cost based on input/output token counts and per-million pricing. Supports compact (single line) and expanded (breakdown table) modes. Cost color shifts from green to amber to red as spend increases.

Props

Name Type Default Description
inputTokens number required Number of input/prompt tokens consumed.
outputTokens number required Number of output/completion tokens consumed.
inputCostPer1M number 3 Cost per 1 million input tokens.
outputCostPer1M number 15 Cost per 1 million output tokens.
currency string "$" Currency symbol.
sessionTotal number 0 Pre-existing session cost to add to the running total.
compact boolean false Single line (true) vs expanded breakdown table (false).
renderCost (cost: number, currency: string) => ReactNode -- Custom render for the cost display.

Color Thresholds

Total Cost Color
< $0.10 Green
$0.10 - $0.99 Amber
>= $1.00 Red

Usage

import { CostTracker } from "@orchetron/storm";

// Expanded breakdown
<CostTracker inputTokens={50000} outputTokens={12000} />
// Renders:
//   Total: $0.33
//     Input:  50K tokens x $3/M = $0.15
//     Output: 12K tokens x $15/M = $0.18

// Compact single-line
<CostTracker inputTokens={50000} outputTokens={12000} compact />
// Renders: $0.33 (50K in x $3/M + 12K out x $15/M)

// Custom pricing (e.g. demo model)
<CostTracker
  inputTokens={100000}
  outputTokens={25000}
  inputCostPer1M={2.5}
  outputCostPer1M={10}
  sessionTotal={5.50}
/>

When to use

Status bars, session summaries, or cost dashboards in AI agent interfaces. Helps users stay aware of API spend in real time. The color-coded thresholds provide instant visual feedback when costs are climbing. Pair with StatusLine or TokenStream for a complete metrics bar.


7. MessageBubble

Chat message display with role-based icons, markdown rendering, timestamps, and action buttons.

Renders a message with a role-appropriate symbol on the left (auto-resolved from role or manually overridden), content area, optional metadata line, optional timestamp, and action hints with keyboard shortcuts. When markdown is true and children is a string, content is rendered through Markdown.

Props

Name Type Default Description
symbol string Role-based default Symbol displayed on the left. Overrides role default.
symbolColor string Role-based default Color for the symbol. Overrides role default.
role "user" | "assistant" | "system" | "tool" -- Message role. Auto-sets symbol and color (see table below).
children ReactNode required Message content. Strings are wrapped in <Text>.
meta string -- Metadata line rendered dim and italic below the message (e.g. timing, token counts).
timestamp string -- Timestamp rendered dim on the right side of the message.
markdown boolean -- When true and children is a string, renders through Markdown.
actions MessageAction[] -- Action hints displayed below the message with keyboard shortcuts.
isFocused boolean true Whether the bubble captures keyboard input for actions.
renderSymbol (symbol: string, color: string) => ReactNode -- Custom renderer for the role symbol.

Role Defaults

Role Symbol Color
user > Brand primary
assistant Brand primary
system Warning
tool Info

MessageAction

Name Type Description
label string Display label for the action.
key string Key the user presses to trigger.
onAction () => void Callback when the action key is pressed.

Usage

import { MessageBubble } from "@orchetron/storm";

// User message
<MessageBubble role="user">What files changed?</MessageBubble>

// Assistant message with markdown
<MessageBubble role="assistant" markdown>
  {"Here are the changes:\n\n```diff\n+ added line\n- removed line\n```"}
</MessageBubble>

// Tool result with metadata and actions
<MessageBubble
  role="tool"
  meta="12 tokens, 0.3s"
  timestamp="14:32"
  actions={[
    { key: "r", label: "retry", onAction: () => retryTool() },
    { key: "c", label: "copy", onAction: () => copyResult() },
  ]}
>
  File written successfully.
</MessageBubble>

// Custom symbol
<MessageBubble symbol="!" symbolColor="#FF0000">
  Warning: approaching token limit.
</MessageBubble>

When to use

The primary building block for AI chat interfaces. Every message in a conversation should be wrapped in a MessageBubble. The role system provides instant visual distinction between user input, AI responses, system messages, and tool outputs. Actions enable inline interactions without leaving the chat flow.


8. ModelBadge

AI model name and provider badge with capability indicators and context size.

Renders a diamond icon colored by provider, the model name in bold, optional capability tags (e.g. [vision], [tools], [code]), and max context window size. Provider colors are built-in with support for custom overrides.

Props

Name Type Default Description
model string required Model name (e.g. "my-model-v2").
provider string -- Provider name: "cloud", "local", "enterprise", "research", "community", "custom". Determines diamond color.
capabilities string[] -- Capability tags rendered as dim badges (e.g. ["vision", "tools", "code"]).
maxTokens number -- Max context window tokens. Formatted as K/M (e.g. 128000 -> "128K").
color string | number Provider-based Override color for the badge diamond.
renderModel (model: string, provider?: string) => ReactNode -- Custom render for the model display.
providerColors Record<string, string> -- Override or extend the built-in provider color map. Merged with defaults.

Built-in Provider Colors

Provider Color
cloud Brand primary (amber)
enterprise Green
research Blue
community Purple (#D18EE2)
custom Orange (#FF7000)
local Gray (#888888)
default Light gray (#AAAAAA)

Usage

import { ModelBadge } from "@orchetron/storm";

// Basic badge
<ModelBadge model="demo-model" />
// Renders: ◆ demo-model

// Full badge with all features
<ModelBadge
  model="demo-model"
  provider="cloud"
  capabilities={["vision", "tools", "code"]}
  maxTokens={200000}
/>
// Renders: ◆ demo-model [vision] [tools] [code] 200K

// Local model
<ModelBadge model="demo-local" provider="local" maxTokens={128000} />

// Custom provider colors
<ModelBadge
  model="my-model"
  provider="internal"
  providerColors={{ internal: "#FF5500" }}
/>

When to use

Status bars, message headers, model selectors, or anywhere the current model identity needs to be displayed. Pair with StatusLine for a persistent model indicator. The capability badges help users understand what the active model can do.


9. OperationTree

Hierarchical operation progress display with animated spinners and tree connectors.

Renders a tree of operations where each node has a status icon, label, optional detail text, and duration. Running nodes animate with a braille spinner using imperative requestRender(). Timer automatically starts/stops based on whether any nodes are in the running state. Supports arbitrary nesting depth with configurable tree connector characters.

Props

Name Type Default Description
nodes OpNode[] required Array of operation nodes (can be nested via children).
maxDepth number -- Maximum tree depth to render. Omit for unlimited.
showDuration boolean true Whether to show duration for nodes that have durationMs.
renderNode (node: OpNode, state: { depth: number }) => ReactNode -- Custom render for each operation node.
spinnerFrames string[] ["⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏"] Custom spinner animation frames.
spinnerInterval number 80 Spinner animation interval in milliseconds.
statusIcons Partial<Record<string, string>> { pending:"○", completed:"✓", failed:"✗", cancelled:"⊘" } Override status icons by status key. Running nodes use the spinner instead.
treeConnectors { branch?: string; last?: string; pipe?: string; space?: string } { branch:"├─", last:"└─", pipe:"│ ", space:" " } Override tree connector characters.

OpNode

Name Type Description
id string Unique identifier for the node.
label string Display label.
status "pending" | "running" | "completed" | "failed" | "cancelled" Current operation status.
children OpNode[] Nested child operations.
detail string Optional detail text shown dim after the label.
durationMs number Operation duration in milliseconds.

Usage

import { OperationTree } from "@orchetron/storm";

<OperationTree
  nodes={[
    {
      id: "plan",
      label: "Planning",
      status: "completed",
      durationMs: 450,
      children: [
        { id: "analyze", label: "Analyze request", status: "completed", durationMs: 200 },
        { id: "strategy", label: "Select strategy", status: "completed", durationMs: 250 },
      ],
    },
    {
      id: "execute",
      label: "Executing",
      status: "running",
      children: [
        { id: "read", label: "Read file", status: "completed", detail: "src/index.ts", durationMs: 50 },
        { id: "edit", label: "Apply edit", status: "running", detail: "line 42" },
        { id: "test", label: "Run tests", status: "pending" },
      ],
    },
  ]}
/>
// Renders:
// ├─ ✓ Planning (450ms)
// │  ├─ ✓ Analyze request (200ms)
// │  └─ ✓ Select strategy (250ms)
// └─ ⠋ Executing
//    ├─ ✓ Read file src/index.ts (50ms)
//    ├─ ⠙ Apply edit line 42
//    └─ ○ Run tests

When to use

Displaying multi-step AI agent workflows -- plan-and-execute patterns, tool chains, parallel operations. The animated spinners on running nodes give immediate visual feedback about what the agent is doing. Stale refs are automatically cleaned up when nodes leave the tree.


10. PerformanceHUD

Live FPS, render time, cell diff, and memory overlay for development profiling.

Developer tool that renders a compact bordered box showing real-time rendering metrics. Tracks FPS and render time history as mini sparklines. All metrics are color-coded: FPS green >30 / amber 15-30 / red <15; render time green <8ms / amber 8-16ms / red >16ms. Uses dim styling to minimize visual interference.

Props

Name Type Default Description
visible boolean true Whether the HUD is rendered.
renderTimeMs number 0 Render time of last frame in milliseconds.
fps number 0 Current frames per second.
componentCount number -- Number of components rendered.
cellsChanged number 0 Number of cells changed in last frame.
totalCells number 0 Total cells in buffer.
memoryMB number -- Memory usage in megabytes.
position "top-right" | "bottom-right" | "top-left" | "bottom-left" "top-right" Position hint (sets alignSelf for flex layout).
renderMetric (label: string, value: string, sparkline: string) => ReactNode -- Custom render for each metric row.
historySize number 20 Number of history samples to keep for sparklines.
title string "Storm HUD" HUD title text.

Usage

import { PerformanceHUD } from "@orchetron/storm";

<PerformanceHUD
  fps={58}
  renderTimeMs={2.3}
  cellsChanged={120}
  totalCells={4800}
  memoryMB={24.3}
  componentCount={42}
/>
// Renders:
// ╭─────────────────────╮
// │ Storm HUD           │
// │ FPS: 58 ▅▆▇█▇▆  RT: 2.3ms ▁▁▂▁▁ │
// │ Cells: 120/4.8K     │
// │ Mem: 24.3 MB        │
// │ Components: 42      │
// ╰─────────────────────╯

// Toggle visibility with a keyboard shortcut
<PerformanceHUD visible={showHud} fps={metrics.fps} renderTimeMs={metrics.rt} />

When to use

Development and debugging only. Add to your app's root layout to monitor rendering performance. The sparklines show trends over the last 20 frames. Useful for identifying slow renders, excessive cell diffs, or memory leaks during widget development.


11. ShimmerText

Loading shimmer animation -- a bright highlight window sweeps across text.

Renders text with a 3-character bright shimmer window that continuously sweeps from left to right. Uses imperative mutation for each of three text segments (before/shimmer/after) with requestRender(). Stops cleanly when active is set to false.

Props

Name Type Default Description
text string required The text to display with shimmer effect.
baseColor string colors.thinking.symbol Color of the non-shimmer text.
shimmerColor string colors.thinking.shimmer Color of the bright shimmer highlight.
interval number personality.animation.durationFast Speed of the shimmer sweep in milliseconds per step.
bold boolean -- Whether the entire text is bold.
active boolean true When false, stops the animation and shows static text.
shimmerWidth number 3 Width of the shimmer highlight window in characters.
renderSegment (text: string, isShimmer: boolean) => ReactNode -- Custom render for each text segment (before, shimmer, after).

Usage

import { ShimmerText } from "@orchetron/storm";

// Basic thinking indicator
<ShimmerText text="Thinking..." />

// Custom colors and speed
<ShimmerText
  text="Analyzing codebase..."
  baseColor="#666666"
  shimmerColor="#FFFFFF"
  interval={100}
  bold
/>

// Wider shimmer window
<ShimmerText text="Processing request" shimmerWidth={5} />

// Stop animation when done
<ShimmerText text="Analysis complete" active={isProcessing} />

When to use

"Thinking" indicators while waiting for AI responses. More visually engaging than a static "Loading..." message. The sweeping shimmer implies ongoing processing. Pair with BlinkDot for a combined status indicator, or use inside MessageBubble as the content while streaming hasn't started yet.


12. StatusLine

Bottom status bar with three layout modes: custom, built-in, and powerline segments.

Supports three modes: (1) Custom layout with arbitrary left/right React nodes, (2) Built-in layout with brand, model, tokens, turns, and extra key-value pairs, and (3) Powerline segments with colored segments and triangle separators. All text renders dim by default.

Props

Name Type Default Description
left ReactNode -- Left-side content (custom layout mode).
right ReactNode -- Right-side content (custom layout mode).
brand string -- Brand name shown with lightning prefix (built-in layout).
model string -- Model display name (built-in layout).
tokens number -- Token count, formatted with K/M suffixes (built-in layout).
turns number -- Turn count (built-in layout).
extra Record<string, string | number> -- Arbitrary key-value pairs rendered on the right (built-in layout).
backgroundColor string colors.surface.raised Background color for the status line.
segments StatusLineSegment[] -- Powerline-style segments with per-segment colors. Overrides all other layout modes.
renderSegment (segment: StatusLineSegment, index: number) => ReactNode -- Custom render for each powerline segment.
powerlineSeparator string "▶" Override the powerline separator character.

StatusLineSegment

Name Type Description
text string Text content of the segment.
color string Foreground color.
bg string Background color.

Usage

import { StatusLine } from "@orchetron/storm";

// Built-in layout
<StatusLine
  brand="Storm"
  model="demo-model"
  tokens={4200}
  turns={12}
  extra={{ cost: "$0.42" }}
/>
// Renders: ⚡ Storm demo-model          tokens:4.2K  turns:12  cost:$0.42

// Custom layout
<StatusLine
  left={<Text bold color="cyan">My App</Text>}
  right={<Text dim>Ready</Text>}
/>

// Powerline segments
<StatusLine segments={[
  { text: "NORMAL", color: "#000", bg: "#88C0D0" },
  { text: "main", color: "#FFF", bg: "#5E81AC" },
  { text: "src/index.ts", color: "#D8DEE9", bg: "#3B4252" },
]} />

When to use

The persistent bottom bar in any AI agent TUI. The built-in layout mode provides everything needed for an AI chat status bar with minimal configuration. Powerline mode is ideal for more customized, vim-style status bars.


13. StreamingText

Typewriter-style streaming text display with blinking cursor.

Renders text with an optional animated blinking cursor () at the end when streaming is active. Supports a typewriter "animate" mode that reveals text character by character at a configurable speed, with an onComplete callback. Cursor blink and typing animation both use imperative requestRender().

Props

Name Type Default Description
text string required Text content to display.
color string | number -- Text color.
cursor boolean true Whether to show a cursor when streaming.
streaming boolean -- Whether the text is currently streaming. Cursor only shows when both cursor and streaming are true.
animate boolean false When true, reveals text character by character (typewriter effect).
speed number 2 Characters revealed per tick when animate is true (~30fps ticks).
onComplete () => void -- Callback fired when all text has been revealed in animate mode.
cursorCharacter string "▊" Override the cursor character.
cursorBlinkInterval number 530 Cursor blink interval in milliseconds.
renderCursor (char: string, visible: boolean) => ReactNode -- Custom render for the cursor. Receives the cursor character and current visibility state.

Usage

import { StreamingText } from "@orchetron/storm";

// Live streaming with cursor
<StreamingText text={partialResponse} streaming={true} />

// Completed stream (no cursor)
<StreamingText text={fullResponse} streaming={false} />

// Typewriter reveal animation
<StreamingText
  text="Hello! I'm your AI assistant."
  animate
  speed={3}
  onComplete={() => setReady(true)}
/>

// Custom cursor
<StreamingText
  text={response}
  streaming={isStreaming}
  cursorCharacter="_"
  cursorBlinkInterval={400}
/>

When to use

Displaying AI model output as it streams in. The blinking cursor provides visual feedback that the model is still generating. The typewriter mode is useful for welcome messages or staged reveals. Both timers clean up automatically when streaming stops or the component unmounts.


14. SyntaxHighlight

Code syntax highlighting supporting 100 languages with multiline state tracking.

Regex-based syntax highlighter with zero external dependencies. Handles keywords, types, strings (including multiline and template literals), comments (line and block), numbers, operators, preprocessor directives, and HTML/XML tags. Supports Tree-sitter integration when available for higher accuracy. Extensible via registerLanguage().

Props

Name Type Default Description
code string required Source code to highlight.
language string -- Language identifier (e.g. "typescript", "python", "rust").
width number -- Width constraint for the output.

Supported Languages (100)

Systems: C, C++, Rust, Go, Zig, Nim, Odin, V, Crystal, Mojo

Application: Java, Kotlin, Swift, Scala, Dart, C#, F#, Objective-C

Scripting: JavaScript, TypeScript, Python, Ruby, PHP, Perl, Lua, R, Julia, MATLAB

Functional: Haskell, Elixir, Erlang, OCaml, Elm, PureScript, Lean, Idris, Agda, Coq, Roc, Unison, Gleam

Lisp family: Clojure, Common Lisp, Scheme, Racket, Fennel, Janet, Hy

AltJS: CoffeeScript, LiveScript, ReScript, Reason

Shell: Bash, Fish, PowerShell, Nix, Zsh

Web: HTML, CSS, SVG, Svelte, Vue, Astro, MDX

Data/Config: JSON, YAML, TOML, INI, XML, Protobuf, Prisma, EdgeQL

Infrastructure: Dockerfile, Terraform/HCL, Makefile, CMake, Puppet, Ansible, Helm, Bicep, TypeSpec

Query: SQL, GraphQL, Cypher

Academic: Prolog, Smalltalk, Fortran, COBOL, TCL

GPU/Hardware: GLSL, HLSL, Solidity, Verilog, VHDL, Assembly, WAT/WASM

Diagram: Mermaid, PlantUML

Other: LaTeX, Regex, Diff/Patch, Groovy, Jsonnet

Usage

import { SyntaxHighlight } from "@orchetron/storm";

<SyntaxHighlight
  code={`function greet(name: string): string {
  return \`Hello, \${name}!\`;
}`}
  language="typescript"
/>

// Python
<SyntaxHighlight code={'def factorial(n):\n  return 1 if n <= 1 else n * factorial(n-1)'} language="python" />

// Width-constrained
<SyntaxHighlight code={sourceCode} language="rust" width={80} />

Extending with Custom Languages

import { registerLanguage } from "@orchetron/storm";

registerLanguage("mylang", {
  keywords: new Set(["fn", "let", "mut", "if", "else", "return"]),
  typeKeywords: new Set(["int", "str", "bool"]),
  lineComment: "//",
  blockCommentStart: "/*",
  blockCommentEnd: "*/",
  stringDelimiters: ['"', "'"],
});

When to use

Inside code blocks, CommandBlock output, Markdown fenced code blocks (which use this internally), or anywhere source code needs to be displayed. The Markdown widget automatically delegates to SyntaxHighlight for fenced code blocks.


15. TokenStream

Live token count, speed, and context progress display.

A compact single-row widget showing model name, token counts (total, input, output), tokens-per-second speed (color-coded), and an optional progress bar when maxTokens is provided. Designed to be fed updated props from your streaming logic -- this is a display widget, not a stream processor.

Props

Name Type Default Description
tokens number required Total tokens so far.
inputTokens number -- Input/prompt tokens.
outputTokens number -- Output/completion tokens.
tokensPerSecond number -- Current speed in tokens per second. Only shown when streaming is true.
maxTokens number -- Context window limit. When provided, shows a progress bar.
model string -- Model name, shown dim with a separator.
streaming boolean -- Whether currently streaming. Controls speed display.
color string | number -- Override color for token counts.
renderMetric (label: string, value: string | number) => ReactNode -- Custom render for each metric (label + value pair).

Speed Color

Speed Color
>= 30 tok/s Green
< 30 tok/s Amber

Progress Bar Color

Usage Color
<= 70% Green
70-90% Amber
> 90% Red

Usage

import { TokenStream } from "@orchetron/storm";

// Basic streaming display
<TokenStream
  tokens={1650}
  inputTokens={1200}
  outputTokens={450}
  tokensPerSecond={42}
  model="demo-model"
  streaming={true}
/>
// Renders: demo-model . 1.7K tokens (1.2K in / 450 out) . 42 tok/s

// With context progress bar
<TokenStream
  tokens={6500}
  maxTokens={8192}
  model="demo-local"
  streaming={false}
/>
// Renders: demo-local . 6.5K tokens . ██████░░ 79%

// Minimal (just total)
<TokenStream tokens={500} />

When to use

Real-time streaming status displays during LLM inference. Place in a status bar or above the chat input to show live metrics. The speed indicator helps users gauge generation performance, and the progress bar warns when context is filling up. Pair with CostTracker for cost alongside performance.



Import Summary

All widgets are exported from the main entry point @orchetron/storm:

import {
  ApprovalPrompt,
  BlinkDot,
  CommandBlock,
  CommandDropdown,
  ContextWindow,
  CostTracker,
  MessageBubble,
  ModelBadge,
  OperationTree,
  PerformanceHUD,
  ShimmerText,
  StatusLine,
  StreamingText,
  SyntaxHighlight,
  TokenStream,
} from "@orchetron/storm";

Architecture Notes

  • Imperative animation pattern: All animated widgets (BlinkDot, ShimmerText, StreamingText, OperationTree) use ref mutation + requestRender() instead of React state. This is because Storm's custom React reconciler does not flush state updates the way React DOM does. See the pitfalls guide for details.

  • Plugin props: Every widget wraps its raw props through usePluginProps("WidgetName", rawProps), allowing plugins to intercept and modify any widget's props globally.

  • Personality system: Animated widgets read timing defaults from usePersonality(), which provides theme-aware animation durations (durationFast, durationSlow).

  • Cleanup: All timer-based widgets register cleanup via useCleanup() to prevent leaked intervals on unmount.

  • Memoization: All widgets are wrapped in React.memo() to minimize re-renders in Storm's reconciler.