@lemoncat7/dsh-theme-xiaohei 0.4.5 → 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 (230) hide show
  1. package/README.md +25 -92
  2. package/THIRD_PARTY_NOTICES.md +13 -1
  3. package/docs/dsh-021-compatibility.md +23 -0
  4. package/docs/releases/0.4.6.md +17 -0
  5. package/docs/releases/0.5.0.md +24 -0
  6. package/docs/releases/README.md +14 -0
  7. package/docs/rift-interaction.md +35 -0
  8. package/docs/rift-preview.md +39 -0
  9. package/lib/client.companion.js +99 -0
  10. package/lib/client.decorations.js +224 -51
  11. package/lib/client.js +532 -2501
  12. package/lib/index.d.ts +1 -2
  13. package/lib/index.js +393 -11
  14. package/lib/rift/boot.d.ts +6 -0
  15. package/package.json +30 -19
  16. package/lib/appearance.d.ts +0 -12
  17. package/lib/appearance.js +0 -42
  18. package/lib/blink.d.ts +0 -4
  19. package/lib/blink.js +0 -110
  20. package/lib/bloub-heixiu/ambient.d.ts +0 -3
  21. package/lib/bloub-heixiu/ambient.js +0 -12
  22. package/lib/bloub-heixiu/character.d.ts +0 -33
  23. package/lib/bloub-heixiu/character.js +0 -124
  24. package/lib/bloub-heixiu/effects.d.ts +0 -4
  25. package/lib/bloub-heixiu/effects.js +0 -91
  26. package/lib/bloub-heixiu/flight.d.ts +0 -15
  27. package/lib/bloub-heixiu/flight.js +0 -66
  28. package/lib/bloub-heixiu/follow.d.ts +0 -13
  29. package/lib/bloub-heixiu/follow.js +0 -23
  30. package/lib/bloub-heixiu/layout.d.ts +0 -18
  31. package/lib/bloub-heixiu/layout.js +0 -12
  32. package/lib/bloub-heixiu/renderer.d.ts +0 -16
  33. package/lib/bloub-heixiu/renderer.js +0 -94
  34. package/lib/bloub-heixiu/runtime.d.ts +0 -6
  35. package/lib/bloub-heixiu/runtime.js +0 -409
  36. package/lib/bloub-heixiu/signals.d.ts +0 -17
  37. package/lib/bloub-heixiu/signals.js +0 -55
  38. package/lib/bloub-heixiu/styles.d.ts +0 -2
  39. package/lib/bloub-heixiu/styles.js +0 -98
  40. package/lib/boot-appearance.d.ts +0 -10
  41. package/lib/boot-appearance.js +0 -47
  42. package/lib/boot-loader.d.ts +0 -5
  43. package/lib/boot-loader.js +0 -158
  44. package/lib/chrome/accessibility.d.ts +0 -3
  45. package/lib/chrome/accessibility.js +0 -69
  46. package/lib/chrome/blink.d.ts +0 -3
  47. package/lib/chrome/blink.js +0 -15
  48. package/lib/chrome/composer-avatar.d.ts +0 -10
  49. package/lib/chrome/composer-avatar.js +0 -599
  50. package/lib/chrome/composer-send-heixiu.d.ts +0 -3
  51. package/lib/chrome/composer-send-heixiu.js +0 -143
  52. package/lib/chrome/composer.d.ts +0 -3
  53. package/lib/chrome/composer.js +0 -135
  54. package/lib/chrome/controls.d.ts +0 -8
  55. package/lib/chrome/controls.js +0 -348
  56. package/lib/chrome/conversation-messages.d.ts +0 -3
  57. package/lib/chrome/conversation-messages.js +0 -329
  58. package/lib/chrome/conversation-submissions.d.ts +0 -3
  59. package/lib/chrome/conversation-submissions.js +0 -68
  60. package/lib/chrome/conversation.d.ts +0 -3
  61. package/lib/chrome/conversation.js +0 -67
  62. package/lib/chrome/frames.d.ts +0 -6
  63. package/lib/chrome/frames.js +0 -134
  64. package/lib/chrome/gaze.d.ts +0 -3
  65. package/lib/chrome/gaze.js +0 -103
  66. package/lib/chrome/identity.d.ts +0 -6
  67. package/lib/chrome/identity.js +0 -47
  68. package/lib/chrome/overlays.d.ts +0 -3
  69. package/lib/chrome/overlays.js +0 -104
  70. package/lib/chrome/portal.d.ts +0 -6
  71. package/lib/chrome/portal.js +0 -169
  72. package/lib/chrome/reactions.d.ts +0 -3
  73. package/lib/chrome/reactions.js +0 -85
  74. package/lib/chrome/sidebar.d.ts +0 -3
  75. package/lib/chrome/sidebar.js +0 -313
  76. package/lib/chrome/tokens.d.ts +0 -3
  77. package/lib/chrome/tokens.js +0 -224
  78. package/lib/chrome/workspace.d.ts +0 -3
  79. package/lib/chrome/workspace.js +0 -94
  80. package/lib/chrome.d.ts +0 -10
  81. package/lib/chrome.js +0 -46
  82. package/lib/client-entry.d.ts +0 -3
  83. package/lib/client-entry.js +0 -3
  84. package/lib/client.d.ts +0 -10
  85. package/lib/client.pose-chin-dark.js +0 -4
  86. package/lib/client.pose-chin-light.js +0 -4
  87. package/lib/client.pose-doze-dark.js +0 -4
  88. package/lib/client.pose-doze-light.js +0 -4
  89. package/lib/client.pose-halfpeek-dark.js +0 -4
  90. package/lib/client.pose-halfpeek-light.js +0 -4
  91. package/lib/client.pose-peek-dark.js +0 -4
  92. package/lib/client.pose-peek-light.js +0 -4
  93. package/lib/client.pose-seated-dark.js +0 -4
  94. package/lib/client.pose-seated-light.js +0 -4
  95. package/lib/client.rig-chin-dark.js +0 -4
  96. package/lib/client.rig-chin-light.js +0 -4
  97. package/lib/client.rig-halfpeek-dark.js +0 -4
  98. package/lib/client.rig-halfpeek-light.js +0 -4
  99. package/lib/client.rig-peek-dark.js +0 -4
  100. package/lib/client.rig-peek-light.js +0 -4
  101. package/lib/client.rig-seated-dark.js +0 -4
  102. package/lib/client.rig-seated-light.js +0 -4
  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-decorations.d.ts +0 -3
  114. package/lib/deferred-decorations.js +0 -51
  115. package/lib/gaze.d.ts +0 -4
  116. package/lib/gaze.js +0 -230
  117. package/lib/generated-backgrounds.d.ts +0 -14
  118. package/lib/generated-backgrounds.js +0 -14
  119. package/lib/generated-character-motion.d.ts +0 -4
  120. package/lib/generated-character-motion.js +0 -2
  121. package/lib/generated-identity.d.ts +0 -6
  122. package/lib/generated-identity.js +0 -6
  123. package/lib/generated-keyart.d.ts +0 -34
  124. package/lib/generated-keyart.js +0 -34
  125. package/lib/generated-loading-assets.d.ts +0 -4
  126. package/lib/generated-loading-assets.js +0 -4
  127. package/lib/heixiu-interactions.d.ts +0 -10
  128. package/lib/heixiu-interactions.js +0 -161
  129. package/lib/host-contract.d.ts +0 -9
  130. package/lib/host-contract.js +0 -13
  131. package/lib/host-dom.d.ts +0 -11
  132. package/lib/host-dom.js +0 -68
  133. package/lib/loading-heixiu.d.ts +0 -8
  134. package/lib/loading-heixiu.js +0 -287
  135. package/lib/metallic-brand-mark.d.ts +0 -10
  136. package/lib/metallic-brand-mark.js +0 -296
  137. package/lib/plugin.d.ts +0 -6
  138. package/lib/plugin.js +0 -60
  139. package/lib/portal.d.ts +0 -40
  140. package/lib/portal.js +0 -225
  141. package/lib/reactions.d.ts +0 -20
  142. package/lib/reactions.js +0 -380
  143. package/lib/scene/avatar-model.d.ts +0 -6
  144. package/lib/scene/avatar-model.js +0 -646
  145. package/lib/scene/avatar-motion.d.ts +0 -3
  146. package/lib/scene/avatar-motion.js +0 -799
  147. package/lib/scene/character-assets.d.ts +0 -13
  148. package/lib/scene/character-assets.js +0 -26
  149. package/lib/scene/character-expression.d.ts +0 -4
  150. package/lib/scene/character-expression.js +0 -15
  151. package/lib/scene/character-eye-material.d.ts +0 -13
  152. package/lib/scene/character-eye-material.js +0 -88
  153. package/lib/scene/character-eye-renderer.d.ts +0 -5
  154. package/lib/scene/character-eye-renderer.js +0 -80
  155. package/lib/scene/character-eye-rig.d.ts +0 -20
  156. package/lib/scene/character-eye-rig.js +0 -35
  157. package/lib/scene/character-gaze.d.ts +0 -16
  158. package/lib/scene/character-gaze.js +0 -36
  159. package/lib/scene/character-idle.d.ts +0 -17
  160. package/lib/scene/character-idle.js +0 -65
  161. package/lib/scene/character-layout.d.ts +0 -24
  162. package/lib/scene/character-layout.js +0 -51
  163. package/lib/scene/character-motion-clock.d.ts +0 -18
  164. package/lib/scene/character-motion-clock.js +0 -70
  165. package/lib/scene/character-motion-types.d.ts +0 -12
  166. package/lib/scene/character-motion-types.js +0 -2
  167. package/lib/scene/character-motion.d.ts +0 -6
  168. package/lib/scene/character-motion.js +0 -187
  169. package/lib/scene/character-poses.d.ts +0 -26
  170. package/lib/scene/character-poses.js +0 -11
  171. package/lib/scene/character-rig-renderer.d.ts +0 -5
  172. package/lib/scene/character-rig-renderer.js +0 -95
  173. package/lib/scene/character-rig.d.ts +0 -22
  174. package/lib/scene/character-rig.js +0 -61
  175. package/lib/scene/heixiu-feedback.d.ts +0 -3
  176. package/lib/scene/heixiu-feedback.js +0 -64
  177. package/lib/scene/heixiu-interactions.d.ts +0 -3
  178. package/lib/scene/heixiu-interactions.js +0 -92
  179. package/lib/scene/ids.d.ts +0 -5
  180. package/lib/scene/ids.js +0 -5
  181. package/lib/scene/pointer-bridge.d.ts +0 -21
  182. package/lib/scene/pointer-bridge.js +0 -155
  183. package/lib/scene/runtime.d.ts +0 -12
  184. package/lib/scene/runtime.js +0 -74
  185. package/lib/scene/state-transitions.d.ts +0 -3
  186. package/lib/scene/state-transitions.js +0 -37
  187. package/lib/scene/styles.d.ts +0 -5
  188. package/lib/scene/styles.js +0 -69
  189. package/lib/scene/sylva-performance.d.ts +0 -11
  190. package/lib/scene/sylva-performance.js +0 -58
  191. package/lib/scene/wallpaper-character-styles.d.ts +0 -3
  192. package/lib/scene/wallpaper-character-styles.js +0 -49
  193. package/lib/scene/wallpaper-character.d.ts +0 -5
  194. package/lib/scene/wallpaper-character.js +0 -222
  195. package/lib/scene.d.ts +0 -8
  196. package/lib/scene.js +0 -8
  197. package/lib/sidebar-glass.d.ts +0 -16
  198. package/lib/sidebar-glass.js +0 -168
  199. package/lib/sidebar-heixiu-escape.d.ts +0 -44
  200. package/lib/sidebar-heixiu-escape.js +0 -340
  201. package/lib/sidebar-heixiu-roaming.d.ts +0 -27
  202. package/lib/sidebar-heixiu-roaming.js +0 -310
  203. package/lib/sidebar-reveal.d.ts +0 -8
  204. package/lib/sidebar-reveal.js +0 -59
  205. package/lib/state.d.ts +0 -21
  206. package/lib/state.js +0 -123
  207. package/lib/theme.d.ts +0 -19
  208. package/lib/theme.js +0 -188
  209. package/lib/vendor/bloub/decor.d.ts +0 -114
  210. package/lib/vendor/bloub/decor.js +0 -198
  211. package/lib/vendor/bloub/engine.d.ts +0 -213
  212. package/lib/vendor/bloub/engine.js +0 -452
  213. package/lib/vendor/bloub/expressions.d.ts +0 -35
  214. package/lib/vendor/bloub/expressions.js +0 -143
  215. package/lib/vendor/bloub/eyefit.d.ts +0 -75
  216. package/lib/vendor/bloub/eyefit.js +0 -393
  217. package/lib/vendor/bloub/face.d.ts +0 -63
  218. package/lib/vendor/bloub/face.js +0 -106
  219. package/lib/vendor/bloub/math.d.ts +0 -22
  220. package/lib/vendor/bloub/math.js +0 -36
  221. package/lib/vendor/bloub/profiles.d.ts +0 -8
  222. package/lib/vendor/bloub/profiles.js +0 -20
  223. package/lib/vendor/bloub/repere.d.ts +0 -30
  224. package/lib/vendor/bloub/repere.js +0 -32
  225. package/lib/vendor/bloub/shape.d.ts +0 -80
  226. package/lib/vendor/bloub/shape.js +0 -268
  227. package/lib/vendor/bloub/skins.d.ts +0 -36
  228. package/lib/vendor/bloub/skins.js +0 -74
  229. package/lib/vendor/bloub/states.d.ts +0 -87
  230. 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,3 +0,0 @@
1
- import type * as Decorations from './decorations-entry.js';
2
- export declare function installDeferredDecorations(doc?: Document | undefined, load?: () => Promise<typeof Decorations>): () => void;
3
- //# sourceMappingURL=deferred-decorations.d.ts.map