agent-robot-avatar 0.6.0 → 0.7.1

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 (39) hide show
  1. package/CHANGELOG.md +20 -1
  2. package/README.md +87 -20
  3. package/agent-robot-avatar-lite.js +44 -0
  4. package/agent-robot-avatar.js +2 -1
  5. package/index.d.ts +64 -0
  6. package/lite.d.ts +5 -0
  7. package/package.json +11 -6
  8. package/src/agent-robot-avatar-core.js +8 -4
  9. package/src/agent-robot-avatar-runtime.js +4 -1
  10. package/src/agent-robot-avatar-skin-patterns.js +234 -0
  11. package/src/agent-robot-avatar-skins.js +256 -0
  12. package/src/agent-robot-avatar-version.js +1 -1
  13. package/src/skins/catalog.js +218 -0
  14. package/src/skins/collection-materials.js +118 -0
  15. package/src/skins/eyelids.js +32 -0
  16. package/src/skins/glaze-variants.js +29 -0
  17. package/src/skins/layered-texture.js +162 -0
  18. package/src/skins/material-data.js +111 -0
  19. package/src/skins/material-library.js +302 -0
  20. package/src/skins/metal-tint.js +11 -0
  21. package/src/skins/more-materials.js +69 -0
  22. package/src/skins/native.js +754 -0
  23. package/src/skins/paints.js +3 -0
  24. package/src/skins/revised-materials.js +44 -0
  25. package/src/skins/second-pass-materials.js +71 -0
  26. package/src/skins/soft-materials.js +111 -0
  27. package/src/skins/sports-materials.js +38 -0
  28. package/src/skins/wood-materials.js +68 -0
  29. package/assets/support/alipay.png +0 -0
  30. package/assets/support/wechat-pay.png +0 -0
  31. package/docs/README.de.md +0 -185
  32. package/docs/README.es.md +0 -185
  33. package/docs/README.fr.md +0 -185
  34. package/docs/README.ja.md +0 -185
  35. package/docs/README.ko.md +0 -185
  36. package/docs/README.pt.md +0 -185
  37. package/docs/README.ru.md +0 -185
  38. package/docs/README.zh-CN.md +0 -202
  39. package/docs/README.zh-TW.md +0 -185
package/CHANGELOG.md CHANGED
@@ -4,7 +4,24 @@ 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.1] - 2026-10-30
8
+
9
+ ### Changed
10
+
11
+ - Falling asleep now ends with the eyelids closing into a slit, instead of the eyes squashing flat.
12
+ - The demo's Sleep button turns into Wake while the avatar sleeps.
13
+
14
+ ## [0.7.0] - 2026-10-29
15
+
16
+ ### Added
17
+
18
+ - 188 skins in 17 series. Pick one by number with `skin="301"` or `setSkin(301)`; `setSkin(null)` goes back to the flat color.
19
+ - 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.
20
+ - Every skin works with every expression and gesture, and its light follows the pointer.
21
+ - `SKINS`, `SKIN_SERIES` and `SKIN_NAMES` list the skins, for building a skin picker.
22
+ - Skin code loads only when a page uses a skin. `loadSkins()` loads it in advance.
23
+ - `agent-robot-avatar/lite`: the same avatar without any skin code.
24
+ - The demo has a Skin Gallery and a page with every skin.
8
25
 
9
26
  ## [0.6.0] - 2026-10-23
10
27
 
@@ -195,6 +212,8 @@ First public release.
195
212
  - npm-compatible package metadata for later package publication
196
213
  - Contribution guide, issue templates, pull request template, MIT License, and Ko-fi funding metadata
197
214
 
215
+ [0.7.1]: https://github.com/CX-ArtLab/agent-robot-avatar/releases/tag/v0.7.1
216
+ [0.7.0]: https://github.com/CX-ArtLab/agent-robot-avatar/releases/tag/v0.7.0
198
217
  [0.6.0]: https://github.com/CX-ArtLab/agent-robot-avatar/releases/tag/v0.6.0
199
218
  [0.5.2]: https://github.com/CX-ArtLab/agent-robot-avatar/releases/tag/v0.5.2
