aaavatars 2.0.0 → 2.1.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 +8 -20
- package/dist/pointer.d.ts +1 -0
- package/dist/pointer.js +53 -0
- package/dist/spec.d.ts +2 -0
- package/dist/spec.js +9 -0
- package/dist/styles.d.ts +1 -1
- package/dist/styles.js +8 -7
- 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` and colours come from the name. `mouth` and `accessory` stay off until you set them. Each name blinks
|
|
43
|
+
Unset `shape`, `eyes` and colours come from the name. `mouth` and `accessory` stay off until you set them. Each name blinks, drifts and loops at its own slightly different tempo and phase, in CSS only. With `look`, eyes follow a mouse or pen anywhere on the page through one shared listener, updated once per frame.
|
|
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
|
@@ -4,6 +4,7 @@ import { EVENT_ANIMATIONS, MOOD_SWAP_REST, MOOD_SWAP_SHOW, } from "./animations.
|
|
|
4
4
|
import { SHAPE_GEOMETRY } from "./geometry.js";
|
|
5
5
|
import { AccessoryShape, EyePair, MoodMouths, MouthShape, mouthSlot, } from "./parts.js";
|
|
6
6
|
import { createSpec, shadeHex, } from "./spec.js";
|
|
7
|
+
import { watchPointer } from "./pointer.js";
|
|
7
8
|
import { AVATAR_CSS } from "./styles.js";
|
|
8
9
|
export const AVATAR_STATUSES = [
|
|
9
10
|
"idle",
|
|
@@ -13,7 +14,6 @@ export const AVATAR_STATUSES = [
|
|
|
13
14
|
"error",
|
|
14
15
|
"sleeping",
|
|
15
16
|
];
|
|
16
|
-
const LOOK_RANGE = 4;
|
|
17
17
|
const DRAG_THRESHOLD = 3;
|
|
18
18
|
const HOLD_MS = 600;
|
|
19
19
|
const SQUISH_LIMIT = 40;
|
|
@@ -85,17 +85,12 @@ export const Avatar = forwardRef(function Avatar({ accessory, background, badge,
|
|
|
85
85
|
return Promise.all(running.current.map((animation) => animation.finished)).then(() => undefined, () => undefined);
|
|
86
86
|
}, []);
|
|
87
87
|
useImperativeHandle(ref, () => ({ play }), [play]);
|
|
88
|
-
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}
|
|
95
|
-
function resetLook(event) {
|
|
96
|
-
event.currentTarget.style.removeProperty("--aaa-look-x");
|
|
97
|
-
event.currentTarget.style.removeProperty("--aaa-look-y");
|
|
98
|
-
}
|
|
88
|
+
useEffect(() => {
|
|
89
|
+
const svg = svgRef.current;
|
|
90
|
+
if (!tracksPointer || !svg || prefersReducedMotion())
|
|
91
|
+
return;
|
|
92
|
+
return watchPointer(svg);
|
|
93
|
+
}, [tracksPointer]);
|
|
99
94
|
function startDrag(event) {
|
|
100
95
|
event.currentTarget.setPointerCapture?.(event.pointerId);
|
|
101
96
|
const state = {
|
|
@@ -150,14 +145,7 @@ export const Avatar = forwardRef(function Avatar({ accessory, background, badge,
|
|
|
150
145
|
}
|
|
151
146
|
void play(event.detail > 1 ? "surprise" : "acknowledge");
|
|
152
147
|
}
|
|
153
|
-
const svg = (_jsxs("svg", { ref: svgRef, "aria-label": label ? `${name}, ${label}` : name, className: className && !badge ? `aaa ${className}` : "aaa", "data-blink": blink ? undefined : "off", "data-interactive": interactive ? "" : undefined, "data-motion": motion ? undefined : "off", "data-status": status, height: size, role: "img", viewBox: "0 0 100 100", width: size, onClick: interactive ? handleClick : undefined, onPointerCancel: interactive ? endDrag : undefined, onPointerDown: interactive ? startDrag : undefined,
|
|
154
|
-
? (event) => {
|
|
155
|
-
if (tracksPointer)
|
|
156
|
-
lookAt(event);
|
|
157
|
-
if (interactive)
|
|
158
|
-
moveDrag(event);
|
|
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", style: {
|
|
148
|
+
const svg = (_jsxs("svg", { ref: svgRef, "aria-label": label ? `${name}, ${label}` : name, className: className && !badge ? `aaa ${className}` : "aaa", "data-blink": blink ? undefined : "off", "data-interactive": interactive ? "" : undefined, "data-motion": motion ? undefined : "off", "data-status": status, height: size, overflow: framed ? undefined : "visible", role: "img", style: { "--aaa-phase": spec.phase, "--aaa-tempo": spec.tempo }, viewBox: "0 0 100 100", width: size, onClick: interactive ? handleClick : undefined, onPointerCancel: interactive ? endDrag : undefined, onPointerDown: interactive ? startDrag : undefined, onPointerMove: interactive ? moveDrag : 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
149
|
animationDelay: `${spec.blinkDelay}s`,
|
|
162
150
|
animationDuration: `${spec.blinkDuration}s`,
|
|
163
151
|
}, 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] }) }) }) })) })] }));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function watchPointer(svg: SVGSVGElement): () => void;
|
package/dist/pointer.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
const LOOK_RANGE = 7;
|
|
2
|
+
const FALLOFF = 240;
|
|
3
|
+
const watchers = new Set();
|
|
4
|
+
let pointer = null;
|
|
5
|
+
let frame = 0;
|
|
6
|
+
function aim() {
|
|
7
|
+
frame = 0;
|
|
8
|
+
const targets = [...watchers].map((svg) => ({ svg, bounds: svg.getBoundingClientRect() }));
|
|
9
|
+
for (const { svg, bounds } of targets) {
|
|
10
|
+
if (!pointer || bounds.bottom < 0 || bounds.top > window.innerHeight) {
|
|
11
|
+
svg.style.removeProperty("--aaa-look-x");
|
|
12
|
+
svg.style.removeProperty("--aaa-look-y");
|
|
13
|
+
continue;
|
|
14
|
+
}
|
|
15
|
+
const dx = pointer.x - (bounds.left + bounds.width / 2);
|
|
16
|
+
const dy = pointer.y - (bounds.top + bounds.height / 2);
|
|
17
|
+
const distance = Math.hypot(dx, dy) || 1;
|
|
18
|
+
const reach = (LOOK_RANGE * Math.min(distance, FALLOFF)) / FALLOFF;
|
|
19
|
+
svg.style.setProperty("--aaa-look-x", `${((dx / distance) * reach).toFixed(2)}px`);
|
|
20
|
+
svg.style.setProperty("--aaa-look-y", `${((dy / distance) * reach).toFixed(2)}px`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function schedule() {
|
|
24
|
+
if (!frame)
|
|
25
|
+
frame = requestAnimationFrame(aim);
|
|
26
|
+
}
|
|
27
|
+
function handleMove(event) {
|
|
28
|
+
if (event.pointerType === "touch")
|
|
29
|
+
return;
|
|
30
|
+
pointer = { x: event.clientX, y: event.clientY };
|
|
31
|
+
schedule();
|
|
32
|
+
}
|
|
33
|
+
function handleLeave() {
|
|
34
|
+
pointer = null;
|
|
35
|
+
schedule();
|
|
36
|
+
}
|
|
37
|
+
export function watchPointer(svg) {
|
|
38
|
+
if (watchers.size === 0) {
|
|
39
|
+
window.addEventListener("pointermove", handleMove, { passive: true });
|
|
40
|
+
document.documentElement.addEventListener("pointerleave", handleLeave);
|
|
41
|
+
}
|
|
42
|
+
watchers.add(svg);
|
|
43
|
+
return () => {
|
|
44
|
+
watchers.delete(svg);
|
|
45
|
+
svg.style.removeProperty("--aaa-look-x");
|
|
46
|
+
svg.style.removeProperty("--aaa-look-y");
|
|
47
|
+
if (watchers.size === 0) {
|
|
48
|
+
window.removeEventListener("pointermove", handleMove);
|
|
49
|
+
document.documentElement.removeEventListener("pointerleave", handleLeave);
|
|
50
|
+
pointer = null;
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
}
|
package/dist/spec.d.ts
CHANGED
package/dist/spec.js
CHANGED
|
@@ -14,6 +14,8 @@ export const ACCESSORIES = ["none", "antenna", "sprout", "hat", "glasses", "bowt
|
|
|
14
14
|
export const FILLS = ["solid", "gradient"];
|
|
15
15
|
const BLINK_MIN_SECONDS = 5;
|
|
16
16
|
const BLINK_SPREAD_SECONDS = 4;
|
|
17
|
+
const TEMPO_MIN = 0.85;
|
|
18
|
+
const TEMPO_SPREAD = 0.3;
|
|
17
19
|
export const DEFAULT_COLORS = ["#264653", "#2A9D8F", "#E9C46A", "#F4A261", "#E76F51"];
|
|
18
20
|
function hash(value) {
|
|
19
21
|
let result = 2166136261;
|
|
@@ -37,6 +39,9 @@ function pick(items, random) {
|
|
|
37
39
|
function roundTenth(value) {
|
|
38
40
|
return Math.round(value * 10) / 10;
|
|
39
41
|
}
|
|
42
|
+
function roundHundredth(value) {
|
|
43
|
+
return Math.round(value * 100) / 100;
|
|
44
|
+
}
|
|
40
45
|
function signedRange(random, limit) {
|
|
41
46
|
return Math.round((random() * 2 - 1) * limit);
|
|
42
47
|
}
|
|
@@ -64,6 +69,8 @@ export function createSpec(name, options = {}) {
|
|
|
64
69
|
const accent = accentCandidates.length ? pick(accentCandidates, random) : colors[0];
|
|
65
70
|
const blinkDuration = roundTenth(BLINK_MIN_SECONDS + random() * BLINK_SPREAD_SECONDS);
|
|
66
71
|
const blinkDelay = -roundTenth(random() * blinkDuration);
|
|
72
|
+
const tempo = roundHundredth(TEMPO_MIN + random() * TEMPO_SPREAD);
|
|
73
|
+
const phase = roundHundredth(random() * 0.99);
|
|
67
74
|
const background = options.background ?? colors[backgroundIndex];
|
|
68
75
|
const body = options.body ?? colors[bodyIndex];
|
|
69
76
|
return {
|
|
@@ -78,8 +85,10 @@ export function createSpec(name, options = {}) {
|
|
|
78
85
|
mouth: options.mouth ?? "none",
|
|
79
86
|
offsetX,
|
|
80
87
|
offsetY,
|
|
88
|
+
phase,
|
|
81
89
|
rotate,
|
|
82
90
|
shape: options.shape ?? shape,
|
|
91
|
+
tempo,
|
|
83
92
|
};
|
|
84
93
|
}
|
|
85
94
|
export function shadeHex(hex, amount) {
|
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 7s infinite}\n.aaa[data-status=idle] .aaa-body-motion{animation:aaa-
|
|
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-drift calc(11s*var(--aaa-tempo,1)) ease-in-out calc(-11s*var(--aaa-phase,0)) infinite}\n.aaa[data-status=thinking] .aaa-body-motion{animation:aaa-sway calc(3s*var(--aaa-tempo,1)) ease-in-out calc(-3s*var(--aaa-phase,0)) infinite}\n.aaa[data-status=thinking] .aaa-eyes-motion{transform:translate(-5px,-6px);animation:aaa-ponder calc(2.4s*var(--aaa-tempo,1)) ease-in-out calc(-2.4s*var(--aaa-phase,0)) infinite}\n.aaa[data-status=working] .aaa-body-motion{animation:aaa-bob calc(0.9s*var(--aaa-tempo,1)) ease-in-out calc(-0.9s*var(--aaa-phase,0)) infinite}\n.aaa[data-status=working] .aaa-eyes-motion{animation:aaa-scan calc(1.1s*var(--aaa-tempo,1)) ease-in-out calc(-1.1s*var(--aaa-phase,0)) infinite}\n.aaa[data-status=waiting] .aaa-body-motion{animation:aaa-hop calc(1.6s*var(--aaa-tempo,1)) ease-out calc(-1.6s*var(--aaa-phase,0)) 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 calc(4.2s*var(--aaa-tempo,1)) ease-in-out calc(-4.2s*var(--aaa-phase,0)) 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-drift{0%,100%{transform:translate(0,0) rotate(0deg) scale(1)}20%{transform:translate(4px,-3px) rotate(5deg) scale(1.02,.98)}45%{transform:translate(-2px,-5px) rotate(-3deg) scale(.98,1.02)}70%{transform:translate(-5px,-1px) rotate(-6deg) scale(1.02,.98)}85%{transform:translate(-1px,1px) rotate(2deg) scale(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
|
@@ -10,17 +10,17 @@ export const AVATAR_CSS = `
|
|
|
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
12
|
.aaa-blink{animation:aaa-blink 7s infinite}
|
|
13
|
-
.aaa[data-status=idle] .aaa-body-motion{animation:aaa-
|
|
14
|
-
.aaa[data-status=thinking] .aaa-body-motion{animation:aaa-sway 3s ease-in-out infinite}
|
|
15
|
-
.aaa[data-status=thinking] .aaa-eyes-motion{transform:translate(-5px,-6px);animation:aaa-ponder 2.4s ease-in-out infinite}
|
|
16
|
-
.aaa[data-status=working] .aaa-body-motion{animation:aaa-bob .9s ease-in-out infinite}
|
|
17
|
-
.aaa[data-status=working] .aaa-eyes-motion{animation:aaa-scan 1.1s ease-in-out infinite}
|
|
18
|
-
.aaa[data-status=waiting] .aaa-body-motion{animation:aaa-hop 1.6s ease-out infinite}
|
|
13
|
+
.aaa[data-status=idle] .aaa-body-motion{animation:aaa-drift calc(11s*var(--aaa-tempo,1)) ease-in-out calc(-11s*var(--aaa-phase,0)) infinite}
|
|
14
|
+
.aaa[data-status=thinking] .aaa-body-motion{animation:aaa-sway calc(3s*var(--aaa-tempo,1)) ease-in-out calc(-3s*var(--aaa-phase,0)) infinite}
|
|
15
|
+
.aaa[data-status=thinking] .aaa-eyes-motion{transform:translate(-5px,-6px);animation:aaa-ponder calc(2.4s*var(--aaa-tempo,1)) ease-in-out calc(-2.4s*var(--aaa-phase,0)) infinite}
|
|
16
|
+
.aaa[data-status=working] .aaa-body-motion{animation:aaa-bob calc(0.9s*var(--aaa-tempo,1)) ease-in-out calc(-0.9s*var(--aaa-phase,0)) infinite}
|
|
17
|
+
.aaa[data-status=working] .aaa-eyes-motion{animation:aaa-scan calc(1.1s*var(--aaa-tempo,1)) ease-in-out calc(-1.1s*var(--aaa-phase,0)) infinite}
|
|
18
|
+
.aaa[data-status=waiting] .aaa-body-motion{animation:aaa-hop calc(1.6s*var(--aaa-tempo,1)) ease-out calc(-1.6s*var(--aaa-phase,0)) infinite}
|
|
19
19
|
.aaa[data-status=waiting] .aaa-eyes-motion{transform:scale(1.18)}
|
|
20
20
|
.aaa[data-status=error] .aaa-body-motion{transform:rotate(-10deg)}
|
|
21
21
|
.aaa[data-status=error] .aaa-eyes-motion{transform:scaleY(.25)}
|
|
22
22
|
.aaa[data-status=error] .aaa-blink{animation:none}
|
|
23
|
-
.aaa[data-status=sleeping] .aaa-body-motion{animation:aaa-breathe 4.2s ease-in-out infinite}
|
|
23
|
+
.aaa[data-status=sleeping] .aaa-body-motion{animation:aaa-breathe calc(4.2s*var(--aaa-tempo,1)) ease-in-out calc(-4.2s*var(--aaa-phase,0)) infinite}
|
|
24
24
|
.aaa[data-status=sleeping] .aaa-eyes-motion{transform:translateY(2px) scaleY(.12)}
|
|
25
25
|
.aaa[data-status=sleeping] .aaa-blink{animation:none}
|
|
26
26
|
.aaa[data-status=working] .aaa-antenna-tip{animation:aaa-signal .9s ease-in-out infinite}
|
|
@@ -45,6 +45,7 @@ export const AVATAR_CSS = `
|
|
|
45
45
|
.aaa[data-blink=off] .aaa-blink{animation:none}
|
|
46
46
|
.aaa[data-motion=off] *{animation:none!important}
|
|
47
47
|
@keyframes aaa-blink{0%,28%,32%,90%,94%,100%{transform:scaleY(1)}30%,92%{transform:scaleY(.1)}}
|
|
48
|
+
@keyframes aaa-drift{0%,100%{transform:translate(0,0) rotate(0deg) scale(1)}20%{transform:translate(4px,-3px) rotate(5deg) scale(1.02,.98)}45%{transform:translate(-2px,-5px) rotate(-3deg) scale(.98,1.02)}70%{transform:translate(-5px,-1px) rotate(-6deg) scale(1.02,.98)}85%{transform:translate(-1px,1px) rotate(2deg) scale(1)}}
|
|
48
49
|
@keyframes aaa-bob{0%,100%{transform:translateY(0)}50%{transform:translateY(-3px)}}
|
|
49
50
|
@keyframes aaa-sway{0%,100%{transform:rotate(-4deg)}50%{transform:rotate(4deg)}}
|
|
50
51
|
@keyframes aaa-ponder{0%,100%{transform:translate(-5px,-6px)}50%{transform:translate(5px,-6px)}}
|