grokbot_widget
纯 Flutter 的 GrokBot 动画头像控件:用 CustomPaint 绘制身体与双眼,无 WebView、无原生 SVG 依赖。
内置 25 种表情、18 种形态、39 种状态(表情池 + 节奏)、视线、转头球面投影、弹簧形变与眨眼。
| 项 | 说明 |
|---|---|
| 包名 | grokbot_widget |
| 版本 | 0.1.0 |
| SDK | Dart >=3.4.0 <4.0.0 · Flutter >=3.22.0 |
| 依赖 | 仅 flutter SDK |
快速开始
依赖
dependencies:
grokbot_widget:
path: ../GrokBot # 按实际路径调整
最小示例
import 'package:flutter/widgets.dart';
import 'package:grokbot_widget/grokbot_widget.dart';
class Avatar extends StatelessWidget {
const Avatar({super.key});
@override
Widget build(BuildContext context) {
return const GrokBot(
size: 160,
state: GrokBotState.thinking,
shape: GrokBotShape.blob,
autoExpression: true,
);
}
}
带控制器(眨眼 / 旋转 / 重置)
final controller = GrokBotController();
GrokBot(
controller: controller,
size: 200,
state: GrokBotState.idle,
shape: GrokBotShape.capsule,
gaze: const Offset(0.3, -0.1),
turn: 0.2, // 弧度
autoBlink: true,
autoExpression: true,
theme: GrokBotThemeData.dark,
)
// 任意时刻:
await controller.blink();
await controller.spin(turns: 1, duration: const Duration(milliseconds: 1200));
await controller.reset();
运行 example 与测试
flutter test
flutter analyze
cd example && flutter run
公开 API
import 'package:grokbot_widget/grokbot_widget.dart';
导出:GrokBot、GrokBotController、GrokBotState / GrokBotShape / GrokBotExpression、GrokBotThemeData。
GrokBot 属性
| 属性 | 类型 | 默认 | 说明 |
|---|---|---|---|
state |
GrokBotState |
idle |
选表情池与自动眨眼 / 换表情节奏 |
shape |
GrokBotShape |
blob |
身体轮廓 + 面部几何校正 |
expression |
GrokBotExpression? |
null |
非空时锁定表情;为 null 时由状态 / 自动切换决定 |
gaze |
Offset |
Offset.zero |
归一化视线,每轴 -1, 1,内部映射约 ±13.2 / ±8.4 |
turn |
double |
0 |
基础转头角,弧度;会与 spin 叠加 |
eyeScale |
double |
1 |
眼睛缩放倍率(须 > 0) |
springFrequency |
double |
7 |
表情切换弹簧自然频率 ω(须 > 0) |
autoBlink |
bool |
true |
是否按状态节奏自动眨眼 |
autoExpression |
bool |
false |
expression == null 时是否按状态池自动换表情 |
flipX |
bool |
false |
水平镜像 |
emphasis |
bool |
false |
眼睛再放大约 18% |
showGuides |
bool |
false |
绘制球面参考与眼睛质心 |
size |
double? |
null |
正方形边长;null 时取父约束最短边 |
theme |
GrokBotThemeData |
浅色默认 | 身体 / 眼睛等颜色 |
controller |
GrokBotController? |
null |
命令式眨眼、旋转、重置 |
semanticLabel |
String |
'GrokBot' |
无障碍标签 |
持久配置用 widget 属性;controller 只驱动短暂动画,不改写父组件传入的属性。
GrokBotController
一个 controller 同时只能挂到一个 GrokBot。
| 方法 | 说明 |
|---|---|
blink() |
触发一次 320ms 眨眼(42% 闭合 + 58% 睁开,最小高度 4%) |
spin({turns, duration}) |
转 turns 圈,默认 1 圈 / 1200ms;新 spin 会接替未完成的 |
reset() |
取消短暂动画,表情回到当前状态池第一项(或锁定的 expression) |
isAttached |
是否已挂到已挂载的 GrokBot |
GrokBotThemeData
| 字段 | 用途 |
|---|---|
bodyColor |
身体填充 |
eyeColor |
眼睛填充 |
guideColor |
辅助球面线 |
centroidColor |
质心标记 |
badgeColor / particleColor |
预留(当前不绘制) |
预设:const GrokBotThemeData()、GrokBotThemeData.dark。支持 copyWith / lerp。
状态 · 形态 · 表情
状态 GrokBotState(39)
每个状态绑定:表情池、表情节奏、眨眼节奏(可为「不自动眨眼」)。
| 分组 | 状态 |
|---|---|
| 生命周期 | sleeping waking idle listening thinking searching working |
| 反应 | excited surprised suspicious angry drowsy happy curious confused bored proud shy sad laughing scared playful celebrate |
| 代理形态 | orbit radar progress |
| 产品周期 | spawning humming loading dictating writing sending receiving uploading notifying alerting dragging bouncing poweringDown |
poweringDown 的展示名(sourceName)为 powering-down。
示例:idle → 表情 [0, 8],换表情 9–16s,眨眼 6–14s;sleeping → 不自动眨眼。
形态 GrokBotShape(18)
blob pebble bean egg squircle tablet capsule cylinder hex gem crystal wedge shield dome arch cloud teardrop leaf
每种包含:圆角轮廓、宽高比、面部校正(偏移 / 缩放 / 眼睛倍率)、转头是否压扁身体。
表情 GrokBotExpression(25)
expression00 … expression24。每个为双眼各 48 点的闭合轮廓;切换时用阻尼弹簧插值。
渲染与动画
state / timers → 弹簧 morph (≈120Hz 步进)
→ 48 点环插值
→ 视线 + 球面投影 (turn)
→ CustomPaint 绘制身体与双眼
- 视线:归一化
gaze→ 画布偏移(约 ±13.2 × ±8.4) - 转头:眼睛质心映射到球面经度,宽度随
cos压缩,转到脑后隐藏 - 眨眼:320ms,闭快于开
- Ticker:仅在 morph / blink / spin 活跃时运行
目录结构
grokbot_widget/
├── lib/
│ ├── grokbot_widget.dart # 库入口
│ └── src/
│ ├── grokbot.dart # GrokBot + Controller
│ ├── grokbot_painter.dart
│ ├── geometry.dart
│ ├── models.dart
│ ├── theme.dart
│ └── data/
│ ├── expression_data.dart
│ ├── shape_data.dart
│ └── state_data.dart
├── example/ # 演示 App
└── test/ # 单元 / Widget / Golden
设计约定
- 声明式配置 + 命令式瞬间 — 状态/形态/视线用属性;眨眼/转圈用
GrokBotController。 - 一个 Controller 对应一个 GrokBot — 重复 attach 会抛
StateError。 expression优先于自动切换 — 锁定表情时不跑自动换表情。- 零第三方绘制依赖 — 便于多端一致与 golden 回归。
版本
见 CHANGELOG.md。当前 0.1.0:表情、视线、转头、眨眼、状态、形态、主题,以及 blink / spin / reset。
Libraries
- grokbot_widget
- A pure Flutter animated GrokBot avatar.