agent-robot-avatar 0.5.2 → 0.7.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.
Files changed (43) hide show
  1. package/CHANGELOG.md +56 -7
  2. package/README.md +93 -16
  3. package/agent-robot-avatar-lite.js +44 -0
  4. package/agent-robot-avatar.js +2 -2
  5. package/index.d.ts +94 -17
  6. package/lite.d.ts +5 -0
  7. package/package.json +12 -5
  8. package/src/agent-robot-avatar-actions.js +17 -14
  9. package/src/agent-robot-avatar-core.js +5 -2
  10. package/src/agent-robot-avatar-gestures.js +9 -0
  11. package/src/agent-robot-avatar-runtime.js +58 -12
  12. package/src/agent-robot-avatar-skin-patterns.js +234 -0
  13. package/src/agent-robot-avatar-skins.js +256 -0
  14. package/src/agent-robot-avatar-version.js +1 -1
  15. package/src/agent-robot-avatar-waiting.js +30 -6
  16. package/src/skins/catalog.js +218 -0
  17. package/src/skins/collection-materials.js +118 -0
  18. package/src/skins/eyelids.js +32 -0
  19. package/src/skins/glaze-variants.js +29 -0
  20. package/src/skins/layered-texture.js +162 -0
  21. package/src/skins/material-data.js +111 -0
  22. package/src/skins/material-library.js +302 -0
  23. package/src/skins/metal-tint.js +11 -0
  24. package/src/skins/more-materials.js +69 -0
  25. package/src/skins/native.js +754 -0
  26. package/src/skins/paints.js +3 -0
  27. package/src/skins/revised-materials.js +44 -0
  28. package/src/skins/second-pass-materials.js +71 -0
  29. package/src/skins/soft-materials.js +111 -0
  30. package/src/skins/sports-materials.js +38 -0
  31. package/src/skins/wood-materials.js +68 -0
  32. package/assets/support/alipay.png +0 -0
  33. package/assets/support/wechat-pay.png +0 -0
  34. package/docs/README.de.md +0 -186
  35. package/docs/README.es.md +0 -186
  36. package/docs/README.fr.md +0 -186
  37. package/docs/README.ja.md +0 -186
  38. package/docs/README.ko.md +0 -186
  39. package/docs/README.pt.md +0 -186
  40. package/docs/README.ru.md +0 -186
  41. package/docs/README.zh-CN.md +0 -190
  42. package/docs/README.zh-TW.md +0 -186
  43. package/src/agent-robot-avatar-antenna-flash.js +0 -127
package/CHANGELOG.md CHANGED
@@ -4,27 +4,72 @@ All notable user-facing changes to Agent Robot Avatar are documented here.
4
4
 
5
5
  The project follows Semantic Versioning for public releases. Internal development build numbers are not part of the public version history.
6
6
 
7
- ## [Unreleased]
7
+ ## [0.7.0] - 2026-10-29
8
8
 
9
- ## [0.5.2] - 2026-10-06
9
+ ### Added
10
10
 
11
- ### Fixed
11
+ - 188 skins in 17 series. Pick one by number with `skin="301"` or `setSkin(301)`; `setSkin(null)` goes back to the flat color.
12
+ - Skin numbers are permanent: the series number plus two digits, so 305 is the fifth skin of series 3. New skins take the next free number, and numbers are never reused.
13
+ - Every skin works with every expression and gesture, and its light follows the pointer.
14
+ - `SKINS`, `SKIN_SERIES` and `SKIN_NAMES` list the skins, for building a skin picker.
15
+ - Skin code loads only when a page uses a skin. `loadSkins()` loads it in advance.
16
+ - `agent-robot-avatar/lite`: the same avatar without any skin code.
17
+ - The demo has a Skin Gallery and a page with every skin.
18
+
19
+ ## [0.6.0] - 2026-10-23
20
+
21
+ ### Upgrading from 0.5.x
22
+
23
+ Several actions are renamed after what the avatar does on screen, instead of the situation they were first written for. The old names keep working in 0.6 and print a one-time notice in the browser console; they stop working in 1.0. To upgrade, replace the old names in `play()` calls and in `action-state` or `face-state` listeners:
24
+
25
+ | Old name | New name | What it looks like |
26
+ | --- | --- | --- |
27
+ | `send` | `affirm` | A nod |
28
+ | `warning` | `wary` | Head turned, one eye close, a guarded up-and-down look |
29
+ | `error`, `system-error`, `connection-error` | `refuse` | A head shake |
30
+ | `blocked`, `policy-blocked` | `angry` | Lowered, glaring eyes |
31
+ | `wait` | `waiting-spin` (or `waiting`) | The default waiting spin |
32
+ | `failed`, `fail` | `failure` | |
33
+ | `verify`, `review` | `inspect` | |
34
+ | `slot` | `random` | |
35
+
36
+ `action-state` now reports `affirm`, `wary`, `angry` and `refuse`, and `face-state` reports `wary` and `refuse`. A shake reads as "no", so use `refuse` when the Agent cannot or will not do something, and `failure` when a task or connection fails. Antenna blinking is removed: `setAntennaFlash()` now does nothing and prints a one-time notice, and it is deleted in 1.0. Packages that depend on `^0.5.x` do not pick up 0.6 automatically.
37
+
38
+ ### Added
39
+
40
+ - Added the `waiting-wave` action: both eyes bob in staggered waves. `startWaiting({ variant: 'wave' })` loops it continuously.
41
+ - Added `waiting-spin` as the explicit name of the default waiting motion, and `startWaiting({ variant: 'spin' })`.
42
+ - Added brand-inspired color palettes to the demo. Colors apply to a stage card around the avatar; hovering a swatch previews it, a dice button picks a random palette, a swap button exchanges the background and head colors, and a reset button appears on the stage while the colors differ from the default. The page opens by rolling the stage through the palettes in step with the eyes' reel spin, ending with a faint rainbow ripple.
43
+
44
+ ### Changed
45
+
46
+ - Renamed actions as listed above.
47
+ - Demo labels now describe the expression: Waiting · Spin, Waiting · Scroll, Affirm, Wary, Angry and Refuse. The toolbar row is one card as wide as the actions, with Head shape and a random-colors button.
48
+ - Refined the wary expression with independently tilted eyes, adjusted eye proportions and eyelids.
49
+
50
+ ### Also in this release
12
51
 
