@dotcraft/avatar 0.6.4 → 0.6.5

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 (32) hide show
  1. package/dist/composer/ComposerMascot.d.ts.map +1 -1
  2. package/dist/composer/ComposerMascot.js +32 -106
  3. package/dist/composer/ComposerMascot.js.map +1 -1
  4. package/dist/composer/MascotIdleStage.d.ts +11 -0
  5. package/dist/composer/MascotIdleStage.d.ts.map +1 -0
  6. package/dist/composer/MascotIdleStage.js +9 -0
  7. package/dist/composer/MascotIdleStage.js.map +1 -0
  8. package/dist/composer/constants.d.ts +12 -1
  9. package/dist/composer/constants.d.ts.map +1 -1
  10. package/dist/composer/constants.js +9 -4
  11. package/dist/composer/constants.js.map +1 -1
  12. package/dist/composer/styles/idle.css +116 -105
  13. package/dist/composer/useComposerAvatarBehavior.d.ts +1 -0
  14. package/dist/composer/useComposerAvatarBehavior.d.ts.map +1 -1
  15. package/dist/composer/useComposerAvatarBehavior.js +2 -2
  16. package/dist/composer/useComposerAvatarBehavior.js.map +1 -1
  17. package/dist/composer/useMascotActiveIdle.d.ts +33 -0
  18. package/dist/composer/useMascotActiveIdle.d.ts.map +1 -0
  19. package/dist/composer/useMascotActiveIdle.js +128 -0
  20. package/dist/composer/useMascotActiveIdle.js.map +1 -0
  21. package/dist/react.d.ts +5 -0
  22. package/dist/react.d.ts.map +1 -1
  23. package/dist/react.js +4 -0
  24. package/dist/react.js.map +1 -1
  25. package/package.json +1 -1
  26. package/src/composer/ComposerMascot.tsx +36 -112
  27. package/src/composer/MascotIdleStage.tsx +23 -0
  28. package/src/composer/constants.ts +25 -4
  29. package/src/composer/styles/idle.css +116 -105
  30. package/src/composer/useComposerAvatarBehavior.ts +3 -2
  31. package/src/composer/useMascotActiveIdle.ts +170 -0
  32. package/src/react.ts +5 -0
@@ -2,74 +2,84 @@
2
2
  opacity: 0;
3
3
  }
4
4
 
