@dealdeploy/skl 0.1.6 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/skills/opentui/SKILL.md +198 -0
- package/.agents/skills/opentui/references/animation/REFERENCE.md +431 -0
- package/.agents/skills/opentui/references/components/REFERENCE.md +143 -0
- package/.agents/skills/opentui/references/components/code-diff.md +496 -0
- package/.agents/skills/opentui/references/components/containers.md +412 -0
- package/.agents/skills/opentui/references/components/inputs.md +531 -0
- package/.agents/skills/opentui/references/components/text-display.md +384 -0
- package/.agents/skills/opentui/references/core/REFERENCE.md +145 -0
- package/.agents/skills/opentui/references/core/api.md +506 -0
- package/.agents/skills/opentui/references/core/configuration.md +166 -0
- package/.agents/skills/opentui/references/core/gotchas.md +393 -0
- package/.agents/skills/opentui/references/core/patterns.md +448 -0
- package/.agents/skills/opentui/references/keyboard/REFERENCE.md +511 -0
- package/.agents/skills/opentui/references/layout/REFERENCE.md +337 -0
- package/.agents/skills/opentui/references/layout/patterns.md +444 -0
- package/.agents/skills/opentui/references/react/REFERENCE.md +174 -0
- package/.agents/skills/opentui/references/react/api.md +435 -0
- package/.agents/skills/opentui/references/react/configuration.md +301 -0
- package/.agents/skills/opentui/references/react/gotchas.md +443 -0
- package/.agents/skills/opentui/references/react/patterns.md +501 -0
- package/.agents/skills/opentui/references/solid/REFERENCE.md +201 -0
- package/.agents/skills/opentui/references/solid/api.md +543 -0
- package/.agents/skills/opentui/references/solid/configuration.md +315 -0
- package/.agents/skills/opentui/references/solid/gotchas.md +415 -0
- package/.agents/skills/opentui/references/solid/patterns.md +558 -0
- package/.agents/skills/opentui/references/testing/REFERENCE.md +614 -0
- package/.claude/settings.local.json +11 -0
- package/.claude/skills/opentui/SKILL.md +198 -0
- package/.claude/skills/opentui/references/animation/REFERENCE.md +431 -0
- package/.claude/skills/opentui/references/components/REFERENCE.md +143 -0
- package/.claude/skills/opentui/references/components/code-diff.md +496 -0
- package/.claude/skills/opentui/references/components/containers.md +412 -0
- package/.claude/skills/opentui/references/components/inputs.md +531 -0
- package/.claude/skills/opentui/references/components/text-display.md +384 -0
- package/.claude/skills/opentui/references/core/REFERENCE.md +145 -0
- package/.claude/skills/opentui/references/core/api.md +506 -0
- package/.claude/skills/opentui/references/core/configuration.md +166 -0
- package/.claude/skills/opentui/references/core/gotchas.md +393 -0
- package/.claude/skills/opentui/references/core/patterns.md +448 -0
- package/.claude/skills/opentui/references/keyboard/REFERENCE.md +511 -0
- package/.claude/skills/opentui/references/layout/REFERENCE.md +337 -0
- package/.claude/skills/opentui/references/layout/patterns.md +444 -0
- package/.claude/skills/opentui/references/react/REFERENCE.md +174 -0
- package/.claude/skills/opentui/references/react/api.md +435 -0
- package/.claude/skills/opentui/references/react/configuration.md +301 -0
- package/.claude/skills/opentui/references/react/gotchas.md +443 -0
- package/.claude/skills/opentui/references/react/patterns.md +501 -0
- package/.claude/skills/opentui/references/solid/REFERENCE.md +201 -0
- package/.claude/skills/opentui/references/solid/api.md +543 -0
- package/.claude/skills/opentui/references/solid/configuration.md +315 -0
- package/.claude/skills/opentui/references/solid/gotchas.md +415 -0
- package/.claude/skills/opentui/references/solid/patterns.md +558 -0
- package/.claude/skills/opentui/references/testing/REFERENCE.md +614 -0
- package/index.ts +429 -86
- package/package.json +2 -1
- package/update.ts +87 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: opentui
|
|
3
|
+
description: Comprehensive OpenTUI skill for building terminal user interfaces. Covers the core imperative API, React reconciler, and Solid reconciler. Use for any TUI development task including components, layout, keyboard handling, animations, and testing.
|
|
4
|
+
metadata:
|
|
5
|
+
references: core, react, solid
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# OpenTUI Platform Skill
|
|
9
|
+
|
|
10
|
+
Consolidated skill for building terminal user interfaces with OpenTUI. Use decision trees below to find the right framework and components, then load detailed references.
|
|
11
|
+
|
|
12
|
+
## Critical Rules
|
|
13
|
+
|
|
14
|
+
**Follow these rules in all OpenTUI code:**
|
|
15
|
+
|
|
16
|
+
1. **Use `create-tui` for new projects.** See framework `REFERENCE.md` quick starts.
|
|
17
|
+
2. **`create-tui` options must come before arguments.** `bunx create-tui -t react my-app` works, `bunx create-tui my-app -t react` does NOT.
|
|
18
|
+
3. **Never call `process.exit()` directly.** Use `renderer.destroy()` (see `core/gotchas.md`).
|
|
19
|
+
4. **Text styling requires nested tags in React/Solid.** Use modifier elements, not props (see `components/text-display.md`).
|
|
20
|
+
|
|
21
|
+
## How to Use This Skill
|
|
22
|
+
|
|
23
|
+
### Reference File Structure
|
|
24
|
+
|
|
25
|
+
Framework references follow a 5-file pattern. Cross-cutting concepts are single-file guides.
|
|
26
|
+
|
|
27
|
+
Each framework in `./references/<framework>/` contains:
|
|
28
|
+
|
|
29
|
+
| File | Purpose | When to Read |
|
|
30
|
+
|------|---------|--------------|
|
|
31
|
+
| `REFERENCE.md` | Overview, when to use, quick start | **Always read first** |
|
|
32
|
+
| `api.md` | Runtime API, components, hooks | Writing code |
|
|
33
|
+
| `configuration.md` | Setup, tsconfig, bundling | Configuring a project |
|
|
34
|
+
| `patterns.md` | Common patterns, best practices | Implementation guidance |
|
|
35
|
+
| `gotchas.md` | Pitfalls, limitations, debugging | Troubleshooting |
|
|
36
|
+
|
|
37
|
+
Cross-cutting concepts in `./references/<concept>/` have `REFERENCE.md` as the entry point.
|
|
38
|
+
|
|
39
|
+
### Reading Order
|
|
40
|
+
|
|
41
|
+
1. Start with `REFERENCE.md` for your chosen framework
|
|
42
|
+
2. Then read additional files relevant to your task:
|
|
43
|
+
- Building components -> `api.md` + `components/<category>.md`
|
|
44
|
+
- Setting up project -> `configuration.md`
|
|
45
|
+
- Layout/positioning -> `layout/REFERENCE.md`
|
|
46
|
+
- Keyboard/input handling -> `keyboard/REFERENCE.md`
|
|
47
|
+
- Animations -> `animation/REFERENCE.md`
|
|
48
|
+
- Troubleshooting -> `gotchas.md` + `testing/REFERENCE.md`
|
|
49
|
+
|
|
50
|
+
### Example Paths
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
./references/react/REFERENCE.md # Start here for React
|
|
54
|
+
./references/react/api.md # React components and hooks
|
|
55
|
+
./references/solid/configuration.md # Solid project setup
|
|
56
|
+
./references/components/inputs.md # Input, Textarea, Select docs
|
|
57
|
+
./references/core/gotchas.md # Core debugging tips
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Runtime Notes
|
|
61
|
+
|
|
62
|
+
OpenTUI runs on Bun and uses Zig for native builds. Read `./references/core/gotchas.md` for runtime requirements and build guidance.
|
|
63
|
+
|
|
64
|
+
## Quick Decision Trees
|
|
65
|
+
|
|
66
|
+
### "Which framework should I use?"
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
Which framework?
|
|
70
|
+
├─ I want full control, maximum performance, no framework overhead
|
|
71
|
+
│ └─ core/ (imperative API)
|
|
72
|
+
├─ I know React, want familiar component patterns
|
|
73
|
+
│ └─ react/ (React reconciler)
|
|
74
|
+
├─ I want fine-grained reactivity, optimal re-renders
|
|
75
|
+
│ └─ solid/ (Solid reconciler)
|
|
76
|
+
└─ I'm building a library/framework on top of OpenTUI
|
|
77
|
+
└─ core/ (imperative API)
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### "I need to display content"
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
Display content?
|
|
84
|
+
├─ Plain or styled text -> components/text-display.md
|
|
85
|
+
├─ Container with borders/background -> components/containers.md
|
|
86
|
+
├─ Scrollable content area -> components/containers.md (scrollbox)
|
|
87
|
+
├─ ASCII art banner/title -> components/text-display.md (ascii-font)
|
|
88
|
+
├─ Code with syntax highlighting -> components/code-diff.md
|
|
89
|
+
├─ Diff viewer (unified/split) -> components/code-diff.md
|
|
90
|
+
├─ Line numbers with diagnostics -> components/code-diff.md
|
|
91
|
+
└─ Markdown content (streaming) -> components/code-diff.md (markdown)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### "I need user input"
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
User input?
|
|
98
|
+
├─ Single-line text field -> components/inputs.md (input)
|
|
99
|
+
├─ Multi-line text editor -> components/inputs.md (textarea)
|
|
100
|
+
├─ Select from a list (vertical) -> components/inputs.md (select)
|
|
101
|
+
├─ Tab-based selection (horizontal) -> components/inputs.md (tab-select)
|
|
102
|
+
└─ Custom keyboard shortcuts -> keyboard/REFERENCE.md
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### "I need layout/positioning"
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
Layout?
|
|
109
|
+
├─ Flexbox-style layouts (row, column, wrap) -> layout/REFERENCE.md
|
|
110
|
+
├─ Absolute positioning -> layout/patterns.md
|
|
111
|
+
├─ Responsive to terminal size -> layout/patterns.md
|
|
112
|
+
├─ Centering content -> layout/patterns.md
|
|
113
|
+
└─ Complex nested layouts -> layout/patterns.md
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### "I need animations"
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
Animations?
|
|
120
|
+
├─ Timeline-based animations -> animation/REFERENCE.md
|
|
121
|
+
├─ Easing functions -> animation/REFERENCE.md
|
|
122
|
+
├─ Property transitions -> animation/REFERENCE.md
|
|
123
|
+
└─ Looping animations -> animation/REFERENCE.md
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### "I need to handle input"
|
|
127
|
+
|
|
128
|
+
```
|
|
129
|
+
Input handling?
|
|
130
|
+
├─ Keyboard events (keypress, release) -> keyboard/REFERENCE.md
|
|
131
|
+
├─ Focus management -> keyboard/REFERENCE.md
|
|
132
|
+
├─ Paste events -> keyboard/REFERENCE.md
|
|
133
|
+
├─ Mouse events -> components/containers.md
|
|
134
|
+
└─ Text selection -> components/text-display.md
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### "I need to test my TUI"
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
Testing?
|
|
141
|
+
├─ Snapshot testing -> testing/REFERENCE.md
|
|
142
|
+
├─ Interaction testing -> testing/REFERENCE.md
|
|
143
|
+
├─ Test renderer setup -> testing/REFERENCE.md
|
|
144
|
+
└─ Debugging tests -> testing/REFERENCE.md
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### "I need to debug/troubleshoot"
|
|
148
|
+
|
|
149
|
+
```
|
|
150
|
+
Troubleshooting?
|
|
151
|
+
├─ Runtime errors, crashes -> <framework>/gotchas.md
|
|
152
|
+
├─ Layout issues -> layout/REFERENCE.md + layout/patterns.md
|
|
153
|
+
├─ Input/focus issues -> keyboard/REFERENCE.md
|
|
154
|
+
└─ Repro + regression tests -> testing/REFERENCE.md
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Troubleshooting Index
|
|
158
|
+
|
|
159
|
+
- Terminal cleanup, crashes -> `core/gotchas.md`
|
|
160
|
+
- Text styling not applying -> `components/text-display.md`
|
|
161
|
+
- Input focus/shortcuts -> `keyboard/REFERENCE.md`
|
|
162
|
+
- Layout misalignment -> `layout/REFERENCE.md`
|
|
163
|
+
- Flaky snapshots -> `testing/REFERENCE.md`
|
|
164
|
+
|
|
165
|
+
For component naming differences and text modifiers, see `components/REFERENCE.md`.
|
|
166
|
+
|
|
167
|
+
## Product Index
|
|
168
|
+
|
|
169
|
+
### Frameworks
|
|
170
|
+
| Framework | Entry File | Description |
|
|
171
|
+
|-----------|------------|-------------|
|
|
172
|
+
| Core | `./references/core/REFERENCE.md` | Imperative API, all primitives |
|
|
173
|
+
| React | `./references/react/REFERENCE.md` | React reconciler for declarative TUI |
|
|
174
|
+
| Solid | `./references/solid/REFERENCE.md` | SolidJS reconciler for declarative TUI |
|
|
175
|
+
|
|
176
|
+
### Cross-Cutting Concepts
|
|
177
|
+
| Concept | Entry File | Description |
|
|
178
|
+
|---------|------------|-------------|
|
|
179
|
+
| Layout | `./references/layout/REFERENCE.md` | Yoga/Flexbox layout system |
|
|
180
|
+
| Components | `./references/components/REFERENCE.md` | Component reference by category |
|
|
181
|
+
| Keyboard | `./references/keyboard/REFERENCE.md` | Keyboard input handling |
|
|
182
|
+
| Animation | `./references/animation/REFERENCE.md` | Timeline-based animations |
|
|
183
|
+
| Testing | `./references/testing/REFERENCE.md` | Test renderer and snapshots |
|
|
184
|
+
|
|
185
|
+
### Component Categories
|
|
186
|
+
| Category | Entry File | Components |
|
|
187
|
+
|----------|------------|------------|
|
|
188
|
+
| Text & Display | `./references/components/text-display.md` | text, ascii-font, styled text |
|
|
189
|
+
| Containers | `./references/components/containers.md` | box, scrollbox, borders |
|
|
190
|
+
| Inputs | `./references/components/inputs.md` | input, textarea, select, tab-select |
|
|
191
|
+
| Code & Diff | `./references/components/code-diff.md` | code, line-number, diff, markdown |
|
|
192
|
+
|
|
193
|
+
## Resources
|
|
194
|
+
|
|
195
|
+
**Repository**: https://github.com/anomalyco/opentui
|
|
196
|
+
**Core Docs**: https://github.com/anomalyco/opentui/tree/main/packages/core/docs
|
|
197
|
+
**Examples**: https://github.com/anomalyco/opentui/tree/main/packages/core/src/examples
|
|
198
|
+
**Awesome List**: https://github.com/msmps/awesome-opentui
|
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
# Animation System
|
|
2
|
+
|
|
3
|
+
OpenTUI provides a timeline-based animation system for smooth property transitions.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Animations in OpenTUI use:
|
|
8
|
+
- **Timeline**: Orchestrates multiple animations
|
|
9
|
+
- **Animation Engine**: Manages timelines and rendering
|
|
10
|
+
- **Easing Functions**: Control animation curves
|
|
11
|
+
|
|
12
|
+
## When to Use
|
|
13
|
+
|
|
14
|
+
Use this reference when you need timeline-driven animations, easing curves, or progressive transitions.
|
|
15
|
+
|
|
16
|
+
## Basic Usage
|
|
17
|
+
|
|
18
|
+
### React
|
|
19
|
+
|
|
20
|
+
```tsx
|
|
21
|
+
import { useTimeline } from "@opentui/react"
|
|
22
|
+
import { useEffect, useState } from "react"
|
|
23
|
+
|
|
24
|
+
function AnimatedBox() {
|
|
25
|
+
const [width, setWidth] = useState(0)
|
|
26
|
+
|
|
27
|
+
const timeline = useTimeline({
|
|
28
|
+
duration: 2000,
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
timeline.add(
|
|
33
|
+
{ width: 0 },
|
|
34
|
+
{
|
|
35
|
+
width: 50,
|
|
36
|
+
duration: 2000,
|
|
37
|
+
ease: "easeOutQuad",
|
|
38
|
+
onUpdate: (anim) => {
|
|
39
|
+
setWidth(Math.round(anim.targets[0].width))
|
|
40
|
+
},
|
|
41
|
+
}
|
|
42
|
+
)
|
|
43
|
+
}, [])
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<box
|
|
47
|
+
width={width}
|
|
48
|
+
height={3}
|
|
49
|
+
backgroundColor="#6a5acd"
|
|
50
|
+
/>
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Solid
|
|
56
|
+
|
|
57
|
+
```tsx
|
|
58
|
+
import { useTimeline } from "@opentui/solid"
|
|
59
|
+
import { createSignal, onMount } from "solid-js"
|
|
60
|
+
|
|
61
|
+
function AnimatedBox() {
|
|
62
|
+
const [width, setWidth] = createSignal(0)
|
|
63
|
+
|
|
64
|
+
const timeline = useTimeline({
|
|
65
|
+
duration: 2000,
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
onMount(() => {
|
|
69
|
+
timeline.add(
|
|
70
|
+
{ width: 0 },
|
|
71
|
+
{
|
|
72
|
+
width: 50,
|
|
73
|
+
duration: 2000,
|
|
74
|
+
ease: "easeOutQuad",
|
|
75
|
+
onUpdate: (anim) => {
|
|
76
|
+
setWidth(Math.round(anim.targets[0].width))
|
|
77
|
+
},
|
|
78
|
+
}
|
|
79
|
+
)
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
return (
|
|
83
|
+
<box
|
|
84
|
+
width={width()}
|
|
85
|
+
height={3}
|
|
86
|
+
backgroundColor="#6a5acd"
|
|
87
|
+
/>
|
|
88
|
+
)
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Core
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
import { createCliRenderer, Timeline, engine } from "@opentui/core"
|
|
96
|
+
|
|
97
|
+
const renderer = await createCliRenderer()
|
|
98
|
+
engine.attach(renderer)
|
|
99
|
+
|
|
100
|
+
const timeline = new Timeline({
|
|
101
|
+
duration: 2000,
|
|
102
|
+
autoplay: true,
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
timeline.add(
|
|
106
|
+
{ x: 0 },
|
|
107
|
+
{
|
|
108
|
+
x: 50,
|
|
109
|
+
duration: 2000,
|
|
110
|
+
ease: "easeOutQuad",
|
|
111
|
+
onUpdate: (anim) => {
|
|
112
|
+
box.setLeft(Math.round(anim.targets[0].x))
|
|
113
|
+
},
|
|
114
|
+
}
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
engine.addTimeline(timeline)
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Timeline Options
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
const timeline = useTimeline({
|
|
124
|
+
duration: 2000, // Total duration in ms
|
|
125
|
+
loop: false, // Loop the timeline
|
|
126
|
+
autoplay: true, // Start automatically
|
|
127
|
+
onComplete: () => {}, // Called when timeline completes
|
|
128
|
+
onPause: () => {}, // Called when timeline pauses
|
|
129
|
+
})
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Timeline Methods
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
// Add animation
|
|
136
|
+
timeline.add(target, properties, startTime?)
|
|
137
|
+
|
|
138
|
+
// Control playback
|
|
139
|
+
timeline.play() // Start/resume
|
|
140
|
+
timeline.pause() // Pause
|
|
141
|
+
timeline.restart() // Restart from beginning
|
|
142
|
+
|
|
143
|
+
// State
|
|
144
|
+
timeline.progress // Current progress (0-1)
|
|
145
|
+
timeline.duration // Total duration
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Animation Properties
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
timeline.add(
|
|
152
|
+
{ value: 0 }, // Target object with initial values
|
|
153
|
+
{
|
|
154
|
+
value: 100, // Final value
|
|
155
|
+
duration: 1000, // Animation duration in ms
|
|
156
|
+
ease: "linear", // Easing function
|
|
157
|
+
delay: 0, // Delay before starting
|
|
158
|
+
onUpdate: (anim) => {
|
|
159
|
+
// Called each frame
|
|
160
|
+
const current = anim.targets[0].value
|
|
161
|
+
},
|
|
162
|
+
onComplete: () => {
|
|
163
|
+
// Called when this animation completes
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
0 // Start time in timeline (optional)
|
|
167
|
+
)
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## Easing Functions
|
|
171
|
+
|
|
172
|
+
Available easing functions:
|
|
173
|
+
|
|
174
|
+
### Linear
|
|
175
|
+
|
|
176
|
+
| Name | Description |
|
|
177
|
+
|------|-------------|
|
|
178
|
+
| `linear` | Constant speed |
|
|
179
|
+
|
|
180
|
+
### Quad (Power of 2)
|
|
181
|
+
|
|
182
|
+
| Name | Description |
|
|
183
|
+
|------|-------------|
|
|
184
|
+
| `easeInQuad` | Slow start |
|
|
185
|
+
| `easeOutQuad` | Slow end |
|
|
186
|
+
| `easeInOutQuad` | Slow start and end |
|
|
187
|
+
|
|
188
|
+
### Cubic (Power of 3)
|
|
189
|
+
|
|
190
|
+
| Name | Description |
|
|
191
|
+
|------|-------------|
|
|
192
|
+
| `easeInCubic` | Slower start |
|
|
193
|
+
| `easeOutCubic` | Slower end |
|
|
194
|
+
| `easeInOutCubic` | Slower start and end |
|
|
195
|
+
|
|
196
|
+
### Quart (Power of 4)
|
|
197
|
+
|
|
198
|
+
| Name | Description |
|
|
199
|
+
|------|-------------|
|
|
200
|
+
| `easeInQuart` | Even slower start |
|
|
201
|
+
| `easeOutQuart` | Even slower end |
|
|
202
|
+
| `easeInOutQuart` | Even slower start and end |
|
|
203
|
+
|
|
204
|
+
### Expo (Exponential)
|
|
205
|
+
|
|
206
|
+
| Name | Description |
|
|
207
|
+
|------|-------------|
|
|
208
|
+
| `easeInExpo` | Exponential start |
|
|
209
|
+
| `easeOutExpo` | Exponential end |
|
|
210
|
+
| `easeInOutExpo` | Exponential start and end |
|
|
211
|
+
|
|
212
|
+
### Back (Overshoot)
|
|
213
|
+
|
|
214
|
+
| Name | Description |
|
|
215
|
+
|------|-------------|
|
|
216
|
+
| `easeInBack` | Pull back, then forward |
|
|
217
|
+
| `easeOutBack` | Overshoot, then settle |
|
|
218
|
+
| `easeInOutBack` | Both |
|
|
219
|
+
|
|
220
|
+
### Elastic
|
|
221
|
+
|
|
222
|
+
| Name | Description |
|
|
223
|
+
|------|-------------|
|
|
224
|
+
| `easeInElastic` | Elastic start |
|
|
225
|
+
| `easeOutElastic` | Elastic end (bouncy) |
|
|
226
|
+
| `easeInOutElastic` | Both |
|
|
227
|
+
|
|
228
|
+
### Bounce
|
|
229
|
+
|
|
230
|
+
| Name | Description |
|
|
231
|
+
|------|-------------|
|
|
232
|
+
| `easeInBounce` | Bounce at start |
|
|
233
|
+
| `easeOutBounce` | Bounce at end |
|
|
234
|
+
| `easeInOutBounce` | Both |
|
|
235
|
+
|
|
236
|
+
## Patterns
|
|
237
|
+
|
|
238
|
+
### Progress Bar
|
|
239
|
+
|
|
240
|
+
```tsx
|
|
241
|
+
function ProgressBar({ progress }: { progress: number }) {
|
|
242
|
+
const [width, setWidth] = useState(0)
|
|
243
|
+
const maxWidth = 50
|
|
244
|
+
|
|
245
|
+
const timeline = useTimeline()
|
|
246
|
+
|
|
247
|
+
useEffect(() => {
|
|
248
|
+
timeline.add(
|
|
249
|
+
{ value: width },
|
|
250
|
+
{
|
|
251
|
+
value: (progress / 100) * maxWidth,
|
|
252
|
+
duration: 300,
|
|
253
|
+
ease: "easeOutQuad",
|
|
254
|
+
onUpdate: (anim) => {
|
|
255
|
+
setWidth(Math.round(anim.targets[0].value))
|
|
256
|
+
},
|
|
257
|
+
}
|
|
258
|
+
)
|
|
259
|
+
}, [progress])
|
|
260
|
+
|
|
261
|
+
return (
|
|
262
|
+
<box flexDirection="column" gap={1}>
|
|
263
|
+
<text>Progress: {progress}%</text>
|
|
264
|
+
<box width={maxWidth} height={1} backgroundColor="#333">
|
|
265
|
+
<box width={width} height={1} backgroundColor="#00FF00" />
|
|
266
|
+
</box>
|
|
267
|
+
</box>
|
|
268
|
+
)
|
|
269
|
+
}
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### Fade In
|
|
273
|
+
|
|
274
|
+
```tsx
|
|
275
|
+
function FadeIn({ children }) {
|
|
276
|
+
const [opacity, setOpacity] = useState(0)
|
|
277
|
+
|
|
278
|
+
const timeline = useTimeline()
|
|
279
|
+
|
|
280
|
+
useEffect(() => {
|
|
281
|
+
timeline.add(
|
|
282
|
+
{ opacity: 0 },
|
|
283
|
+
{
|
|
284
|
+
opacity: 1,
|
|
285
|
+
duration: 500,
|
|
286
|
+
ease: "easeOutQuad",
|
|
287
|
+
onUpdate: (anim) => {
|
|
288
|
+
setOpacity(anim.targets[0].opacity)
|
|
289
|
+
},
|
|
290
|
+
}
|
|
291
|
+
)
|
|
292
|
+
}, [])
|
|
293
|
+
|
|
294
|
+
return (
|
|
295
|
+
<box style={{ opacity }}>
|
|
296
|
+
{children}
|
|
297
|
+
</box>
|
|
298
|
+
)
|
|
299
|
+
}
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### Looping Animation
|
|
303
|
+
|
|
304
|
+
```tsx
|
|
305
|
+
function Spinner() {
|
|
306
|
+
const [frame, setFrame] = useState(0)
|
|
307
|
+
const frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]
|
|
308
|
+
|
|
309
|
+
useEffect(() => {
|
|
310
|
+
const interval = setInterval(() => {
|
|
311
|
+
setFrame(f => (f + 1) % frames.length)
|
|
312
|
+
}, 80)
|
|
313
|
+
|
|
314
|
+
return () => clearInterval(interval)
|
|
315
|
+
}, [])
|
|
316
|
+
|
|
317
|
+
return <text>{frames[frame]} Loading...</text>
|
|
318
|
+
}
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
### Staggered Animation
|
|
322
|
+
|
|
323
|
+
```tsx
|
|
324
|
+
function StaggeredList({ items }) {
|
|
325
|
+
const [visibleCount, setVisibleCount] = useState(0)
|
|
326
|
+
|
|
327
|
+
useEffect(() => {
|
|
328
|
+
let count = 0
|
|
329
|
+
const interval = setInterval(() => {
|
|
330
|
+
count++
|
|
331
|
+
setVisibleCount(count)
|
|
332
|
+
if (count >= items.length) {
|
|
333
|
+
clearInterval(interval)
|
|
334
|
+
}
|
|
335
|
+
}, 100)
|
|
336
|
+
|
|
337
|
+
return () => clearInterval(interval)
|
|
338
|
+
}, [items.length])
|
|
339
|
+
|
|
340
|
+
return (
|
|
341
|
+
<box flexDirection="column">
|
|
342
|
+
{items.slice(0, visibleCount).map((item, i) => (
|
|
343
|
+
<text key={i}>{item}</text>
|
|
344
|
+
))}
|
|
345
|
+
</box>
|
|
346
|
+
)
|
|
347
|
+
}
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
### Slide In
|
|
351
|
+
|
|
352
|
+
```tsx
|
|
353
|
+
function SlideIn({ children, from = "left" }) {
|
|
354
|
+
const [offset, setOffset] = useState(from === "left" ? -20 : 20)
|
|
355
|
+
|
|
356
|
+
const timeline = useTimeline()
|
|
357
|
+
|
|
358
|
+
useEffect(() => {
|
|
359
|
+
timeline.add(
|
|
360
|
+
{ offset: from === "left" ? -20 : 20 },
|
|
361
|
+
{
|
|
362
|
+
offset: 0,
|
|
363
|
+
duration: 300,
|
|
364
|
+
ease: "easeOutCubic",
|
|
365
|
+
onUpdate: (anim) => {
|
|
366
|
+
setOffset(Math.round(anim.targets[0].offset))
|
|
367
|
+
},
|
|
368
|
+
}
|
|
369
|
+
)
|
|
370
|
+
}, [])
|
|
371
|
+
|
|
372
|
+
return (
|
|
373
|
+
<box position="relative" left={offset}>
|
|
374
|
+
{children}
|
|
375
|
+
</box>
|
|
376
|
+
)
|
|
377
|
+
}
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
## Performance Tips
|
|
381
|
+
|
|
382
|
+
### Batch Updates
|
|
383
|
+
|
|
384
|
+
Timeline automatically batches updates within the render loop.
|
|
385
|
+
|
|
386
|
+
### Use Integer Values
|
|
387
|
+
|
|
388
|
+
Round animated values for character-based positioning:
|
|
389
|
+
|
|
390
|
+
```typescript
|
|
391
|
+
onUpdate: (anim) => {
|
|
392
|
+
setX(Math.round(anim.targets[0].x))
|
|
393
|
+
}
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
### Clean Up Timelines
|
|
397
|
+
|
|
398
|
+
Hooks automatically clean up, but for core:
|
|
399
|
+
|
|
400
|
+
```typescript
|
|
401
|
+
// When done with timeline
|
|
402
|
+
engine.removeTimeline(timeline)
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
## Gotchas
|
|
406
|
+
|
|
407
|
+
### Terminal Refresh Rate
|
|
408
|
+
|
|
409
|
+
Terminal UIs typically refresh at 60 FPS max. Very fast animations may appear choppy.
|
|
410
|
+
|
|
411
|
+
### Character Grid
|
|
412
|
+
|
|
413
|
+
Animations are constrained to character cells. Sub-pixel positioning isn't possible.
|
|
414
|
+
|
|
415
|
+
### Cleanup in Effects
|
|
416
|
+
|
|
417
|
+
Always clean up intervals and timelines:
|
|
418
|
+
|
|
419
|
+
```tsx
|
|
420
|
+
useEffect(() => {
|
|
421
|
+
const interval = setInterval(...)
|
|
422
|
+
return () => clearInterval(interval)
|
|
423
|
+
}, [])
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
## See Also
|
|
427
|
+
|
|
428
|
+
- [React API](../react/api.md) - `useTimeline` hook reference
|
|
429
|
+
- [Solid API](../solid/api.md) - `useTimeline` hook reference
|
|
430
|
+
- [Core API](../core/api.md) - `AnimationEngine` and `Timeline` classes
|
|
431
|
+
- [Layout Patterns](../layout/patterns.md) - Animated positioning and transitions
|