13
- - Corrected the repository URL case in `package.json` so npm provenance publishing succeeds.
52
+ - The embedded eyes engine for robot and dev-board screens is still in development. It will get its own version number and release; progress is tracked in [embedded/CHANGELOG.md](embedded/CHANGELOG.md).
14
53
 
15
- ## [0.5.1] - 2026-10-05
54
+ ### Removed
55
+
56
+ - Removed antenna blinking (`setAntennaFlash()`), which added little and is no longer shown in the demo.
16
57
 
17
58
  ### Fixed
18
59
 
19
- - `love` now shows the full heart under reduced motion, and `love` and `random` follow motion preference changes while they play.
60
+ - The demo no longer shows intermediate layouts while loading, keeps its action rows even and stable on phones and under browser page translators, and keeps an open panel on screen.
20
61
 
21
- ## [0.5.0] - 2026-10-05
62
+ ## [0.5.2] - 2026-10-06
22
63
 
23
64
  ### Added
24
65
 
25
66
  - Added the `love` action: the eyes lean together into a heart, beat three times, then return.
26
67
  - Added the `random` action (alias `slot`): the eyes roll like slot-machine reels, then settle with a bounce.
27
68
 
69
+ ### Fixed
70
+
71
+ - `love` now shows the full heart under reduced motion, and `love` and `random` follow motion preference changes while they play.
72
+
28
73
  ## [0.4.3] - 2026-09-22
29
74
 
30
75
  ### Fixed
@@ -160,6 +205,8 @@ First public release.
160
205
  - npm-compatible package metadata for later package publication
161
206
  - Contribution guide, issue templates, pull request template, MIT License, and Ko-fi funding metadata
162
207
 
208
+ [0.6.0]: https://github.com/CX-ArtLab/agent-robot-avatar/releases/tag/v0.6.0
209
+ [0.5.2]: https://github.com/CX-ArtLab/agent-robot-avatar/releases/tag/v0.5.2
163
210
  [0.4.3]: https://github.com/CX-ArtLab/agent-robot-avatar/releases/tag/v0.4.3
164
211
  [0.4.2]: https://github.com/CX-ArtLab/agent-robot-avatar/releases/tag/v0.4.2
165
212
  [0.3.2]: https://github.com/CX-ArtLab/agent-robot-avatar/releases/tag/v0.3.2
@@ -168,3 +215,5 @@ First public release.
168
215
  [0.2.1]: https://github.com/CX-ArtLab/agent-robot-avatar/releases/tag/v0.2.1
169
216
  [0.2.0]: https://github.com/CX-ARTLab/agent-robot-avatar/releases/tag/v0.2.0
170
217
  [0.1.0]: https://github.com/CX-ARTLab/agent-robot-avatar/releases/tag/v0.1.0
