(null)
+
+ useEffect(() => {
+ async function load() {
+ try {
+ const response = await fetch("https://api.example.com/data")
+ const json = await response.json()
+ setData(json.items)
+ } catch (e) {
+ setError(e instanceof Error ? e.message : "Unknown error")
+ } finally {
+ setLoading(false)
+ }
+ }
+ load()
+ }, [])
+
+ if (loading) {
+ return Loading...
+ }
+
+ if (error) {
+ return Error: {error}
+ }
+
+ return (
+
+ {data?.map((item, i) => (
+ {item}
+ ))}
+
+ )
+}
+```
+
+## Animation Patterns
+
+### Simple Animations
+
+```tsx
+import { useState, useEffect } from "react"
+import { useTimeline } from "@opentui/react"
+
+function ProgressBar() {
+ const [progress, setProgress] = useState(0)
+
+ const timeline = useTimeline({ duration: 3000 })
+
+ useEffect(() => {
+ timeline.add(
+ { value: 0 },
+ {
+ value: 100,
+ duration: 3000,
+ ease: "linear",
+ onUpdate: (anim) => {
+ setProgress(Math.round(anim.targets[0].value))
+ },
+ }
+ )
+ }, [])
+
+ return (
+
+ Progress: {progress}%
+
+
+
+
+ )
+}
+```
+
+### Interval-based Updates
+
+```tsx
+function Clock() {
+ const [time, setTime] = useState(new Date())
+
+ useEffect(() => {
+ const interval = setInterval(() => {
+ setTime(new Date())
+ }, 1000)
+
+ return () => clearInterval(interval)
+ }, [])
+
+ return {time.toLocaleTimeString()}
+}
+```
+
+## Component Composition
+
+### Render Props
+
+```tsx
+function Focusable({
+ children
+}: {
+ children: (focused: boolean) => React.ReactNode
+}) {
+ const [focused, setFocused] = useState(false)
+
+ return (
+ setFocused(true)}
+ onMouseUp={() => setFocused(false)}
+ >
+ {children(focused)}
+
+ )
+}
+
+// Usage
+
+ {(focused) => (
+
+ {focused ? "Focused!" : "Click me"}
+
+ )}
+
+```
+
+### Higher-Order Components
+
+```tsx
+function withBorder(
+ Component: React.ComponentType
,
+ borderStyle: string = "single"
+) {
+ return function BorderedComponent(props: P) {
+ return (
+
+
+
+ )
+ }
+}
+
+// Usage
+const BorderedText = withBorder(({ content }: { content: string }) => (
+ {content}
+))
+
+
+```
diff --git a/.opencode/skill/opentui/references/solid/REFERENCE.md b/.opencode/skill/opentui/references/solid/REFERENCE.md
new file mode 100644
index 00000000..b6205915
--- /dev/null
+++ b/.opencode/skill/opentui/references/solid/REFERENCE.md
@@ -0,0 +1,201 @@
+# OpenTUI Solid (@opentui/solid)
+
+A SolidJS reconciler for building terminal user interfaces with fine-grained reactivity. Get optimal performance with Solid's signal-based approach.
+
+## Overview
+
+OpenTUI Solid provides:
+- **Custom reconciler**: Solid components render to OpenTUI renderables
+- **JSX intrinsics**: ``, ``, ``, etc.
+- **Hooks**: `useKeyboard`, `useRenderer`, `useTimeline`, etc.
+- **Fine-grained reactivity**: Only what changes re-renders
+- **Portal & Dynamic**: Advanced composition primitives
+
+## When to Use Solid
+
+Use the Solid reconciler when:
+- You want optimal re-rendering performance
+- You prefer signal-based reactivity
+- You need fine-grained control over updates
+- Building performance-critical applications
+- You already know SolidJS
+
+## When NOT to Use Solid
+
+| Scenario | Use Instead |
+|----------|-------------|
+| Team knows React, not Solid | `@opentui/react` |
+| Maximum control needed | `@opentui/core` |
+| Smallest bundle size | `@opentui/core` |
+| Building a framework/library | `@opentui/core` |
+
+## Quick Start
+
+```bash
+bunx create-tui@latest -t solid my-app
+cd my-app && bun install
+```
+
+The CLI creates the `my-app` directory for you - it must **not already exist**.
+
+Options: `--no-git` (skip git init), `--no-install` (skip bun install)
+
+**Agent guidance**: Always use autonomous mode with `-t ` flag. Never use interactive mode (`bunx create-tui@latest my-app` without `-t`) as it requires user prompts that agents cannot respond to.
+
+Or manually:
+
+```bash
+bun install @opentui/solid @opentui/core solid-js
+```
+
+```tsx
+import { render } from "@opentui/solid"
+import { createSignal } from "solid-js"
+
+function App() {
+ const [count, setCount] = createSignal(0)
+
+ return (
+
+ Count: {count()}
+ setCount(c => c + 1)}
+ >
+ Click me!
+
+
+ )
+}
+
+render(() => )
+```
+
+## Core Concepts
+
+### Signals
+
+Solid uses signals for reactive state:
+
+```tsx
+import { createSignal, createEffect } from "solid-js"
+
+function Counter() {
+ const [count, setCount] = createSignal(0)
+
+ // Effect runs when count changes
+ createEffect(() => {
+ console.log("Count is now:", count())
+ })
+
+ return Count: {count()}
+}
+```
+
+### JSX Elements
+
+Solid maps JSX intrinsic elements to OpenTUI renderables:
+
+```tsx
+// Note: Some use underscores (Solid convention)
+Hello // TextRenderable
+Content // BoxRenderable
+ // InputRenderable
+ // SelectRenderable
+ // TabSelectRenderable (underscore!)
+ // ASCIIFontRenderable (underscore!)
+ // LineNumberRenderable (underscore!)
+```
+
+### Text Modifiers
+
+Inside ``, use modifier elements:
+
+```tsx
+
+ Bold, italic, and underlined
+ Colored text
+
+ New line with link
+
+```
+
+## Available Components
+
+### Layout & Display
+- `` - Styled text content
+- `` - Container with borders and layout
+- `` - Scrollable container
+- `` - ASCII art text (note underscore)
+
+### Input
+- `` - Single-line text input
+- `}
+ >
+ Content is visible!
+
+
+ )
+}
+```
+
+### Lists with For
+
+```tsx
+import { For, createSignal } from "solid-js"
+
+function TodoList() {
+ const [todos, setTodos] = createSignal([
+ { id: 1, text: "Learn Solid", done: false },
+ { id: 2, text: "Build TUI", done: false },
+ ])
+
+ const toggle = (id: number) => {
+ setTodos(todos =>
+ todos.map(t =>
+ t.id === id ? { ...t, done: !t.done } : t
+ )
+ )
+ }
+
+ return (
+
+
+ {(todo) => (
+ toggle(todo.id)}>
+
+ {todo.done ? "[x]" : "[ ]"} {todo.text}
+
+
+ )}
+
+
+ )
+}
+```
+
+### Index for Primitive Arrays
+
+Use `Index` when array items are primitives:
+
+```tsx
+import { Index, createSignal } from "solid-js"
+
+function StringList() {
+ const [items, setItems] = createSignal(["apple", "banana", "cherry"])
+
+ return (
+
+
+ {(item, index) => (
+ {index}: {item()}
+ )}
+
+
+ )
+}
+```
+
+### Switch/Match for Multiple Conditions
+
+```tsx
+import { Switch, Match, createSignal } from "solid-js"
+
+type Status = "idle" | "loading" | "success" | "error"
+
+function StatusDisplay() {
+ const [status, setStatus] = createSignal("idle")
+
+ return (
+
+
+ Ready
+
+
+ Loading...
+
+
+ Success!
+
+
+ Error occurred
+
+
+ )
+}
+```
+
+## Focus Management
+
+### Focus State
+
+```tsx
+import { createSignal } from "solid-js"
+import { useKeyboard } from "@opentui/solid"
+
+function FocusableForm() {
+ const [focusIndex, setFocusIndex] = createSignal(0)
+ const fields = ["name", "email", "message"]
+
+ useKeyboard((key) => {
+ if (key.name === "tab") {
+ setFocusIndex(i => (i + 1) % fields.length)
+ }
+ if (key.shift && key.name === "tab") {
+ setFocusIndex(i => (i - 1 + fields.length) % fields.length)
+ }
+ })
+
+ return (
+
+
+ {(field, i) => (
+
+ )}
+
+
+ )
+}
+```
+
+## Keyboard Navigation
+
+### Global Shortcuts
+
+```tsx
+import { useKeyboard } from "@opentui/solid"
+
+function App() {
+ const renderer = useRenderer()
+
+ useKeyboard((key) => {
+ if (key.name === "escape") {
+ renderer.destroy() // Never use process.exit() directly!
+ }
+
+ if (key.ctrl && key.name === "s") {
+ save()
+ }
+
+ // Vim-style
+ if (key.name === "j") moveDown()
+ if (key.name === "k") moveUp()
+ })
+
+ return {/* ... */}
+}
+```
+
+## Responsive Design
+
+### Terminal-size Responsive
+
+```tsx
+import { useTerminalDimensions } from "@opentui/solid"
+
+function ResponsiveLayout() {
+ const dims = useTerminalDimensions()
+
+ return (
+ 80 ? "row" : "column"}>
+
+ Panel 1
+
+
+ Panel 2
+
+
+ )
+}
+```
+
+## Async Data
+
+### Resources
+
+```tsx
+import { createResource, Suspense } from "solid-js"
+
+async function fetchData() {
+ const response = await fetch("https://api.example.com/data")
+ return response.json()
+}
+
+function DataDisplay() {
+ const [data] = createResource(fetchData)
+
+ return (
+ Loading...}>
+
+ {(items) => (
+
+ {(item) => {item.name}}
+
+ )}
+
+
+ )
+}
+```
+
+### Error Handling
+
+```tsx
+import { createResource, Show, ErrorBoundary } from "solid-js"
+
+function SafeDataDisplay() {
+ const [data] = createResource(fetchData)
+
+ return (
+ Error: {err.message}}>
+ Loading...