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.
package/CHANGELOG.md ADDED
@@ -0,0 +1,37 @@
1
+ # Changelog
2
+
3
+ [简体中文](CHANGELOG.zh-CN.md)
4
+
5
+ All notable changes to this project are documented here.
6
+
7
+ ## [0.2.0] - 2026-08-26
8
+
9
+ ### Added
10
+
11
+ - Added a static rendering mode with `animated: false` for non-animated previews and thumbnails.
12
+ - Added 2D and 3D view modes with a lightweight CSS depth treatment, material highlights, and cursor-driven posture.
13
+ - Added `outlineVisible` / `setOutlineVisible()` and declarative `show-outline` support.
14
+ - Added interchangeable face accessory registration through `registerFaceAccessory()` and `setFaceAccessory()`.
15
+ - Added npm CommonJS and ESM entry points, browser CDN metadata, and TypeScript declarations.
16
+ - Added bilingual demo preview images and expanded the interactive demo controls.
17
+
18
+ ### Changed
19
+
20
+ - Redesigned the Cat character with a charcoal palette, floating whiskers, updated facial details, and a rebuilt tail geometry.
21
+ - Improved 3D posture with pitch/yaw head turning, cursor-following highlights, and volume compensation at angled views.
22
+ - Moved the Cat tail behind the body in 3D mode and split its motion into layered animation channels.
23
+ - Reworked Loading to use a shared rotating ring and whole-rig bounce; softened global shadows and aligned foot filters with emotion state.
24
+ - Gated automatic hopping by emotion so it no longer interrupts unrelated states.
25
+ - Redrew the Bored expression and adjusted Sprout, Cat, and Robot bodies for upright breathing motion.
26
+ - Refined the Ghost hem with masking to remove visible seams.
27
+ - Updated README usage to document npm imports while retaining CDN, local, and framework integrations.
28
+
29
+ ### Fixed
30
+
31
+ - Fixed source CommonJS loading so emotion definitions are available instead of an empty registry.
32
+ - Fixed the npm entry to register all five bundled characters when loaded from Node/CommonJS.
33
+
34
+ ### Packaging
35
+
36
+ - Moved the build-only `esbuild` dependency to `devDependencies`.
37
+ - Added generated `dist/lively-mascot.cjs`, `dist/lively-mascot.mjs`, and `types/index.d.ts` to the published package.
@@ -0,0 +1,37 @@
1
+ # 更新日志
2
+
3
+ [English](CHANGELOG.md)
4
+
5
+ 这里记录项目的重要更新。
6
+
7
+ ## [0.2.0] - 2026-08-26
8
+
9
+ ### 新增
10
+
11
+ - 新增 `animated: false` 静态渲染模式,用于缩略图和非动画场景。
12
+ - 新增 2D / 3D 视图模式,包含轻量景深、材质高光和基于光标的姿态变化。
13
+ - 新增 `outlineVisible` / `setOutlineVisible()`,以及声明式 `show-outline` 属性。
14
+ - 新增通过 `registerFaceAccessory()` 和 `setFaceAccessory()` 注册、切换脸部配饰的能力。
15
+ - 新增 npm CommonJS、ESM 入口,浏览器 CDN 元数据和 TypeScript 类型声明。
16
+ - 新增中英文演示预览图,并扩展交互式演示控制项。
17
+
18
+ ### 变更
19
+
20
+ - 重绘 Cat 角色:炭灰配色、悬浮胡须、面部细节和尾巴几何结构全面更新。
21
+ - 改进 3D 姿态:支持 pitch/yaw 头部转向、随光标变化的高光和视角体积补偿。
22
+ - 3D 模式下将 Cat 尾巴移至身体后方,并拆分为分层动画通道。
23
+ - 重做 Loading 状态:使用共享旋转环和整 rig 弹跳;柔化全局阴影并同步脚掌滤镜与表情状态。
24
+ - 自动 Hop 改为按表情门控,避免打断无关状态。
25
+ - 重绘 Bored 表情,并调整 Sprout、Cat、Robot 的直立呼吸动画。
26
+ - 使用 mask 修复 Ghost 下摆可见接缝。
27
+ - README 改为优先介绍 npm 引入,同时保留 CDN、本地分文件和框架集成方式。
28
+
29
+ ### 修复
30
+
31
+ - 修复源码 CommonJS 加载时表情注册表为空的问题。
32
+ - 修复 npm 入口在 Node/CommonJS 环境下未自动注册 5 个内置角色的问题。
33
+
34
+ ### 发布
35
+
36
+ - 将构建所需的 `esbuild` 移至 `devDependencies`。
37
+ - 将 `dist/lively-mascot.cjs`、`dist/lively-mascot.mjs`、`types/index.d.ts` 纳入发布包。
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 lively-mascot contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,357 @@
1
+ # ✦ lively-mascot
2
+
3
+ **English** · [简体中文](README.zh-CN.md)
4
+
5
+ > Tamagotchi engine: 40 Emotions · 5 Characters · Pure SVG · Zero Dependencies · Data-Driven · Drop-in.
6
+
7
+ An expression system for chatbots, desktop pets, web widgets, and AI assistants. Pick a character (Sprout / Cat / Robot / Ghost / Jelly) and switch expressions with `setEmotion(id)` — each emotion drives independent body, accessory, limb, and facial animations.
8
+
9
+ **[Live Demo](https://jingluoguo.github.io/lively-mascot/)**
10
+
11
+ ## Features
12
+
13
+ <p align="center">
14
+ <img src="src/doc/en/e1.png" width="370" alt="lively-mascot demo 1" />
15
+ <img src="src/doc/en/e2.png" width="370" alt="lively-mascot demo 2" />
16
+ </p>
17
+
18
+ - **40 Status Emotions**: Covers lifecycle (sleep/idle), emotional reactions (happy/angry), work states (thinking/searching), and extended states (bored/nervous/eureka/waiting).
19
+ - **Multi-Character**: Ships with five bundled characters — **Sprout** (plant-styled), **Cat** (pet-styled), **Robot** (tech blocky head + antenna), **Ghost** (domed floating translucent with a 3-lobe wavy hem), and **Jelly** (bouncy blob). Swappable via `type` option with zero engine-level changes.
20
+ - **Full-Element Control**: Each emotion controls eyes, mouth, blush, body, accessories (leaf/ears/tail), and limbs — independent animation channels per character anatomy.
21
+ - **Configuration Driven**: Each emotion is a pure data combination (animations + filters + behavior params), supporting runtime registration.
22
+ - **Zero Dependencies, Zero Build**: Native JS, no framework, standard `<script>` tag order.
23
+ - **Plug-and-play**: Web Component `<lively-mascot>` and functional API `createMascot`.
24
+ - **Gaze Tracking**: Eyes follow the pointer smoothly; automatically pauses during emotions and resumes smoothly after.
25
+ - **Theming**: Multi-instance theme switching (`setTheme`), all styles via CSS variables.
26
+
27
+ ## Quick Start
28
+
29
+ ### Option A — npm (recommended for apps)
30
+
31
+ Install the package and import the SDK and stylesheet from your bundler:
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
+ ### Option B — One-line CDN (no download, no build)
48
+
49
+ The whole engine + all 5 characters ship as a single bundled file on jsDelivr. Just two tags:
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
+ // Sprout (plant mascot) — default
58
+ var s = LivelyMascot.createMascot(document.getElementById('slot'), {
59
+ type: 'sprout', size: 180
60
+ });
61
+
62
+ // Switch emotion (same API across all characters)
63
+ s.setEmotion('10'); // Happy
64
+ s.setEmotion('20'); // Thinking
65
+ s.clearEmotion(); // Back to idle
66
+ </script>
67
+ ```
68
+
69
+ > Tip: pin a version with `@latest` instead of `@master` for reproducible builds.
70
+
71
+ ### Option C — Local / modular (split files)
72
+
73
+ If you prefer to serve the source files yourself (e.g. bundle via your own toolchain):
74
+
75
+ ```html
76
+ <!-- Core: engine styles + emotions data + 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
+ <!-- Character styles + renderers (order doesn't matter among characters) -->
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
+ // Sprout (plant mascot) — default
97
+ var s = LivelyMascot.createMascot(document.getElementById('slot'), {
98
+ type: 'sprout', size: 180
99
+ });
100
+
101
+ // Cat / Robot / Ghost / Jelly — same engine, different anatomy
102
+ // var c = LivelyMascot.createMascot(c, {
103
+ // type: 'cat', size: 180
104
+ // });
105
+
106
+ // Switch emotion (same API across all characters)
107
+ s.setEmotion('10'); // Happy
108
+ s.setEmotion('20'); // Thinking
109
+ s.clearEmotion(); // Back to idle
110
+ </script>
111
+ ```
112
+
113
+ ### Option D — Using in React / Vue
114
+
115
+ For npm-based React/Vue apps, import the API and stylesheet directly:
116
+
117
+ ```js
118
+ import { createMascot } from "lively-mascot";
119
+ import "lively-mascot/dist/lively-mascot.min.css";
120
+ ```
121
+
122
+ Alternatively, load the engine script once via CDN; it registers the global `LivelyMascot`:
123
+
124
+ ```html
125
+ <!-- Add to your entry HTML once, app-wide -->
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 (imperative + ref, so you can drive emotions from code)**
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
+ // Re-create only when type / size change
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")}>Happy</button>
149
+ <button onClick={() => inst.current.setEmotion("20")}>Thinking</button>
150
+ <button onClick={() => inst.current.clearEmotion()}>Idle</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')">Happy</button>
180
+ <button @click="set('20')">Thinking</button>
181
+ <button @click="reset()">Idle</button>
182
+ </div>
183
+ </template>
184
+ ```
185
+
186
+ > Tip: if you only need a **static** mascot (no code-driven emotion switching), the easiest path is calling `LivelyMascot.defineMascotElement()` once, then just dropping the tag into your template (attribute changes auto-rebuild it).
187
+
188
+ **Plain HTML (no framework needed)**
189
+
190
+ ```html
191
+ <script>
192
+ LivelyMascot.defineMascotElement(); // register <lively-mascot>, once app-wide
193
+ </script>
194
+
195
+ <!-- Declarative usage; the browser renders and loops the idle animation -->
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
+ > Note: the declarative tag reacts to the `type` / `color` / `size` / `view-mode` / `show-outline` attributes and rebuilds when any of them change. It does not expose an instance, so you cannot call `setEmotion` directly. When you need code-driven emotion or view-mode switching, use the `createMascot` approach above.
225
+
226
+ ## Building from Source
227
+
228
+ ### npm / bundler
229
+
230
+ The package exposes CommonJS and ESM entry points, plus TypeScript declarations:
231
+
232
+ ```js
233
+ import { createMascot, emotions } from "lively-mascot";
234
+ // CommonJS: const { createMascot } = require("lively-mascot");
235
+ ```
236
+
237
+ The browser-only CDN bundle remains available at `dist/lively-mascot.min.js`.
238
+
239
+ The single-file bundles in `dist/` are generated by `scripts/build-dist.mjs` (esbuild), which concatenates the engine + all 5 characters and minifies them.
240
+
241
+ ```bash
242
+ npm install # install esbuild (the only build dependency)
243
+ npm run build # equivalent to: node scripts/build-dist.mjs
244
+ ```
245
+
246
+ This regenerates `dist/lively-mascot.min.js` and `dist/lively-mascot.min.css`. Run it whenever you edit anything under `src/`. The `dist/` folder is included in the npm package (`files` in `package.json`) and served via jsDelivr's `@master` / `@vX.Y.Z` references.
247
+
248
+ ## API
249
+
250
+ ### `createMascot(target, options)`
251
+
252
+ | Option | Type | Default | Description |
253
+ | -------------- | --------- | ---------- | ------------------------- |
254
+ | `type` | `string` | `"sprout"` | Character ID |
255
+ | `color` | `string` | — | Body color |
256
+ | `outline` | `string` | — | Outline / eye color |
257
+ | `accent` | `string` | — | Accent color (blush etc.) |
258
+ | `size` | `number` | `106` | Container size in px |
259
+ | `followCursor` | `boolean` | `true` | Enable gaze tracking |
260
+ | `viewMode` | `string` | `"3d"` | Visual mode: `"2d"` or `"3d"` (lightweight depth) |
261
+ | `outlineVisible` | `boolean` | `true` | Show the outer silhouette outline |
262
+
263
+ **Returns**: `{ el, type, viewMode, setViewMode(mode), outlineVisible, setOutlineVisible(visible), setTheme, setEmotion(id), clearEmotion(), destroy() }`
264
+
265
+ 3D is a lightweight CSS depth treatment with no WebGL dependency. Switch a live instance with `setViewMode("2d")` / `setViewMode("3d")`; declarative `<lively-mascot>` also accepts `view-mode="2d"` (with `mode` as an alias).
266
+
267
+ Set `outlineVisible: false` or call `setOutlineVisible(false)` to hide the outer silhouette ink while keeping facial details visible. The declarative element accepts `show-outline="false"` as well.
268
+
269
+ Character renderers can register interchangeable face decorations through the rig API: `rig.registerFaceAccessory(name, element)` and `rig.setFaceAccessory(name)`. This is useful for optional whiskers, masks, glasses, or other model-specific details.
270
+
271
+ ### Emotion Behaviors
272
+
273
+ Each emotion can configure:
274
+
275
+ | Field | Description |
276
+ | ------------ | ------------------------------------------------------ |
277
+ | `bodyAnim` | Body CSS animation |
278
+ | `bodyFilter` | Body filter (dim, grayscale, etc.) |
279
+ | `leafAnim` | Leaf CSS animation |
280
+ | `footAnim` | Feet CSS animation |
281
+ | `blink` | `false` to disable blinking, `"fast"` for rapid blinks |
282
+ | `gaze` | `false` to pause gaze tracking |
283
+
284
+ ### Emotion ID Mapping
285
+
286
+ | Group | ID | Emotions |
287
+ | :-------------- | :---- | :--------------------------------------------------------------------------------------------------------------------------- |
288
+ | **Lifecycle** | 00-09 | Sleep · Wake · Idle · Breathe · Ready · Pause · Refresh · LowBattery · Offline · Boot |
289
+ | **Reactions** | 10-19 | Happy · Excited · Sad · Angry · Surprised · Shy · Love · Confused · Cool · Smug |
290
+ | **Work States** | 20-31 | Thinking · Listening · Talking · Searching · Reading · Writing · Coding · Designing · Loading · Processing · Success · Error |
291
+ | **Extended** | 32-39 | Grateful · Retrying · Cancelled · Crying · Bored · Nervous · Eureka · Waiting |
292
+
293
+ ## Extension Guide
294
+
295
+ ### Registering a New Character
296
+
297
+ A character is just a `render(api, gazeEl)` function that draws its DOM and registers moving parts with the rig **api**. The gaze wrapper `gazeEl` is where every part is appended, so the whole character leans/turns together with the body posture.
298
+
299
+ ```js
300
+ function renderMyChar(rig, gazeEl) {
301
+ // 1. Body — must be appended to gazeEl and registered
302
+ var body = document.createElement('div');
303
+ body.className = 'lively-body lively-body--myChar';
304
+ rig.registerBody(body);
305
+
306
+ // 2. Face — reuse the shared, emotion-aware face builder
307
+ // (eyes / pupils are wired internally; do NOT register them by hand)
308
+ var face = LivelyMascot.buildFaceSvg(rig);
309
+ body.appendChild(face.wrap);
310
+
311
+ // 3. Optional top decoration (leaf/ears/antenna) → registerLeaf
312
+ // Pass { useLeafAnim: false } to drive its motion via your own CSS.
313
+ // rig.registerLeaf(decoEl, { useLeafAnim: false });
314
+
315
+ // 4. Optional bottom channel (feet / tail / hem) → registerFeet
316
+ // rig.registerFeet(feetEl);
317
+
318
+ gazeEl.appendChild(body);
319
+ }
320
+ LivelyMascot.registerCharacter('myChar', renderMyChar, 'My Char');
321
+ ```
322
+
323
+ ### Registering New Emotions
324
+
325
+ ```js
326
+ LivelyMascot.emotions['50'] = {
327
+ id: '50', name: 'Custom', group: 'custom', desc: 'Custom',
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
+ ## Project Structure
335
+
336
+ ```
337
+ lively-mascot/
338
+ ├── index.html # Demo: Hero + Color/Emotion + Character switcher
339
+ ├── src/
340
+ │ ├── core/
341
+ │ │ ├── emotions.js # 40 Emotion definitions (pure data)
342
+ │ │ └── rig.js # Animation engine (gaze / blink / hop / emotion state)
343
+ │ ├── characters/
344
+ │ │ ├── sprout.js / .css # Sprout (plant: body + leaf + feet)
345
+ │ │ ├── cat.js / .css # Cat (pet: body + ears + tail + paws)
346
+ │ │ ├── robot.js / .css # Robot (blocky head + antenna + mech feet)
347
+ │ │ ├── ghost.js / .css # Ghost (domed translucent body + in-body 3-lobe hem)
348
+ │ │ └── jelly.js / .css # Jelly (translucent bouncy blob, no leaf/feet)
349
+ │ ├── lively-mascot.js # Core SDK (character registry + createMascot)
350
+ │ └── lively-mascot.css # Engine-level styles (structure + emotion selectors)
351
+ ├── package.json
352
+ └── README.md
353
+ ```
354
+
355
+ ## License
356
+
357
+ MIT