218
+
219
+
package/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  [English](https://github.com/CX-ArtLab/agent-robot-avatar/blob/main/README.md) | [简体中文](https://github.com/CX-ArtLab/agent-robot-avatar/blob/main/docs/README.zh-CN.md) | [Español](https://github.com/CX-ArtLab/agent-robot-avatar/blob/main/docs/README.es.md) | [Русский](https://github.com/CX-ArtLab/agent-robot-avatar/blob/main/docs/README.ru.md) | [Français](https://github.com/CX-ArtLab/agent-robot-avatar/blob/main/docs/README.fr.md) | [Português](https://github.com/CX-ArtLab/agent-robot-avatar/blob/main/docs/README.pt.md) | [Deutsch](https://github.com/CX-ArtLab/agent-robot-avatar/blob/main/docs/README.de.md) | [日本語](https://github.com/CX-ArtLab/agent-robot-avatar/blob/main/docs/README.ja.md) | [한국어](https://github.com/CX-ArtLab/agent-robot-avatar/blob/main/docs/README.ko.md) | [繁體中文](https://github.com/CX-ArtLab/agent-robot-avatar/blob/main/docs/README.zh-TW.md)
8
8
 
9
- ![Version](https://img.shields.io/badge/version-v0.5.2-111111?style=flat-square) [![License](https://img.shields.io/badge/license-MIT-0A7EA4?style=flat-square)](./LICENSE) [![CI](https://github.com/CX-ArtLab/agent-robot-avatar/actions/workflows/validate.yml/badge.svg?branch=main)](https://github.com/CX-ArtLab/agent-robot-avatar/actions/workflows/validate.yml) [![Ko-fi](https://img.shields.io/badge/Ko--fi-Support-FF5E5B?style=flat-square&logo=ko-fi&logoColor=white)](https://ko-fi.com/P0E625WIOI)
9
+ ![Version](https://img.shields.io/badge/version-v0.6.0-111111?style=flat-square) [![License](https://img.shields.io/badge/license-MIT-0A7EA4?style=flat-square)](./LICENSE) [![CI](https://github.com/CX-ArtLab/agent-robot-avatar/actions/workflows/validate.yml/badge.svg?branch=main)](https://github.com/CX-ArtLab/agent-robot-avatar/actions/workflows/validate.yml) [![Ko-fi](https://img.shields.io/badge/Ko--fi-Support-FF5E5B?style=flat-square&logo=ko-fi&logoColor=white)](https://ko-fi.com/P0E625WIOI)
10
10
 
11
11
  ![Vanilla JavaScript](https://img.shields.io/badge/Vanilla-JavaScript-F7DF1E?style=flat-square&logo=javascript&logoColor=000) ![Web Component](https://img.shields.io/badge/Web-Native%20Component-5A67D8?style=flat-square) ![SVG](https://img.shields.io/badge/Rendering-SVG-FFB13B?style=flat-square&logo=svg&logoColor=000) ![Zero Dependencies](https://img.shields.io/badge/Dependencies-0-2EA44F?style=flat-square)
12
12
 
@@ -26,7 +26,7 @@ Built with SVG and vanilla JavaScript, it works as a native custom element with
26
26
 
27
27
  ## Live Demo
28
28
 
29
- [Open the interactive demo](https://cx-artlab.github.io/agent-robot-avatar/)
29
+ [Open the interactive demo](https://cx-artlab.github.io/agent-robot-avatar/) · [Visit the Skin Gallery](https://cx-artlab.github.io/agent-robot-avatar/skins.html)
30
30
 
31
31
  ## Highlights
32
32
 
@@ -38,11 +38,12 @@ Built with SVG and vanilla JavaScript, it works as a native custom element with
38
38
  - Jelly-style drag deformation with elastic recovery
39
39
  - Press-and-hold squeeze and draggable spring antenna interactions
40
40
  - Programmatically controlled Agent states and expressions
41
- - Waiting, success, failure, warning, review, blocked, and system-error feedback
41
+ - Expressions for waiting, success, failure, affirm, wary, inspect, angry, refuse, love and more
42
42
  - Reduced-motion support
43
43
  - Configurable sleep behavior
44
44
  - Adjustable head roundness
45
- - Optional antenna status flashing
45
+ - 188 numbered skins in 17 series, with light that follows the pointer
46
+ - A lite build without skins for the smallest pages
46
47
  - TypeScript declarations included
47
48
 
48
49
  ## Install
@@ -69,27 +70,54 @@ Then add the component:
69
70
 
70
71
  No initialization code is required. The avatar enters its default idle behavior automatically.
71
72
 
73
+ ### Lite build
74
+
75
+ For pages that never use skins, `agent-robot-avatar/lite` is the same avatar without any skin code:
76
+
77
+ ```js
78
+ import 'agent-robot-avatar/lite';
79
+ ```
80
+
81
+ In the lite build the `skin` attribute is ignored, and the console notes that skins need the full build.
82
+
72
83
  ## Basic usage
73
84
 
74
85
  ```js
75
86
  const avatar = document.querySelector('#avatar');
76
87
 
77
88
  avatar.play('success');
78
- avatar.play('warning');
79
- avatar.play('error');
89
+ avatar.play('wary');
90
+ avatar.play('refuse');
80
91
 
81
92
  avatar.reset();
82
93
  ```
83
94
 
84
95
  Available actions:
85
96
 
86
- `idle` · `bored` · `waiting` · `waiting-wrap` · `input` · `send` · `success` · `failure` · `warning` · `inspect` · `blocked` · `error` · `surprise` · `love` · `random` · `sleep` · `wake`
87
-
88
- `failure` is intended for a task that completed unsuccessfully, while `error` is intended for connection, service, or system failures.
89
-
90
- `love` expresses affection or thanks: the two eyes lean together into a single heart, beat three times, then return.
91
-
92
- `random` plays a slot-machine spin: each eye rolls over a drum, then the left eye slows, bounces and settles, followed by the right. `slot` is an alias.
97
+ | Action | Looks like | Use when |
98
+ | --- | --- | --- |
99
+ | `idle` | Blinks and glances around | Default state |
100
+ | `bored` | Glances slowly from side to side | Nothing has happened for a while |
101
+ | `waiting-spin` | Eyes circle from side to side | Waiting for a reply (default) |
102
+ | `waiting-wrap` | Eyes slide out one side and back in the other | Waiting for a reply |
103
+ | `waiting-wave` | Eyes bob up and down in turn | Waiting for a reply |
104
+ | `input` | Eyes become blinking text cursors | The user is typing |
105
+ | `affirm` | Nods | Got it, confirmed |
106
+ | `success` | Happy, smiling eyes | Task completed |
107
+ | `failure` | Head and eyes droop | Task or connection failed |
108
+ | `wary` | Turns its head and gives a guarded up-and-down look | An action needs confirmation |
109
+ | `inspect` | Narrows its eyes and scans up and down | Checking or reviewing something |
110
+ | `angry` | Lowered, glaring eyes | Content blocked |
111
+ | `refuse` | Shakes its head | Cannot or will not do the request |
112
+ | `surprise` | Wide-open eyes | Something unexpected |
113
+ | `love` | Eyes merge into a beating heart | Thanks, affection |
114
+ | `random` | Eyes spin like slot-machine reels | Random pick, playful moment |
115
+ | `sleep` | Closes its eyes and sleeps | No activity for a long time |
116
+ | `wake` | Opens its eyes and wakes up | Activity resumes |
117
+
118
+ Waiting actions play one round with `play()`. `startWaiting({ variant: 'spin' | 'wrap' | 'wave' })` loops until another action starts or `stopWaiting()` is called.
119
+
120
+ Names from 0.5 (`send`, `warning`, `error`, `blocked`, `slot` and others) still work with a console notice until 1.0; see the [upgrade table](CHANGELOG.md#upgrading-from-05x).
93
121
 
94
122
  For a real Agent request lifecycle:
95
123
 
@@ -99,11 +127,14 @@ avatar.startWaiting();
99
127
  // Alternative waiting motion: eyes turn out through one side and return through the other.
100
128
  avatar.startWaiting({ variant: 'wrap' });
101
129
 
130
+ // Alternative waiting motion: staggered vertical eye waves.
131
+ avatar.startWaiting({ variant: 'wave' });
132
+
102
133
  try {
103
134
  const result = await runAgentRequest();
104
135
  await avatar.play(result.ok ? 'success' : 'failure');
105
136
  } catch (error) {
106
- await avatar.play('error');
137
+ await avatar.play('failure');
107
138
  }
108
139
  ```
109
140
 
@@ -128,19 +159,60 @@ try {
128
159
  | `motion` | Motion policy: `auto`, `reduce`, or `full` |
129
160
  | `press-squeeze` | Center press-and-hold squeeze; set to `false` to disable |
130
161
  | `antenna-drag` | Antenna drag, spring return, and angry reaction; set to `false` to disable |
162
+ | `skin` | Skin number, such as `301`; leave it out for the flat color |
131
163
 
132
164
  Common runtime controls:
133
165
 
134
166
  ```js
135
167
  avatar.setPointerFollow(false);
136
168
  avatar.setHeadRoundness(75);
137
- avatar.setAntennaFlash(true);
138
169
  avatar.setPressSqueeze(true);
139
170
  avatar.setAntennaDrag(true);
140
171
  ```
141
172
 
142
173
  The avatar center begins the squeeze interaction. Moving more than 4 CSS pixels transfers the same pointer gesture to the existing head drag. Dragging the antenna uses the same pull limit as head dragging and ends with the existing angry reaction.
143
174
 
175
+ ## Skins · New in 0.7
176
+
177
+ 188 skins in 17 series, with light that follows the pointer. Every skin has a permanent number: the series number followed by two digits, so 305 is the fifth skin of series 3. Titles may be reworded later; numbers never change and are never reused.
178
+
179
+ <img src="./assets/readme/skin-gallery.jpg" alt="Skin Gallery: featured skins, filters and search" width="100%">
180
+
181
+ ```html
182
+ <agent-robot-avatar skin="301"></agent-robot-avatar>
183
+ ```
184
+
185
+ ```js
186
+ avatar.setSkin(102); // or '102'
187
+ avatar.setSkin(null); // back to the flat color
188
+ ```
189
+
190
+ See every skin with its number on the [all skins page](https://cx-artlab.github.io/agent-robot-avatar/materials/).
191
+
192
+ | Series | Numbers |
193
+ | --- | --- |
194
+ | Glaze | 101–106 |
195
+ | Ice glass | 201–206 |
196
+ | Gummy | 301–312 |
197
+ | Candy glass | 401–406 |
198
+ | Acrylic | 501–512 |
199
+ | Jelly | 601–612 |
200
+ | Gradient | 701–712 |
201
+ | Frosted glass | 801–806 |
202
+ | Metal | 901–930 |
203
+ | Gems and ceramics | 1001–1012 |
204
+ | Wood | 1101–1106 |
205
+ | Balls | 1201–1210 |
206
+ | Clear and shimmer | 1301–1305 |
207
+ | Fabric and leather | 1401–1412 |
208
+ | Sweets and fruit | 1501–1512 |
209
+ | Nature | 1601–1612 |
210
+ | Patterns and tech | 1701–1717 |
211
+
212
+ Skin painters download the first time a skin is used, so a page without skins never loads them. `await loadSkins()` loads them in advance. `SKINS` holds each skin’s Chinese and English titles and colors, `SKIN_SERIES` the series, and `SKIN_NAMES` every number.
213
+
214
+ Every expression and gesture works with a skin. When the skin is removed, the `color` attribute applies again.
215
+
144
216
  ## Events and integration
145
217
 
146
218
  The component emits `face-state` for visual state changes and `action-state` for semantic action lifecycle changes.
@@ -155,13 +227,17 @@ Designed for modern browsers with support for ES Modules, Custom Elements, SVG,
155
227
 
156
228
  Automated browser tests cover Chromium, Firefox, and WebKit.
157
229
 
230
+ ## Hardware version (in development)
231
+
232
+ A C++ version that shows the avatar's expressions on robot and dev-board screens (it draws only the eyes) is in development and not released yet. See the [hardware guide](https://github.com/CX-ArtLab/agent-robot-avatar/tree/main/embedded).
233
+
158
234
  ## Contributing
159
235
 
160
236
  Issues and pull requests are welcome. See [`CONTRIBUTING.md`](./CONTRIBUTING.md) before submitting changes.
161
237
 
162
238
  ## Project status
163
239
 
164
- **Current public version: v0.5.2**
240
+ **Current public version: v0.6.0**
165
241
 
166
242
  The public API is intentionally kept compact while the project evolves toward a future `1.0.0` stability commitment.
167
243
 
@@ -184,3 +260,4 @@ MIT License. See [`LICENSE`](./LICENSE).
184
260
  If this project is useful to you, you can buy me a coffee.
185
261
 
186
262
  <a href='https://ko-fi.com/P0E625WIOI' target='_blank'><img height='36' style='border:0px;height:36px;' src='https://storage.ko-fi.com/cdn/kofi6.png?v=6' border='0' alt='Buy Me a Coffee at ko-fi.com' /></a>
263
+
@@ -0,0 +1,44 @@
1
+ // The smallest build: every expression and gesture, without skins. The skin
2
+ // attribute and setSkin() only explain where skins live, so a page written for
3
+ // the full build keeps working with the plain avatar.
4
+ import AgentRobotAvatar from './src/agent-robot-avatar-extension-host.js';
5
+ import './src/agent-robot-avatar-actions.js';
6
+ import './src/agent-robot-avatar-antenna.js';
7
+ import './src/agent-robot-avatar-waiting.js';
8
+ import './src/agent-robot-avatar-inspect.js';
9
+ import './src/agent-robot-avatar-failure.js';
10
+ import './src/agent-robot-avatar-love.js';
11
+ import './src/agent-robot-avatar-random.js';
12
+ import './src/agent-robot-avatar-head-roundness.js';
13
+ import './src/agent-robot-avatar-gestures.js';
14
+ import './src/agent-robot-avatar-runtime.js';
15
+ import { VERSION } from './src/agent-robot-avatar-version.js';
16
+
17
+ const proto = AgentRobotAvatar.prototype;
18
+ let warned = false;
19
+ function explain() {
20
+ if (warned) return;
21
+ warned = true;
22
+ console.warn('agent-robot-avatar: skins are not part of the lite build; import "agent-robot-avatar" instead of "agent-robot-avatar/lite" to use them.');
23
+ }
24
+ if (!proto.setSkin) {
25
+ proto._applySkinAttribute = function() { if (this.getAttribute('skin')) explain(); };
26
+ proto.setSkin = function(value = null) {
27
+ if (value !== null && value !== 'none') explain();
28
+ return this;
29
+ };
30
+ proto.getSkin = () => null;
31
+ }
32
+
33
+ // Elements already present in markup can upgrade while the core module is
34
+ // loading, before runtime extensions finish installing their prototype hooks.
35
+ if (typeof document !== 'undefined') {
36
+ document.querySelectorAll('agent-robot-avatar').forEach(avatar => avatar._resumeFrames?.());
37
+ }
38
+
39
+ if (typeof window !== 'undefined') {
40
+ window.AgentRobotAvatarVersion = VERSION;
41
+ }
42
+
43
+ export { AgentRobotAvatar, VERSION };
44
+ export default AgentRobotAvatar;
@@ -2,13 +2,13 @@ import AgentRobotAvatar from './src/agent-robot-avatar-extension-host.js';
2
2
  import './src/agent-robot-avatar-actions.js';
3
3
  import './src/agent-robot-avatar-antenna.js';
4
4
  import './src/agent-robot-avatar-waiting.js';
5
- import './src/agent-robot-avatar-antenna-flash.js';
6
5
  import './src/agent-robot-avatar-inspect.js';
7
6
  import './src/agent-robot-avatar-failure.js';
8
7
  import './src/agent-robot-avatar-love.js';
9
8
  import './src/agent-robot-avatar-random.js';
10
9
  import './src/agent-robot-avatar-head-roundness.js';
11
10
  import './src/agent-robot-avatar-gestures.js';
11
+ import { SKIN_NAMES, SKINS, SKIN_SERIES, loadSkins } from './src/agent-robot-avatar-skins.js';
12
12
  import './src/agent-robot-avatar-runtime.js';
13
13
  import { VERSION } from './src/agent-robot-avatar-version.js';
14
14
 
@@ -24,5 +24,5 @@ if (typeof window !== 'undefined') {
24
24
  window.AgentRobotAvatarVersion = VERSION;
25
25
  }
26
26
 
27
- export { AgentRobotAvatar, VERSION };
27
+ export { AgentRobotAvatar, SKIN_NAMES, SKINS, SKIN_SERIES, VERSION, loadSkins };
28
28
  export default AgentRobotAvatar;
package/index.d.ts CHANGED
@@ -2,30 +2,99 @@ export type AgentRobotAvatarAction =
2
2
  | 'idle'
3
3
  | 'bored'
4
4
  | 'waiting'
5
- | 'wait'
5
+ | 'waiting-spin'
6
6
  | 'waiting-wrap'
7
+ | 'waiting-wave'
7
8
  | 'input'
8
- | 'send'
9
+ | 'affirm'
9
10
  | 'success'
10
11
  | 'failure'
12
+ | 'wary'
13
+ | 'inspect'
14
+ | 'angry'
15
+ | 'refuse'
16
+ | 'surprise'
17
+ | 'love'
18
+ | 'random'
19
+ | 'sleep'
20
+ | 'wake'
21
+ | AgentRobotAvatarDeprecatedAction;
22
+
23
+ /**
24
+ * Older names that still play the same action but log a one-time deprecation
25
+ * notice. They are removed in 1.0.
26
+ */
27
+ export type AgentRobotAvatarDeprecatedAction =
28
+ | 'wait'
29
+ | 'send'
11
30
  | 'failed'
12
31
  | 'fail'
13
32
  | 'warning'
14
- | 'inspect'
15
33
  | 'verify'
16
34
  | 'review'
17
- | 'angry'
18
35
  | 'blocked'
19
36
  | 'policy-blocked'
20
37
  | 'error'
21
38
  | 'system-error'
22
39
  | 'connection-error'
23
- | 'surprise'
24
- | 'love'
25
- | 'random'
26
- | 'slot'
27
- | 'sleep'
28
- | 'wake';
40
+ | 'slot';
41
+
42
+ /**
43
+ * Skin numbers for the `skin` attribute and `setSkin()`: the series number
44
+ * followed by two digits, so `305` is the fifth skin of series 3. A number is
45
+ * permanent; titles may be reworded, numbers never change and are never reused.
46
+ */
47
+ export type AgentRobotAvatarSkin =
48
+ | '101' | '102' | '103' | '104' | '105' | '106' | '201' | '202' | '203' | '204' | '205' | '206'
49
+ | '301' | '302' | '303' | '304' | '305' | '306' | '307' | '308' | '309' | '310' | '311' | '312'
50
+ | '401' | '402' | '403' | '404' | '405' | '406' | '501' | '502' | '503' | '504' | '505' | '506'
51
+ | '507' | '508' | '509' | '510' | '511' | '512' | '601' | '602' | '603' | '604' | '605' | '606'
52
+ | '607' | '608' | '609' | '610' | '611' | '612' | '701' | '702' | '703' | '704' | '705' | '706'
53
+ | '707' | '708' | '709' | '710' | '711' | '712' | '801' | '802' | '803' | '804' | '805' | '806'
54
+ | '901' | '902' | '903' | '904' | '905' | '906' | '907' | '908' | '909' | '910' | '911' | '912'
55
+ | '913' | '914' | '915' | '916' | '917' | '918' | '919' | '920' | '921' | '922' | '923' | '924'
56
+ | '925' | '926' | '927' | '928' | '929' | '930' | '1001' | '1002' | '1003' | '1004' | '1005' | '1006'
57
+ | '1007' | '1008' | '1009' | '1010' | '1011' | '1012' | '1101' | '1102' | '1103' | '1104' | '1105' | '1106'
58
+ | '1201' | '1202' | '1203' | '1204' | '1205' | '1206' | '1207' | '1208' | '1209' | '1210' | '1301' | '1302'
59
+ | '1303' | '1304' | '1305' | '1401' | '1402' | '1403' | '1404' | '1405' | '1406' | '1407' | '1408' | '1409'
60
+ | '1410' | '1411' | '1412' | '1501' | '1502' | '1503' | '1504' | '1505' | '1506' | '1507' | '1508' | '1509'
61
+ | '1510' | '1511' | '1512' | '1601' | '1602' | '1603' | '1604' | '1605' | '1606' | '1607' | '1608' | '1609'
62
+ | '1610' | '1611' | '1612' | '1701' | '1702' | '1703' | '1704' | '1705' | '1706' | '1707' | '1708' | '1709'
63
+ | '1710' | '1711' | '1712' | '1713' | '1714' | '1715' | '1716' | '1717';
64
+
65
+ /** Display information for one skin. */
66
+ export interface AgentRobotAvatarSkinInfo {
67
+ /** The series id, such as `'glaze'` or `'metal'`. */
68
+ readonly series: string;
69
+ /** Chinese title. */
70
+ readonly title: string;
71
+ /** English title. */
72
+ readonly titleEn: string;
73
+ /** Representative colors, light to dark. */
74
+ readonly base: readonly string[];
75
+ }
76
+
77
+ /** A group of related skins, in gallery order. */
78
+ export interface AgentRobotAvatarSkinSeries {
79
+ readonly id: string;
80
+ /** The first digits of every skin number in the series. */
81
+ readonly number: number;
82
+ readonly title: string;
83
+ readonly titleEn: string;
84
+ readonly skins: readonly AgentRobotAvatarSkin[];
85
+ }
86
+
87
+ /** Every skin number, in gallery order. */
88
+ export declare const SKIN_NAMES: readonly AgentRobotAvatarSkin[];
89
+ /** Titles and colors for every skin, by number. */
90
+ export declare const SKINS: Readonly<Record<AgentRobotAvatarSkin, AgentRobotAvatarSkinInfo>>;
91
+ /** The skin series, in gallery order. */
92
+ export declare const SKIN_SERIES: readonly AgentRobotAvatarSkinSeries[];
93
+ /**
94
+ * Skin painters download the first time a skin is used, so the first skin shows
95
+ * a moment after it is set. Await this to load them in advance.
96
+ */
97
+ export declare function loadSkins(): Promise<void>;
29
98
 
30
99
  export type AgentRobotAvatarState =
31
100
  | 'idle'
@@ -39,8 +108,8 @@ export type AgentRobotAvatarState =
39
108
  | 'love'
40
109
  | 'random'
41
110
  | 'waiting'
42
- | 'warning'
43
- | 'error'
111
+ | 'wary'
112
+ | 'refuse'
44
113
  | 'inspect'
45
114
  | 'failure'
46
115
  | 'squeeze'
@@ -51,14 +120,13 @@ export type AgentRobotAvatarCanonicalAction =
51
120
  | 'bored'
52
121
  | 'waiting'
53
122
  | 'input'
54
- | 'send'
123
+ | 'affirm'
55
124
  | 'success'
56
125
  | 'failure'
57
- | 'warning'
126
+ | 'wary'
58
127
  | 'inspect'
59
128
  | 'angry'
60
- | 'blocked'
61
- | 'error'
129
+ | 'refuse'
62
130
  | 'surprise'
63
131
  | 'love'
64
132
  | 'random'
@@ -73,7 +141,7 @@ export type AgentRobotAvatarActionSource = 'api' | 'interaction' | 'automatic';
73
141
  export type AgentRobotAvatarWakeOn = 'activity' | 'interaction' | 'manual';
74
142
  export type AgentRobotAvatarMotion = 'auto' | 'reduce' | 'full';
75
143
  export interface AgentRobotAvatarWaitingOptions {
76
- variant?: 'default' | 'wrap';
144
+ variant?: 'default' | 'spin' | 'wrap' | 'wave';
77
145
  }
78
146
 
79
147
  export interface AgentRobotAvatarActionStateDetail {
@@ -97,11 +165,19 @@ export declare class AgentRobotAvatar extends HTMLElement {
97
165
  startWaiting(options?: AgentRobotAvatarWaitingOptions): Promise<this>;
98
166
  stopWaiting(): this;
99
167
  setPointerFollow(enabled?: boolean): this;
168
+ /** @deprecated Removed in 0.6; does nothing and logs a one-time notice. Deleted in 1.0. */
100
169
  setAntennaFlash(enabled?: boolean): this;
101
170
  setPressSqueeze(enabled?: boolean): this;
102
171
  setAntennaDrag(enabled?: boolean): this;
103
172
  setHeadRoundness(value?: number): this;
104
173
  getHeadRoundness(): number;
174
+ /**
175
+ * Dresses the head in a numbered skin with light that follows the pointer.
176
+ * Same as the `skin` attribute; `null` or `'none'` returns to the flat color.
177
+ * Throws for an unknown number.
178
+ */
179
+ setSkin(skin?: AgentRobotAvatarSkin | number | 'none' | null): this;
180
+ getSkin(): AgentRobotAvatarSkin | null;
105
181
  noteActivity(wake?: boolean): void;
106
182
 
107
183
  addEventListener<K extends keyof AgentRobotAvatarEventMap>(
@@ -126,3 +202,4 @@ declare global {
126
202
  'agent-robot-avatar': AgentRobotAvatar;
127
203
  }
128
204
  }
205
+
package/lite.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ // The lite build: the same avatar without skins. setSkin() keeps its type so a
2
+ // page can switch builds, but it only logs that skins need the full build.
3
+ export { AgentRobotAvatar, VERSION } from './index.js';
4
+ export { default } from './index.js';
5
+ export type * from './index.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-robot-avatar",
3
- "version": "0.5.2",
3
+ "version": "0.7.0",
4
4
  "description": "A lightweight expressive robot avatar Web Component for AI agents and interactive applications.",
5
5
  "type": "module",
6
6
  "main": "./agent-robot-avatar.js",
@@ -14,6 +14,11 @@
14
14
  "types": "./index.d.ts",
15
15
  "import": "./agent-robot-avatar.js",
16
16
  "default": "./agent-robot-avatar.js"
17
+ },
18
+ "./lite": {
19
+ "types": "./lite.d.ts",
20
+ "import": "./agent-robot-avatar-lite.js",
21
+ "default": "./agent-robot-avatar-lite.js"
17
22
  }
18
23
  },
19
24
  "sideEffects": true,
@@ -21,20 +26,22 @@
21
26
  "dev": "node scripts/serve.mjs",
22
27
  "build:pages": "node scripts/build-pages.mjs",
23
28
  "check": "node scripts/check-source.mjs",
24
- "test": "npm run check && npm run test:types && npm run test:release && npm run test:package && npm run test:browser && npm run build:pages",
29
+ "test": "npm run check && npm run test:types && npm run test:release && npm run test:package && npm run test:waiting && npm run test:browser && npm run test:pages",
25
30
  "release:check": "npm test && npm publish --dry-run --ignore-scripts --tag latest",
26
31
  "prepublishOnly": "npm test && node scripts/check-publish-tag.mjs",
27
32
  "test:types": "tsc -p tsconfig.types.json",
28
33
  "test:release": "node --test tests/release.test.mjs",
29
34
  "test:package": "node --test tests/package.test.mjs",
30
- "test:browser": "playwright test"
35
+ "test:waiting": "node --test tests/waiting-wave.test.mjs",
36
+ "test:browser": "playwright test",
37
+ "test:pages": "node --test tests/pages-public.test.mjs"
31
38
  },
32
39
  "files": [
33
40
  "agent-robot-avatar.js",
41
+ "agent-robot-avatar-lite.js",
34
42
  "index.d.ts",
43
+ "lite.d.ts",
35
44
  "src/",
36
- "assets/support/",
37
- "docs/",
38
45
  "README.md",
39
46
  "CHANGELOG.md",
40
47
  "LICENSE"
@@ -23,7 +23,7 @@ const WARNING_TIMING = Object.freeze({
23
23
  W5: 200,
24
24
  W5P: 300,
25
25
  W6: 200,
26
- W6P: 300,
26
+ W6P: 500,
27
27
  W7: 100,
28
28
  W8: 800,
29
29
  W9: 227,
@@ -200,7 +200,7 @@ proto.error = async function() {
200
200
  const eyeDuration = 980;
201
201
  const headDuration = 1380;
202
202
  this._systemErrorShake = { start: performance.now(), duration: eyeDuration };
203
- dispatchActionState(this, 'error');
203
+ dispatchActionState(this, 'refuse');
204
204
 
205
205
  centerHeadTransform(this);
206
206
  if (this._headMotion?.animate) {
@@ -234,7 +234,7 @@ proto.warning = async function() {
234
234
  const token = this._transitionToken;
235
235
  const duration = WARNING_PHASES.duration;
236
236
  this._warningFx = { start: performance.now(), duration };
237
- dispatchActionState(this, 'warning');
237
+ dispatchActionState(this, 'wary');
238
238
 
239
239
  centerHeadTransform(this);
240
240
  if (this._headMotion?.animate) {
@@ -345,29 +345,32 @@ function drawWarning(now) {
345
345
  farDeepLidDrop = segment(elapsed, WARNING_PHASES.w6Start, WARNING_PHASES.w6End, 3.5, 0);
346
346
  }
347
347
 
348
- const nearSX = lerp(1, 1.48, proximity);
348
+ const nearSX = lerp(1, 1.37, proximity);
349
349
  const nearSY = lerp(1, 1.40, proximity);
350
- const farSX = lerp(1, 0.78, proximity);
351
- const farSY = lerp(1, 0.97, proximity);
350
+ const farSX = lerp(1, 0.68, proximity);
351
+ const farSY = lerp(1, 0.99, proximity);
352
+
353
+ const nearTilt = lerp(0, -6.5, proximity);
354
+ const farTilt = lerp(0, 7.5, proximity);
352
355
 
353
356
  const nearX = lerp(86, 102.0, proximity);
354
- const farX = lerp(154, 178.5, proximity);
357
+ const farX = lerp(154, 174.5, proximity);
355
358
  const nearY = lerp(126, 125.5, proximity);
356
- const farY = lerp(126, 134.0, proximity) + farLowOffset;
359
+ const farY = lerp(126, 133.5, proximity) + farLowOffset;
357
360
 
358
361
  this._leftEye.setAttribute(
359
362
  'transform',
360
- `translate(${nearX.toFixed(2)} ${nearY.toFixed(2)}) scale(${nearSX.toFixed(3)} ${nearSY.toFixed(3)})`
363
+ `translate(${nearX.toFixed(2)} ${nearY.toFixed(2)}) rotate(${nearTilt.toFixed(2)}) scale(${nearSX.toFixed(3)} ${nearSY.toFixed(3)})`
361
364
  );
362
365
  this._rightEye.setAttribute(
363
366
  'transform',
364
- `translate(${farX.toFixed(2)} ${farY.toFixed(2)}) scale(${farSX.toFixed(3)} ${farSY.toFixed(3)})`
367
+ `translate(${farX.toFixed(2)} ${farY.toFixed(2)}) rotate(${farTilt.toFixed(2)}) scale(${farSX.toFixed(3)} ${farSY.toFixed(3)})`
365
368
  );
366
369
 
367
- const nearTopY = lerp(-36, -10.0, lids) + lidShift;
368
- const farTopY = lerp(-36, -18.0, lids) + lidShift * 0.95 + farDeepLidDrop;
369
- const nearTopRot = lerp(0, 10.0, lids);
370
- const farTopRot = lerp(0, -7.5, lids);
370
+ const nearTopY = lerp(-36, -8.0, lids) + lidShift;
371
+ const farTopY = lerp(-36, -10.0, lids) + lidShift * 0.95 + farDeepLidDrop;
372
+ const nearTopRot = lerp(0, 25.0, lids);
373
+ const farTopRot = lerp(0, -17.0, lids);
371
374
 
372
375
  this._leftTop.setAttribute('y', (nearTopY - 90).toFixed(2));
373
376
  this._leftTop.setAttribute('height', '90');