@lemoncat7/dsh-theme-xiaohei 0.4.6 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (232) hide show
  1. package/README.md +15 -9
  2. package/THIRD_PARTY_NOTICES.md +13 -1
  3. package/docs/dsh-021-compatibility.md +23 -0
  4. package/docs/releases/0.5.0.md +24 -0
  5. package/docs/rift-interaction.md +35 -0
  6. package/docs/rift-preview.md +39 -0
  7. package/lib/client.companion.js +3 -4
  8. package/lib/client.decorations.js +224 -51
  9. package/lib/client.js +532 -2405
  10. package/lib/index.d.ts +1 -2
  11. package/lib/index.js +393 -11
  12. package/lib/rift/boot.d.ts +6 -0
  13. package/package.json +29 -19
  14. package/lib/appearance.d.ts +0 -12
  15. package/lib/appearance.js +0 -42
  16. package/lib/blink.d.ts +0 -4
  17. package/lib/blink.js +0 -110
  18. package/lib/bloub-heixiu/ambient.d.ts +0 -3
  19. package/lib/bloub-heixiu/ambient.js +0 -12
  20. package/lib/bloub-heixiu/character.d.ts +0 -33
  21. package/lib/bloub-heixiu/character.js +0 -124
  22. package/lib/bloub-heixiu/effects.d.ts +0 -4
  23. package/lib/bloub-heixiu/effects.js +0 -91
  24. package/lib/bloub-heixiu/flight.d.ts +0 -15
  25. package/lib/bloub-heixiu/flight.js +0 -66
  26. package/lib/bloub-heixiu/follow.d.ts +0 -13
  27. package/lib/bloub-heixiu/follow.js +0 -23
  28. package/lib/bloub-heixiu/layout.d.ts +0 -34
  29. package/lib/bloub-heixiu/layout.js +0 -26
  30. package/lib/bloub-heixiu/renderer.d.ts +0 -16
  31. package/lib/bloub-heixiu/renderer.js +0 -94
  32. package/lib/bloub-heixiu/runtime.d.ts +0 -6
  33. package/lib/bloub-heixiu/runtime.js +0 -440
  34. package/lib/bloub-heixiu/signals.d.ts +0 -17
  35. package/lib/bloub-heixiu/signals.js +0 -55
  36. package/lib/bloub-heixiu/styles.d.ts +0 -2
  37. package/lib/bloub-heixiu/styles.js +0 -98
  38. package/lib/boot-appearance.d.ts +0 -10
  39. package/lib/boot-appearance.js +0 -47
  40. package/lib/boot-loader.d.ts +0 -5
  41. package/lib/boot-loader.js +0 -158
  42. package/lib/chrome/accessibility.d.ts +0 -3
  43. package/lib/chrome/accessibility.js +0 -69
  44. package/lib/chrome/blink.d.ts +0 -3
  45. package/lib/chrome/blink.js +0 -15
  46. package/lib/chrome/composer-avatar.d.ts +0 -10
  47. package/lib/chrome/composer-avatar.js +0 -599
  48. package/lib/chrome/composer-send-heixiu.d.ts +0 -3
  49. package/lib/chrome/composer-send-heixiu.js +0 -143
  50. package/lib/chrome/composer.d.ts +0 -3
  51. package/lib/chrome/composer.js +0 -135
  52. package/lib/chrome/controls.d.ts +0 -8
  53. package/lib/chrome/controls.js +0 -348
  54. package/lib/chrome/conversation-messages.d.ts +0 -3
  55. package/lib/chrome/conversation-messages.js +0 -329
  56. package/lib/chrome/conversation-submissions.d.ts +0 -3
  57. package/lib/chrome/conversation-submissions.js +0 -68
  58. package/lib/chrome/conversation.d.ts +0 -3
  59. package/lib/chrome/conversation.js +0 -67
  60. package/lib/chrome/frames.d.ts +0 -6
  61. package/lib/chrome/frames.js +0 -134
  62. package/lib/chrome/gaze.d.ts +0 -3
  63. package/lib/chrome/gaze.js +0 -103
  64. package/lib/chrome/identity.d.ts +0 -6
  65. package/lib/chrome/identity.js +0 -47
  66. package/lib/chrome/overlays.d.ts +0 -3
  67. package/lib/chrome/overlays.js +0 -104
  68. package/lib/chrome/portal.d.ts +0 -6
  69. package/lib/chrome/portal.js +0 -169
  70. package/lib/chrome/reactions.d.ts +0 -3
  71. package/lib/chrome/reactions.js +0 -85
  72. package/lib/chrome/sidebar.d.ts +0 -3
  73. package/lib/chrome/sidebar.js +0 -313
  74. package/lib/chrome/tokens.d.ts +0 -3
  75. package/lib/chrome/tokens.js +0 -224
  76. package/lib/chrome/workspace.d.ts +0 -3
  77. package/lib/chrome/workspace.js +0 -94
  78. package/lib/chrome.d.ts +0 -10
  79. package/lib/chrome.js +0 -46
  80. package/lib/client-entry.d.ts +0 -3
  81. package/lib/client-entry.js +0 -3
  82. package/lib/client.d.ts +0 -10
  83. package/lib/client.pose-chin-dark.js +0 -4
  84. package/lib/client.pose-chin-light.js +0 -4
  85. package/lib/client.pose-doze-dark.js +0 -4
  86. package/lib/client.pose-doze-light.js +0 -4
  87. package/lib/client.pose-halfpeek-dark.js +0 -4
  88. package/lib/client.pose-halfpeek-light.js +0 -4
  89. package/lib/client.pose-peek-dark.js +0 -4
  90. package/lib/client.pose-peek-light.js +0 -4
  91. package/lib/client.pose-seated-dark.js +0 -4
  92. package/lib/client.pose-seated-light.js +0 -4
  93. package/lib/client.rig-chin-dark.js +0 -4
  94. package/lib/client.rig-chin-light.js +0 -4
  95. package/lib/client.rig-halfpeek-dark.js +0 -4
  96. package/lib/client.rig-halfpeek-light.js +0 -4
  97. package/lib/client.rig-peek-dark.js +0 -4
  98. package/lib/client.rig-peek-light.js +0 -4
  99. package/lib/client.rig-seated-dark.js +0 -4
  100. package/lib/client.rig-seated-light.js +0 -4
  101. package/lib/companion-entry.d.ts +0 -3
  102. package/lib/companion-entry.js +0 -3
  103. package/lib/composer-avatar.d.ts +0 -18
  104. package/lib/composer-avatar.js +0 -441
  105. package/lib/composer-draft-preview.d.ts +0 -4
  106. package/lib/composer-draft-preview.js +0 -8
  107. package/lib/composer-send-heixiu.d.ts +0 -8
  108. package/lib/composer-send-heixiu.js +0 -133
  109. package/lib/current-session.d.ts +0 -6
  110. package/lib/current-session.js +0 -5
  111. package/lib/decorations-entry.d.ts +0 -3
  112. package/lib/decorations-entry.js +0 -18
  113. package/lib/deferred-companion.d.ts +0 -5
  114. package/lib/deferred-companion.js +0 -9
  115. package/lib/deferred-decorations.d.ts +0 -3
  116. package/lib/deferred-decorations.js +0 -51
  117. package/lib/gaze.d.ts +0 -4
  118. package/lib/gaze.js +0 -230
  119. package/lib/generated-backgrounds.d.ts +0 -14
  120. package/lib/generated-backgrounds.js +0 -14
  121. package/lib/generated-character-motion.d.ts +0 -4
  122. package/lib/generated-character-motion.js +0 -2
  123. package/lib/generated-identity.d.ts +0 -6
  124. package/lib/generated-identity.js +0 -6
  125. package/lib/generated-keyart.d.ts +0 -34
  126. package/lib/generated-keyart.js +0 -34
  127. package/lib/generated-loading-assets.d.ts +0 -4
  128. package/lib/generated-loading-assets.js +0 -4
  129. package/lib/heixiu-interactions.d.ts +0 -10
  130. package/lib/heixiu-interactions.js +0 -161
  131. package/lib/host-contract.d.ts +0 -9
  132. package/lib/host-contract.js +0 -13
  133. package/lib/host-dom.d.ts +0 -11
  134. package/lib/host-dom.js +0 -72
  135. package/lib/loading-heixiu.d.ts +0 -8
  136. package/lib/loading-heixiu.js +0 -287
  137. package/lib/metallic-brand-mark.d.ts +0 -10
  138. package/lib/metallic-brand-mark.js +0 -296
  139. package/lib/plugin.d.ts +0 -6
  140. package/lib/plugin.js +0 -60
  141. package/lib/portal.d.ts +0 -40
  142. package/lib/portal.js +0 -225
  143. package/lib/reactions.d.ts +0 -20
  144. package/lib/reactions.js +0 -380
  145. package/lib/scene/avatar-model.d.ts +0 -6
  146. package/lib/scene/avatar-model.js +0 -646
  147. package/lib/scene/avatar-motion.d.ts +0 -3
  148. package/lib/scene/avatar-motion.js +0 -799
  149. package/lib/scene/character-assets.d.ts +0 -13
  150. package/lib/scene/character-assets.js +0 -26
  151. package/lib/scene/character-expression.d.ts +0 -4
  152. package/lib/scene/character-expression.js +0 -15
  153. package/lib/scene/character-eye-material.d.ts +0 -13
  154. package/lib/scene/character-eye-material.js +0 -88
  155. package/lib/scene/character-eye-renderer.d.ts +0 -5
  156. package/lib/scene/character-eye-renderer.js +0 -80
  157. package/lib/scene/character-eye-rig.d.ts +0 -20
  158. package/lib/scene/character-eye-rig.js +0 -35
  159. package/lib/scene/character-gaze.d.ts +0 -16
  160. package/lib/scene/character-gaze.js +0 -36
  161. package/lib/scene/character-idle.d.ts +0 -17
  162. package/lib/scene/character-idle.js +0 -65
  163. package/lib/scene/character-layout.d.ts +0 -24
  164. package/lib/scene/character-layout.js +0 -51
  165. package/lib/scene/character-motion-clock.d.ts +0 -18
  166. package/lib/scene/character-motion-clock.js +0 -70
  167. package/lib/scene/character-motion-types.d.ts +0 -12
  168. package/lib/scene/character-motion-types.js +0 -2
  169. package/lib/scene/character-motion.d.ts +0 -6
  170. package/lib/scene/character-motion.js +0 -187
  171. package/lib/scene/character-poses.d.ts +0 -26
  172. package/lib/scene/character-poses.js +0 -11
  173. package/lib/scene/character-rig-renderer.d.ts +0 -5
  174. package/lib/scene/character-rig-renderer.js +0 -95
  175. package/lib/scene/character-rig.d.ts +0 -22
  176. package/lib/scene/character-rig.js +0 -61
  177. package/lib/scene/heixiu-feedback.d.ts +0 -3
  178. package/lib/scene/heixiu-feedback.js +0 -64
  179. package/lib/scene/heixiu-interactions.d.ts +0 -3
  180. package/lib/scene/heixiu-interactions.js +0 -92
  181. package/lib/scene/ids.d.ts +0 -5
  182. package/lib/scene/ids.js +0 -5
  183. package/lib/scene/pointer-bridge.d.ts +0 -21
  184. package/lib/scene/pointer-bridge.js +0 -155
  185. package/lib/scene/runtime.d.ts +0 -12
  186. package/lib/scene/runtime.js +0 -74
  187. package/lib/scene/state-transitions.d.ts +0 -3
  188. package/lib/scene/state-transitions.js +0 -37
  189. package/lib/scene/styles.d.ts +0 -5
  190. package/lib/scene/styles.js +0 -69
  191. package/lib/scene/sylva-performance.d.ts +0 -11
  192. package/lib/scene/sylva-performance.js +0 -58
  193. package/lib/scene/wallpaper-character-styles.d.ts +0 -3
  194. package/lib/scene/wallpaper-character-styles.js +0 -49
  195. package/lib/scene/wallpaper-character.d.ts +0 -5
  196. package/lib/scene/wallpaper-character.js +0 -222
  197. package/lib/scene.d.ts +0 -8
  198. package/lib/scene.js +0 -8
  199. package/lib/sidebar-glass.d.ts +0 -16
  200. package/lib/sidebar-glass.js +0 -168
  201. package/lib/sidebar-heixiu-escape.d.ts +0 -44
  202. package/lib/sidebar-heixiu-escape.js +0 -340
  203. package/lib/sidebar-heixiu-roaming.d.ts +0 -27
  204. package/lib/sidebar-heixiu-roaming.js +0 -310
  205. package/lib/sidebar-reveal.d.ts +0 -8
  206. package/lib/sidebar-reveal.js +0 -59
  207. package/lib/state.d.ts +0 -21
  208. package/lib/state.js +0 -123
  209. package/lib/theme.d.ts +0 -19
  210. package/lib/theme.js +0 -188
  211. package/lib/vendor/bloub/decor.d.ts +0 -114
  212. package/lib/vendor/bloub/decor.js +0 -198
  213. package/lib/vendor/bloub/engine.d.ts +0 -213
  214. package/lib/vendor/bloub/engine.js +0 -452
  215. package/lib/vendor/bloub/expressions.d.ts +0 -35
  216. package/lib/vendor/bloub/expressions.js +0 -143
  217. package/lib/vendor/bloub/eyefit.d.ts +0 -75
  218. package/lib/vendor/bloub/eyefit.js +0 -393
  219. package/lib/vendor/bloub/face.d.ts +0 -63
  220. package/lib/vendor/bloub/face.js +0 -106
  221. package/lib/vendor/bloub/math.d.ts +0 -22
  222. package/lib/vendor/bloub/math.js +0 -36
  223. package/lib/vendor/bloub/profiles.d.ts +0 -8
  224. package/lib/vendor/bloub/profiles.js +0 -20
  225. package/lib/vendor/bloub/repere.d.ts +0 -30
  226. package/lib/vendor/bloub/repere.js +0 -32
  227. package/lib/vendor/bloub/shape.d.ts +0 -80
  228. package/lib/vendor/bloub/shape.js +0 -268
  229. package/lib/vendor/bloub/skins.d.ts +0 -36
  230. package/lib/vendor/bloub/skins.js +0 -74
  231. package/lib/vendor/bloub/states.d.ts +0 -87
  232. package/lib/vendor/bloub/states.js +0 -468