5
- .composer-mascot-active-idle .composer-mascot-motion {
5
+ /* A trip heads `--mascot-idle-dir`; each leg moves along `--mascot-idle-travel-sign` (left is -1). */
6
+ .composer-mascot-active-idle {
7
+ --mascot-idle-dir: -1;
8
+ --mascot-idle-travel-sign: -1;
9
+ }
10
+
11
+ .composer-mascot-active-idle[data-mascot-idle-direction='right'] {
12
+ --mascot-idle-dir: 1;
13
+ }
14
+
15
+ .composer-mascot-active-idle[data-mascot-idle-travel='right'] {
16
+ --mascot-idle-travel-sign: 1;
17
+ }
18
+
19
+ .composer-mascot-active-idle .composer-mascot-stage {
20
+ position: relative;
6
21
  top: 0;
7
22
  left: 0;
8
23
  }
9
24
 
10
- .composer-mascot-active-idle[data-mascot-idle-phase='away'] .composer-mascot-breathe {
25
+ .composer-mascot-active-idle[data-mascot-idle-phase='away'] .composer-mascot-body {
11
26
  animation: none;
12
27
  transform: scale(1);
13
28
  }
14
29
 
15
- .composer-mascot-active-idle[data-mascot-active-idle='hop'][data-mascot-idle-phase='away'] .composer-mascot-motion,
16
- .composer-mascot-active-idle[data-mascot-active-idle='hop'][data-mascot-idle-phase='inbound'] .composer-mascot-motion {
17
- left: -210px;
30
+ /* The stage parks at the far end in its own (possibly scaled) space while the travel layer rests at zero. */
31
+ .composer-mascot-active-idle[data-mascot-active-idle='hop'][data-mascot-idle-phase='away'] .composer-mascot-stage,
32
+ .composer-mascot-active-idle[data-mascot-active-idle='hop'][data-mascot-idle-phase='inbound'] .composer-mascot-stage {
33
+ left: calc(280px * var(--mascot-idle-stage-scale, 1) * var(--mascot-idle-dir, -1));
18
34
  }
19
35
 
20
- .composer-mascot-active-idle[data-mascot-active-idle='rocket'][data-mascot-idle-phase='away'] .composer-mascot-motion,
21
- .composer-mascot-active-idle[data-mascot-active-idle='rocket'][data-mascot-idle-phase='inbound'] .composer-mascot-motion {
22
- left: -220px;
36
+ .composer-mascot-active-idle[data-mascot-active-idle='rocket'][data-mascot-idle-phase='away'] .composer-mascot-stage,
37
+ .composer-mascot-active-idle[data-mascot-active-idle='rocket'][data-mascot-idle-phase='inbound'] .composer-mascot-stage {
38
+ left: calc(293.33px * var(--mascot-idle-stage-scale, 1) * var(--mascot-idle-dir, -1));
23
39
  }
24
40
 
25
- .composer-mascot-active-idle[data-mascot-active-idle='hover'][data-mascot-idle-phase='away'] .composer-mascot-motion,
26
- .composer-mascot-active-idle[data-mascot-active-idle='hover'][data-mascot-idle-phase='inbound'] .composer-mascot-motion {
27
- top: -96px;
28
- left: -150px;
41
+ .composer-mascot-active-idle[data-mascot-active-idle='hover'][data-mascot-idle-phase='away'] .composer-mascot-stage,
42
+ .composer-mascot-active-idle[data-mascot-active-idle='hover'][data-mascot-idle-phase='inbound'] .composer-mascot-stage {
43
+ top: calc(-128px * var(--mascot-idle-stage-scale, 1));
44
+ left: calc(200px * var(--mascot-idle-stage-scale, 1) * var(--mascot-idle-dir, -1));
29
45
  }
30
46
 
31
- .composer-mascot-active-idle .composer-mascot-motion > div:first-child,
32
- .composer-mascot-active-idle .composer-mascot-motion > div:first-child > div:first-child,
33
- .composer-mascot-active-idle .composer-mascot-breathe {
47
+ .composer-mascot-active-idle .composer-mascot-travel,
48
+ .composer-mascot-active-idle .composer-mascot-lift,
49
+ .composer-mascot-active-idle .composer-mascot-body {
34
50
  transform-origin: bottom center;
35
51
  will-change: transform;
36
52
  }
37
53
 
38
- .composer-mascot-active-idle .composer-mascot-motion > div:first-child > div:first-child {
54
+ .composer-mascot-active-idle .composer-mascot-travel {
55
+ position: relative;
56
+ }
57
+
58
+ .composer-mascot-active-idle .composer-mascot-lift {
39
59
  position: relative;
40
60
  z-index: 1;
41
61
  }
42
62
 
43
- .composer-mascot-active-idle[data-mascot-active-idle='hop'][data-mascot-idle-phase='outbound'] .composer-mascot-motion > div:first-child,
44
- .composer-mascot-active-idle[data-mascot-active-idle='hop'][data-mascot-idle-phase='inbound'] .composer-mascot-motion > div:first-child {
63
+ .composer-mascot-active-idle[data-mascot-active-idle='hop'][data-mascot-idle-phase='outbound'] .composer-mascot-travel,
64
+ .composer-mascot-active-idle[data-mascot-active-idle='hop'][data-mascot-idle-phase='inbound'] .composer-mascot-travel {
45
65
  --mascot-hop-compress-y: 0.82px;
46
66
  --mascot-hop-apex-y: -11.44px;
47
67
  --mascot-hop-fall-y: -2.86px;
48
68
  --mascot-hop-land-y: 0.41px;
69
+ --mascot-hop-distance: calc(280px * var(--mascot-idle-travel-sign, -1));
70
+ --mascot-hop-x-1: calc(70px * var(--mascot-idle-travel-sign, -1));
71
+ --mascot-hop-x-2: calc(140px * var(--mascot-idle-travel-sign, -1));
72
+ --mascot-hop-x-3: calc(210px * var(--mascot-idle-travel-sign, -1));
49
73
  animation: composer-mascot-idle-hop-travel 2.4s linear forwards;
50
74
  }
51
75
 
52
- .composer-mascot-active-idle[data-mascot-active-idle='hop'][data-mascot-idle-phase='outbound'] .composer-mascot-motion > div:first-child {
53
- --mascot-hop-distance: -280px;
54
- --mascot-hop-x-1: -70px;
55
- --mascot-hop-x-2: -140px;
56
- --mascot-hop-x-3: -210px;
57
- }
58
-
59
- .composer-mascot-active-idle[data-mascot-active-idle='hop'][data-mascot-idle-phase='inbound'] .composer-mascot-motion > div:first-child {
60
- --mascot-hop-distance: 280px;
61
- --mascot-hop-x-1: 70px;
62
- --mascot-hop-x-2: 140px;
63
- --mascot-hop-x-3: 210px;
64
- }
65
-
66
- .composer-mascot-active-idle[data-mascot-active-idle='hop'][data-mascot-idle-phase='outbound'] .composer-mascot-breathe,
67
- .composer-mascot-active-idle[data-mascot-active-idle='hop'][data-mascot-idle-phase='inbound'] .composer-mascot-breathe {
76
+ .composer-mascot-active-idle[data-mascot-active-idle='hop'][data-mascot-idle-phase='outbound'] .composer-mascot-body,
77
+ .composer-mascot-active-idle[data-mascot-active-idle='hop'][data-mascot-idle-phase='inbound'] .composer-mascot-body {
68
78
  animation: composer-mascot-idle-hop-body 600ms linear 4;
69
79
  }
70
80
 
71
- .composer-mascot-active-idle[data-mascot-active-idle='hop'] .composer-mascot-motion > div:first-child::before,
72
- .composer-mascot-active-idle[data-mascot-active-idle='rocket'] .composer-mascot-motion > div:first-child::before {
81
+ .composer-mascot-active-idle[data-mascot-active-idle='hop'] .composer-mascot-travel::before,
82
+ .composer-mascot-active-idle[data-mascot-active-idle='rocket'] .composer-mascot-travel::before {
73
83
  content: '';
74
84
  position: absolute;
75
85
  bottom: -1px;
@@ -85,8 +95,8 @@
85
95
  transform-origin: center;
86
96
  }
87
97
 
88
- .composer-mascot-active-idle[data-mascot-active-idle='hop'][data-mascot-idle-phase='outbound'] .composer-mascot-motion > div:first-child::before,
89
- .composer-mascot-active-idle[data-mascot-active-idle='hop'][data-mascot-idle-phase='inbound'] .composer-mascot-motion > div:first-child::before {
98
+ .composer-mascot-active-idle[data-mascot-active-idle='hop'][data-mascot-idle-phase='outbound'] .composer-mascot-travel::before,
99
+ .composer-mascot-active-idle[data-mascot-active-idle='hop'][data-mascot-idle-phase='inbound'] .composer-mascot-travel::before {
90
100
  animation: composer-mascot-idle-hop-shadow 600ms ease-in-out 4;
91
101
  }
92
102
 
@@ -115,48 +125,40 @@
115
125
  90% { opacity: 0.76; transform: translateX(-50%) scaleX(1.12); }
116
126
  }
117
127
 
118
- .composer-mascot-active-idle[data-mascot-active-idle='rocket'][data-mascot-idle-phase='outbound'] .composer-mascot-motion > div:first-child,
119
- .composer-mascot-active-idle[data-mascot-active-idle='rocket'][data-mascot-idle-phase='inbound'] .composer-mascot-motion > div:first-child {
128
+ .composer-mascot-active-idle[data-mascot-active-idle='rocket'][data-mascot-idle-phase='outbound'] .composer-mascot-travel,
129
+ .composer-mascot-active-idle[data-mascot-active-idle='rocket'][data-mascot-idle-phase='inbound'] .composer-mascot-travel {
120
130
  --mascot-rocket-apex-y: -66.99px;
121
131
  --mascot-rocket-crouch-y: 1.23px;
122
132
  --mascot-rocket-air-y: -2.04px;
123
133
  --mascot-rocket-approach-y: -0.82px;
124
134
  --mascot-rocket-rebound-y: -1.23px;
135
+ --mascot-flight-distance: calc(293.33px * var(--mascot-idle-travel-sign, -1));
136
+ --mascot-rocket-tilt: calc(8deg * var(--mascot-idle-travel-sign, -1));
125
137
  animation: composer-mascot-idle-rocket-flight-x 1.8s linear forwards;
126
138
  }
127
139
 
128
- .composer-mascot-active-idle[data-mascot-active-idle='rocket'][data-mascot-idle-phase='outbound'] .composer-mascot-motion > div:first-child {
129
- --mascot-flight-distance: -293.33px;
130
- --mascot-rocket-tilt: -8deg;
131
- }
132
-
133
- .composer-mascot-active-idle[data-mascot-active-idle='rocket'][data-mascot-idle-phase='inbound'] .composer-mascot-motion > div:first-child {
134
- --mascot-flight-distance: 293.33px;
135
- --mascot-rocket-tilt: 8deg;
136
- }
137
-
138
- .composer-mascot-active-idle[data-mascot-active-idle='rocket'][data-mascot-idle-phase='outbound'] .composer-mascot-motion > div:first-child > div:first-child,
139
- .composer-mascot-active-idle[data-mascot-active-idle='rocket'][data-mascot-idle-phase='inbound'] .composer-mascot-motion > div:first-child > div:first-child {
140
+ .composer-mascot-active-idle[data-mascot-active-idle='rocket'][data-mascot-idle-phase='outbound'] .composer-mascot-lift,
141
+ .composer-mascot-active-idle[data-mascot-active-idle='rocket'][data-mascot-idle-phase='inbound'] .composer-mascot-lift {
140
142
  animation: composer-mascot-idle-rocket-flight-y 1.8s linear forwards;
141
143
  }
142
144
 
143
- .composer-mascot-active-idle[data-mascot-active-idle='rocket'][data-mascot-idle-phase='outbound'] .composer-mascot-breathe,
144
- .composer-mascot-active-idle[data-mascot-active-idle='rocket'][data-mascot-idle-phase='inbound'] .composer-mascot-breathe {
145
+ .composer-mascot-active-idle[data-mascot-active-idle='rocket'][data-mascot-idle-phase='outbound'] .composer-mascot-body,
146
+ .composer-mascot-active-idle[data-mascot-active-idle='rocket'][data-mascot-idle-phase='inbound'] .composer-mascot-body {
145
147
  animation: composer-mascot-idle-rocket-body 1.8s ease-out forwards;
146
148
  }
147
149
 
148
- .composer-mascot-active-idle[data-mascot-active-idle='rocket'][data-mascot-idle-phase='outbound'] .composer-mascot-motion > div:first-child::before,
149
- .composer-mascot-active-idle[data-mascot-active-idle='rocket'][data-mascot-idle-phase='inbound'] .composer-mascot-motion > div:first-child::before {
150
+ .composer-mascot-active-idle[data-mascot-active-idle='rocket'][data-mascot-idle-phase='outbound'] .composer-mascot-travel::before,
151
+ .composer-mascot-active-idle[data-mascot-active-idle='rocket'][data-mascot-idle-phase='inbound'] .composer-mascot-travel::before {
150
152
  animation: composer-mascot-idle-flight-shadow 1.8s ease-in-out forwards;
151
153
  }
152
154
 
153
- .composer-mascot-active-idle[data-mascot-active-idle='rocket'] .composer-mascot-jelly {
155
+ .composer-mascot-active-idle[data-mascot-active-idle='rocket'] .composer-mascot-trail {
154
156
  position: relative;
155
157
  isolation: isolate;
156
158
  }
157
159
 
158
- .composer-mascot-active-idle[data-mascot-active-idle='rocket'][data-mascot-idle-phase='outbound'] .composer-mascot-jelly::before,
159
- .composer-mascot-active-idle[data-mascot-active-idle='rocket'][data-mascot-idle-phase='inbound'] .composer-mascot-jelly::before {
160
+ .composer-mascot-active-idle[data-mascot-active-idle='rocket'][data-mascot-idle-phase='outbound'] .composer-mascot-trail::before,
161
+ .composer-mascot-active-idle[data-mascot-active-idle='rocket'][data-mascot-idle-phase='inbound'] .composer-mascot-trail::before {
160
162
  content: '';
161
163
  position: absolute;
162
164
  top: 17px;
@@ -169,7 +171,8 @@
169
171
  animation: composer-mascot-idle-rocket-trail 1.8s ease-out forwards;
170
172
  }
171
173
 
172
- .composer-mascot-active-idle[data-mascot-active-idle='rocket'][data-mascot-idle-phase='outbound'] .composer-mascot-jelly::before {
174
+ /* The exhaust streams behind the leg's direction of travel. */
175
+ .composer-mascot-active-idle[data-mascot-active-idle='rocket'][data-mascot-idle-travel='left'] .composer-mascot-trail::before {
173
176
  left: calc(100% - 2px);
174
177
  background:
175
178
  linear-gradient(90deg, #f5f7fa, #8fa5ff 28%, transparent 100%) 0 1px / 34px 2px no-repeat,
@@ -178,7 +181,7 @@
178
181
  transform-origin: left center;
179
182
  }
180
183
 
181
- .composer-mascot-active-idle[data-mascot-active-idle='rocket'][data-mascot-idle-phase='inbound'] .composer-mascot-jelly::before {
184
+ .composer-mascot-active-idle[data-mascot-active-idle='rocket'][data-mascot-idle-travel='right'] .composer-mascot-trail::before {
182
185
  right: calc(100% - 2px);
183
186
  background:
184
187
  linear-gradient(90deg, transparent 0%, #8fa5ff 72%, #f5f7fa 100%) 100% 1px / 34px 2px no-repeat,
@@ -224,77 +227,78 @@
224
227
  86%, 100% { opacity: 0.7; transform: translateX(-50%) scaleX(1.12); }
225
228
  }
226
229
 
227
- .composer-mascot-active-idle[data-mascot-active-idle='hover'][data-mascot-idle-phase='outbound'] .composer-mascot-motion > div:first-child {
228
- --mascot-hover-x: -200px;
230
+ .composer-mascot-active-idle[data-mascot-active-idle='hover'][data-mascot-idle-phase='outbound'] .composer-mascot-travel {
231
+ --mascot-hover-x: calc(200px * var(--mascot-idle-travel-sign, -1));
229
232
  --mascot-hover-y: -128px;
230
233
  animation: composer-mascot-idle-hover-rise-x 1.8s cubic-bezier(0.26, 0.55, 0.24, 1) forwards;
231
234
  }
232
235
 
233
- .composer-mascot-active-idle[data-mascot-active-idle='hover'][data-mascot-idle-phase='outbound'] .composer-mascot-motion > div:first-child > div:first-child {
236
+ .composer-mascot-active-idle[data-mascot-active-idle='hover'][data-mascot-idle-phase='outbound'] .composer-mascot-lift {
234
237
  animation: composer-mascot-idle-hover-rise-y 1.8s linear forwards;
235
238
  }
236
239
 
237
- .composer-mascot-active-idle[data-mascot-active-idle='hover'][data-mascot-idle-phase='away'] .composer-mascot-motion > div:first-child > div:first-child {
240
+ .composer-mascot-active-idle[data-mascot-active-idle='hover'][data-mascot-idle-phase='away'] .composer-mascot-lift {
238
241
  animation: composer-mascot-idle-hover-float 2.8s ease-in-out forwards;
239
242
  }
240
243
 
241
- .composer-mascot-active-idle[data-mascot-active-idle='hover'][data-mascot-idle-phase='inbound'] .composer-mascot-motion > div:first-child {
242
- --mascot-hover-x: 200px;
244
+ .composer-mascot-active-idle[data-mascot-active-idle='hover'][data-mascot-idle-phase='inbound'] .composer-mascot-travel {
245
+ --mascot-hover-x: calc(200px * var(--mascot-idle-travel-sign, -1));
243
246
  --mascot-hover-y: 128px;
244
247
  animation: composer-mascot-idle-hover-return-x 1.8s cubic-bezier(0.38, 0.04, 0.34, 1) forwards;
245
248
  }
246
249
 
247
- .composer-mascot-active-idle[data-mascot-active-idle='hover'][data-mascot-idle-phase='inbound'] .composer-mascot-motion > div:first-child > div:first-child {
250
+ .composer-mascot-active-idle[data-mascot-active-idle='hover'][data-mascot-idle-phase='inbound'] .composer-mascot-lift {
248
251
  animation: composer-mascot-idle-hover-return-y 1.8s linear forwards;
249
252
  }
250
253
 
251
- .composer-mascot-active-idle[data-mascot-active-idle='hover'][data-mascot-idle-phase='outbound'] .composer-mascot-breathe {
254
+ .composer-mascot-active-idle[data-mascot-active-idle='hover'][data-mascot-idle-phase='outbound'] .composer-mascot-body {
252
255
  animation: composer-mascot-idle-hover-launch-body 1.8s ease-out forwards;
253
256
  }
254
257
 
255
- .composer-mascot-active-idle[data-mascot-active-idle='hover'][data-mascot-idle-phase='away'] .composer-mascot-breathe {
258
+ .composer-mascot-active-idle[data-mascot-active-idle='hover'][data-mascot-idle-phase='away'] .composer-mascot-body {
256
259
  animation: composer-mascot-idle-hover-hold-body 2.8s ease-in-out forwards;
257
260
  }
258
261
 
259
- .composer-mascot-active-idle[data-mascot-active-idle='hover'][data-mascot-idle-phase='inbound'] .composer-mascot-breathe {
262
+ .composer-mascot-active-idle[data-mascot-active-idle='hover'][data-mascot-idle-phase='inbound'] .composer-mascot-body {
260
263
  animation: composer-mascot-idle-hover-land-body 1.8s ease-in forwards;
261
264
  }
262
265
 
263
- .composer-mascot-active-idle[data-mascot-active-idle='hover'][data-mascot-idle-phase='away'] .composer-mascot-jelly {
266
+ .composer-mascot-active-idle[data-mascot-active-idle='hover'][data-mascot-idle-phase='away'] .composer-mascot-trail {
264
267
  animation: composer-mascot-idle-hover-scan-body 2.8s ease-in-out forwards;
265
268
  }
266
269
 
267
- .composer-mascot-active-idle[data-mascot-active-idle='hover'] .composer-mascot-jelly {
270
+ .composer-mascot-active-idle[data-mascot-active-idle='hover'] .composer-mascot-trail {
268
271
  position: relative;
269
272
  isolation: isolate;
270
273
  }
271
274
 
272
- .composer-mascot-active-idle[data-mascot-active-idle='hover'] .composer-mascot-jelly::before {
275
+ .composer-mascot-active-idle[data-mascot-active-idle='hover'] .composer-mascot-trail::before {
273
276
  content: '';
274
277
  position: absolute;
275
278
  top: 16px;
276
- left: 40px;
277
279
  z-index: 1;
278
280
  width: 58px;
279
281
  height: 32px;
282
+ opacity: 0;
283
+ pointer-events: none;
284
+ }
285
+
286
+ /* The side jet fires against the leg's direction of travel. */
287
+ .composer-mascot-active-idle[data-mascot-active-idle='hover'][data-mascot-idle-travel='left'] .composer-mascot-trail::before {
288
+ --mascot-idle-jet-tilt: 22deg;
289
+ left: 40px;
280
290
  background:
281
291
  linear-gradient(90deg, #f8fbff 0%, #9fb5ff 28%, transparent 94%) 0 3px / 42px 3px no-repeat,
282
292
  linear-gradient(90deg, #f8fbff 0%, #7894f8 26%, transparent 96%) 0 14px / 58px 3px no-repeat,
283
293
  linear-gradient(90deg, #dce6ff 0%, #6f8cf5 32%, transparent 94%) 0 25px / 34px 3px no-repeat;
284
294
  filter: drop-shadow(6px 3px 5px color-mix(in srgb, #6f8dff 54%, transparent));
285
- opacity: 0;
286
- pointer-events: none;
287
295
  transform: rotate(22deg) scaleX(0.18);
288
296
  transform-origin: left center;
289
297
  }
290
298
 
291
- .composer-mascot-active-idle[data-mascot-active-idle='hover'][data-mascot-idle-phase='outbound'] .composer-mascot-jelly::before {
292
- animation: composer-mascot-idle-hover-side-jet-launch 1.8s ease-out forwards;
293
- }
294
-
295
- .composer-mascot-active-idle[data-mascot-active-idle='hover'][data-mascot-idle-phase='inbound'] .composer-mascot-jelly::before {
299
+ .composer-mascot-active-idle[data-mascot-active-idle='hover'][data-mascot-idle-travel='right'] .composer-mascot-trail::before {
300
+ --mascot-idle-jet-tilt: -18deg;
296
301
  right: 40px;
297
- left: auto;
298
302
  background:
299
303
  linear-gradient(90deg, transparent 6%, #9fb5ff 72%, #f8fbff 100%) 100% 3px / 42px 3px no-repeat,
300
304
  linear-gradient(90deg, transparent 4%, #7894f8 74%, #f8fbff 100%) 100% 14px / 58px 3px no-repeat,
@@ -302,10 +306,17 @@
302
306
  filter: drop-shadow(-5px 3px 5px color-mix(in srgb, #6f8dff 54%, transparent));
303
307
  transform: rotate(-18deg) scaleX(0.18);
304
308
  transform-origin: right center;
309
+ }
310
+
311
+ .composer-mascot-active-idle[data-mascot-active-idle='hover'][data-mascot-idle-phase='outbound'] .composer-mascot-trail::before {
312
+ animation: composer-mascot-idle-hover-side-jet-launch 1.8s ease-out forwards;
313
+ }
314
+
315
+ .composer-mascot-active-idle[data-mascot-active-idle='hover'][data-mascot-idle-phase='inbound'] .composer-mascot-trail::before {
305
316
  animation: composer-mascot-idle-hover-side-jet-return 1.8s ease-out forwards;
306
317
  }
307
318
 
308
- .composer-mascot-active-idle[data-mascot-active-idle='hover'] .composer-mascot-jelly::after {
319
+ .composer-mascot-active-idle[data-mascot-active-idle='hover'] .composer-mascot-trail::after {
309
320
  content: '';
310
321
  position: absolute;
311
322
  top: 46px;
@@ -327,15 +338,15 @@
327
338
  transform-origin: top center;
328
339
  }
329
340
 
330
- .composer-mascot-active-idle[data-mascot-active-idle='hover'][data-mascot-idle-phase='outbound'] .composer-mascot-jelly::after {
341
+ .composer-mascot-active-idle[data-mascot-active-idle='hover'][data-mascot-idle-phase='outbound'] .composer-mascot-trail::after {
331
342
  animation: composer-mascot-idle-hover-bottom-handoff 1.8s ease-out forwards;
332
343
  }
333
344
 
334
- .composer-mascot-active-idle[data-mascot-active-idle='hover'][data-mascot-idle-phase='away'] .composer-mascot-jelly::after {
345
+ .composer-mascot-active-idle[data-mascot-active-idle='hover'][data-mascot-idle-phase='away'] .composer-mascot-trail::after {
335
346
  animation: composer-mascot-idle-hover-bottom-hold 360ms ease-in-out infinite;
336
347
  }
337
348
 
338
- .composer-mascot-active-idle[data-mascot-active-idle='hover'][data-mascot-idle-phase='inbound'] .composer-mascot-jelly::after {
349
+ .composer-mascot-active-idle[data-mascot-active-idle='hover'][data-mascot-idle-phase='inbound'] .composer-mascot-trail::after {
339
350
  animation: composer-mascot-idle-hover-bottom-return 1.8s linear forwards;
340
351
  }
341
352
 
@@ -373,9 +384,9 @@
373
384
  @keyframes composer-mascot-idle-hover-launch-body {
374
385
  0% { transform: translateY(0) scale(1); }
375
386
  10% { transform: translateY(2px) scale(1.12, 0.82); }
376
- 22% { transform: translateY(-3px) rotate(-8deg) scale(0.94, 1.09); }
377
- 72% { transform: translateY(-2px) rotate(-5deg) scale(0.98, 1.035); }
378
- 90% { transform: translateY(1px) rotate(-2deg) scale(1.02, 0.98); }
387
+ 22% { transform: translateY(-3px) rotate(calc(8deg * var(--mascot-idle-travel-sign, -1))) scale(0.94, 1.09); }
388
+ 72% { transform: translateY(-2px) rotate(calc(5deg * var(--mascot-idle-travel-sign, -1))) scale(0.98, 1.035); }
389
+ 90% { transform: translateY(1px) rotate(calc(2deg * var(--mascot-idle-travel-sign, -1))) scale(1.02, 0.98); }
379
390
  100% { transform: translateY(0) rotate(0) scale(1); }
380
391
  }
381
392
 
@@ -387,8 +398,8 @@
387
398
 
388
399
  @keyframes composer-mascot-idle-hover-land-body {
389
400
  0% { transform: translateY(0) rotate(0) scale(1); }
390
- 18% { transform: translateY(-1px) rotate(5deg) scale(0.99, 1.02); }
391
- 66% { transform: translateY(-1px) rotate(3deg) scale(0.99, 1.02); }
401
+ 18% { transform: translateY(-1px) rotate(calc(5deg * var(--mascot-idle-travel-sign, -1))) scale(0.99, 1.02); }
402
+ 66% { transform: translateY(-1px) rotate(calc(3deg * var(--mascot-idle-travel-sign, -1))) scale(0.99, 1.02); }
392
403
  86% { transform: translateY(0) rotate(0) scale(1); }
393
404
  91% { transform: translateY(1px) rotate(0) scale(1.1, 0.88); }
394
405
  95% { transform: translateY(-1px) rotate(0) scale(0.99, 1.02); }
@@ -402,19 +413,19 @@
402
413
  }
403
414
 
404
415
  @keyframes composer-mascot-idle-hover-side-jet-launch {
405
- 0% { opacity: 0.34; transform: rotate(22deg) scaleX(0.34); }
406
- 12% { opacity: 0.94; transform: rotate(22deg) scaleX(1.08); }
407
- 68% { opacity: 0.76; transform: rotate(22deg) scaleX(0.84); }
408
- 84% { opacity: 0.42; transform: rotate(22deg) scaleX(0.48); }
409
- 100% { opacity: 0; transform: rotate(22deg) scaleX(0.12); }
416
+ 0% { opacity: 0.34; transform: rotate(var(--mascot-idle-jet-tilt, 22deg)) scaleX(0.34); }
417
+ 12% { opacity: 0.94; transform: rotate(var(--mascot-idle-jet-tilt, 22deg)) scaleX(1.08); }
418
+ 68% { opacity: 0.76; transform: rotate(var(--mascot-idle-jet-tilt, 22deg)) scaleX(0.84); }
419
+ 84% { opacity: 0.42; transform: rotate(var(--mascot-idle-jet-tilt, 22deg)) scaleX(0.48); }
420
+ 100% { opacity: 0; transform: rotate(var(--mascot-idle-jet-tilt, 22deg)) scaleX(0.12); }
410
421
  }
411
422
 
412
423
  @keyframes composer-mascot-idle-hover-side-jet-return {
413
- 0% { opacity: 0.28; transform: rotate(-18deg) scaleX(0.28); }
414
- 12% { opacity: 0.88; transform: rotate(-18deg) scaleX(0.92); }
415
- 52% { opacity: 0.66; transform: rotate(-18deg) scaleX(0.62); }
416
- 74% { opacity: 0.3; transform: rotate(-18deg) scaleX(0.34); }
417
- 86%, 100% { opacity: 0; transform: rotate(-18deg) scaleX(0.12); }
424
+ 0% { opacity: 0.28; transform: rotate(var(--mascot-idle-jet-tilt, -18deg)) scaleX(0.28); }
425
+ 12% { opacity: 0.88; transform: rotate(var(--mascot-idle-jet-tilt, -18deg)) scaleX(0.92); }
426
+ 52% { opacity: 0.66; transform: rotate(var(--mascot-idle-jet-tilt, -18deg)) scaleX(0.62); }
427
+ 74% { opacity: 0.3; transform: rotate(var(--mascot-idle-jet-tilt, -18deg)) scaleX(0.34); }
428
+ 86%, 100% { opacity: 0; transform: rotate(var(--mascot-idle-jet-tilt, -18deg)) scaleX(0.12); }
418
429
  }
419
430
 
420
431
  @keyframes composer-mascot-idle-hover-bottom-handoff {
@@ -430,9 +441,9 @@
430
441
 
431
442
  @keyframes composer-mascot-idle-hover-bottom-return {
432
443
  0% { opacity: 0.78; transform: translateX(-50%) rotate(0) scaleY(0.72); animation-timing-function: ease-in-out; }
433
- 24% { opacity: 0.68; transform: translateX(-50%) rotate(8deg) scaleY(0.58); }
434
- 58% { opacity: 0.44; transform: translateX(-50%) rotate(7deg) scaleY(0.38); }
435
- 78% { opacity: 0.86; transform: translateX(-50%) rotate(3deg) scaleY(0.84); }
444
+ 24% { opacity: 0.68; transform: translateX(-50%) rotate(calc(8deg * var(--mascot-idle-travel-sign, -1))) scaleY(0.58); }
445
+ 58% { opacity: 0.44; transform: translateX(-50%) rotate(calc(7deg * var(--mascot-idle-travel-sign, -1))) scaleY(0.38); }
446
+ 78% { opacity: 0.86; transform: translateX(-50%) rotate(calc(3deg * var(--mascot-idle-travel-sign, -1))) scaleY(0.84); }
436
447
  91% { opacity: 0.98; transform: translateX(-50%) rotate(0) scaleY(1.04); }
437
448
  100% { opacity: 0; transform: translateX(-50%) rotate(0) scaleY(0.14); }
438
449
  }
@@ -11,6 +11,7 @@ interface ComposerAvatarBehaviorOptions {
11
11
  activeIdle: boolean;
12
12
  bounceSignal: number;
13
13
  reducedMotion: boolean;
14
+ directionalGestures?: boolean;
14
15
  }
15
16
  export declare function useComposerAvatarBehavior(options: ComposerAvatarBehaviorOptions): {
16
17
  pose: AvatarPose;
@@ -1 +1 @@
1
- {"version":3,"file":"useComposerAvatarBehavior.d.ts","sourceRoot":"","sources":["../../src/composer/useComposerAvatarBehavior.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAC7C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAElD,MAAM,MAAM,qBAAqB,GAAG,OAAO,GAAG,WAAW,GAAG,YAAY,GAAG,aAAa,CAAA;AAExF,UAAU,6BAA6B;IACrC,YAAY,EAAE,UAAU,CAAA;IACxB,cAAc,EAAE,gBAAgB,CAAA;IAChC,OAAO,EAAE,OAAO,CAAA;IAChB,QAAQ,EAAE,OAAO,CAAA;IACjB,QAAQ,EAAE,OAAO,CAAA;IACjB,MAAM,EAAE,OAAO,CAAA;IACf,UAAU,EAAE,OAAO,CAAA;IACnB,YAAY,EAAE,MAAM,CAAA;IACpB,aAAa,EAAE,OAAO,CAAA;CACvB;AAED,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,6BAA6B,GAAG;IACjF,IAAI,EAAE,UAAU,CAAA;IAChB,UAAU,EAAE,MAAM,GAAG,OAAO,GAAG,UAAU,GAAG,OAAO,GAAG,SAAS,CAAA;IAC/D,OAAO,EAAE,qBAAqB,GAAG,SAAS,CAAA;IAC1C,eAAe,EAAE,MAAM,CAAA;IACvB,YAAY,EAAE,MAAM,IAAI,CAAA;IACxB,eAAe,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAA;CAC5C,CAuEA"}
1
+ {"version":3,"file":"useComposerAvatarBehavior.d.ts","sourceRoot":"","sources":["../../src/composer/useComposerAvatarBehavior.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAC7C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAElD,MAAM,MAAM,qBAAqB,GAAG,OAAO,GAAG,WAAW,GAAG,YAAY,GAAG,aAAa,CAAA;AAExF,UAAU,6BAA6B;IACrC,YAAY,EAAE,UAAU,CAAA;IACxB,cAAc,EAAE,gBAAgB,CAAA;IAChC,OAAO,EAAE,OAAO,CAAA;IAChB,QAAQ,EAAE,OAAO,CAAA;IACjB,QAAQ,EAAE,OAAO,CAAA;IACjB,MAAM,EAAE,OAAO,CAAA;IACf,UAAU,EAAE,OAAO,CAAA;IACnB,YAAY,EAAE,MAAM,CAAA;IACpB,aAAa,EAAE,OAAO,CAAA;IACtB,mBAAmB,CAAC,EAAE,OAAO,CAAA;CAC9B;AAED,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,6BAA6B,GAAG;IACjF,IAAI,EAAE,UAAU,CAAA;IAChB,UAAU,EAAE,MAAM,GAAG,OAAO,GAAG,UAAU,GAAG,OAAO,GAAG,SAAS,CAAA;IAC/D,OAAO,EAAE,qBAAqB,GAAG,SAAS,CAAA;IAC1C,eAAe,EAAE,MAAM,CAAA;IACvB,YAAY,EAAE,MAAM,IAAI,CAAA;IACxB,eAAe,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAA;CAC5C,CAuEA"}
@@ -36,7 +36,7 @@ export function useComposerAvatarBehavior(options) {
36
36
  : value < 0.86
37
37
  ? 'antenna-bob'
38
38
  : undefined;
39
- if (next) {
39
+ if (next && (options.directionalGestures !== false || (next !== 'look-left' && next !== 'look-right'))) {
40
40
  setGesture(next);
41
41
  setGestureSequence((sequence) => sequence + 1);
42
42
  }
@@ -46,7 +46,7 @@ export function useComposerAvatarBehavior(options) {
46
46
  };
47
47
  schedule();
48
48
  return () => { window.clearTimeout(timer); };
49
- }, [options.sleeping, options.activeIdle, options.reducedMotion, options.baseExpression]);
49
+ }, [options.sleeping, options.activeIdle, options.reducedMotion, options.baseExpression, options.directionalGestures]);
50
50
  const clearGesture = useCallback(() => setGesture(undefined), []);
51
51
  const completeGesture = useCallback((sequence) => {
52
52
  setGesture((current) => sequence === gestureSequence ? undefined : current);
@@ -1 +1 @@
1
- {"version":3,"file":"useComposerAvatarBehavior.js","sourceRoot":"","sources":["../../src/composer/useComposerAvatarBehavior.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAkBhE,MAAM,UAAU,yBAAyB,CAAC,OAAsC;IAQ9E,MAAM,CAAC,oBAAoB,EAAE,uBAAuB,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IACvE,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,EAAyB,CAAA;IAC/D,MAAM,CAAC,eAAe,EAAE,kBAAkB,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAA;IACzD,MAAM,cAAc,GAAG,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,CAAA;IAEnD,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,OAAO,CAAC,aAAa,IAAI,OAAO,CAAC,YAAY,KAAK,MAAM,EAAE,CAAC;YAC7D,cAAc,CAAC,OAAO,GAAG,OAAO,CAAC,YAAY,CAAA;YAC7C,uBAAuB,CAAC,KAAK,CAAC,CAAA;YAC9B,OAAM;QACR,CAAC;QACD,IAAI,OAAO,CAAC,YAAY,KAAK,cAAc,CAAC,OAAO;YAAE,OAAM;QAC3D,cAAc,CAAC,OAAO,GAAG,OAAO,CAAC,YAAY,CAAA;QAC7C,uBAAuB,CAAC,IAAI,CAAC,CAAA;QAC7B,MAAM,KAAK,GAAG,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,uBAAuB,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAA;QAC1E,OAAO,GAAG,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,CAAA;IACzC,CAAC,EAAE,CAAC,OAAO,CAAC,YAAY,EAAE,OAAO,CAAC,aAAa,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC,CAAA;IAEvE,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,UAAU,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;YACpE,UAAU,CAAC,SAAS,CAAC,CAAA;YACrB,OAAM;QACR,CAAC;QACD,IAAI,OAAO,CAAC,cAAc,KAAK,SAAS,IAAI,OAAO,CAAC,cAAc,KAAK,OAAO;YAAE,OAAM;QACtF,IAAI,KAAK,GAAG,CAAC,CAAA;QACb,MAAM,QAAQ,GAAG,GAAS,EAAE;YAC1B,KAAK,GAAG,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE;gBAC7B,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;oBACrB,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,CAAA;oBAC3B,MAAM,IAAI,GAAG,KAAK,GAAG,GAAG;wBACtB,CAAC,CAAC,OAAO;wBACT,CAAC,CAAC,KAAK,GAAG,IAAI;4BACZ,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,YAAY,CAAC;4BACpD,CAAC,CAAC,KAAK,GAAG,IAAI;gCACZ,CAAC,CAAC,aAAa;gCACf,CAAC,CAAC,SAAS,CAAA;oBACjB,IAAI,IAAI,EAAE,CAAC;wBACT,UAAU,CAAC,IAAI,CAAC,CAAA;wBAChB,kBAAkB,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAA;oBAChD,CAAC;gBACH,CAAC;gBACD,QAAQ,EAAE,CAAA;YACZ,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAA;QACjC,CAAC,CAAA;QACD,QAAQ,EAAE,CAAA;QACV,OAAO,GAAG,EAAE,GAAG,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,CAAA,CAAC,CAAC,CAAA;IAC7C,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,UAAU,EAAE,OAAO,CAAC,aAAa,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC,CAAA;IAEzF,MAAM,YAAY,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,EAAE,CAAC,CAAA;IACjE,MAAM,eAAe,GAAG,WAAW,CAAC,CAAC,QAAgB,EAAE,EAAE;QACvD,UAAU,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,QAAQ,KAAK,eAAe,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAA;IAC7E,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC,CAAA;IAErB,MAAM,UAAU,GAAG,OAAO,CAAC,YAAY,KAAK,MAAM;QAChD,CAAC,CAAC,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,OAAO;YACjC,CAAC,CAAC,OAAO;YACT,CAAC,CAAC,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,cAAc,KAAK,UAAU;gBACzD,CAAC,CAAC,UAAU;gBACZ,CAAC,CAAC,OAAO,CAAC,QAAQ;oBAChB,CAAC,CAAC,OAAO;oBACT,CAAC,CAAC,MAAM;QACd,CAAC,CAAC,SAAS,CAAA;IACb,OAAO;QACL,IAAI,EAAE,OAAO,CAAC,YAAY,KAAK,MAAM,IAAI,oBAAoB,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY;QACpG,UAAU;QACV,OAAO;QACP,eAAe;QACf,YAAY;QACZ,eAAe;KAChB,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"useComposerAvatarBehavior.js","sourceRoot":"","sources":["../../src/composer/useComposerAvatarBehavior.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ import { type AnimationEvent } from 'react';
2
+ import { type MascotActiveIdle, type MascotActiveIdleMotion, type MascotActiveIdlePhase, type MascotActiveIdlePlan, type MascotIdleDirection } from './constants.js';
3
+ export interface MascotActiveIdleAttributes {
4
+ 'data-mascot-active-idle'?: MascotActiveIdleMotion;
5
+ 'data-mascot-idle-phase'?: MascotActiveIdlePhase;
6
+ 'data-mascot-idle-direction'?: MascotIdleDirection;
7
+ 'data-mascot-idle-travel'?: MascotIdleDirection;
8
+ }
9
+ export interface MascotActiveIdleOptions {
10
+ /** True while the character is free to wander: idle, awake, unfocused, and motion allowed. */
11
+ enabled: boolean;
12
+ onStart?: () => void;
13
+ /** Runs on user activity, before the schedule-reset throttle. */
14
+ onActivity?: () => void;
15
+ /** Decides direction and motion pool at launch; `null` skips this round. */
16
+ plan?: () => MascotActiveIdlePlan | null;
17
+ /** Whether pointer movement aborts a trip in flight; it always defers the next one. */
18
+ interruptOnPointerMove?: boolean;
19
+ }
20
+ export interface MascotActiveIdleHandle {
21
+ activeIdle: MascotActiveIdle | null;
22
+ activityRevision: number;
23
+ className: 'composer-mascot-active-idle' | undefined;
24
+ attributes: MascotActiveIdleAttributes;
25
+ cancel: () => void;
26
+ onAnimationEnd: (event: AnimationEvent<Element>) => void;
27
+ }
28
+ /**
29
+ * Schedules the traveling idle antics (hop, rocket, hover) after a quiet stretch. Any host that
30
+ * renders the stage classes (see MascotIdleStage) can spread the returned attributes on its root.
31
+ */
32
+ export declare function useMascotActiveIdle(options: MascotActiveIdleOptions): MascotActiveIdleHandle;
33
+ //# sourceMappingURL=useMascotActiveIdle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useMascotActiveIdle.d.ts","sourceRoot":"","sources":["../../src/composer/useMascotActiveIdle.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4C,KAAK,cAAc,EAAE,MAAM,OAAO,CAAA;AACrF,OAAO,EAOL,KAAK,gBAAgB,EACrB,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACzB,MAAM,gBAAgB,CAAA;AAEvB,MAAM,WAAW,0BAA0B;IACzC,yBAAyB,CAAC,EAAE,sBAAsB,CAAA;IAClD,wBAAwB,CAAC,EAAE,qBAAqB,CAAA;IAChD,4BAA4B,CAAC,EAAE,mBAAmB,CAAA;IAClD,yBAAyB,CAAC,EAAE,mBAAmB,CAAA;CAChD;AAED,MAAM,WAAW,uBAAuB;IACtC,8FAA8F;IAC9F,OAAO,EAAE,OAAO,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB,iEAAiE;IACjE,UAAU,CAAC,EAAE,MAAM,IAAI,CAAA;IACvB,4EAA4E;IAC5E,IAAI,CAAC,EAAE,MAAM,oBAAoB,GAAG,IAAI,CAAA;IACxC,uFAAuF;IACvF,sBAAsB,CAAC,EAAE,OAAO,CAAA;CACjC;AAED,MAAM,WAAW,sBAAsB;IACrC,UAAU,EAAE,gBAAgB,GAAG,IAAI,CAAA;IACnC,gBAAgB,EAAE,MAAM,CAAA;IACxB,SAAS,EAAE,6BAA6B,GAAG,SAAS,CAAA;IACpD,UAAU,EAAE,0BAA0B,CAAA;IACtC,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,cAAc,EAAE,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,CAAC,KAAK,IAAI,CAAA;CACzD;AAsBD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,uBAAuB,GAAG,sBAAsB,CAsG5F"}
@@ -0,0 +1,128 @@
1
+ import { useCallback, useEffect, useRef, useState } from 'react';
2
+ import { MASCOT_ACTIVE_IDLE_ACTIVITY_THROTTLE_MS, MASCOT_ACTIVE_IDLE_HOLD_MS, MASCOT_ACTIVE_IDLE_JITTER_MS, MASCOT_ACTIVE_IDLE_MIN_MS, MASCOT_ACTIVE_IDLE_TRAVEL_MS, pickMascotActiveIdle } from './constants.js';
3
+ const RETRY_MS = 5000;
4
+ const LEG_SETTLE_MS = 160;
5
+ function opposite(direction) {
6
+ return direction === 'left' ? 'right' : 'left';
7
+ }
8
+ function finisherOf(trip) {
9
+ if (trip.motion === 'hop')
10
+ return 'composer-mascot-idle-hop-travel';
11
+ if (trip.motion === 'rocket')
12
+ return 'composer-mascot-idle-rocket-flight-x';
13
+ return trip.phase === 'outbound' ? 'composer-mascot-idle-hover-launch-body' : 'composer-mascot-idle-hover-land-body';
14
+ }
15
+ function advance(trip) {
16
+ if (!trip)
17
+ return null;
18
+ if (trip.phase === 'outbound')
19
+ return { ...trip, phase: 'away' };
20
+ if (trip.phase === 'away')
21
+ return { ...trip, phase: 'inbound', travel: opposite(trip.direction) };
22
+ return null;
23
+ }
24
+ /**
25
+ * Schedules the traveling idle antics (hop, rocket, hover) after a quiet stretch. Any host that
26
+ * renders the stage classes (see MascotIdleStage) can spread the returned attributes on its root.
27
+ */
28
+ export function useMascotActiveIdle(options) {
29
+ const { enabled, interruptOnPointerMove = true } = options;
30
+ const [activeIdle, setActiveIdle] = useState(null);
31
+ const [activityRevision, setActivityRevision] = useState(0);
32
+ const optionsRef = useRef(options);
33
+ optionsRef.current = options;
34
+ const activeRef = useRef(activeIdle);
35
+ activeRef.current = activeIdle;
36
+ const lastActivityRef = useRef(0);
37
+ const lastMotionRef = useRef(null);
38
+ const cancel = useCallback(() => setActiveIdle(null), []);
39
+ const markActivity = useCallback((interrupt) => {
40
+ if (interrupt)
41
+ setActiveIdle(null);
42
+ optionsRef.current.onActivity?.();
43
+ const now = Date.now();
44
+ if (now - lastActivityRef.current < MASCOT_ACTIVE_IDLE_ACTIVITY_THROTTLE_MS)
45
+ return;
46
+ lastActivityRef.current = now;
47
+ setActivityRevision((value) => value + 1);
48
+ }, []);
49
+ useEffect(() => {
50
+ const interrupt = () => markActivity(true);
51
+ const pointerMove = () => {
52
+ if (Date.now() - lastActivityRef.current >= MASCOT_ACTIVE_IDLE_ACTIVITY_THROTTLE_MS) {
53
+ markActivity(interruptOnPointerMove);
54
+ }
55
+ };
56
+ window.addEventListener('keydown', interrupt);
57
+ window.addEventListener('pointerdown', interrupt);
58
+ window.addEventListener('pointermove', pointerMove, { passive: true });
59
+ window.addEventListener('wheel', interrupt, { passive: true });
60
+ window.addEventListener('focusin', interrupt);
61
+ return () => {
62
+ window.removeEventListener('keydown', interrupt);
63
+ window.removeEventListener('pointerdown', interrupt);
64
+ window.removeEventListener('pointermove', pointerMove);
65
+ window.removeEventListener('wheel', interrupt);
66
+ window.removeEventListener('focusin', interrupt);
67
+ };
68
+ }, [markActivity, interruptOnPointerMove]);
69
+ useEffect(() => {
70
+ if (!enabled) {
71
+ setActiveIdle(null);
72
+ return undefined;
73
+ }
74
+ let timer = 0;
75
+ const wait = () => MASCOT_ACTIVE_IDLE_MIN_MS + Math.random() * MASCOT_ACTIVE_IDLE_JITTER_MS;
76
+ const start = () => {
77
+ if (document.hidden || activeRef.current) {
78
+ timer = window.setTimeout(start, RETRY_MS);
79
+ return;
80
+ }
81
+ const plan = optionsRef.current.plan?.();
82
+ if (plan === null) {
83
+ timer = window.setTimeout(start, wait());
84
+ return;
85
+ }
86
+ const motion = pickMascotActiveIdle(Math.random(), lastMotionRef.current, plan?.motions);
87
+ lastMotionRef.current = motion;
88
+ optionsRef.current.onStart?.();
89
+ const direction = plan?.direction ?? 'left';
90
+ setActiveIdle({ motion, phase: 'outbound', direction, travel: direction });
91
+ };
92
+ timer = window.setTimeout(start, wait());
93
+ return () => window.clearTimeout(timer);
94
+ }, [enabled, activityRevision]);
95
+ useEffect(() => {
96
+ if (!activeIdle)
97
+ return undefined;
98
+ const delay = activeIdle.phase === 'away'
99
+ ? MASCOT_ACTIVE_IDLE_HOLD_MS[activeIdle.motion]
100
+ : MASCOT_ACTIVE_IDLE_TRAVEL_MS[activeIdle.motion] + LEG_SETTLE_MS;
101
+ const timer = window.setTimeout(() => setActiveIdle(advance), delay);
102
+ return () => window.clearTimeout(timer);
103
+ }, [activeIdle]);
104
+ const onAnimationEnd = useCallback((event) => {
105
+ setActiveIdle((current) => {
106
+ if (!current || event.animationName !== finisherOf(current))
107
+ return current;
108
+ return current.phase === 'outbound' ? { ...current, phase: 'away' } : null;
109
+ });
110
+ }, []);
111
+ const attributes = activeIdle
112
+ ? {
113
+ 'data-mascot-active-idle': activeIdle.motion,
114
+ 'data-mascot-idle-phase': activeIdle.phase,
115
+ 'data-mascot-idle-direction': activeIdle.direction,
116
+ 'data-mascot-idle-travel': activeIdle.travel
117
+ }
118
+ : {};
119
+ return {
120
+ activeIdle,
121
+ activityRevision,
122
+ className: activeIdle ? 'composer-mascot-active-idle' : undefined,
123
+ attributes,
124
+ cancel,
125
+ onAnimationEnd
126
+ };
127
+ }
128
+ //# sourceMappingURL=useMascotActiveIdle.js.map