lively-mascot 0.2.0

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.
@@ -0,0 +1,357 @@
1
+ # ✦ lively-mascot
2
+
3
+ [English](README.md) · **简体中文**
4
+
5
+ > 电子宠物引擎:40 种状态表情 · 5 个角色 · 纯 SVG 驱动 · 零依赖 · 纯数据配置 · 即插即用。
6
+
7
+ 一套为聊天机器人、桌面宠物、网页插件及 AI 助手打造的表情系统。可选角色(🌱嫩芽 / 🐱小猫 / 🤖机器人 / 👻幽灵 / 🟢果冻),通过 `setEmotion(id)` 即可切换对应表情,每个表情自带独立的身体、附属件、四肢动画和面部表情。
8
+
9
+ **[在线预览](https://jingluoguo.github.io/lively-mascot/)**
10
+
11
+ ## 特性
12
+
13
+ <p align="center">
14
+ <img src="src/doc/zh/z1.png" width="370" alt="lively-mascot 演示图 1" />
15
+ <img src="src/doc/zh/z2.png" width="370" alt="lively-mascot 演示图 2" />
16
+ </p>
17
+
18
+ - **40 种状态表情**:覆盖生命周期(睡眠/待机)、情绪反应(开心/生气)、工作状态(思考/搜索)与扩展状态(无聊/紧张/灵光一现/等待)。
19
+ - **多角色内置**:随库附赠 5 个角色 —— **嫩芽**(植物系)、**小猫**(宠物系)、**机器人**(科技方块头+天线)、**幽灵**(圆顶浮空半透明、3 道波浪裙边)、**果冻**(Q 弹形变)。通过 `type` 选项切换,引擎层零改动。
20
+ - **全要素联动**:每个表情控制眼睛、嘴巴、腮红、身体、附属件(叶子/耳朵/尾巴)及四肢 —— 依据角色解剖结构提供独立动画通道。
21
+ - **配置驱动**:每个表情都是纯数据组合(动画 + 滤镜 + 行为参数),支持运行时注册新表情。
22
+ - **零依赖、零构建**:原生 JS,无框架依赖,按标准 `<script>` 标签顺序引入即可。
23
+ - **即插即用**:支持 Web Component `<lively-mascot>` 和函数式 API `createMascot`。
24
+ - **视线跟随**:眼睛平滑跟随指针;表情激活时自动暂停跟随,结束后平滑恢复。
25
+ - **主题化**:支持多实例主题切换(`setTheme`),所有样式基于 CSS 变量。
26
+
27
+ ## 快速开始
28
+
29
+ ### 方式 A — npm(应用项目推荐)
30
+
31
+ 安装 npm 包,并通过构建工具引入 SDK 和样式:
32
+
33
+ ```bash
34
+ npm install lively-mascot
35
+ ```
36
+
37
+ ```js
38
+ import { createMascot } from "lively-mascot";
39
+ import "lively-mascot/dist/lively-mascot.min.css";
40
+
41
+ const mascot = createMascot(document.getElementById("slot"), {
42
+ type: "sprout", size: 180
43
+ });
44
+ mascot.setEmotion("10");
45
+ ```
46
+
47
+ ### 方式 B — 一行 CDN 引入(免下载、免构建)
48
+
49
+ 整个引擎 + 5 个角色已打包成单文件放在 jsDelivr 上,只需两个标签:
50
+
51
+ ```html
52
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/jingluoguo/lively-mascot@master/dist/lively-mascot.min.css" />
53
+ <script src="https://cdn.jsdelivr.net/gh/jingluoguo/lively-mascot@master/dist/lively-mascot.min.js"></script>
54
+
55
+ <div id="slot"></div>
56
+ <script>
57
+ // 嫩芽(植物系吉祥物)— 默认
58
+ var s = LivelyMascot.createMascot(document.getElementById('slot'), {
59
+ type: 'sprout', size: 180
60
+ });
61
+
62
+ // 切换表情(所有角色共用同一套 API)
63
+ s.setEmotion('10'); // 开心
64
+ s.setEmotion('20'); // 思考中
65
+ s.clearEmotion(); // 恢复待机
66
+ </script>
67
+ ```
68
+
69
+ > 提示:把 `@master` 换成 `@latest` 可锁定版本,保证构建可复现。
70
+
71
+ ### 方式 C — 本地 / 模块化(分文件)
72
+
73
+ 如果你更想自己托管源码文件(例如接入自己的构建工具链):
74
+
75
+ ```html
76
+ <!-- 核心:引擎样式 + 表情数据 + SDK -->
77
+ <link rel="stylesheet" href="src/lively-mascot.css" />
78
+ <script src="src/core/emotions.js"></script>
79
+ <script src="src/core/rig.js"></script>
80
+ <script src="src/lively-mascot.js"></script>
81
+
82
+ <!-- 角色样式 + 渲染器(角色之间引入顺序无关) -->
83
+ <link rel="stylesheet" href="src/characters/sprout.css" />
84
+ <link rel="stylesheet" href="src/characters/cat.css" />
85
+ <link rel="stylesheet" href="src/characters/robot.css" />
86
+ <link rel="stylesheet" href="src/characters/ghost.css" />
87
+ <link rel="stylesheet" href="src/characters/jelly.css" />
88
+ <script src="src/characters/sprout.js"></script>
89
+ <script src="src/characters/cat.js"></script>
90
+ <script src="src/characters/robot.js"></script>
91
+ <script src="src/characters/ghost.js"></script>
92
+ <script src="src/characters/jelly.js"></script>
93
+
94
+ <div id="slot"></div>
95
+ <script>
96
+ // 嫩芽(植物系吉祥物)— 默认
97
+ var s = LivelyMascot.createMascot(document.getElementById('slot'), {
98
+ type: 'sprout', size: 180
99
+ });
100
+
101
+ // 小猫 / 机器人 / 幽灵 / 果冻 — 相同引擎,不同解剖结构
102
+ // var c = LivelyMascot.createMascot(document.getElementById('slot'), {
103
+ // type: 'cat', size: 180
104
+ // });
105
+
106
+ // 切换表情(所有角色共用同一套 API)
107
+ s.setEmotion('10'); // 开心
108
+ s.setEmotion('20'); // 思考中
109
+ s.clearEmotion(); // 恢复待机
110
+ </script>
111
+ ```
112
+
113
+ ### 方式 D — 在 React / Vue 中使用
114
+
115
+ npm 项目的 React/Vue 应用可直接导入 API 和样式:
116
+
117
+ ```js
118
+ import { createMascot } from "lively-mascot";
119
+ import "lively-mascot/dist/lively-mascot.min.css";
120
+ ```
121
+
122
+ 也可以通过 CDN 加载一次引擎脚本,它会注册全局变量 `LivelyMascot`:
123
+
124
+ ```html
125
+ <!-- 放在入口 HTML,全局只需一次 -->
126
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/jingluoguo/lively-mascot@master/dist/lively-mascot.min.css" />
127
+ <script src="https://cdn.jsdelivr.net/gh/jingluoguo/lively-mascot@master/dist/lively-mascot.min.js"></script>
128
+ ```
129
+
130
+ **React(命令式 + ref,便于用代码切换表情)**
131
+
132
+ ```jsx
133
+ import { useEffect, useRef } from "react";
134
+
135
+ export function Mascot({ type = "sprout", size = 180 }) {
136
+ const host = useRef(null);
137
+ const inst = useRef(null);
138
+
139
+ // 仅在 type / size 变化时重建实例
140
+ useEffect(() => {
141
+ inst.current = LivelyMascot.createMascot(host.current, { type, size });
142
+ return () => inst.current && inst.current.destroy();
143
+ }, [type, size]);
144
+
145
+ return (
146
+ <div>
147
+ <div ref={host} />
148
+ <button onClick={() => inst.current.setEmotion("10")}>开心</button>
149
+ <button onClick={() => inst.current.setEmotion("20")}>思考</button>
150
+ <button onClick={() => inst.current.clearEmotion()}>待机</button>
151
+ </div>
152
+ );
153
+ }
154
+ ```
155
+
156
+ **Vue 3(`<script setup>`)**
157
+
158
+ ```vue
159
+ <script setup>
160
+ import { ref, onMounted, onBeforeUnmount, watch } from "vue";
161
+
162
+ const props = defineProps({ type: { default: "sprout" }, size: { default: 180 } });
163
+ const el = ref(null);
164
+ let inst = null;
165
+
166
+ const mount = () =>
167
+ (inst = LivelyMascot.createMascot(el.value, { type: props.type, size: props.size }));
168
+ onMounted(mount);
169
+ onBeforeUnmount(() => inst && inst.destroy());
170
+ watch(() => [props.type, props.size], () => { inst && inst.destroy(); mount(); });
171
+
172
+ const set = (id) => inst && inst.setEmotion(id);
173
+ const reset = () => inst && inst.clearEmotion();
174
+ </script>
175
+
176
+ <template>
177
+ <div>
178
+ <div ref="el" />
179
+ <button @click="set('10')">开心</button>
180
+ <button @click="set('20')">思考</button>
181
+ <button @click="reset()">待机</button>
182
+ </div>
183
+ </template>
184
+ ```
185
+
186
+ > 小提示:若只要一个**静态**角色、不需要代码切表情,更省事的是先调用一次 `LivelyMascot.defineMascotElement()` 注册自定义标签,然后在模板里直接写标签即可(属性变化会自动重建)。
187
+
188
+ **纯 HTML(无需任何框架)**
189
+
190
+ ```html
191
+ <script>
192
+ LivelyMascot.defineMascotElement(); // 注册 <lively-mascot>,全局只需一次
193
+ </script>
194
+
195
+ <!-- 直接声明式使用,浏览器自动渲染并循环待机动画 -->
196
+ <lively-mascot type="cat" color="#ffd66b" size="180" view-mode="3d"></lively-mascot>
197
+ <lively-mascot type="ghost" color="#9be7ff" size="160"></lively-mascot>
198
+ ```
199
+
200
+ **React**
201
+
202
+ ```jsx
203
+ import { useEffect } from "react";
204
+
205
+ export function Mascot() {
206
+ useEffect(() => { LivelyMascot.defineMascotElement(); }, []);
207
+ return <lively-mascot type="cat" color="#ffd66b" size="180" />;
208
+ }
209
+ ```
210
+
211
+ **Vue 3**
212
+
213
+ ```vue
214
+ <script setup>
215
+ import { onMounted } from "vue";
216
+ onMounted(() => LivelyMascot.defineMascotElement());
217
+ </script>
218
+
219
+ <template>
220
+ <lively-mascot type="cat" color="#ffd66b" size="180" />
221
+ </template>
222
+ ```
223
+
224
+ > 注意:声明式标签响应 `type` / `color` / `size` / `view-mode` / `show-outline` 属性,改其中之一即自动重建;它拿不到实例、无法直接调 `setEmotion`。需要代码驱动切换表情或视图时,请改用上方的 `createMascot` 用法。
225
+
226
+ ## 从源码构建
227
+
228
+ ### npm / 构建工具
229
+
230
+ npm 包已提供 CommonJS、ESM 入口和 TypeScript 类型声明:
231
+
232
+ ```js
233
+ import { createMascot, emotions } from "lively-mascot";
234
+ // CommonJS:const { createMascot } = require("lively-mascot");
235
+ ```
236
+
237
+ 浏览器 CDN 场景仍使用 `dist/lively-mascot.min.js` 单文件。
238
+
239
+ `dist/` 里的单文件是由 `scripts/build-dist.mjs`(基于 esbuild)生成的,它会把引擎与 5 个角色的源码按顺序拼接并压缩:
240
+
241
+ ```bash
242
+ npm install # 安装 esbuild(唯一的构建依赖)
243
+ npm run build # 等价于:node scripts/build-dist.mjs
244
+ ```
245
+
246
+ 执行后会重新生成 `dist/lively-mascot.min.js` 和 `dist/lively-mascot.min.css`。只要改动了 `src/` 下任何文件,重跑一次即可。`dist/` 目录已纳入 npm 发布范围(`package.json` 的 `files`),并通过 jsDelivr 的 `@master` / `@vX.Y.Z` 引用对外提供。
247
+
248
+ ## API
249
+
250
+ ### `createMascot(target, options)`
251
+
252
+ | 选项 | 类型 | 默认值 | 描述 |
253
+ | -------------- | --------- | ---------- | ---------------- |
254
+ | `type` | `string` | `"sprout"` | 角色 ID |
255
+ | `color` | `string` | — | 身体颜色 |
256
+ | `outline` | `string` | — | 描边/眼睛颜色 |
257
+ | `accent` | `string` | — | 点缀色(腮红等) |
258
+ | `size` | `number` | `106` | 容器尺寸 px |
259
+ | `followCursor` | `boolean` | `true` | 是否跟随光标 |
260
+ | `viewMode` | `string` | `"3d"` | 视觉模式:`"2d"` 或 `"3d"`(轻量景深) |
261
+ | `outlineVisible` | `boolean` | `true` | 是否显示外轮廓 |
262
+
263
+ **返回实例**:`{ el, type, viewMode, setViewMode(mode), outlineVisible, setOutlineVisible(visible), setTheme, setEmotion(id), clearEmotion(), destroy() }`
264
+
265
+ 3D 是基于 CSS 的轻量景深效果,不依赖 WebGL。运行中的实例可通过 `setViewMode("2d")` / `setViewMode("3d")` 切换;声明式 `<lively-mascot>` 支持 `view-mode="2d"`(也兼容 `mode`)属性。
266
+
267
+ 设置 `outlineVisible: false` 或调用 `setOutlineVisible(false)` 可隐藏外轮廓线,同时保留眼睛和表情细节。声明式标签也支持 `show-outline="false"`。
268
+
269
+ 角色渲染器可以通过 rig API 注册和切换可替换的脸部配饰:`rig.registerFaceAccessory(name, element)` 与 `rig.setFaceAccessory(name)`。适合胡须、面罩、眼镜等模型细节。
270
+
271
+ ### 表情行为
272
+
273
+ 每个表情可配置以下行为:
274
+
275
+ | 字段 | 说明 |
276
+ | ------------ | ----------------------------------- |
277
+ | `bodyAnim` | 身体 CSS 动画 |
278
+ | `bodyFilter` | 身体滤镜(如变暗、变灰) |
279
+ | `leafAnim` | 叶子 CSS 动画 |
280
+ | `footAnim` | 脚部 CSS 动画 |
281
+ | `blink` | `false` 禁用眨眼,`"fast"` 快速眨眼 |
282
+ | `gaze` | `false` 暂停视线跟随 |
283
+
284
+ ### 表情 ID 映射
285
+
286
+ | 分组 | ID | 表情 |
287
+ | :----------- | :---- | :--------------------------------------------------------------------------------------------------------------------------- |
288
+ | **生命周期** | 00-09 | Sleep · Wake · Idle · Breathe · Ready · Pause · Refresh · LowBattery · Offline · Boot |
289
+ | **情绪反应** | 10-19 | Happy · Excited · Sad · Angry · Surprised · Shy · Love · Confused · Cool · Smug |
290
+ | **工作状态** | 20-31 | Thinking · Listening · Talking · Searching · Reading · Writing · Coding · Designing · Loading · Processing · Success · Error |
291
+ | **扩展状态** | 32-39 | Grateful · Retrying · Cancelled · Crying · Bored · Nervous · Eureka · Waiting |
292
+
293
+ ## 扩展指南
294
+
295
+ ### 注册新角色
296
+
297
+ 角色就是一个 `render(api, gazeEl)` 函数:绘制自身 DOM,并通过 rig 的 **api** 注册动点。`gazeEl` 是所有角色的挂载容器,把部件挂在这里,整个角色就会随身体姿态一起倾斜/转向。
298
+
299
+ ```js
300
+ function renderMyChar(rig, gazeEl) {
301
+ // 1. 身体 —— 必须挂到 gazeEl 并注册
302
+ var body = document.createElement('div');
303
+ body.className = 'lively-body lively-body--myChar';
304
+ rig.registerBody(body);
305
+
306
+ // 2. 面部 —— 复用共享、自带表情逻辑的脸部构建器
307
+ // (眼睛/瞳孔在内部已接线,无需手动 registerEye/registerPupil)
308
+ var face = LivelyMascot.buildFaceSvg(rig);
309
+ body.appendChild(face.wrap);
310
+
311
+ // 3. 可选顶部装饰(叶/耳/天线)→ registerLeaf
312
+ // 传 { useLeafAnim: false } 则由你自己的 CSS 驱动其动作。
313
+ // rig.registerLeaf(decoEl, { useLeafAnim: false });
314
+
315
+ // 4. 可选底部通道(脚/尾巴/裙边)→ registerFeet
316
+ // rig.registerFeet(feetEl);
317
+
318
+ gazeEl.appendChild(body);
319
+ }
320
+ LivelyMascot.registerCharacter('myChar', renderMyChar, 'My Char');
321
+ ```
322
+
323
+ ### 注册新表情
324
+
325
+ ```js
326
+ LivelyMascot.emotions['50'] = {
327
+ id: '50', name: 'Custom', group: 'custom', desc: '自定义',
328
+ bodyAnim: 'my-custom-anim 1s ease-in-out',
329
+ leafAnim: 'my-leaf-anim 1s ease-in-out',
330
+ footAnim: 'my-foot-anim 1s ease-in-out',
331
+ };
332
+ ```
333
+
334
+ ## 项目结构
335
+
336
+ ```
337
+ lively-mascot/
338
+ ├── index.html # 演示站点:Hero + 颜色/表情 + 角色切换
339
+ ├── src/
340
+ │ ├── core/
341
+ │ │ ├── emotions.js # 40 种表情定义(纯数据)
342
+ │ │ └── rig.js # 动画引擎(视线/眨眼/跳跃/情绪状态)
343
+ │ ├── characters/
344
+ │ │ ├── sprout.js / .css # 嫩芽 (植物:身体 + 叶 + 脚)
345
+ │ │ ├── cat.js / .css # 小猫 (身体 + 耳朵 + 尾巴 + 爪)
346
+ │ │ ├── robot.js / .css # 机器人(方块头 + 天线 + 机械脚)
347
+ │ │ ├── ghost.js / .css # 幽灵 (圆顶半透明身体 + 体内 3 道波浪裙边)
348
+ │ │ └── jelly.js / .css # 果冻 (半透明 Q 弹,无叶无脚)
349
+ │ ├── lively-mascot.js # 核心 SDK(角色注册表 + createMascot)
350
+ │ └── lively-mascot.css # 引擎层样式(结构 + 情绪选择器)
351
+ ├── package.json
352
+ └── README.md
353
+ ```
354
+
355
+ ## 许可证
356
+
357
+ MIT
@@ -0,0 +1 @@
1
+ module.exports = require("../src/lively-mascot.js");