@@ -1,441 +0,0 @@
1
- import { XIAOHEI_BREAKFRAME_BLINK, XIAOHEI_BREAKFRAME_BRACE, XIAOHEI_BREAKFRAME_COMPLETE, XIAOHEI_BREAKFRAME_ERROR, XIAOHEI_BREAKFRAME_IDLE, XIAOHEI_BREAKFRAME_REACH, XIAOHEI_BREAKFRAME_THINKING, XIAOHEI_BREAKFRAME_WORKING, } from './generated-keyart.js';
2
- import { XIAOHEI_HOST_SELECTORS } from './host-contract.js';
3
- import { subscribeXiaoheiHostDom } from './host-dom.js';
4
- export const XIAOHEI_COMPOSER_AVATAR_CLASS = 'xiaohei-composer-avatar';
5
- export const XIAOHEI_COMPOSER_IDLE_MOTIONS = [
6
- 'glance-left',
7
- 'glance-right',
8
- 'nod',
9
- 'perk',
10
- 'peek',
11
- 'double-blink',
12
- 'ponder',
13
- ];
14
- /** Pick a varied idle gesture without visibly repeating the previous one. */
15
- export function resolveXiaoheiComposerIdleMotion(random = Math.random, previous) {
16
- const candidates = previous === undefined
17
- ? XIAOHEI_COMPOSER_IDLE_MOTIONS
18
- : XIAOHEI_COMPOSER_IDLE_MOTIONS.filter(motion => motion !== previous);
19
- const index = Math.min(candidates.length - 1, Math.max(0, Math.floor(random() * candidates.length)));
20
- return candidates[index] ?? XIAOHEI_COMPOSER_IDLE_MOTIONS[0];
21
- }
22
- const XIAOHEI_IDLE_MOTION_DURATION = {
23
- 'glance-left': 1_760,
24
- 'glance-right': 1_760,
25
- 'nod': 1_520,
26
- 'perk': 1_640,
27
- 'peek': 1_860,
28
- 'double-blink': 760,
29
- 'ponder': 2_260,
30
- };
31
- /** Resolve the avatar target without coupling to generated Host class names. */
32
- export function resolveXiaoheiComposerAvatarPosition(composer, viewportWidth, viewportHeight) {
33
- const avatarWidth = 172;
34
- const avatarHeight = 184;
35
- const mobile = viewportWidth <= 760;
36
- const hero = composer.top < viewportHeight * 0.58;
37
- let placement;
38
- let scale;
39
- let x;
40
- let y;
41
- if (mobile) {
42
- placement = 'mobile';
43
- scale = 0.72;
44
- x = composer.left + 8;
45
- y = composer.top - avatarHeight * scale - 8;
46
- }
47
- else if (hero) {
48
- placement = 'hero';
49
- scale = 0.92;
50
- x = composer.left + composer.width / 2 - avatarWidth / 2;
51
- y = composer.top - avatarHeight * scale - 12;
52
- }
53
- else {
54
- placement = 'docked';
55
- scale = 0.9;
56
- x = composer.left - avatarWidth * scale - 16;
57
- y = composer.bottom - avatarHeight * scale + 8;
58
- }
59
- return {
60
- placement,
61
- scale,
62
- x: Math.round(Math.max(8, Math.min(viewportWidth - avatarWidth * scale - 8, x))),
63
- y: Math.round(Math.max(8, Math.min(viewportHeight - avatarHeight * scale - 8, y))),
64
- };
65
- }
66
- /** Mount one persistent avatar and let the native composer remain fully owned by DSH. */
67
- export function installXiaoheiComposerAvatar(doc = typeof document === 'undefined' ? undefined : document) {
68
- if (doc === undefined)
69
- return () => { };
70
- const win = doc.defaultView;
71
- if (win === null)
72
- return () => { };
73
- doc.querySelector(`.${XIAOHEI_COMPOSER_AVATAR_CLASS}`)?.remove();
74
- const avatar = doc.createElement('span');
75
- avatar.className = XIAOHEI_COMPOSER_AVATAR_CLASS;
76
- avatar.setAttribute('aria-hidden', 'true');
77
- avatar.dataset.xiaoheiPortrait = 'idle';
78
- const effectsBack = createAvatarLayer(doc, 'effects-back');
79
- const ringBack = createAvatarLayer(doc, 'ring-back');
80
- const circle = createAvatarLayer(doc, 'circle');
81
- circle.append(...createPortraitImages(doc, 'inside'));
82
- const overflow = createAvatarLayer(doc, 'overflow');
83
- overflow.append(...createPortraitImages(doc, 'overflow'));
84
- const ringFront = createAvatarLayer(doc, 'ring-front');
85
- const breakoutRight = createAvatarLayer(doc, 'breakout-right');
86
- breakoutRight.append(...createBreakoutRightImages(doc));
87
- const effectsFront = createAvatarLayer(doc, 'effects-front');
88
- avatar.append(effectsBack, ringBack, circle, overflow, ringFront, breakoutRight, effectsFront);
89
- doc.body.append(avatar);
90
- let disposed = false;
91
- let composer;
92
- let resizeObserver;
93
- let frameRequest;
94
- let pointerRequest;
95
- let reactionTimer;
96
- let reactionStageTimers = [];
97
- let stateTimer;
98
- let blinkTimer;
99
- let blinkResetTimer;
100
- let idleTimer;
101
- let idleResetTimer;
102
- let portraitRequest = 0;
103
- let reactionRequest = 0;
104
- let previousIdleMotion;
105
- let desiredHostPortrait = resolveDisplayPortrait(doc.documentElement.dataset.xiaoheiState);
106
- let layoutReady = false;
107
- let idlePortraitReady = false;
108
- let pointerX = 0;
109
- let pointerY = 0;
110
- const revealAvatar = () => {
111
- if (layoutReady && idlePortraitReady)
112
- avatar.dataset.xiaoheiAvatarReady = 'true';
113
- };
114
- const portraitImages = Array.from(avatar.querySelectorAll('[data-xiaohei-portrait-frame]'));
115
- const imagesByState = new Map();
116
- for (const image of portraitImages) {
117
- const state = image.dataset.xiaoheiPortraitFrame;
118
- const images = imagesByState.get(state) ?? [];
119
- images.push(image);
120
- imagesByState.set(state, images);
121
- }
122
- const decodedStates = new Set();
123
- const decodeTasks = new Map();
124
- const ensurePortraitDecoded = (state) => {
125
- if (decodedStates.has(state))
126
- return Promise.resolve(true);
127
- const existing = decodeTasks.get(state);
128
- if (existing !== undefined)
129
- return existing;
130
- const task = Promise.all((imagesByState.get(state) ?? []).map(decodePortraitImage))
131
- .then((results) => {
132
- const decoded = results.length > 0 && results.every(Boolean);
133
- if (decoded)
134
- decodedStates.add(state);
135
- return decoded;
136
- });
137
- decodeTasks.set(state, task);
138
- return task;
139
- };
140
- const showPortrait = async (state) => {
141
- const request = ++portraitRequest;
142
- const decoded = await ensurePortraitDecoded(state);
143
- if (disposed || request !== portraitRequest || !decoded)
144
- return;
145
- avatar.dataset.xiaoheiPortrait = state;
146
- };
147
- const applyHostPortrait = () => {
148
- if (avatar.dataset.xiaoheiAvatarReaction !== undefined)
149
- return;
150
- void showPortrait(desiredHostPortrait);
151
- };
152
- const scheduleHostPortrait = () => {
153
- desiredHostPortrait = resolveDisplayPortrait(doc.documentElement.dataset.xiaoheiState);
154
- if (stateTimer !== undefined)
155
- clearTimeout(stateTimer);
156
- stateTimer = setTimeout(() => {
157
- stateTimer = undefined;
158
- applyHostPortrait();
159
- }, 150);
160
- };
161
- const measure = () => {
162
- frameRequest = undefined;
163
- if (disposed || composer === undefined || !composer.isConnected) {
164
- avatar.removeAttribute('data-xiaohei-avatar-ready');
165
- layoutReady = false;
166
- return;
167
- }
168
- const bounds = composer.getBoundingClientRect();
169
- const viewport = win.visualViewport;
170
- const viewportWidth = viewport?.width ?? win.innerWidth;
171
- const viewportHeight = viewport?.height ?? win.innerHeight;
172
- const position = resolveXiaoheiComposerAvatarPosition(bounds, viewportWidth, viewportHeight);
173
- avatar.style.setProperty('--xiaohei-composer-avatar-x', `${position.x}px`);
174
- avatar.style.setProperty('--xiaohei-composer-avatar-y', `${position.y}px`);
175
- avatar.style.setProperty('--xiaohei-composer-avatar-scale', String(position.scale));
176
- avatar.dataset.xiaoheiAvatarPlacement = position.placement;
177
- if (!layoutReady) {
178
- avatar.getBoundingClientRect();
179
- layoutReady = true;
180
- revealAvatar();
181
- }
182
- };
183
- const scheduleMeasure = () => {
184
- if (disposed || frameRequest !== undefined)
185
- return;
186
- frameRequest = win.requestAnimationFrame(measure);
187
- };
188
- const bindComposer = () => {
189
- const next = doc.querySelector(XIAOHEI_HOST_SELECTORS.composerCard) ?? undefined;
190
- if (next !== composer) {
191
- resizeObserver?.disconnect();
192
- resizeObserver = undefined;
193
- composer = next;
194
- if (composer !== undefined && typeof win.ResizeObserver === 'function') {
195
- resizeObserver = new win.ResizeObserver(scheduleMeasure);
196
- resizeObserver.observe(composer);
197
- }
198
- }
199
- scheduleMeasure();
200
- };
201
- const handleViewportChange = () => scheduleMeasure();
202
- const renderPointerResponse = () => {
203
- pointerRequest = undefined;
204
- const bounds = avatar.getBoundingClientRect();
205
- const centerX = bounds.left + bounds.width / 2;
206
- const centerY = bounds.top + bounds.height / 2;
207
- const deltaX = pointerX - centerX;
208
- const deltaY = pointerY - centerY;
209
- const distance = Math.hypot(deltaX, deltaY);
210
- const proximity = Math.max(0, 1 - distance / 220);
211
- avatar.style.setProperty('--xiaohei-avatar-look-x', `${Math.max(-2.5, Math.min(2.5, deltaX / 62)) * proximity}px`);
212
- avatar.style.setProperty('--xiaohei-avatar-look-y', `${Math.max(-1.6, Math.min(1.6, deltaY / 88)) * proximity}px`);
213
- avatar.style.setProperty('--xiaohei-avatar-look-rotation', `${Math.max(-1.2, Math.min(1.2, deltaX / 170)) * proximity}deg`);
214
- avatar.toggleAttribute('data-xiaohei-avatar-aware', proximity > 0);
215
- avatar.toggleAttribute('data-xiaohei-avatar-near', distance < 104);
216
- };
217
- const handlePointerMove = (event) => {
218
- pointerX = event.clientX;
219
- pointerY = event.clientY;
220
- if (pointerRequest === undefined)
221
- pointerRequest = win.requestAnimationFrame(renderPointerResponse);
222
- };
223
- const handleAvatarClick = () => {
224
- if (avatar.dataset.xiaoheiAvatarReaction !== undefined)
225
- return;
226
- if (reactionTimer !== undefined)
227
- clearTimeout(reactionTimer);
228
- for (const timer of reactionStageTimers)
229
- clearTimeout(timer);
230
- reactionStageTimers = [];
231
- const request = ++reactionRequest;
232
- if (idleResetTimer !== undefined)
233
- clearTimeout(idleResetTimer);
234
- idleResetTimer = undefined;
235
- delete avatar.dataset.xiaoheiAvatarIdle;
236
- avatar.dataset.xiaoheiAvatarReaction = 'touch';
237
- avatar.dataset.xiaoheiAvatarReactionStage = 'anticipate';
238
- reactionStageTimers.push(setTimeout(() => {
239
- if (request !== reactionRequest)
240
- return;
241
- avatar.dataset.xiaoheiAvatarReactionStage = 'brace';
242
- void showPortrait('brace');
243
- }, 170), setTimeout(() => {
244
- if (request !== reactionRequest)
245
- return;
246
- avatar.dataset.xiaoheiAvatarReactionStage = 'break';
247
- void showPortrait('reach');
248
- }, 430), setTimeout(() => {
249
- if (request !== reactionRequest)
250
- return;
251
- avatar.dataset.xiaoheiAvatarReactionStage = 'recover';
252
- void showPortrait('brace');
253
- }, 820), setTimeout(() => {
254
- if (request !== reactionRequest)
255
- return;
256
- avatar.dataset.xiaoheiAvatarReactionStage = 'settle';
257
- void showPortrait(desiredHostPortrait);
258
- }, 1_090));
259
- reactionTimer = setTimeout(() => {
260
- if (request !== reactionRequest)
261
- return;
262
- delete avatar.dataset.xiaoheiAvatarReaction;
263
- delete avatar.dataset.xiaoheiAvatarReactionStage;
264
- reactionTimer = undefined;
265
- reactionStageTimers = [];
266
- applyHostPortrait();
267
- }, 1_340);
268
- };
269
- const scheduleBlink = () => {
270
- if (disposed || blinkTimer !== undefined)
271
- return;
272
- blinkTimer = setTimeout(() => {
273
- blinkTimer = undefined;
274
- if (!doc.hidden
275
- && avatar.dataset.xiaoheiPortrait === 'idle'
276
- && avatar.dataset.xiaoheiAvatarReaction === undefined
277
- && avatar.dataset.xiaoheiAvatarIdle === undefined) {
278
- void ensurePortraitDecoded('blink').then((decoded) => {
279
- if (!decoded || disposed || avatar.dataset.xiaoheiPortrait !== 'idle')
280
- return;
281
- avatar.dataset.xiaoheiAvatarBlink = 'true';
282
- if (blinkResetTimer !== undefined)
283
- clearTimeout(blinkResetTimer);
284
- blinkResetTimer = setTimeout(() => {
285
- delete avatar.dataset.xiaoheiAvatarBlink;
286
- blinkResetTimer = undefined;
287
- }, 130);
288
- });
289
- }
290
- scheduleBlink();
291
- }, 4200 + Math.random() * 3600);
292
- };
293
- const scheduleIdleMotion = () => {
294
- if (disposed || idleTimer !== undefined)
295
- return;
296
- idleTimer = setTimeout(() => {
297
- idleTimer = undefined;
298
- if (!doc.hidden
299
- && desiredHostPortrait === 'idle'
300
- && avatar.dataset.xiaoheiAvatarReaction === undefined) {
301
- const motion = resolveXiaoheiComposerIdleMotion(Math.random, previousIdleMotion);
302
- previousIdleMotion = motion;
303
- avatar.dataset.xiaoheiAvatarIdle = motion;
304
- if (motion === 'ponder')
305
- void showPortrait('thinking');
306
- idleResetTimer = setTimeout(() => {
307
- delete avatar.dataset.xiaoheiAvatarIdle;
308
- idleResetTimer = undefined;
309
- if (motion === 'ponder')
310
- applyHostPortrait();
311
- }, XIAOHEI_IDLE_MOTION_DURATION[motion]);
312
- }
313
- scheduleIdleMotion();
314
- }, 4_800 + Math.random() * 5_600);
315
- };
316
- const handleTransitionEnd = (event) => {
317
- if (composer === undefined)
318
- return;
319
- const target = event.target;
320
- if (target instanceof win.Node && (target === composer || composer.contains(target)))
321
- scheduleMeasure();
322
- };
323
- const unsubscribeHostDom = subscribeXiaoheiHostDom(doc, bindComposer);
324
- const stateObserver = new win.MutationObserver(scheduleHostPortrait);
325
- stateObserver.observe(doc.documentElement, {
326
- attributes: true,
327
- attributeFilter: ['data-xiaohei-state'],
328
- });
329
- win.addEventListener('resize', handleViewportChange, { passive: true });
330
- win.addEventListener('pointermove', handlePointerMove, { passive: true });
331
- win.visualViewport?.addEventListener('resize', handleViewportChange, { passive: true });
332
- win.visualViewport?.addEventListener('scroll', handleViewportChange, { passive: true });
333
- doc.addEventListener('transitionend', handleTransitionEnd, true);
334
- avatar.addEventListener('click', handleAvatarClick);
335
- bindComposer();
336
- void ensurePortraitDecoded('idle').then((decoded) => {
337
- if (!decoded || disposed)
338
- return;
339
- idlePortraitReady = true;
340
- revealAvatar();
341
- });
342
- for (const [state] of PORTRAIT_SOURCES) {
343
- if (state !== 'idle')
344
- void ensurePortraitDecoded(state);
345
- }
346
- scheduleHostPortrait();
347
- scheduleBlink();
348
- scheduleIdleMotion();
349
- return () => {
350
- disposed = true;
351
- unsubscribeHostDom();
352
- stateObserver.disconnect();
353
- resizeObserver?.disconnect();
354
- if (frameRequest !== undefined)
355
- win.cancelAnimationFrame(frameRequest);
356
- if (pointerRequest !== undefined)
357
- win.cancelAnimationFrame(pointerRequest);
358
- if (reactionTimer !== undefined)
359
- clearTimeout(reactionTimer);
360
- for (const timer of reactionStageTimers)
361
- clearTimeout(timer);
362
- if (stateTimer !== undefined)
363
- clearTimeout(stateTimer);
364
- if (blinkTimer !== undefined)
365
- clearTimeout(blinkTimer);
366
- if (blinkResetTimer !== undefined)
367
- clearTimeout(blinkResetTimer);
368
- if (idleTimer !== undefined)
369
- clearTimeout(idleTimer);
370
- if (idleResetTimer !== undefined)
371
- clearTimeout(idleResetTimer);
372
- win.removeEventListener('resize', handleViewportChange);
373
- win.removeEventListener('pointermove', handlePointerMove);
374
- win.visualViewport?.removeEventListener('resize', handleViewportChange);
375
- win.visualViewport?.removeEventListener('scroll', handleViewportChange);
376
- doc.removeEventListener('transitionend', handleTransitionEnd, true);
377
- avatar.removeEventListener('click', handleAvatarClick);
378
- avatar.remove();
379
- };
380
- }
381
- function createAvatarImage(doc, source, state) {
382
- const image = doc.createElement('img');
383
- image.className = `${XIAOHEI_COMPOSER_AVATAR_CLASS}__image ${XIAOHEI_COMPOSER_AVATAR_CLASS}__image--${state}`;
384
- image.alt = '';
385
- image.decoding = 'async';
386
- const portraitState = state.slice(state.lastIndexOf('-') + 1);
387
- image.dataset.xiaoheiPortraitFrame = portraitState;
388
- image.fetchPriority = portraitState === 'idle' ? 'high' : 'low';
389
- image.src = source;
390
- return image;
391
- }
392
- function resolveDisplayPortrait(state) {
393
- switch (state) {
394
- case 'thinking':
395
- case 'waiting':
396
- return 'thinking';
397
- case 'tool':
398
- case 'streaming':
399
- return 'working';
400
- case 'complete':
401
- return 'complete';
402
- case 'error':
403
- return 'error';
404
- default:
405
- return 'idle';
406
- }
407
- }
408
- async function decodePortraitImage(image) {
409
- try {
410
- if (typeof image.decode === 'function')
411
- await image.decode();
412
- return image.naturalWidth > 0 || image.complete;
413
- }
414
- catch {
415
- return image.complete && image.naturalWidth > 0;
416
- }
417
- }
418
- const PORTRAIT_SOURCES = [
419
- ['idle', XIAOHEI_BREAKFRAME_IDLE],
420
- ['blink', XIAOHEI_BREAKFRAME_BLINK],
421
- ['brace', XIAOHEI_BREAKFRAME_BRACE],
422
- ['reach', XIAOHEI_BREAKFRAME_REACH],
423
- ['thinking', XIAOHEI_BREAKFRAME_THINKING],
424
- ['working', XIAOHEI_BREAKFRAME_WORKING],
425
- ['complete', XIAOHEI_BREAKFRAME_COMPLETE],
426
- ['error', XIAOHEI_BREAKFRAME_ERROR],
427
- ];
428
- function createPortraitImages(doc, layer) {
429
- return PORTRAIT_SOURCES.map(([state, source]) => createAvatarImage(doc, source, `${layer}-${state}`));
430
- }
431
- function createBreakoutRightImages(doc) {
432
- return PORTRAIT_SOURCES
433
- .filter(([state]) => state === 'brace' || state === 'reach')
434
- .map(([state, source]) => createAvatarImage(doc, source, `breakout-right-${state}`));
435
- }
436
- function createAvatarLayer(doc, name) {
437
- const layer = doc.createElement('span');
438
- layer.className = `${XIAOHEI_COMPOSER_AVATAR_CLASS}__${name}`;
439
- return layer;
440
- }
441
- //# sourceMappingURL=composer-avatar.js.map
@@ -1,4 +0,0 @@
1
- import type { PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
2
- /** A read-only local projection. The native editor owns draft and send lifetime. */
3
- export declare function XiaoheiDraftPreview({ input }: PropsRuntime<'conversation.input.dock'>): import("react").JSX.Element | null;
4
- //# sourceMappingURL=composer-draft-preview.d.ts.map
@@ -1,8 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- /** A read-only local projection. The native editor owns draft and send lifetime. */
3
- export function XiaoheiDraftPreview({ input }) {
4
- if (!input.draft.trim() || input.phase === 'submitting' || input.phase === 'adjudicating')
5
- return null;
6
- return _jsxs("section", { "data-xiaohei-draft-preview": true, "aria-label": "\u8349\u7A3F \u00B7 \u672A\u53D1\u9001", children: [_jsx("div", { className: "xiaohei-draft-label", children: "\u8349\u7A3F \u00B7 \u672A\u53D1\u9001" }), _jsx("div", { className: "xiaohei-draft-bubble", tabIndex: 0, "aria-label": "\u8349\u7A3F\u5185\u5BB9", children: input.draft })] });
7
- }
8
- //# sourceMappingURL=composer-draft-preview.js.map
@@ -1,8 +0,0 @@
1
- /** Keep idle blinks sparse without making their rhythm mechanical. */
2
- export declare function resolveXiaoheiSendBlinkDelay(random?: () => number): number;
3
- /**
4
- * Turn the Host's real primary button into Heixiu without replacing its click,
5
- * keyboard, disabled, tooltip, or accessible-name behaviour.
6
- */
7
- export declare function installXiaoheiComposerSendHeixiu(doc?: Document | undefined): () => void;
8
- //# sourceMappingURL=composer-send-heixiu.d.ts.map
@@ -1,133 +0,0 @@
1
- import { XIAOHEI_HEIXIU_BLINK, XIAOHEI_HEIXIU_OPEN } from './generated-keyart.js';
2
- import { XIAOHEI_HOST_SELECTORS } from './host-contract.js';
3
- import { subscribeXiaoheiHostDom } from './host-dom.js';
4
- const SEND_BUTTON_SELECTOR = ':scope > :last-child > :last-child > button:last-child';
5
- const SEND_ATTRIBUTE = 'data-xiaohei-send-heixiu';
6
- const BLINK_ATTRIBUTE = 'data-xiaohei-blink';
7
- const HEIXIU_CLASS = 'xiaohei-composer-send-heixiu';
8
- const BLINK_DELAY_MIN_MS = 4600;
9
- const BLINK_DELAY_MAX_MS = 8200;
10
- const BLINK_CLOSED_MS = 128;
11
- /** Keep idle blinks sparse without making their rhythm mechanical. */
12
- export function resolveXiaoheiSendBlinkDelay(random = Math.random) {
13
- const sample = Math.min(1, Math.max(0, random()));
14
- return Math.round(BLINK_DELAY_MIN_MS + sample * (BLINK_DELAY_MAX_MS - BLINK_DELAY_MIN_MS));
15
- }
16
- function createFrame(doc, source, className) {
17
- const image = doc.createElement('img');
18
- image.className = className;
19
- image.src = source;
20
- image.alt = '';
21
- image.draggable = false;
22
- return image;
23
- }
24
- function createHeixiu(doc) {
25
- const element = doc.createElement('span');
26
- element.className = HEIXIU_CLASS;
27
- element.setAttribute('aria-hidden', 'true');
28
- element.append(createFrame(doc, XIAOHEI_HEIXIU_OPEN, `${HEIXIU_CLASS}__open`), createFrame(doc, XIAOHEI_HEIXIU_BLINK, `${HEIXIU_CLASS}__blink`));
29
- return element;
30
- }
31
- /** The Host renders a rect only when the primary action has become Stop. */
32
- function isSendAction(button) {
33
- const hostGlyph = [...button.children].find(child => child.localName === 'svg');
34
- return hostGlyph !== undefined && hostGlyph.querySelector('rect') === null;
35
- }
36
- /**
37
- * Turn the Host's real primary button into Heixiu without replacing its click,
38
- * keyboard, disabled, tooltip, or accessible-name behaviour.
39
- */
40
- export function installXiaoheiComposerSendHeixiu(doc = typeof document === 'undefined' ? undefined : document) {
41
- if (doc?.body === undefined || doc.defaultView === null)
42
- return () => { };
43
- const win = doc.defaultView;
44
- const reducedMotion = win.matchMedia('(prefers-reduced-motion: reduce)');
45
- const decorations = new Map();
46
- let blinkTimer = 0;
47
- let reopenTimer = 0;
48
- const canBlink = () => (decorations.size > 0
49
- && doc.visibilityState !== 'hidden'
50
- && !reducedMotion.matches);
51
- const setClosed = (closed) => {
52
- for (const decoration of decorations.values()) {
53
- if (closed)
54
- decoration.setAttribute(BLINK_ATTRIBUTE, 'closed');
55
- else
56
- decoration.removeAttribute(BLINK_ATTRIBUTE);
57
- }
58
- };
59
- const clearTimers = () => {
60
- if (blinkTimer !== 0)
61
- win.clearTimeout(blinkTimer);
62
- if (reopenTimer !== 0)
63
- win.clearTimeout(reopenTimer);
64
- blinkTimer = 0;
65
- reopenTimer = 0;
66
- };
67
- const scheduleBlink = () => {
68
- if (!canBlink() || blinkTimer !== 0 || reopenTimer !== 0)
69
- return;
70
- blinkTimer = win.setTimeout(() => {
71
- blinkTimer = 0;
72
- if (!canBlink())
73
- return;
74
- setClosed(true);
75
- reopenTimer = win.setTimeout(() => {
76
- reopenTimer = 0;
77
- setClosed(false);
78
- scheduleBlink();
79
- }, BLINK_CLOSED_MS);
80
- }, resolveXiaoheiSendBlinkDelay());
81
- };
82
- const restartBlink = () => {
83
- clearTimers();
84
- setClosed(false);
85
- scheduleBlink();
86
- };
87
- const detach = (button, decoration) => {
88
- decoration.remove();
89
- button.removeAttribute(SEND_ATTRIBUTE);
90
- decorations.delete(button);
91
- };
92
- const reconcile = () => {
93
- const candidates = new Set();
94
- for (const card of doc.querySelectorAll(XIAOHEI_HOST_SELECTORS.composerCard)) {
95
- const button = card.querySelector(SEND_BUTTON_SELECTOR);
96
- if (button !== null && isSendAction(button))
97
- candidates.add(button);
98
- }
99
- const hadDecorations = decorations.size > 0;
100
- for (const [button, decoration] of decorations) {
101
- if (candidates.has(button) && decoration.parentElement === button)
102
- continue;
103
- detach(button, decoration);
104
- }
105
- for (const button of candidates) {
106
- if (decorations.has(button))
107
- continue;
108
- const decoration = createHeixiu(doc);
109
- button.setAttribute(SEND_ATTRIBUTE, 'true');
110
- button.insertBefore(decoration, button.firstChild);
111
- decorations.set(button, decoration);
112
- }
113
- if (!hadDecorations && decorations.size > 0)
114
- scheduleBlink();
115
- else if (hadDecorations && decorations.size === 0)
116
- restartBlink();
117
- };
118
- const onEnvironmentChange = () => restartBlink();
119
- reconcile();
120
- const unsubscribeHostDom = subscribeXiaoheiHostDom(doc, reconcile);
121
- doc.addEventListener('visibilitychange', onEnvironmentChange);
122
- reducedMotion.addEventListener('change', onEnvironmentChange);
123
- return () => {
124
- clearTimers();
125
- unsubscribeHostDom();
126
- doc.removeEventListener('visibilitychange', onEnvironmentChange);
127
- reducedMotion.removeEventListener('change', onEnvironmentChange);
128
- for (const [button, decoration] of decorations)
129
- detach(button, decoration);
130
- decorations.clear();
131
- };
132
- }
133
- //# sourceMappingURL=composer-send-heixiu.js.map
@@ -1,6 +0,0 @@
1
- import type { SessionListState, SessionSummary } from '@deepseek-ai/dsh-api-session-controller/client';
2
- /** Keep the host session-selection contract out of visual state reducers. */
3
- export declare function currentSession(state: SessionListState & {
4
- current?: SessionSummary['id'];
5
- }): SessionSummary['id'] | undefined;
6
- //# sourceMappingURL=current-session.d.ts.map
@@ -1,5 +0,0 @@
1
- /** Keep the host session-selection contract out of visual state reducers. */
2
- export function currentSession(state) {
3
- return Object.values(state.byId ?? {}).find(row => (row.retainedBy?.mainView ?? 0) > 0)?.id ?? state.current;
4
- }
5
- //# sourceMappingURL=current-session.js.map
@@ -1,3 +0,0 @@
1
- /** Self-contained native DSH chunk; no new HTTP routes or Desktop origin assumptions. */
2
- export declare function installDecorations(doc: Document): () => void;
3
- //# sourceMappingURL=decorations-entry.d.ts.map
@@ -1,18 +0,0 @@
1
- import { installXiaoheiWallpaperCharacter } from './scene/wallpaper-character.js';
2
- import { XIAOHEI_WALLPAPER_CHARACTER_CSS } from './scene/wallpaper-character-styles.js';
3
- /** Self-contained native DSH chunk; no new HTTP routes or Desktop origin assumptions. */
4
- export function installDecorations(doc) {
5
- const style = doc.createElement('style');
6
- style.id = 'dsh-theme-xiaohei/character-style';
7
- style.textContent = XIAOHEI_WALLPAPER_CHARACTER_CSS;
8
- doc.head.append(style);
9
- try {
10
- const disposeCharacter = installXiaoheiWallpaperCharacter(doc);
11
- return () => { disposeCharacter(); style.remove(); };
12
- }
13
- catch (error) {
14
- style.remove();
15
- throw error;
16
- }
17
- }
18
- //# sourceMappingURL=decorations-entry.js.map
@@ -1,5 +0,0 @@
1
- import type * as Companion from './companion-entry.js';
2
- import type { HeixiuSignals } from './bloub-heixiu/signals.js';
3
- /** Keep the SVG engine and its initialization off the conversation's first paint. */
4
- export declare function installDeferredCompanion(signals: HeixiuSignals, doc?: Document | undefined, load?: () => Promise<typeof Companion>): () => void;
5
- //# sourceMappingURL=deferred-companion.d.ts.map
@@ -1,9 +0,0 @@
1
- import { installDeferredDecorations } from './deferred-decorations.js';
2
- /** Keep the SVG engine and its initialization off the conversation's first paint. */
3
- export function installDeferredCompanion(signals, doc = typeof document === 'undefined' ? undefined : document, load = () => require.async('./client.companion.js')) {
4
- return installDeferredDecorations(doc, async () => {
5
- const module = await load();
6
- return { installDecorations: (target) => module.installComposerBloub(target, signals) };
7
- }, '#root [data-composer-card="true"]');
8
- }
9
- //# sourceMappingURL=deferred-companion.js.map
@@ -1,3 +0,0 @@
1
- import type * as Decorations from './decorations-entry.js';
2
- export declare function installDeferredDecorations(doc?: Document | undefined, load?: () => Promise<typeof Decorations>, readySelector?: string): () => void;
3
- //# sourceMappingURL=deferred-decorations.d.ts.map