aaavatars 1.0.0 → 2.0.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/README.md +1 -1
- package/dist/Avatar.js +4 -1
- package/dist/spec.d.ts +2 -0
- package/dist/spec.js +11 -16
- package/dist/styles.d.ts +1 -1
- package/dist/styles.js +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -40,7 +40,7 @@ await avatar.current?.play("done");
|
|
|
40
40
|
| `blink` / `look` / `motion` | turn blinking, pointer following or looping off |
|
|
41
41
|
| `interactive` | click, double-click, drag-to-squish and press-and-hold reactions |
|
|
42
42
|
|
|
43
|
-
Unset `shape`, `eyes
|
|
43
|
+
Unset `shape`, `eyes` and colours come from the name. `mouth` and `accessory` stay off until you set them. Each name blinks on its own rhythm, in CSS only.
|
|
44
44
|
|
|
45
45
|
`play(event)` accepts `acknowledge`, `handoff`, `done`, `success`, `failure`, `surprise`, `wake` and resolves when the animation ends. Under `prefers-reduced-motion`, or while the page is hidden, it resolves immediately.
|
|
46
46
|
|
package/dist/Avatar.js
CHANGED
|
@@ -157,7 +157,10 @@ export const Avatar = forwardRef(function Avatar({ accessory, background, badge,
|
|
|
157
157
|
if (interactive)
|
|
158
158
|
moveDrag(event);
|
|
159
159
|
}
|
|
160
|
-
: undefined, onPointerUp: interactive ? endDrag : undefined, children: [label ? _jsx("title", { children: label }) : null, _jsx("style", { children: AVATAR_CSS }), _jsxs("defs", { children: [framed ? (_jsx("clipPath", { id: `${uid}-frame`, children: _jsx("rect", { width: 100, height: 100, rx: radius }) })) : null, fill === "gradient" ? (_jsxs("linearGradient", { id: `${uid}-fill`, x1: "0", y1: "0", x2: "1", y2: "1", children: [_jsx("stop", { offset: "0%", stopColor: shadeHex(spec.body, 0.18) }), _jsx("stop", { offset: "100%", stopColor: shadeHex(spec.body, -0.22) })] })) : null, shading > 0 ? (_jsxs("radialGradient", { id: `${uid}-shade`, cx: "0.35", cy: "0.3", r: "0.85", children: [_jsx("stop", { offset: "0%", stopColor: "#ffffff", stopOpacity: 0.55 * shading }), _jsx("stop", { offset: "45%", stopColor: "#ffffff", stopOpacity: 0 }), _jsx("stop", { offset: "100%", stopColor: "#000000", stopOpacity: 0.35 * shading })] })) : null] }), framed ? (_jsx("rect", { "data-frame": "", width: 100, height: 100, rx: radius, fill: spec.background })) : null, _jsx("g", { clipPath: framed ? `url(#${uid}-frame)` : undefined, children: showImage ? (_jsx("g", { ref: bodyRef, className: "aaa-react", children: _jsx("image", { "data-image": "", height: 100, href: src, preserveAspectRatio: "xMidYMid slice", width: 100, onError: () => setImageFailed(true) }) })) : (_jsx("g", { transform: placement, children: _jsx("g", { ref: squishRef, className: "aaa-squish", children: _jsx("g", { className: "aaa-body-motion", children: _jsxs("g", { ref: bodyRef, className: "aaa-react", children: [accessoryBehind ? (_jsx(AccessoryShape, { accent: spec.accent, accessory: spec.accessory, body: spec.body, geometry: geometry })) : null, _jsx("path", { d: geometry.path, fill: bodyFill, stroke: bodyFill, strokeLinejoin: "round", strokeWidth: 8 }), shading > 0 ? (_jsx("path", { d: geometry.path, fill: `url(#${uid}-shade)`, stroke: `url(#${uid}-shade)`, strokeLinejoin: "round", strokeWidth: 8 })) : null, _jsx("g", { ref: eyesRef, className: "aaa-eyes-react", fill: spec.eyeColor, children: _jsx("g", { className: "aaa-look", children: content === "initial" ? (_jsx("text", { dominantBaseline: "central", fontFamily: "system-ui, sans-serif", fontSize: 38, fontWeight: 700, textAnchor: "middle", x: 50, y: (geometry.top + geometry.bottom) / 2 + 2, children: name.trim().charAt(0).toUpperCase() })) : (_jsx("g", { className: "aaa-eyes-motion", children: _jsx("g", { className: "aaa-blink",
|
|
160
|
+
: undefined, onPointerUp: interactive ? endDrag : undefined, children: [label ? _jsx("title", { children: label }) : null, _jsx("style", { children: AVATAR_CSS }), _jsxs("defs", { children: [framed ? (_jsx("clipPath", { id: `${uid}-frame`, children: _jsx("rect", { width: 100, height: 100, rx: radius }) })) : null, fill === "gradient" ? (_jsxs("linearGradient", { id: `${uid}-fill`, x1: "0", y1: "0", x2: "1", y2: "1", children: [_jsx("stop", { offset: "0%", stopColor: shadeHex(spec.body, 0.18) }), _jsx("stop", { offset: "100%", stopColor: shadeHex(spec.body, -0.22) })] })) : null, shading > 0 ? (_jsxs("radialGradient", { id: `${uid}-shade`, cx: "0.35", cy: "0.3", r: "0.85", children: [_jsx("stop", { offset: "0%", stopColor: "#ffffff", stopOpacity: 0.55 * shading }), _jsx("stop", { offset: "45%", stopColor: "#ffffff", stopOpacity: 0 }), _jsx("stop", { offset: "100%", stopColor: "#000000", stopOpacity: 0.35 * shading })] })) : null] }), framed ? (_jsx("rect", { "data-frame": "", width: 100, height: 100, rx: radius, fill: spec.background })) : null, _jsx("g", { clipPath: framed ? `url(#${uid}-frame)` : undefined, children: showImage ? (_jsx("g", { ref: bodyRef, className: "aaa-react", children: _jsx("image", { "data-image": "", height: 100, href: src, preserveAspectRatio: "xMidYMid slice", width: 100, onError: () => setImageFailed(true) }) })) : (_jsx("g", { transform: placement, children: _jsx("g", { ref: squishRef, className: "aaa-squish", children: _jsx("g", { className: "aaa-body-motion", children: _jsxs("g", { ref: bodyRef, className: "aaa-react", children: [accessoryBehind ? (_jsx(AccessoryShape, { accent: spec.accent, accessory: spec.accessory, body: spec.body, geometry: geometry })) : null, _jsx("path", { d: geometry.path, fill: bodyFill, stroke: bodyFill, strokeLinejoin: "round", strokeWidth: 8 }), shading > 0 ? (_jsx("path", { d: geometry.path, fill: `url(#${uid}-shade)`, stroke: `url(#${uid}-shade)`, strokeLinejoin: "round", strokeWidth: 8 })) : null, _jsx("g", { ref: eyesRef, className: "aaa-eyes-react", fill: spec.eyeColor, children: _jsx("g", { className: "aaa-look", children: content === "initial" ? (_jsx("text", { dominantBaseline: "central", fontFamily: "system-ui, sans-serif", fontSize: 38, fontWeight: 700, textAnchor: "middle", x: 50, y: (geometry.top + geometry.bottom) / 2 + 2, children: name.trim().charAt(0).toUpperCase() })) : (_jsx("g", { className: "aaa-eyes-motion", children: _jsx("g", { className: "aaa-blink", style: {
|
|
161
|
+
animationDelay: `${spec.blinkDelay}s`,
|
|
162
|
+
animationDuration: `${spec.blinkDuration}s`,
|
|
163
|
+
}, children: _jsx(EyePair, { eyes: spec.eyes, gap: geometry.eyeGap, y: geometry.eyeY }) }) })) }) }), hasMouth ? (_jsxs("g", { className: "aaa-look", children: [_jsx("g", { className: "aaa-mouth-rest", children: renderMouth ? (renderMouth(slot)) : (_jsx(MouthShape, { mouth: spec.mouth, slot: slot })) }), _jsx(MoodMouths, { slot: slot })] })) : null, !accessoryBehind && (spec.accessory !== "glasses" || content === "face") ? (_jsx(AccessoryShape, { accent: spec.accent, accessory: spec.accessory, body: spec.body, geometry: geometry })) : null] }) }) }) })) })] }));
|
|
161
164
|
if (!badge)
|
|
162
165
|
return svg;
|
|
163
166
|
return (_jsxs("span", { className: className, style: {
|
package/dist/spec.d.ts
CHANGED
package/dist/spec.js
CHANGED
|
@@ -12,18 +12,8 @@ export const EYES = ["round", "dot", "tall", "wide"];
|
|
|
12
12
|
export const MOUTHS = ["none", "smile", "flat", "open"];
|
|
13
13
|
export const ACCESSORIES = ["none", "antenna", "sprout", "hat", "glasses", "bowtie"];
|
|
14
14
|
export const FILLS = ["solid", "gradient"];
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
"none",
|
|
18
|
-
"none",
|
|
19
|
-
"none",
|
|
20
|
-
"none",
|
|
21
|
-
"antenna",
|
|
22
|
-
"sprout",
|
|
23
|
-
"hat",
|
|
24
|
-
"glasses",
|
|
25
|
-
"bowtie",
|
|
26
|
-
];
|
|
15
|
+
const BLINK_MIN_SECONDS = 5;
|
|
16
|
+
const BLINK_SPREAD_SECONDS = 4;
|
|
27
17
|
export const DEFAULT_COLORS = ["#264653", "#2A9D8F", "#E9C46A", "#F4A261", "#E76F51"];
|
|
28
18
|
function hash(value) {
|
|
29
19
|
let result = 2166136261;
|
|
@@ -44,6 +34,9 @@ function seededRandom(seed) {
|
|
|
44
34
|
function pick(items, random) {
|
|
45
35
|
return items[Math.floor(random() * items.length)];
|
|
46
36
|
}
|
|
37
|
+
function roundTenth(value) {
|
|
38
|
+
return Math.round(value * 10) / 10;
|
|
39
|
+
}
|
|
47
40
|
function signedRange(random, limit) {
|
|
48
41
|
return Math.round((random() * 2 - 1) * limit);
|
|
49
42
|
}
|
|
@@ -67,20 +60,22 @@ export function createSpec(name, options = {}) {
|
|
|
67
60
|
const offsetX = signedRange(random, 6);
|
|
68
61
|
const offsetY = signedRange(random, 5);
|
|
69
62
|
const rotate = signedRange(random, 12);
|
|
70
|
-
const mouth = pick(HASHED_MOUTHS, random);
|
|
71
|
-
const accessory = pick(HASHED_ACCESSORIES, random);
|
|
72
63
|
const accentCandidates = colors.filter((_, index) => index !== bodyIndex && index !== backgroundIndex);
|
|
73
64
|
const accent = accentCandidates.length ? pick(accentCandidates, random) : colors[0];
|
|
65
|
+
const blinkDuration = roundTenth(BLINK_MIN_SECONDS + random() * BLINK_SPREAD_SECONDS);
|
|
66
|
+
const blinkDelay = -roundTenth(random() * blinkDuration);
|
|
74
67
|
const background = options.background ?? colors[backgroundIndex];
|
|
75
68
|
const body = options.body ?? colors[bodyIndex];
|
|
76
69
|
return {
|
|
77
70
|
accent,
|
|
78
|
-
accessory: options.accessory ??
|
|
71
|
+
accessory: options.accessory ?? "none",
|
|
79
72
|
background,
|
|
73
|
+
blinkDelay,
|
|
74
|
+
blinkDuration,
|
|
80
75
|
body,
|
|
81
76
|
eyeColor: relativeLuminance(body) > 0.4 ? "#141414" : "#FFFFFF",
|
|
82
77
|
eyes: options.eyes ?? eyes,
|
|
83
|
-
mouth: options.mouth ??
|
|
78
|
+
mouth: options.mouth ?? "none",
|
|
84
79
|
offsetX,
|
|
85
80
|
offsetY,
|
|
86
81
|
rotate,
|
package/dist/styles.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const AVATAR_CSS = "\n.aaa-body-motion,.aaa-react,.aaa-eyes-react,.aaa-eyes-motion,.aaa-blink,.aaa-squish{transform-box:fill-box;transform-origin:center}\n.aaa-mouth-rest,.aaa-mood{transform-box:fill-box;transform-origin:center;transition:opacity .2s,transform .2s}\n.aaa-mood{opacity:0}\n.aaa-accessory{transform-box:fill-box;transform-origin:50% 100%;transition:transform .3s ease-out}\n.aaa-accessory[data-accessory=glasses],.aaa-accessory[data-accessory=bowtie]{transform-origin:center}\n.aaa-squish{transition:transform .45s cubic-bezier(.34,1.56,.64,1)}\n.aaa-squish[data-dragging]{transition:none}\n.aaa[data-interactive]{cursor:grab;touch-action:none}\n.aaa[data-interactive]:active{cursor:grabbing}\n.aaa-look{transform:translate(var(--aaa-look-x,0px),var(--aaa-look-y,0px));transition:transform .25s ease-out}\n.aaa-blink{animation:aaa-blink
|
|
1
|
+
export declare const AVATAR_CSS = "\n.aaa-body-motion,.aaa-react,.aaa-eyes-react,.aaa-eyes-motion,.aaa-blink,.aaa-squish{transform-box:fill-box;transform-origin:center}\n.aaa-mouth-rest,.aaa-mood{transform-box:fill-box;transform-origin:center;transition:opacity .2s,transform .2s}\n.aaa-mood{opacity:0}\n.aaa-accessory{transform-box:fill-box;transform-origin:50% 100%;transition:transform .3s ease-out}\n.aaa-accessory[data-accessory=glasses],.aaa-accessory[data-accessory=bowtie]{transform-origin:center}\n.aaa-squish{transition:transform .45s cubic-bezier(.34,1.56,.64,1)}\n.aaa-squish[data-dragging]{transition:none}\n.aaa[data-interactive]{cursor:grab;touch-action:none}\n.aaa[data-interactive]:active{cursor:grabbing}\n.aaa-look{transform:translate(var(--aaa-look-x,0px),var(--aaa-look-y,0px));transition:transform .25s ease-out}\n.aaa-blink{animation:aaa-blink 7s infinite}\n.aaa[data-status=idle] .aaa-body-motion{animation:aaa-bob 3.6s ease-in-out infinite}\n.aaa[data-status=thinking] .aaa-body-motion{animation:aaa-sway 3s ease-in-out infinite}\n.aaa[data-status=thinking] .aaa-eyes-motion{transform:translate(-5px,-6px);animation:aaa-ponder 2.4s ease-in-out infinite}\n.aaa[data-status=working] .aaa-body-motion{animation:aaa-bob .9s ease-in-out infinite}\n.aaa[data-status=working] .aaa-eyes-motion{animation:aaa-scan 1.1s ease-in-out infinite}\n.aaa[data-status=waiting] .aaa-body-motion{animation:aaa-hop 1.6s ease-out infinite}\n.aaa[data-status=waiting] .aaa-eyes-motion{transform:scale(1.18)}\n.aaa[data-status=error] .aaa-body-motion{transform:rotate(-10deg)}\n.aaa[data-status=error] .aaa-eyes-motion{transform:scaleY(.25)}\n.aaa[data-status=error] .aaa-blink{animation:none}\n.aaa[data-status=sleeping] .aaa-body-motion{animation:aaa-breathe 4.2s ease-in-out infinite}\n.aaa[data-status=sleeping] .aaa-eyes-motion{transform:translateY(2px) scaleY(.12)}\n.aaa[data-status=sleeping] .aaa-blink{animation:none}\n.aaa[data-status=working] .aaa-antenna-tip{animation:aaa-signal .9s ease-in-out infinite}\n.aaa[data-status=thinking] .aaa-mouth-rest{opacity:0}\n.aaa[data-status=thinking] .aaa-mood-small{opacity:1}\n.aaa[data-status=thinking] .aaa-accessory:is([data-accessory=antenna],[data-accessory=sprout]){animation:aaa-acc-sway 2.4s ease-in-out infinite}\n.aaa[data-status=thinking] .aaa-accessory[data-accessory=glasses]{animation:aaa-glasses-think 2.4s ease-in-out infinite}\n.aaa[data-status=working] .aaa-mouth-rest{transform:scaleX(.7)}\n.aaa[data-status=working] .aaa-accessory[data-accessory=bowtie]{animation:aaa-wobble .9s ease-in-out infinite}\n.aaa[data-status=waiting] .aaa-mouth-rest{opacity:0}\n.aaa[data-status=waiting] .aaa-mood-happy{opacity:1}\n.aaa[data-status=waiting] .aaa-accessory:not([data-accessory=glasses]){animation:aaa-wobble 1.6s ease-in-out infinite}\n.aaa[data-status=error] .aaa-mouth-rest{opacity:0}\n.aaa[data-status=error] .aaa-mood-sad{opacity:1}\n.aaa[data-status=error] .aaa-accessory:is([data-accessory=antenna],[data-accessory=sprout]){transform:rotate(28deg)}\n.aaa[data-status=error] .aaa-accessory:is([data-accessory=hat],[data-accessory=glasses]){transform:translateY(3px) rotate(8deg)}\n.aaa[data-status=error] .aaa-accessory[data-accessory=bowtie]{transform:rotate(18deg)}\n.aaa[data-status=sleeping] .aaa-mouth-rest{opacity:0}\n.aaa[data-status=sleeping] .aaa-mood-o{opacity:1;animation:aaa-snore 4.2s ease-in-out infinite}\n.aaa[data-status=sleeping] .aaa-accessory:is([data-accessory=antenna],[data-accessory=sprout]){transform:rotate(-35deg)}\n.aaa[data-status=sleeping] .aaa-accessory:is([data-accessory=hat],[data-accessory=glasses]){transform:translateY(5px)}\n.aaa[data-blink=off] .aaa-blink{animation:none}\n.aaa[data-motion=off] *{animation:none!important}\n@keyframes aaa-blink{0%,28%,32%,90%,94%,100%{transform:scaleY(1)}30%,92%{transform:scaleY(.1)}}\n@keyframes aaa-bob{0%,100%{transform:translateY(0)}50%{transform:translateY(-3px)}}\n@keyframes aaa-sway{0%,100%{transform:rotate(-4deg)}50%{transform:rotate(4deg)}}\n@keyframes aaa-ponder{0%,100%{transform:translate(-5px,-6px)}50%{transform:translate(5px,-6px)}}\n@keyframes aaa-scan{0%,100%{transform:translateX(-5px)}50%{transform:translateX(5px)}}\n@keyframes aaa-breathe{0%,100%{transform:scale(1)}50%{transform:scale(1.035,.97)}}\n@keyframes aaa-signal{0%,100%{opacity:1}50%{opacity:.25}}\n@keyframes aaa-acc-sway{0%,100%{transform:rotate(-8deg)}50%{transform:rotate(8deg)}}\n@keyframes aaa-wobble{0%,100%{transform:rotate(-12deg)}50%{transform:rotate(12deg)}}\n@keyframes aaa-glasses-think{0%,100%{transform:translateY(0)}50%{transform:translateY(-3px)}}\n@keyframes aaa-snore{0%,100%{transform:scale(.7)}50%{transform:scale(1.1)}}\n@keyframes aaa-hop{0%,55%,100%{transform:translateY(0)}68%{transform:translateY(-7px)}80%{transform:translateY(0)}90%{transform:translateY(-3px)}}\n@media (prefers-reduced-motion:reduce){.aaa *{animation:none!important;transition:none!important}}\n";
|
package/dist/styles.js
CHANGED
|
@@ -9,7 +9,7 @@ export const AVATAR_CSS = `
|
|
|
9
9
|
.aaa[data-interactive]{cursor:grab;touch-action:none}
|
|
10
10
|
.aaa[data-interactive]:active{cursor:grabbing}
|
|
11
11
|
.aaa-look{transform:translate(var(--aaa-look-x,0px),var(--aaa-look-y,0px));transition:transform .25s ease-out}
|
|
12
|
-
.aaa-blink{animation:aaa-blink
|
|
12
|
+
.aaa-blink{animation:aaa-blink 7s infinite}
|
|
13
13
|
.aaa[data-status=idle] .aaa-body-motion{animation:aaa-bob 3.6s ease-in-out infinite}
|
|
14
14
|
.aaa[data-status=thinking] .aaa-body-motion{animation:aaa-sway 3s ease-in-out infinite}
|
|
15
15
|
.aaa[data-status=thinking] .aaa-eyes-motion{transform:translate(-5px,-6px);animation:aaa-ponder 2.4s ease-in-out infinite}
|
|
@@ -44,7 +44,7 @@ export const AVATAR_CSS = `
|
|
|
44
44
|
.aaa[data-status=sleeping] .aaa-accessory:is([data-accessory=hat],[data-accessory=glasses]){transform:translateY(5px)}
|
|
45
45
|
.aaa[data-blink=off] .aaa-blink{animation:none}
|
|
46
46
|
.aaa[data-motion=off] *{animation:none!important}
|
|
47
|
-
@keyframes aaa-blink{0%,
|
|
47
|
+
@keyframes aaa-blink{0%,28%,32%,90%,94%,100%{transform:scaleY(1)}30%,92%{transform:scaleY(.1)}}
|
|
48
48
|
@keyframes aaa-bob{0%,100%{transform:translateY(0)}50%{transform:translateY(-3px)}}
|
|
49
49
|
@keyframes aaa-sway{0%,100%{transform:rotate(-4deg)}50%{transform:rotate(4deg)}}
|
|
50
50
|
@keyframes aaa-ponder{0%,100%{transform:translate(-5px,-6px)}50%{transform:translate(5px,-6px)}}
|