
Ink
Render AI- or hand-authored JSON UI specs as interactive Ink terminal interfaces without rebuilding layouts in React for every change.
Overview
ink is an agent skill for the Build phase that maps @json-render/ink JSON specs to interactive Ink terminal component trees with catalogs, binding, and actions.
Install
npx skills add https://github.com/vercel-labs/json-render --skill inkWhat is this skill?
- Converts json-render specs into Ink component trees with data binding and dynamic props
- Ships standard component and action definitions plus Zod-validated custom catalog entries
- Supports visibility rules, slots, and action handlers for interactive terminal flows
- Pairs defineCatalog with defineRegistry so only custom widgets need explicit registration
- Designed for @json-render/ink when rendering AI-generated or stored JSON specs in the terminal
Adoption & trust: 737 installs on skills.sh; 15k GitHub stars; 3/3 security scanners passed (skills.sh audits).
What problem does it solve?
You have structured UI intent as JSON but lack a fast, typed path to render it as an interactive terminal app with Ink.
Who is it for?
Solo builders already on json-render who want terminal parity with web or AI-generated UI specs for CLIs and agent tools.
Skip if: Teams that only need static stdout logs or full TUI frameworks without JSON-driven specs and the json-render dependency chain.
When should I use this skill?
Working with @json-render/ink, building terminal UIs from JSON, creating terminal component catalogs, or rendering AI-generated specs in the terminal.
What do I get? / Deliverables
You get a catalog-plus-registry setup and Renderer wiring so specs render as bound, actionable terminal UIs ready to plug into your CLI or agent loop.
- Catalog definition with standard and custom Ink components and actions
- Registry mapping custom components to Ink render functions
- Runnable App wiring JSONUIProvider and Renderer to a spec
Recommended Skills
Journey fit
Terminal UI implementation sits in Build when you wire specs, catalogs, and registries into a runnable CLI or agent-facing interface. Frontend subphase fits because Ink composes component trees and bindings—the same mental model as UI work, adapted to the terminal.
How it compares
Use for JSON-spec terminal rendering with Ink—not raw Blessed/Inquirer scripts or unrelated React web json-render paths without the Ink package.
Common Questions / FAQ
Who is ink for?
Indie and solo developers building CLIs or agent surfaces who standardize on @json-render/ink and want catalog-driven terminal UIs from JSON.
When should I use ink?
During Build when integrating @json-render/ink, authoring terminal component catalogs, or rendering AI-generated JSON specs in the terminal.
Is ink safe to install?
Review the Security Audits panel on this Prism page and treat third-party @json-render/ink dependencies like any npm install before production use.
SKILL.md
READMESKILL.md - Ink
# @json-render/ink Ink terminal renderer that converts JSON specs into interactive terminal component trees with standard components, data binding, visibility, actions, and dynamic props. ## Quick Start ```typescript import { defineCatalog } from "@json-render/core"; import { schema } from "@json-render/ink/schema"; import { standardComponentDefinitions, standardActionDefinitions, } from "@json-render/ink/catalog"; import { defineRegistry, Renderer, type Components } from "@json-render/ink"; import { z } from "zod"; // Create catalog with standard + custom components const catalog = defineCatalog(schema, { components: { ...standardComponentDefinitions, CustomWidget: { props: z.object({ title: z.string() }), slots: [], description: "Custom widget", }, }, actions: standardActionDefinitions, }); // Register only custom components (standard ones are built-in) const { registry } = defineRegistry(catalog, { components: { CustomWidget: ({ props }) => <Text>{props.title}</Text>, } as Components<typeof catalog>, }); // Render function App({ spec }) { return ( <JSONUIProvider initialState={{}}> <Renderer spec={spec} registry={registry} /> </JSONUIProvider> ); } ``` ## Spec Structure (Flat Element Map) The Ink schema uses a flat element map with a root key: ```json { "root": "main", "elements": { "main": { "type": "Box", "props": { "flexDirection": "column", "padding": 1 }, "children": ["heading", "content"] }, "heading": { "type": "Heading", "props": { "text": "Dashboard", "level": "h1" }, "children": [] }, "content": { "type": "Text", "props": { "text": "Hello from the terminal!" }, "children": [] } } } ``` ## Standard Components ### Layout - `Box` - Flexbox layout container (like a terminal `<div>`). Use for grouping, spacing, borders, alignment. Default flexDirection is row. - `Text` - Text output with optional styling (color, bold, italic, etc.) - `Newline` - Inserts blank lines. Must be inside a Box with flexDirection column. - `Spacer` - Flexible empty space that expands along the main axis. ### Content - `Heading` - Section heading (h1: bold+underlined, h2: bold, h3: bold+dimmed, h4: dimmed) - `Divider` - Horizontal separator with optional centered title - `Badge` - Colored inline label (variants: default, info, success, warning, error) - `Spinner` - Animated loading spinner with optional label - `ProgressBar` - Horizontal progress bar (0-1) - `Sparkline` - Inline chart using Unicode block characters - `BarChart` - Horizontal bar chart with labels and values - `Table` - Tabular data with headers and rows - `List` - Bulleted or numbered list - `ListItem` - Structured list row with title, subtitle, leading/trailing text - `Card` - Bordered container with optional title - `KeyValue` - Key-value pair display - `Link` - Clickable URL with optional label - `StatusLine` - Status message with colored icon (info, success, warning, error) - `Markdown` - Renders markdown text with terminal styling ### Interactive - `TextInput` - Text input field (events: submit, change) - `Select` - Selection menu with arrow key navigation (events: change) - `MultiSelect` - Multi-selection with space to toggle (events: change, submit) - `ConfirmInput` - Yes/No confirmation prompt (events: confirm, deny) - `Tabs` - Tab bar navigation with left/right arrow keys (events: change) ## Visibility Conditions Use `visible` on elements to show/hide based on state. Syntax: `{ "$state": "/path" }`, `{ "$state": "/path", "eq": value }`, `{ "$state": "/path", "not": true }`, `{ "$and": [cond1, cond2] }` for AND, `{ "$or": [cond1, c