200
219
  [0.4.3]: https://github.com/CX-ArtLab/agent-robot-avatar/releases/tag/v0.4.3
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.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)
9
+ ![Version](https://img.shields.io/badge/version-v0.7.1-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,19 +38,14 @@ 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
- ## Embedded eyes (experimental)
49
-
50
- An independent, allocation-free C++11 eyes-only engine draws the same 18 expressions on robot and dev-board screens. Firmware examples cover 26 board and screen configurations across ESP32, ESP32-S3 and RP2040 — ST7789, ST7735, GC9A01 round, ILI9341/9342/9488, CO5300 AMOLED, ST7701S RGB panels and SSD1306/SH1106 OLEDs, including LilyGO, M5Stack, Waveshare, Seeed and Espressif boards. Every example compiles in CI; none is verified on real hardware yet, so please send a hardware report if you try one.
51
-
52
- See the [embedded guide](https://github.com/CX-ArtLab/agent-robot-avatar/tree/main/embedded) and [中文说明](https://github.com/CX-ArtLab/agent-robot-avatar/blob/main/embedded/README.zh-CN.md). The Web component's installation and behavior are unchanged.
53
-
54
49
  ## Install
55
50
 
56
51
  ```bash
@@ -75,6 +70,16 @@ Then add the component:
75
70
 
76
71
  No initialization code is required. The avatar enters its default idle behavior automatically.
77
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
+
78
83
  ## Basic usage
79
84
 
80
85
  ```js
@@ -89,15 +94,30 @@ avatar.reset();
89
94
 
90
95
  Available actions:
91
96
 
92
- `idle` · `bored` · `waiting-spin` · `waiting-wrap` · `waiting-wave` · `input` · `affirm` · `success` · `failure` · `wary` · `inspect` · `angry` · `refuse` · `surprise` · `love` · `random` · `sleep` · `wake`
93
-
94
- `waiting-wave` plays three 1.1-second waves: the eyes bob vertically with a staggered rhythm and amplitude of 10 SVG units, then settle. Use `startWaiting({ variant: 'wave' })` for seamless continuous waiting, and `stopWaiting()` to stop. It honors the component's reduced-motion setting and reports the canonical `waiting` action lifecycle.
95
-
96
- Action names describe what the avatar does. `refuse` shakes the head, for a request the Agent cannot or will not carry out; `failure` is for a task or connection that did not succeed; `wary` turns the head and gives a guarded up-and-down look, for an action that needs confirmation. Names from 0.5 (`send`, `warning`, `error`, `blocked` and others) still work with a console notice until 1.0; see the [upgrade table](CHANGELOG.md#upgrading-from-05x).
97
-
98
- `love` expresses affection or thanks: the two eyes lean together into a single heart, beat three times, then return.
99
-
100
- `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).
101
121
 
102
122
  For a real Agent request lifecycle:
103
123
 
@@ -139,6 +159,7 @@ try {
139
159
  | `motion` | Motion policy: `auto`, `reduce`, or `full` |
140
160
  | `press-squeeze` | Center press-and-hold squeeze; set to `false` to disable |
141
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 |
142
163
 
143
164
  Common runtime controls:
144
165
 
@@ -151,6 +172,49 @@ avatar.setAntennaDrag(true);
151
172
 
152
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.
153
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
+ Every skin is still pure SVG: no images, canvas or WebGL.
180
+
181
+ <img src="./assets/readme/skin-gallery.jpg" alt="Skin Gallery: featured skins, filters and search" width="100%">
182
+
183
+ ```html
184
+ <agent-robot-avatar skin="301"></agent-robot-avatar>
185
+ ```
186
+
187
+ ```js
188
+ avatar.setSkin(102); // or '102'
189
+ avatar.setSkin(null); // back to the flat color
190
+ ```
191
+
192
+ See every skin with its number on the [all skins page](https://cx-artlab.github.io/agent-robot-avatar/materials/).
193
+
194
+ | Series | Numbers |
195
+ | --- | --- |
196
+ | Glaze | 101–106 |
197
+ | Ice glass | 201–206 |
198
+ | Gummy | 301–312 |
199
+ | Candy glass | 401–406 |
200
+ | Acrylic | 501–512 |
201
+ | Jelly | 601–612 |
202
+ | Gradient | 701–712 |
203
+ | Frosted glass | 801–806 |
204
+ | Metal | 901–930 |
205
+ | Gems and ceramics | 1001–1012 |
206
+ | Wood | 1101–1106 |
207
+ | Balls | 1201–1210 |
208
+ | Clear and shimmer | 1301–1305 |
209
+ | Fabric and leather | 1401–1412 |
210
+ | Sweets and fruit | 1501–1512 |
211
+ | Nature | 1601–1612 |
212
+ | Patterns and tech | 1701–1717 |
213
+
214
+ 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.
215
+
216
+ Every expression and gesture works with a skin. When the skin is removed, the `color` attribute applies again.
217
+
154
218
  ## Events and integration
155
219
 
156
220
  The component emits `face-state` for visual state changes and `action-state` for semantic action lifecycle changes.
@@ -165,6 +229,10 @@ Designed for modern browsers with support for ES Modules, Custom Elements, SVG,
165
229
 
166
230
  Automated browser tests cover Chromium, Firefox, and WebKit.
167
231
 
232
+ ## Hardware version (in development)
233
+
234
+ 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).
235
+
168
236
  ## Contributing
169
237
 
170
238
  Issues and pull requests are welcome. See [`CONTRIBUTING.md`](./CONTRIBUTING.md) before submitting changes.
@@ -195,4 +263,3 @@ If this project is useful to you, you can buy me a coffee.
195
263
 
196
264
  <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>
197
265
 
198
-
@@ -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;
@@ -8,6 +8,7 @@ import './src/agent-robot-avatar-love.js';
8
8
  import './src/agent-robot-avatar-random.js';
9
9
  import './src/agent-robot-avatar-head-roundness.js';
10
10
  import './src/agent-robot-avatar-gestures.js';
11
+ import { SKIN_NAMES, SKINS, SKIN_SERIES, loadSkins } from './src/agent-robot-avatar-skins.js';
11
12
  import './src/agent-robot-avatar-runtime.js';
12
13
  import { VERSION } from './src/agent-robot-avatar-version.js';
13
14
 
@@ -23,5 +24,5 @@ if (typeof window !== 'undefined') {
23
24
  window.AgentRobotAvatarVersion = VERSION;
24
25
  }
25
26
 
26
- export { AgentRobotAvatar, VERSION };
27
+ export { AgentRobotAvatar, SKIN_NAMES, SKINS, SKIN_SERIES, VERSION, loadSkins };
27
28
  export default AgentRobotAvatar;
package/index.d.ts CHANGED
@@ -39,6 +39,63 @@ export type AgentRobotAvatarDeprecatedAction =
39
39
  | 'connection-error'
40
40
  | 'slot';
41
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>;
98
+
42
99
  export type AgentRobotAvatarState =
43
100
  | 'idle'
44
101
  | 'happy'
@@ -114,6 +171,13 @@ export declare class AgentRobotAvatar extends HTMLElement {
114
171
  setAntennaDrag(enabled?: boolean): this;
115
172
  setHeadRoundness(value?: number): this;
116
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;
117
181
  noteActivity(wake?: boolean): void;
118
182
 
119
183
  addEventListener<K extends keyof AgentRobotAvatarEventMap>(
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.6.0",
3
+ "version": "0.7.1",
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,21 +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:waiting && 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
35
  "test:waiting": "node --test tests/waiting-wave.test.mjs",
31
- "test:browser": "playwright test"
36
+ "test:browser": "playwright test",
37
+ "test:pages": "node --test tests/pages-public.test.mjs"
32
38
  },
33
39
  "files": [
34
40
  "agent-robot-avatar.js",
41
+ "agent-robot-avatar-lite.js",
35
42
  "index.d.ts",
43
+ "lite.d.ts",
36
44
  "src/",
37
- "assets/support/",
38
- "docs/",
39
45
  "README.md",
40
46
  "CHANGELOG.md",
41
47
  "LICENSE"
@@ -76,4 +82,3 @@
76
82
  "typescript": "7.0.2"
77
83
  }
78
84
  }
79
-
@@ -42,9 +42,10 @@ const AgentRobotAvatar = (() => {
42
42
  topAL: 0, topAR: 0, bottomAL: 0, bottomAR: 0,
43
43
  scale: 1,
44
44
  },
45
+ // Same eye as sleepy; the lids meet in a thin slit instead of squashing it.
45
46
  sleep: {
46
- w: 62, h: 10, rx: 2,
47
- topY: -20, bottomY: 20,
47
+ w: 58, h: 56, rx: 28,
48
+ topY: 7, bottomY: 14,
48
49
  topAL: 0, topAR: 0, bottomAL: 0, bottomAR: 0,
49
50
  scale: 1,
50
51
  },
@@ -374,8 +375,11 @@ const AgentRobotAvatar = (() => {
374
375
  const near = Math.max(r.width, r.height) * 2.55;
375
376
  const dist = Math.hypot(dx, dy);
376
377
  const influence = clamp(1 - dist / near, 0, 1);
377
- this._pointer.x = clamp(dx * .42, -48, 48);
378
- this._pointer.y = clamp(dy * .38, -34, 34);
378
+ // Measure the pointer offset as if the avatar were demo-sized, so a large
379
+ // avatar does not look further than a small one for the same gesture.
380
+ const scale = Math.min(1, 120 / Math.max(1, r.width, r.height));
381
+ this._pointer.x = clamp(dx * .42 * scale, -48, 48);
382
+ this._pointer.y = clamp(dy * .38 * scale, -34, 34);
379
383
  this._pointer.active = influence > 0.001;
380
384
  this._pointer.influence = influence;
381
385
  this._pointer.lastMove = performance.now();
@@ -444,15 +444,18 @@ function ensureRuntime(instance) {
444
444
  if (record.attributeName === 'size') applySize(instance);
445
445
  if (record.attributeName === 'motion') motionChanged = true;
446
446
  if (record.attributeName === 'auto-sleep') autoSleepChanged = true;
447
+ if (record.attributeName === 'skin') instance._applySkinAttribute?.();
447
448
  }
448
449
  if (motionChanged) handleMotionChange(instance);
449
450
  if (autoSleepChanged) scheduleAutoSleep(instance);
450
451
  });
451
452
  instance._runtimeAttributeObserver.observe(instance, {
452
453
  attributes: true,
453
- attributeFilter: ['size', 'motion', 'wake-on', 'auto-sleep'],
454
+ attributeFilter: ['size', 'motion', 'wake-on', 'auto-sleep', 'skin'],
454
455
  });
455
456
  }
457
+ // A skin set with setSkin() survives a reconnect; markup only applies when present.
458
+ if (instance.hasAttribute('skin')) instance._applySkinAttribute?.();
456
459
 
457
460
  if (typeof IntersectionObserver !== 'undefined') {
458
461
  instance._runtimeIntersectionObserver = new IntersectionObserver(entries => {