diff --git a/AGENTS.md b/AGENTS.md
new file mode 100644
index 0000000..7ef7902
--- /dev/null
+++ b/AGENTS.md
@@ -0,0 +1,2 @@
+- 默认使用最新的C#语法糖简化代码的写法
+- C#的summary注释使用中文,并且行尾不添加类似 `。` `,` 之类的中文符号
diff --git a/TODO.md b/TODO.md
new file mode 100644
index 0000000..491a8de
--- /dev/null
+++ b/TODO.md
@@ -0,0 +1,65 @@
+# TODO
+
+## Success Criteria
+
+最终成功应该具备这些能力:
+
+- 能作为一个 C# TUI 类库被其他控制台程序引用。
+- 能启动和停止终端运行时,并在退出时恢复终端状态。
+- 能读取键盘输入,并把普通字符、方向键、组合键、回车、退格、Esc 等转换成统一事件。
+- 能处理粘贴输入,避免大段粘贴被拆成混乱的按键事件。
+- 能监听终端窗口尺寸变化,并触发重新布局和重新渲染。
+- 能用组件树描述界面,而不是让组件直接写控制台。
+- 能支持焦点管理,让当前焦点组件接收输入。
+- 能渲染基础组件,包括文本、容器、单行输入框、多行编辑器、选择列表和加载状态。
+- 能支持 overlay 弹层,用于菜单、弹窗、提示框和临时输入。
+- 能正确显示中文、emoji、ANSI 样式文本,并避免宽度计算错位。
+- 能进行全量渲染,保证最小版本可以稳定显示。
+- 能进行差分渲染,只刷新变化的行,减少闪烁。
+- 能提供一组示例程序,展示输入、编辑、列表选择、overlay 和动态刷新。
+- 能提供测试覆盖核心模块,包括输入解析、宽度计算、渲染输出和组件行为。
+- 能在 Windows Terminal / PowerShell 环境下稳定运行。
+
+## Architecture
+
+整体分成几个大模块:
+
+- STDIO 模块:负责读取键盘输入、监听窗口尺寸变化、管理 raw mode 和生命周期。
+- STDOUT 模块:负责向终端输出文本和 ANSI 控制序列。
+- Input 模块:负责把原始输入转换成统一的按键、粘贴、控制事件。
+- Runtime 模块:负责管理组件树、焦点、事件分发和渲染调度。
+- Renderer 模块:负责把组件输出同步到终端,先全量渲染,后续升级成差分渲染。
+- Text Width 模块:负责计算终端显示宽度,处理 ANSI、中文、emoji、截断和换行。
+- Component 模块:负责提供 Text、Input、Container、Box 等基础 UI 组件。
+- Overlay 模块:负责弹层显示、遮盖合成、焦点切换和恢复。
+- Example 模块:负责验证框架 API 和真实交互流程。
+- Test 模块:负责覆盖输入解析、渲染输出、宽度计算和组件行为。
+
+大致依赖方向:
+
+```text
+Example
+ -> Runtime
+ -> Component
+ -> Overlay
+ -> Renderer
+ -> STDOUT
+ -> Text Width
+ -> Input
+ -> STDIO
+```
+
+## Steps
+
+1. 定义核心模块边界:STDIO/STDOUT、输入解析、运行时、渲染器、组件、示例。
+2. 实现终端 IO 模块,统一封装控制台输入、输出、尺寸和生命周期。
+3. 实现输入解析模块,把原始按键和控制序列转换成框架事件。
+4. 实现组件运行时,管理组件树、焦点、事件分发和渲染请求。
+5. 实现基础渲染器,先完成全量渲染和清屏重画。
+6. 实现文本宽度模块,统一处理 ANSI、中文、emoji 和截断。
+7. 实现差分渲染器,只更新变化的终端行。
+8. 实现基础组件集,包括 Text、Input、Container 和 Box。
+9. 实现 Overlay 模块,支持弹层显示、遮盖合成和焦点切换。
+10. 实现高级组件集,包括 Editor、SelectList、Markdown 和 Loader。
+11. 完善示例程序,用真实场景验证输入、渲染、焦点和 overlay。
+12. 补齐测试和基准,覆盖输入解析、宽度计算、渲染输出和组件行为。
diff --git a/src/TinyTUI/Components/Container.cs b/src/TinyTUI/Components/Container.cs
new file mode 100644
index 0000000..379737c
--- /dev/null
+++ b/src/TinyTUI/Components/Container.cs
@@ -0,0 +1,58 @@
+namespace TinyTUI.Components;
+
+///
+/// 按添加顺序纵向渲染子组件的容器组件
+///
+public class Container : IComponent
+{
+ ///
+ /// 获取当前子组件列表
+ ///
+ public List Children { get; } = [];
+
+ ///
+ /// 向容器添加子组件
+ ///
+ public void Add(IComponent component)
+ {
+ Children.Add(component);
+ }
+
+ ///
+ /// 从容器移除子组件
+ ///
+ public void Remove(IComponent component)
+ {
+ Children.Remove(component);
+ }
+
+ ///
+ /// 移除容器中的所有子组件
+ ///
+ public void Clear()
+ {
+ Children.Clear();
+ }
+
+ ///
+ public virtual IReadOnlyList Render(int width)
+ {
+ var lines = new List();
+
+ foreach (var child in Children)
+ {
+ lines.AddRange(child.Render(width));
+ }
+
+ return lines;
+ }
+
+ ///
+ public virtual void Invalidate()
+ {
+ foreach (var child in Children)
+ {
+ child.Invalidate();
+ }
+ }
+}
diff --git a/src/TinyTUI/Components/IComponent.cs b/src/TinyTUI/Components/IComponent.cs
new file mode 100644
index 0000000..3d2f406
--- /dev/null
+++ b/src/TinyTUI/Components/IComponent.cs
@@ -0,0 +1,17 @@
+namespace TinyTUI.Components;
+
+///
+/// 定义 TUI 组件树中的最小可渲染单元
+///
+public interface IComponent
+{
+ ///
+ /// 按给定视口宽度将组件渲染为终端行
+ ///
+ IReadOnlyList Render(int width);
+
+ ///
+ /// 清除组件持有的渲染缓存状态
+ ///
+ void Invalidate() { }
+}
diff --git a/src/TinyTUI/Components/IInputComponent.cs b/src/TinyTUI/Components/IInputComponent.cs
new file mode 100644
index 0000000..8680034
--- /dev/null
+++ b/src/TinyTUI/Components/IInputComponent.cs
@@ -0,0 +1,14 @@
+using TinyTUI.Input;
+
+namespace TinyTUI.Components;
+
+///
+/// 定义聚焦后可以接收标准化输入事件的组件
+///
+public interface IInputComponent : IComponent
+{
+ ///
+ /// 处理运行时分发的标准化输入事件
+ ///
+ void HandleInput(TuiInputEvent input);
+}
diff --git a/src/TinyTUI/Input/IInputParser.cs b/src/TinyTUI/Input/IInputParser.cs
new file mode 100644
index 0000000..c61b9f8
--- /dev/null
+++ b/src/TinyTUI/Input/IInputParser.cs
@@ -0,0 +1,12 @@
+namespace TinyTUI.Input;
+
+///
+/// 将终端原始输入数据转换为标准化 TUI 输入事件
+///
+public interface IInputParser
+{
+ ///
+ /// 将一段原始输入解析为零个或多个标准化输入事件
+ ///
+ IReadOnlyList Parse(string data);
+}
diff --git a/src/TinyTUI/Input/TuiInputEvent.cs b/src/TinyTUI/Input/TuiInputEvent.cs
new file mode 100644
index 0000000..eb9aa35
--- /dev/null
+++ b/src/TinyTUI/Input/TuiInputEvent.cs
@@ -0,0 +1,32 @@
+namespace TinyTUI.Input;
+
+///
+/// 标识 TUI 运行时消费的高级输入事件类型
+///
+public enum TuiInputEventKind
+{
+ ///
+ /// 可打印文本输入
+ ///
+ Text,
+
+ ///
+ /// 非文本按键或组合键
+ ///
+ Key,
+
+ ///
+ /// 成组的粘贴输入
+ ///
+ Paste,
+
+ ///
+ /// 终端尺寸变化输入事件
+ ///
+ Resize,
+}
+
+///
+/// 表示原始终端数据解析后的标准化输入事件
+///
+public sealed record TuiInputEvent(TuiInputEventKind Kind, string Value);
diff --git a/src/TinyTUI/Overlay/IOverlayHandle.cs b/src/TinyTUI/Overlay/IOverlayHandle.cs
new file mode 100644
index 0000000..8d91c90
--- /dev/null
+++ b/src/TinyTUI/Overlay/IOverlayHandle.cs
@@ -0,0 +1,17 @@
+namespace TinyTUI.Overlay;
+
+///
+/// 控制已显示 overlay 的生命周期和可见性
+///
+public interface IOverlayHandle
+{
+ ///
+ /// 永久隐藏并移除 overlay
+ ///
+ void Hide();
+
+ ///
+ /// 临时切换 overlay 是否参与渲染和焦点处理
+ ///
+ void SetHidden(bool hidden);
+}
diff --git a/src/TinyTUI/Overlay/IOverlayManager.cs b/src/TinyTUI/Overlay/IOverlayManager.cs
new file mode 100644
index 0000000..bd4ff22
--- /dev/null
+++ b/src/TinyTUI/Overlay/IOverlayManager.cs
@@ -0,0 +1,24 @@
+using TinyTUI.Components;
+
+namespace TinyTUI.Overlay;
+
+///
+/// 管理渲染在基础组件树之上的临时组件
+///
+public interface IOverlayManager
+{
+ ///
+ /// 获取当前是否存在至少一个 overlay
+ ///
+ bool HasOverlay { get; }
+
+ ///
+ /// 显示 overlay 组件并返回控制句柄
+ ///
+ IOverlayHandle Show(IComponent component);
+
+ ///
+ /// 隐藏最上层 overlay
+ ///
+ void HideTop();
+}
diff --git a/src/TinyTUI/Rendering/IRenderer.cs b/src/TinyTUI/Rendering/IRenderer.cs
new file mode 100644
index 0000000..a2088f1
--- /dev/null
+++ b/src/TinyTUI/Rendering/IRenderer.cs
@@ -0,0 +1,17 @@
+namespace TinyTUI.Rendering;
+
+///
+/// 将渲染后的终端行同步到终端输出
+///
+public interface IRenderer
+{
+ ///
+ /// 将给定的逻辑终端行渲染到当前终端视口
+ ///
+ void Render(IReadOnlyList lines, TerminalSize size);
+
+ ///
+ /// 清除渲染器状态 让下一次渲染从干净基线开始
+ ///
+ void Reset();
+}
diff --git a/src/TinyTUI/Runtime/ITuiRuntime.cs b/src/TinyTUI/Runtime/ITuiRuntime.cs
new file mode 100644
index 0000000..1f6fa3c
--- /dev/null
+++ b/src/TinyTUI/Runtime/ITuiRuntime.cs
@@ -0,0 +1,39 @@
+using TinyTUI.Components;
+
+namespace TinyTUI.Runtime;
+
+///
+/// 协调组件状态 输入分发 渲染和终端生命周期
+///
+public interface ITuiRuntime : IDisposable
+{
+ ///
+ /// 向根组件树添加组件
+ ///
+ void Add(IComponent component);
+
+ ///
+ /// 从根组件树移除组件
+ ///
+ void Remove(IComponent component);
+
+ ///
+ /// 设置接收输入事件的组件
+ ///
+ void SetFocus(IComponent? component);
+
+ ///
+ /// 请求一次渲染
+ ///
+ void RequestRender();
+
+ ///
+ /// 启动 TUI 运行时
+ ///
+ void Start();
+
+ ///
+ /// 停止 TUI 运行时并恢复终端状态
+ ///
+ void Stop();
+}
diff --git a/src/TinyTUI/Stdio/ITerminalInput.cs b/src/TinyTUI/Stdio/ITerminalInput.cs
new file mode 100644
index 0000000..7b8d205
--- /dev/null
+++ b/src/TinyTUI/Stdio/ITerminalInput.cs
@@ -0,0 +1,32 @@
+namespace TinyTUI.Stdio;
+
+///
+/// 提供终端原始输入 尺寸变化通知和输入生命周期控制
+///
+public interface ITerminalInput : IDisposable
+{
+ ///
+ /// 获取最近一次记录的终端视口尺寸
+ ///
+ TerminalSize CurrentSize { get; }
+
+ ///
+ /// 在终端收到原始输入数据时触发
+ ///
+ event EventHandler? DataReceived;
+
+ ///
+ /// 在终端视口尺寸变化时触发
+ ///
+ event EventHandler? Resized;
+
+ ///
+ /// 开始读取终端输入和尺寸变化事件
+ ///
+ void Start();
+
+ ///
+ /// 停止读取终端输入并恢复输入相关的终端状态
+ ///
+ void Stop();
+}
diff --git a/src/TinyTUI/Stdout/ITerminalOutput.cs b/src/TinyTUI/Stdout/ITerminalOutput.cs
new file mode 100644
index 0000000..569b4e4
--- /dev/null
+++ b/src/TinyTUI/Stdout/ITerminalOutput.cs
@@ -0,0 +1,32 @@
+namespace TinyTUI.Stdout;
+
+///
+/// 提供渲染器和运行时使用的终端输出操作
+///
+public interface ITerminalOutput
+{
+ ///
+ /// 向输出流写入原始文本或终端控制序列
+ ///
+ void Write(string value);
+
+ ///
+ /// 将缓冲的输出刷新到终端
+ ///
+ void Flush();
+
+ ///
+ /// 清空可见终端屏幕
+ ///
+ void ClearScreen();
+
+ ///
+ /// 隐藏硬件光标
+ ///
+ void HideCursor();
+
+ ///
+ /// 显示硬件光标
+ ///
+ void ShowCursor();
+}
diff --git a/src/TinyTUI/TerminalSize.cs b/src/TinyTUI/TerminalSize.cs
new file mode 100644
index 0000000..7f23b37
--- /dev/null
+++ b/src/TinyTUI/TerminalSize.cs
@@ -0,0 +1,6 @@
+namespace TinyTUI;
+
+///
+/// 表示当前终端视口的字符单元尺寸
+///
+public readonly record struct TerminalSize(int Columns, int Rows);
diff --git a/src/TinyTUI/Text/ITextMeasurer.cs b/src/TinyTUI/Text/ITextMeasurer.cs
new file mode 100644
index 0000000..bc1a11d
--- /dev/null
+++ b/src/TinyTUI/Text/ITextMeasurer.cs
@@ -0,0 +1,17 @@
+namespace TinyTUI.Text;
+
+///
+/// 按终端字符单元宽度规则测量和裁剪字符串
+///
+public interface ITextMeasurer
+{
+ ///
+ /// 获取字符串占用的终端字符单元数量
+ ///
+ int GetWidth(string value);
+
+ ///
+ /// 裁剪字符串使其渲染宽度不超过给定字符单元宽度
+ ///
+ string Truncate(string value, int maxWidth);
+}
diff --git a/ttui.slnx b/ttui.slnx
index e128125..358266e 100644
--- a/ttui.slnx
+++ b/ttui.slnx
@@ -1,9 +1,11 @@
+
+