@lemoncat7/dsh-theme-xiaohei 0.3.0-alpha.23 → 0.3.2

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 (222) hide show
  1. package/README.md +39 -17
  2. package/THIRD_PARTY_NOTICES.md +41 -0
  3. package/lib/appearance.js +26 -10
  4. package/lib/blink.js +3 -3
  5. package/lib/bloub-heixiu/ambient.d.ts +3 -0
  6. package/lib/bloub-heixiu/ambient.js +12 -0
  7. package/lib/bloub-heixiu/character.d.ts +33 -0
  8. package/lib/bloub-heixiu/character.js +124 -0
  9. package/lib/bloub-heixiu/effects.d.ts +4 -0
  10. package/lib/bloub-heixiu/effects.js +91 -0
  11. package/lib/bloub-heixiu/flight.d.ts +15 -0
  12. package/lib/bloub-heixiu/flight.js +66 -0
  13. package/lib/bloub-heixiu/follow.d.ts +13 -0
  14. package/lib/bloub-heixiu/follow.js +23 -0
  15. package/lib/bloub-heixiu/layout.d.ts +18 -0
  16. package/lib/bloub-heixiu/layout.js +12 -0
  17. package/lib/bloub-heixiu/renderer.d.ts +16 -0
  18. package/lib/bloub-heixiu/renderer.js +94 -0
  19. package/lib/bloub-heixiu/runtime.d.ts +6 -0
  20. package/lib/bloub-heixiu/runtime.js +395 -0
  21. package/lib/bloub-heixiu/signals.d.ts +17 -0
  22. package/lib/bloub-heixiu/signals.js +53 -0
  23. package/lib/bloub-heixiu/styles.d.ts +2 -0
  24. package/lib/bloub-heixiu/styles.js +98 -0
  25. package/lib/chrome/accessibility.d.ts +1 -1
  26. package/lib/chrome/accessibility.js +5 -13
  27. package/lib/chrome/composer-avatar.d.ts +10 -0
  28. package/lib/chrome/composer-avatar.js +599 -0
  29. package/lib/chrome/composer-send-heixiu.d.ts +3 -0
  30. package/lib/chrome/composer-send-heixiu.js +143 -0
  31. package/lib/chrome/composer.d.ts +2 -2
  32. package/lib/chrome/composer.js +84 -95
  33. package/lib/chrome/controls.d.ts +8 -0
  34. package/lib/chrome/controls.js +348 -0
  35. package/lib/chrome/conversation-messages.d.ts +1 -1
  36. package/lib/chrome/conversation-messages.js +207 -9
  37. package/lib/chrome/conversation.d.ts +1 -1
  38. package/lib/chrome/conversation.js +6 -0
  39. package/lib/chrome/identity.js +4 -18
  40. package/lib/chrome/portal.d.ts +1 -1
  41. package/lib/chrome/portal.js +1 -1
  42. package/lib/chrome/sidebar.d.ts +1 -1
  43. package/lib/chrome/sidebar.js +134 -153
  44. package/lib/chrome/tokens.d.ts +1 -1
  45. package/lib/chrome/tokens.js +121 -68
  46. package/lib/chrome/workspace.d.ts +2 -2
  47. package/lib/chrome/workspace.js +35 -254
  48. package/lib/chrome.js +4 -0
  49. package/lib/client.d.ts +5 -12
  50. package/lib/client.js +6262 -4455
  51. package/lib/composer-avatar.d.ts +18 -0
  52. package/lib/composer-avatar.js +441 -0
  53. package/lib/composer-send-heixiu.d.ts +8 -0
  54. package/lib/composer-send-heixiu.js +133 -0
  55. package/lib/gaze.js +3 -3
  56. package/lib/generated-backgrounds.d.ts +14 -0
  57. package/lib/generated-backgrounds.js +14 -0
  58. package/lib/generated-character-motion.d.ts +4 -0
  59. package/lib/generated-character-motion.js +2 -0
  60. package/lib/generated-identity.d.ts +1 -0
  61. package/lib/generated-identity.js +1 -0
  62. package/lib/generated-keyart.d.ts +18 -3
  63. package/lib/generated-keyart.js +18 -3
  64. package/lib/host-contract.d.ts +9 -0
  65. package/lib/host-contract.js +13 -0
  66. package/lib/host-dom.d.ts +11 -0
  67. package/lib/host-dom.js +60 -0
  68. package/lib/loading-heixiu.js +3 -3
  69. package/lib/metallic-brand-mark.d.ts +10 -0
  70. package/lib/metallic-brand-mark.js +323 -0
  71. package/lib/plugin.d.ts +1 -1
  72. package/lib/plugin.js +31 -16
  73. package/lib/portal.js +11 -10
  74. package/lib/reactions.js +3 -3
  75. package/lib/scene/avatar-model.d.ts +6 -0
  76. package/lib/scene/avatar-model.js +646 -0
  77. package/lib/scene/avatar-motion.d.ts +3 -0
  78. package/lib/scene/avatar-motion.js +799 -0
  79. package/lib/scene/character-idle.d.ts +17 -0
  80. package/lib/scene/character-idle.js +65 -0
  81. package/lib/scene/character-layout.d.ts +24 -0
  82. package/lib/scene/character-layout.js +51 -0
  83. package/lib/scene/character-motion-clock.d.ts +18 -0
  84. package/lib/scene/character-motion-clock.js +57 -0
  85. package/lib/scene/character-motion-types.d.ts +12 -0
  86. package/lib/scene/character-motion-types.js +2 -0
  87. package/lib/scene/character-motion.d.ts +6 -0
  88. package/lib/scene/character-motion.js +126 -0
  89. package/lib/scene/character-poses.d.ts +26 -0
  90. package/lib/scene/character-poses.js +11 -0
  91. package/lib/scene/character-rig-renderer.d.ts +4 -0
  92. package/lib/scene/character-rig-renderer.js +85 -0
  93. package/lib/scene/character-rig.d.ts +20 -0
  94. package/lib/scene/character-rig.js +53 -0
  95. package/lib/scene/heixiu-feedback.d.ts +1 -1
  96. package/lib/scene/heixiu-feedback.js +0 -17
  97. package/lib/scene/pointer-bridge.d.ts +21 -0
  98. package/lib/scene/pointer-bridge.js +155 -0
  99. package/lib/scene/runtime.d.ts +12 -0
  100. package/lib/scene/runtime.js +87 -0
  101. package/lib/scene/styles.d.ts +7 -0
  102. package/lib/scene/styles.js +75 -0
  103. package/lib/scene/sylva-performance.d.ts +11 -0
  104. package/lib/scene/sylva-performance.js +58 -0
  105. package/lib/scene/wallpaper-character-styles.d.ts +3 -0
  106. package/lib/scene/wallpaper-character-styles.js +53 -0
  107. package/lib/scene/wallpaper-character.d.ts +4 -0
  108. package/lib/scene/wallpaper-character.js +213 -0
  109. package/lib/scene.d.ts +7 -13
  110. package/lib/scene.js +7 -1023
  111. package/lib/sidebar-glass.js +99 -36
  112. package/lib/sidebar-heixiu-roaming.js +5 -5
  113. package/lib/sidebar-reveal.d.ts +8 -0
  114. package/lib/sidebar-reveal.js +51 -0
  115. package/lib/state.d.ts +14 -2
  116. package/lib/state.js +12 -4
  117. package/lib/theme.js +2 -2
  118. package/lib/vendor/bloub/decor.d.ts +114 -0
  119. package/lib/vendor/bloub/decor.js +198 -0
  120. package/lib/vendor/bloub/engine.d.ts +213 -0
  121. package/lib/vendor/bloub/engine.js +452 -0
  122. package/lib/vendor/bloub/expressions.d.ts +35 -0
  123. package/lib/vendor/bloub/expressions.js +143 -0
  124. package/lib/vendor/bloub/eyefit.d.ts +75 -0
  125. package/lib/vendor/bloub/eyefit.js +393 -0
  126. package/lib/vendor/bloub/face.d.ts +63 -0
  127. package/lib/vendor/bloub/face.js +106 -0
  128. package/lib/vendor/bloub/math.d.ts +22 -0
  129. package/lib/vendor/bloub/math.js +36 -0
  130. package/lib/vendor/bloub/profiles.d.ts +8 -0
  131. package/lib/vendor/bloub/profiles.js +20 -0
  132. package/lib/vendor/bloub/repere.d.ts +30 -0
  133. package/lib/vendor/bloub/repere.js +32 -0
  134. package/lib/vendor/bloub/shape.d.ts +80 -0
  135. package/lib/vendor/bloub/shape.js +268 -0
  136. package/lib/vendor/bloub/skins.d.ts +36 -0
  137. package/lib/vendor/bloub/skins.js +74 -0
  138. package/lib/vendor/bloub/states.d.ts +87 -0
  139. package/lib/vendor/bloub/states.js +468 -0
  140. package/package.json +23 -6
  141. package/lib/appearance.d.ts.map +0 -1
  142. package/lib/appearance.js.map +0 -1
  143. package/lib/blink.d.ts.map +0 -1
  144. package/lib/blink.js.map +0 -1
  145. package/lib/boot-appearance.d.ts.map +0 -1
  146. package/lib/boot-appearance.js.map +0 -1
  147. package/lib/boot-loader.d.ts.map +0 -1
  148. package/lib/boot-loader.js.map +0 -1
  149. package/lib/chrome/accessibility.d.ts.map +0 -1
  150. package/lib/chrome/accessibility.js.map +0 -1
  151. package/lib/chrome/blink.d.ts.map +0 -1
  152. package/lib/chrome/blink.js.map +0 -1
  153. package/lib/chrome/composer.d.ts.map +0 -1
  154. package/lib/chrome/composer.js.map +0 -1
  155. package/lib/chrome/conversation-messages.d.ts.map +0 -1
  156. package/lib/chrome/conversation-messages.js.map +0 -1
  157. package/lib/chrome/conversation.d.ts.map +0 -1
  158. package/lib/chrome/conversation.js.map +0 -1
  159. package/lib/chrome/frames.d.ts.map +0 -1
  160. package/lib/chrome/frames.js.map +0 -1
  161. package/lib/chrome/gaze.d.ts.map +0 -1
  162. package/lib/chrome/gaze.js.map +0 -1
  163. package/lib/chrome/identity.d.ts.map +0 -1
  164. package/lib/chrome/identity.js.map +0 -1
  165. package/lib/chrome/overlays.d.ts.map +0 -1
  166. package/lib/chrome/overlays.js.map +0 -1
  167. package/lib/chrome/portal.d.ts.map +0 -1
  168. package/lib/chrome/portal.js.map +0 -1
  169. package/lib/chrome/reactions.d.ts.map +0 -1
  170. package/lib/chrome/reactions.js.map +0 -1
  171. package/lib/chrome/sidebar.d.ts.map +0 -1
  172. package/lib/chrome/sidebar.js.map +0 -1
  173. package/lib/chrome/tokens.d.ts.map +0 -1
  174. package/lib/chrome/tokens.js.map +0 -1
  175. package/lib/chrome/workspace.d.ts.map +0 -1
  176. package/lib/chrome/workspace.js.map +0 -1
  177. package/lib/chrome.d.ts.map +0 -1
  178. package/lib/chrome.js.map +0 -1
  179. package/lib/client.d.ts.map +0 -1
  180. package/lib/client.js.map +0 -7
  181. package/lib/gaze.d.ts.map +0 -1
  182. package/lib/gaze.js.map +0 -1
  183. package/lib/generated-identity.d.ts.map +0 -1
  184. package/lib/generated-identity.js.map +0 -1
  185. package/lib/generated-keyart.d.ts.map +0 -1
  186. package/lib/generated-keyart.js.map +0 -1
  187. package/lib/generated-loading-assets.d.ts.map +0 -1
  188. package/lib/generated-loading-assets.js.map +0 -1
  189. package/lib/generated-sidebar-assets.d.ts +0 -4
  190. package/lib/generated-sidebar-assets.d.ts.map +0 -1
  191. package/lib/generated-sidebar-assets.js +0 -4
  192. package/lib/generated-sidebar-assets.js.map +0 -1
  193. package/lib/heixiu-interactions.d.ts.map +0 -1
  194. package/lib/heixiu-interactions.js.map +0 -1
  195. package/lib/index.d.ts.map +0 -1
  196. package/lib/index.js.map +0 -1
  197. package/lib/loading-heixiu.d.ts.map +0 -1
  198. package/lib/loading-heixiu.js.map +0 -1
  199. package/lib/plugin.d.ts.map +0 -1
  200. package/lib/plugin.js.map +0 -1
  201. package/lib/portal.d.ts.map +0 -1
  202. package/lib/portal.js.map +0 -1
  203. package/lib/reactions.d.ts.map +0 -1
  204. package/lib/reactions.js.map +0 -1
  205. package/lib/scene/heixiu-feedback.d.ts.map +0 -1
  206. package/lib/scene/heixiu-feedback.js.map +0 -1
  207. package/lib/scene/heixiu-interactions.d.ts.map +0 -1
  208. package/lib/scene/heixiu-interactions.js.map +0 -1
  209. package/lib/scene/state-transitions.d.ts.map +0 -1
  210. package/lib/scene/state-transitions.js.map +0 -1
  211. package/lib/scene.d.ts.map +0 -1
  212. package/lib/scene.js.map +0 -1
  213. package/lib/sidebar-glass.d.ts.map +0 -1
  214. package/lib/sidebar-glass.js.map +0 -1
  215. package/lib/sidebar-heixiu-escape.d.ts.map +0 -1
  216. package/lib/sidebar-heixiu-escape.js.map +0 -1
  217. package/lib/sidebar-heixiu-roaming.d.ts.map +0 -1
  218. package/lib/sidebar-heixiu-roaming.js.map +0 -1
  219. package/lib/state.d.ts.map +0 -1
  220. package/lib/state.js.map +0 -1
  221. package/lib/theme.d.ts.map +0 -1
  222. package/lib/theme.js.map +0 -1
@@ -0,0 +1,9 @@
1
+ export declare const XIAOHEI_HOST_SELECTORS: {
2
+ readonly sidebar: "[data-slot='sidebar']";
3
+ readonly sidebarShell: "#root [data-slot='sidebar'] > div";
4
+ readonly sidebarColumn: "#root :has(> [data-slot='sidebar'])";
5
+ readonly composerCard: "#root [data-composer-card='true']";
6
+ readonly composerHeroMark: "#root .xiaohei-brand-mark[data-brand-context='hero']";
7
+ readonly composerHeroRow: "[class*='_headline']";
8
+ };
9
+ //# sourceMappingURL=host-contract.d.ts.map
@@ -0,0 +1,13 @@
1
+ /** Keep stable DSH selectors in one compatibility boundary. */
2
+ const sidebar = "[data-slot='sidebar']";
3
+ export const XIAOHEI_HOST_SELECTORS = {
4
+ sidebar,
5
+ sidebarShell: `#root ${sidebar} > div`,
6
+ // The shell holds its expanded width while its contents fade. Only the
7
+ // outer layout column represents the currently visible animated width.
8
+ sidebarColumn: `#root :has(> ${sidebar})`,
9
+ composerCard: "#root [data-composer-card='true']",
10
+ composerHeroMark: "#root .xiaohei-brand-mark[data-brand-context='hero']",
11
+ composerHeroRow: "[class*='_headline']",
12
+ };
13
+ //# sourceMappingURL=host-contract.js.map
@@ -0,0 +1,11 @@
1
+ /** A listener that reconciles plugin-owned DOM after the DSH host tree changes. */
2
+ export type XiaoheiHostDomListener = () => void;
3
+ /**
4
+ * Share one batched body observer across all runtime theme behaviours.
5
+ *
6
+ * The Host owns the React tree and may replace slots at any time. Theme modules
7
+ * subscribe here instead of observing the full document independently. The
8
+ * first subscriber creates the observer and the last cleanup disconnects it.
9
+ */
10
+ export declare function subscribeXiaoheiHostDom(doc: Document, listener: XiaoheiHostDomListener): () => void;
11
+ //# sourceMappingURL=host-dom.d.ts.map
@@ -0,0 +1,60 @@
1
+ const hubs = new WeakMap();
2
+ /**
3
+ * Share one batched body observer across all runtime theme behaviours.
4
+ *
5
+ * The Host owns the React tree and may replace slots at any time. Theme modules
6
+ * subscribe here instead of observing the full document independently. The
7
+ * first subscriber creates the observer and the last cleanup disconnects it.
8
+ */
9
+ export function subscribeXiaoheiHostDom(doc, listener) {
10
+ const win = doc.defaultView;
11
+ if (doc.body === undefined || win === null || typeof win.MutationObserver !== 'function') {
12
+ return () => { };
13
+ }
14
+ let hub = hubs.get(doc);
15
+ if (hub === undefined) {
16
+ const listeners = new Set();
17
+ const nextHub = {
18
+ listeners,
19
+ queued: false,
20
+ };
21
+ const flush = () => {
22
+ nextHub.queued = false;
23
+ if (hubs.get(doc) !== nextHub)
24
+ return;
25
+ for (const subscriber of [...listeners]) {
26
+ try {
27
+ subscriber();
28
+ }
29
+ catch (error) {
30
+ win.setTimeout(() => { throw error; }, 0);
31
+ }
32
+ }
33
+ };
34
+ nextHub.observer = new win.MutationObserver(() => {
35
+ if (nextHub.queued)
36
+ return;
37
+ nextHub.queued = true;
38
+ queueMicrotask(flush);
39
+ });
40
+ nextHub.observer.observe(doc.body, { childList: true, subtree: true });
41
+ hubs.set(doc, nextHub);
42
+ hub = nextHub;
43
+ }
44
+ hub.listeners.add(listener);
45
+ let subscribed = true;
46
+ return () => {
47
+ if (!subscribed)
48
+ return;
49
+ subscribed = false;
50
+ const activeHub = hubs.get(doc);
51
+ if (activeHub === undefined)
52
+ return;
53
+ activeHub.listeners.delete(listener);
54
+ if (activeHub.listeners.size > 0)
55
+ return;
56
+ activeHub.observer?.disconnect();
57
+ hubs.delete(doc);
58
+ };
59
+ }
60
+ //# sourceMappingURL=host-dom.js.map
@@ -1,4 +1,5 @@
1
1
  import { XIAOHEI_LOADING_HEIXIU_BLINK, XIAOHEI_LOADING_HEIXIU_OPEN, } from './generated-loading-assets.js';
2
+ import { subscribeXiaoheiHostDom } from './host-dom.js';
2
3
  export const XIAOHEI_PLUGIN_LOADING_STYLE_ID = 'dsh-theme-xiaohei/plugin-loading-style';
3
4
  export const XIAOHEI_PLUGIN_LOADING_CLASS = 'xiaohei-plugin-loader__track';
4
5
  const LOADING_HINTS = new Set(['Loading plugins...', 'Loading plugins…']);
@@ -250,11 +251,10 @@ export function installXiaoheiPluginLoading(doc = typeof document === 'undefined
250
251
  });
251
252
  };
252
253
  sync();
253
- const observer = new win.MutationObserver(queueSync);
254
- observer.observe(doc.body, { childList: true, subtree: true });
254
+ const unsubscribeHostDom = subscribeXiaoheiHostDom(doc, queueSync);
255
255
  return () => {
256
256
  disposed = true;
257
- observer.disconnect();
257
+ unsubscribeHostDom();
258
258
  clearCard();
259
259
  style.remove();
260
260
  };
@@ -0,0 +1,10 @@
1
+ interface XiaoheiBrandMarkProps {
2
+ size: number;
3
+ className?: string | undefined;
4
+ }
5
+ /** Official sidebar brand occupant with a compact, lifecycle-safe metallic shader. */
6
+ export declare function XiaoheiMetallicBrandMark({ size, className }: XiaoheiBrandMarkProps): import("react/jsx-runtime").JSX.Element;
7
+ /** Official sidebar brand-name occupant paired with the Xiaohei mark. */
8
+ export declare function XiaoheiBrandName(): import("react/jsx-runtime").JSX.Element;
9
+ export {};
10
+ //# sourceMappingURL=metallic-brand-mark.d.ts.map
@@ -0,0 +1,323 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useRef, useState } from 'react';
3
+ import { XIAOHEI_BRAND_AVATAR } from './generated-identity.js';
4
+ // Native wide/rail switches remount this slot. A tiny navigation mark does not
5
+ // need a fresh GPU context and shader compilation on every toggle.
6
+ let sidebarMetallicSnapshot;
7
+ const VERTEX_SHADER = `#version 300 es
8
+ precision highp float;
9
+ in vec2 a_position;
10
+ out vec2 vP;
11
+ void main(){vP=a_position*.5+.5;gl_Position=vec4(a_position,0.,1.);}`;
12
+ /* Adapted from React Bits MetallicPaint. The source avatar is already a
13
+ * transparent tonal map, so the expensive browser-side depth solve is not
14
+ * needed for this compact brand mark. */
15
+ const FRAGMENT_SHADER = `#version 300 es
16
+ precision highp float;
17
+ in vec2 vP;
18
+ out vec4 oC;
19
+ uniform sampler2D u_tex;
20
+ uniform float u_time,u_ratio,u_imgRatio,u_seed,u_scale,u_refract,u_blur,u_liquid;
21
+ uniform float u_bright,u_contrast,u_angle,u_fresnel,u_sharp,u_wave,u_noise,u_chroma;
22
+ uniform float u_distort,u_contour;
23
+ uniform vec3 u_lightColor,u_darkColor,u_tint;
24
+
25
+ vec3 sC,sM;
26
+
27
+ vec3 pW(vec3 v){
28
+ vec3 i=floor(v),f=fract(v),s=sign(fract(v*.5)-.5),h=fract(sM*i+i.yzx),c=f*(f-1.);
29
+ return s*c*((h*16.-4.)*c-1.);
30
+ }
31
+
32
+ vec3 aF(vec3 b,vec3 c){return pW(b+c.zxy-pW(b.zxy+c.yzx)+pW(b.yzx+c.xyz));}
33
+ vec3 lM(vec3 s,vec3 p){return(p+aF(s,p))*.5;}
34
+
35
+ vec2 fA(){
36
+ vec2 c=vP-.5;
37
+ c.x*=u_ratio>u_imgRatio?u_ratio/u_imgRatio:1.;
38
+ c.y*=u_ratio>u_imgRatio?1.:u_imgRatio/u_ratio;
39
+ return vec2(c.x+.5,.5-c.y);
40
+ }
41
+
42
+ vec2 rot(vec2 p,float r){float c=cos(r),s=sin(r);return vec2(p.x*c+p.y*s,p.y*c-p.x*s);}
43
+
44
+ float bM(vec2 c,float t){
45
+ vec2 l=smoothstep(vec2(0.),vec2(t),c),u=smoothstep(vec2(0.),vec2(t),1.-c);
46
+ return l.x*l.y*u.x*u.y;
47
+ }
48
+
49
+ float mG(float hi,float lo,float t,float sh,float cv){
50
+ sh*=(2.-u_sharp);
51
+ float ci=smoothstep(.15,.85,cv),r=lo;
52
+ float e1=.08/u_scale;
53
+ r=mix(r,hi,smoothstep(0.,sh*1.5,t));
54
+ r=mix(r,lo,smoothstep(e1-sh,e1+sh,t));
55
+ float e2=e1+.05/u_scale*(1.-ci*.35);
56
+ r=mix(r,hi,smoothstep(e2-sh,e2+sh,t));
57
+ float e3=e2+.025/u_scale*(1.-ci*.45);
58
+ r=mix(r,lo,smoothstep(e3-sh,e3+sh,t));
59
+ float e4=e1+.1/u_scale;
60
+ r=mix(r,hi,smoothstep(e4-sh,e4+sh,t));
61
+ float rm=1.-e4,gT=clamp((t-e4)/rm,0.,1.);
62
+ r=mix(r,mix(hi,lo,smoothstep(0.,1.,gT)),smoothstep(e4-sh*.5,e4+sh*.5,t));
63
+ return r;
64
+ }
65
+
66
+ void main(){
67
+ sC=fract(vec3(.7548,.5698,.4154)*(u_seed+17.31))+.5;
68
+ sM=fract(sC.zxy-sC.yzx*1.618);
69
+ vec2 sc=vec2(vP.x*u_ratio,1.-vP.y);
70
+ float angleRad=u_angle*3.14159/180.;
71
+ sc=rot(sc-.5,angleRad)+.5;
72
+ sc=clamp(sc,0.,1.);
73
+ float sl=sc.x-sc.y,an=u_time*.001;
74
+ vec2 iC=fA();
75
+ vec4 texSample=texture(u_tex,iC);
76
+ float dp=texSample.r;
77
+ float shapeMask=texSample.a;
78
+ vec3 hi=u_lightColor*u_bright;
79
+ vec3 lo=u_darkColor*(2.-u_bright);
80
+ lo.b+=smoothstep(.6,1.4,sc.x+sc.y)*.08;
81
+ vec2 fC=sc-.5;
82
+ float rd=length(fC+vec2(0.,sl*.15));
83
+ vec2 ag=rot(fC,(.22-sl*.18)*3.14159);
84
+ float cv=1.-pow(rd*1.65,1.15);
85
+ cv*=pow(sc.y,.35);
86
+ float vs=shapeMask;
87
+ vs*=bM(iC,.01);
88
+ float fr=pow(1.-cv,u_fresnel)*.3;
89
+ vs=min(vs+fr*vs,1.);
90
+ float mT=an*.0625;
91
+ vec3 wO=vec3(-1.05,1.35,1.55);
92
+ vec3 wA=aF(vec3(31.,73.,56.),mT+wO)*.22*u_wave;
93
+ vec3 wB=aF(vec3(24.,64.,42.),mT-wO.yzx)*.22*u_wave;
94
+ vec2 nC=sc*45.*u_noise;
95
+ nC+=aF(sC.zxy,an*.17*sC.yzx-sc.yxy*.35).xy*18.*u_wave;
96
+ vec3 tC=vec3(.00041,.00053,.00076)*mT+wB*nC.x+wA*nC.y;
97
+ tC=lM(sC,tC);
98
+ tC=lM(sC+1.618,tC);
99
+ float tb=sin(tC.x*3.14159)*.5+.5;
100
+ tb=tb*2.-1.;
101
+ float noiseVal=pW(vec3(sc*8.+an,an*.5)).x;
102
+ float edgeFactor=smoothstep(0.,.5,dp)*smoothstep(1.,.5,dp);
103
+ float lD=dp+(1.-dp)*u_liquid*tb;
104
+ lD+=noiseVal*u_distort*.15*edgeFactor;
105
+ float rB=clamp(1.-cv,0.,1.);
106
+ float fl=ag.x+sl;
107
+ fl+=noiseVal*sl*u_distort*edgeFactor;
108
+ fl*=mix(1.,1.-dp*.5,u_contour);
109
+ fl-=dp*u_contour*.8;
110
+ float eI=smoothstep(0.,1.,lD)*smoothstep(1.,0.,lD);
111
+ fl-=tb*sl*1.8*eI;
112
+ float cA=cv*clamp(pow(sc.y,.12),.25,1.);
113
+ fl*=.12+(1.05-lD)*cA;
114
+ fl*=smoothstep(1.,.65,lD);
115
+ float vA1=smoothstep(.08,.18,sc.y)*smoothstep(.38,.18,sc.y);
116
+ float vA2=smoothstep(.08,.18,1.-sc.y)*smoothstep(.38,.18,1.-sc.y);
117
+ fl+=vA1*.16+vA2*.025;
118
+ fl*=.45+pow(sc.y,2.)*.55;
119
+ fl*=u_scale;
120
+ fl-=an;
121
+ float rO=rB+cv*tb*.025;
122
+ float vM1=smoothstep(-.12,.18,sc.y)*smoothstep(.48,.08,sc.y);
123
+ float cM1=smoothstep(.35,.55,cv)*smoothstep(.95,.35,cv);
124
+ rO+=vM1*cM1*4.5;
125
+ rO-=sl;
126
+ float bO=rB*1.25;
127
+ float vM2=smoothstep(-.02,.35,sc.y)*smoothstep(.75,.08,sc.y);
128
+ float cM2=smoothstep(.35,.55,cv)*smoothstep(.75,.35,cv);
129
+ bO+=vM2*cM2*.9;
130
+ bO-=lD*.18;
131
+ rO*=u_refract*u_chroma;
132
+ bO*=u_refract*u_chroma;
133
+ float sf=u_blur;
134
+ float rP=fract(fl+rO);
135
+ float rC=mG(hi.r,lo.r,rP,sf+.018+u_refract*cv*.025,cv);
136
+ float gP=fract(fl);
137
+ float gC=mG(hi.g,lo.g,gP,sf+.008/max(.01,1.-sl),cv);
138
+ float bP=fract(fl-bO);
139
+ float bC=mG(hi.b,lo.b,bP,sf+.008,cv);
140
+ vec3 col=vec3(rC,gC,bC);
141
+ col=(col-.5)*u_contrast+.5;
142
+ col=clamp(col,0.,1.);
143
+ col=mix(col,1.-min(vec3(1.),(1.-col)/max(u_tint,vec3(.001))),length(u_tint-1.)*.5);
144
+ col=clamp(col,0.,1.);
145
+ oC=vec4(col*vs,vs);
146
+ }`;
147
+ const UNIFORM_NAMES = [
148
+ 'u_tex', 'u_time', 'u_ratio', 'u_imgRatio', 'u_seed', 'u_scale', 'u_refract',
149
+ 'u_blur', 'u_liquid', 'u_bright', 'u_contrast', 'u_angle', 'u_fresnel',
150
+ 'u_sharp', 'u_wave', 'u_noise', 'u_chroma', 'u_distort', 'u_contour',
151
+ 'u_lightColor', 'u_darkColor', 'u_tint',
152
+ ];
153
+ function compileShader(gl, type, source) {
154
+ const shader = gl.createShader(type);
155
+ if (shader === null)
156
+ return undefined;
157
+ gl.shaderSource(shader, source);
158
+ gl.compileShader(shader);
159
+ if (gl.getShaderParameter(shader, gl.COMPILE_STATUS) === true)
160
+ return shader;
161
+ gl.deleteShader(shader);
162
+ return undefined;
163
+ }
164
+ function setRgb(gl, location, color) {
165
+ gl.uniform3f(location, color[0], color[1], color[2]);
166
+ }
167
+ /** Official sidebar brand occupant with a compact, lifecycle-safe metallic shader. */
168
+ export function XiaoheiMetallicBrandMark({ size, className }) {
169
+ const canvasRef = useRef(null);
170
+ const [ready, setReady] = useState(false);
171
+ const visualSize = Math.max(24, size + 4);
172
+ const context = size >= 32 ? 'hero' : 'sidebar';
173
+ const [snapshot, setSnapshot] = useState(context === 'sidebar' ? sidebarMetallicSnapshot : undefined);
174
+ useEffect(() => {
175
+ if (snapshot !== undefined)
176
+ return;
177
+ const canvas = canvasRef.current;
178
+ if (canvas === null)
179
+ return;
180
+ const gl = canvas.getContext('webgl2', {
181
+ alpha: true,
182
+ antialias: true,
183
+ powerPreference: 'low-power',
184
+ premultipliedAlpha: true,
185
+ });
186
+ if (gl === null)
187
+ return;
188
+ const vertex = compileShader(gl, gl.VERTEX_SHADER, VERTEX_SHADER);
189
+ const fragment = compileShader(gl, gl.FRAGMENT_SHADER, FRAGMENT_SHADER);
190
+ if (vertex === undefined || fragment === undefined) {
191
+ if (vertex !== undefined)
192
+ gl.deleteShader(vertex);
193
+ if (fragment !== undefined)
194
+ gl.deleteShader(fragment);
195
+ return;
196
+ }
197
+ const program = gl.createProgram();
198
+ const buffer = gl.createBuffer();
199
+ if (program === null || buffer === null) {
200
+ gl.deleteShader(vertex);
201
+ gl.deleteShader(fragment);
202
+ return;
203
+ }
204
+ gl.attachShader(program, vertex);
205
+ gl.attachShader(program, fragment);
206
+ gl.linkProgram(program);
207
+ gl.deleteShader(vertex);
208
+ gl.deleteShader(fragment);
209
+ if (gl.getProgramParameter(program, gl.LINK_STATUS) !== true) {
210
+ gl.deleteBuffer(buffer);
211
+ gl.deleteProgram(program);
212
+ return;
213
+ }
214
+ const uniforms = Object.fromEntries(UNIFORM_NAMES.map(name => [name, gl.getUniformLocation(program, name)]));
215
+ const pixelRatio = Math.min(window.devicePixelRatio || 1, 2);
216
+ const renderSize = Math.max(96, Math.ceil(visualSize * pixelRatio * 2));
217
+ canvas.width = renderSize;
218
+ canvas.height = renderSize;
219
+ gl.viewport(0, 0, renderSize, renderSize);
220
+ gl.useProgram(program);
221
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
222
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]), gl.STATIC_DRAW);
223
+ const position = gl.getAttribLocation(program, 'a_position');
224
+ gl.enableVertexAttribArray(position);
225
+ gl.vertexAttribPointer(position, 2, gl.FLOAT, false, 0, 0);
226
+ gl.uniform1f(uniforms.u_ratio, 1);
227
+ gl.uniform1f(uniforms.u_imgRatio, 1);
228
+ gl.uniform1f(uniforms.u_seed, 42);
229
+ gl.uniform1f(uniforms.u_scale, 3.2);
230
+ gl.uniform1f(uniforms.u_refract, 0.012);
231
+ gl.uniform1f(uniforms.u_blur, 0.018);
232
+ gl.uniform1f(uniforms.u_liquid, 0.58);
233
+ gl.uniform1f(uniforms.u_bright, 1.35);
234
+ gl.uniform1f(uniforms.u_contrast, 1.08);
235
+ gl.uniform1f(uniforms.u_angle, -12);
236
+ gl.uniform1f(uniforms.u_fresnel, 0.8);
237
+ gl.uniform1f(uniforms.u_sharp, 1.15);
238
+ gl.uniform1f(uniforms.u_wave, 0.65);
239
+ gl.uniform1f(uniforms.u_noise, 0.45);
240
+ gl.uniform1f(uniforms.u_chroma, 0.7);
241
+ gl.uniform1f(uniforms.u_distort, 0.35);
242
+ gl.uniform1f(uniforms.u_contour, 0.38);
243
+ setRgb(gl, uniforms.u_lightColor, [0.96, 0.97, 0.95]);
244
+ setRgb(gl, uniforms.u_darkColor, [0.025, 0.04, 0.045]);
245
+ setRgb(gl, uniforms.u_tint, [0.84, 0.92, 0.89]);
246
+ let disposed = false;
247
+ let visible = true;
248
+ let animationFrame;
249
+ let lastFrame = 0;
250
+ let metallicTime = 1450;
251
+ const reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)');
252
+ const texture = gl.createTexture();
253
+ const image = new Image();
254
+ const draw = () => {
255
+ gl.uniform1f(uniforms.u_time, metallicTime);
256
+ gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
257
+ };
258
+ const render = (now) => {
259
+ if (disposed)
260
+ return;
261
+ if (visible && document.visibilityState !== 'hidden' && now - lastFrame >= 40) {
262
+ const delta = lastFrame === 0 ? 0 : Math.min(80, now - lastFrame);
263
+ lastFrame = now;
264
+ metallicTime += delta * 0.11;
265
+ draw();
266
+ }
267
+ animationFrame = window.requestAnimationFrame(render);
268
+ };
269
+ image.onload = () => {
270
+ if (disposed || texture === null)
271
+ return;
272
+ gl.activeTexture(gl.TEXTURE0);
273
+ gl.bindTexture(gl.TEXTURE_2D, texture);
274
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
275
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
276
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
277
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
278
+ gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
279
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
280
+ gl.uniform1i(uniforms.u_tex, 0);
281
+ draw();
282
+ if (context === 'sidebar') {
283
+ sidebarMetallicSnapshot = canvas.toDataURL();
284
+ setSnapshot(sidebarMetallicSnapshot);
285
+ return;
286
+ }
287
+ setReady(true);
288
+ if (!reduceMotion.matches)
289
+ animationFrame = window.requestAnimationFrame(render);
290
+ };
291
+ image.src = XIAOHEI_BRAND_AVATAR;
292
+ const visibilityObserver = typeof IntersectionObserver === 'function'
293
+ ? new IntersectionObserver(entries => {
294
+ visible = entries.some(entry => entry.isIntersecting);
295
+ if (visible)
296
+ lastFrame = 0;
297
+ })
298
+ : undefined;
299
+ visibilityObserver?.observe(canvas);
300
+ return () => {
301
+ disposed = true;
302
+ if (animationFrame !== undefined)
303
+ window.cancelAnimationFrame(animationFrame);
304
+ visibilityObserver?.disconnect();
305
+ if (texture !== null)
306
+ gl.deleteTexture(texture);
307
+ gl.deleteBuffer(buffer);
308
+ gl.deleteProgram(program);
309
+ gl.getExtension('WEBGL_lose_context')?.loseContext();
310
+ };
311
+ }, [visualSize, context, snapshot]);
312
+ const geometry = {
313
+ '--xiaohei-brand-mark-size': `${visualSize}px`,
314
+ };
315
+ return (_jsxs("span", { className: className === undefined ? 'xiaohei-brand-mark' : `${className} xiaohei-brand-mark`, "data-brand-context": context, "data-metallic-ready": ready || snapshot !== undefined ? 'true' : 'false', style: geometry, "aria-hidden": "true", children: [_jsx("img", { className: "xiaohei-brand-mark__fallback", src: XIAOHEI_BRAND_AVATAR, alt: "" }), snapshot !== undefined
316
+ ? _jsx("img", { className: "xiaohei-brand-mark__metal", src: snapshot, alt: "" })
317
+ : _jsx("canvas", { className: "xiaohei-brand-mark__metal", ref: canvasRef })] }));
318
+ }
319
+ /** Official sidebar brand-name occupant paired with the Xiaohei mark. */
320
+ export function XiaoheiBrandName() {
321
+ return _jsx("span", { className: "xiaohei-brand-name", children: "\u7F57\u5C0F\u9ED1 \u00B7 \u5996\u7075\u4F1A\u9986" });
322
+ }
323
+ //# sourceMappingURL=metallic-brand-mark.js.map
package/lib/plugin.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';
1
+ import type { Context as ClientContext } from '@deepseek-ai/cordis';
2
2
  /** Boot decoration has no service dependency; the full theme waits below. */
3
3
  export declare const inject: string[];
4
4
  /** Shade DSH's native appearance modes without replacing its preference UI. */
package/lib/plugin.js CHANGED
@@ -1,22 +1,39 @@
1
1
  import { bindXiaoheiAppearance } from './appearance.js';
2
- import { installXiaoheiBlink } from './blink.js';
3
2
  import { installXiaoheiChrome } from './chrome.js';
4
- import { installXiaoheiGaze } from './gaze.js';
5
- import { installXiaoheiHeixiuInteractions } from './heixiu-interactions.js';
3
+ import { installXiaoheiComposerSendHeixiu } from './composer-send-heixiu.js';
6
4
  import { installXiaoheiPluginLoading } from './loading-heixiu.js';
7
- import { installXiaoheiPortalTransit } from './portal.js';
8
- import { installXiaoheiIdleReactions } from './reactions.js';
9
5
  import { installXiaoheiScene } from './scene.js';
10
6
  import { installXiaoheiSidebarGlass } from './sidebar-glass.js';
11
- import { installXiaoheiSidebarHeixiuRoaming } from './sidebar-heixiu-roaming.js';
12
- import { bindXiaoheiSessionState } from './state.js';
7
+ import { installXiaoheiWallpaperCharacter } from './scene/wallpaper-character.js';
8
+ import { installComposerBloub } from './bloub-heixiu/runtime.js';
9
+ import { bindHeixiuSessions, createHeixiuSignals } from './bloub-heixiu/signals.js';
13
10
  import { XIAOHEI_THEME_TOKEN_OVERRIDES } from './theme.js';
11
+ import { XiaoheiBrandName, XiaoheiMetallicBrandMark } from './metallic-brand-mark.js';
14
12
  /** Boot decoration has no service dependency; the full theme waits below. */
15
13
  export const inject = [];
16
14
  /** Shade DSH's native appearance modes without replacing its preference UI. */
17
15
  export function apply(ctx) {
18
16
  ctx.effect(installXiaoheiPluginLoading, 'xiaohei-theme: replace plugin spinner with hopping Heixiu');
19
- ctx.inject(['theme', 'sessions'], (readyCtx) => installXiaoheiTheme(readyCtx));
17
+ ctx.inject(['slots'], readyCtx => {
18
+ const disposeSidebarMark = readyCtx.slots.inject('sidebar.brand.mark', () => readyCtx.slots.register({
19
+ name: 'sidebar.brand.mark',
20
+ priority: -20,
21
+ }, XiaoheiMetallicBrandMark));
22
+ const disposeSidebarName = readyCtx.slots.inject('sidebar.brand.name', () => readyCtx.slots.register({
23
+ name: 'sidebar.brand.name',
24
+ priority: -20,
25
+ }, XiaoheiBrandName));
26
+ const disposeHeroMark = readyCtx.slots.inject('conversation.hero.brand.mark', () => readyCtx.slots.register({
27
+ name: 'conversation.hero.brand.mark',
28
+ priority: -20,
29
+ }, XiaoheiMetallicBrandMark));
30
+ return () => {
31
+ disposeHeroMark();
32
+ disposeSidebarName();
33
+ disposeSidebarMark();
34
+ };
35
+ });
36
+ ctx.inject(['theme'], (readyCtx) => installXiaoheiTheme(readyCtx));
20
37
  }
21
38
  /** Mount the complete theme only after its runtime services become available. */
22
39
  function installXiaoheiTheme(ctx) {
@@ -25,14 +42,12 @@ function installXiaoheiTheme(ctx) {
25
42
  }, 'xiaohei-theme: shade native Light / Dark / System palettes');
26
43
  ctx.effect(() => bindXiaoheiAppearance(ctx), 'xiaohei-theme: follow resolved appearance');
27
44
  ctx.effect(installXiaoheiChrome, 'xiaohei-theme: install spirit control skin');
28
- ctx.effect(installXiaoheiScene, 'xiaohei-theme: install moonlit forest scene');
45
+ ctx.effect(installXiaoheiComposerSendHeixiu, 'xiaohei-theme: turn the native send action into blinking Heixiu');
46
+ ctx.effect(installXiaoheiScene, 'xiaohei-theme: install paired atmosphere');
29
47
  ctx.effect(installXiaoheiSidebarGlass, 'xiaohei-theme: install isolated sidebar glass');
30
- ctx.effect(installXiaoheiSidebarHeixiuRoaming, 'xiaohei-theme: let sidebar Heixiu roam safely');
31
- ctx.effect(installXiaoheiHeixiuInteractions, 'xiaohei-theme: bind Heixiu companion interactions');
32
- ctx.effect(installXiaoheiPortalTransit, 'xiaohei-theme: install random Heixiu portal visits');
33
- ctx.effect(installXiaoheiGaze, 'xiaohei-theme: install proximity gaze');
34
- ctx.effect(installXiaoheiBlink, 'xiaohei-theme: synchronize complete-frame blinking');
35
- ctx.effect(installXiaoheiIdleReactions, 'xiaohei-theme: install sparse idle reactions');
36
- ctx.effect(() => bindXiaoheiSessionState(ctx.sessions), 'xiaohei-theme: follow current session agent state');
48
+ ctx.effect(installXiaoheiWallpaperCharacter, 'xiaohei-theme: place responsive character poses');
49
+ const heixiuSignals = createHeixiuSignals();
50
+ ctx.effect(() => installComposerBloub(undefined, heixiuSignals), 'xiaohei-theme: mount bloub Heixiu beside composer');
51
+ ctx.inject(['sessions'], ready => bindHeixiuSessions(ready.sessions, heixiuSignals));
37
52
  }
38
53
  //# sourceMappingURL=plugin.js.map
package/lib/portal.js CHANGED
@@ -1,6 +1,8 @@
1
1
  import { XIAOHEI_HEIXIU_BLINK, XIAOHEI_HEIXIU_OPEN } from './generated-keyart.js';
2
2
  import { XIAOHEI_PORTAL_CSS } from './chrome/portal.js';
3
- import { XIAOHEI_SCENE_LAYER_ID } from './scene.js';
3
+ import { subscribeXiaoheiHostDom } from './host-dom.js';
4
+ import { XIAOHEI_HOST_SELECTORS } from './host-contract.js';
5
+ import { XIAOHEI_SCENE_LAYER_ID, XIAOHEI_SCENE_WORLD_CLASS } from './scene.js';
4
6
  export const XIAOHEI_PORTAL_STYLE_ID = 'dsh-theme-xiaohei/portal-style';
5
7
  export const XIAOHEI_PORTAL_LAYER_ID = 'dsh-theme-xiaohei/portal-layer';
6
8
  export const XIAOHEI_PORTAL_DURATION_MS = 2600;
@@ -63,9 +65,9 @@ export function installXiaoheiPortalTransit(doc = typeof document === 'undefined
63
65
  const scene = doc.getElementById(XIAOHEI_SCENE_LAYER_ID);
64
66
  if (scene === null)
65
67
  return false;
66
- const veil = scene.querySelector('.xiaohei-scene__veil');
67
68
  if (layer.parentElement !== scene) {
68
- scene.insertBefore(layer, veil?.nextSibling ?? null);
69
+ const world = scene.querySelector(`.${XIAOHEI_SCENE_WORLD_CLASS}`);
70
+ scene.insertBefore(layer, world?.nextSibling ?? scene.firstChild);
69
71
  }
70
72
  return true;
71
73
  };
@@ -146,25 +148,24 @@ export function installXiaoheiPortalTransit(doc = typeof document === 'undefined
146
148
  visitsStarted = true;
147
149
  scheduleVisit(true);
148
150
  };
149
- let mountObserver;
151
+ let unsubscribeHostDom = () => { };
150
152
  if (mount()) {
151
153
  startVisits();
152
154
  }
153
155
  else {
154
- mountObserver = new MutationObserver(() => {
156
+ unsubscribeHostDom = subscribeXiaoheiHostDom(doc, () => {
155
157
  if (!mount())
156
158
  return;
157
- mountObserver?.disconnect();
159
+ unsubscribeHostDom();
158
160
  startVisits();
159
161
  });
160
- mountObserver.observe(doc.body, { childList: true });
161
162
  }
162
163
  return () => {
163
164
  disposed = true;
164
165
  clearTimer(animationTimer);
165
166
  clearTimer(visitTimer);
166
167
  endInteraction();
167
- mountObserver?.disconnect();
168
+ unsubscribeHostDom();
168
169
  if (layer.dataset.running === 'true')
169
170
  dispatchPortalActivity(doc, false);
170
171
  layer.remove();
@@ -201,8 +202,8 @@ function choosePortalPoints(doc) {
201
202
  const win = doc.defaultView;
202
203
  const width = Math.max(640, win?.innerWidth ?? 1280);
203
204
  const height = Math.max(480, win?.innerHeight ?? 720);
204
- const sidebarRight = doc.querySelector("#root [data-slot='sidebar']")?.getBoundingClientRect().right ?? 0;
205
- const composerRect = doc.querySelector("#root [data-composer-card='true']")?.getBoundingClientRect();
205
+ const sidebarRight = doc.querySelector(XIAOHEI_HOST_SELECTORS.sidebar)?.getBoundingClientRect().right ?? 0;
206
+ const composerRect = doc.querySelector(XIAOHEI_HOST_SELECTORS.composerCard)?.getBoundingClientRect();
206
207
  const contentLeft = composerRect?.left ?? width * 0.37;
207
208
  const contentRight = composerRect?.right ?? width * 0.77;
208
209
  const leftMin = Math.max(sidebarRight + 80, 90);
package/lib/reactions.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { XIAOHEI_IDLE_EAR_LEFT, XIAOHEI_IDLE_EAR_RIGHT, XIAOHEI_IDLE_TAIL, } from './generated-keyart.js';
2
2
  import { XIAOHEI_REACTION_CSS } from './chrome/reactions.js';
3
+ import { subscribeXiaoheiHostDom } from './host-dom.js';
3
4
  import { XIAOHEI_HEIXIU_GREETING_EVENT, } from './heixiu-interactions.js';
4
5
  import { XIAOHEI_PORTAL_PROXIMITY_EVENT, } from './portal.js';
5
6
  export const XIAOHEI_REACTION_STYLE_ID = 'dsh-theme-xiaohei/reaction-style';
@@ -332,8 +333,7 @@ export function installXiaoheiIdleReactions(doc = typeof document === 'undefined
332
333
  scheduleIdleTail();
333
334
  syncPointerEarLoop();
334
335
  };
335
- const mountObserver = new win.MutationObserver(attach);
336
- mountObserver.observe(doc.body, { childList: true, subtree: true });
336
+ const unsubscribeHostDom = subscribeXiaoheiHostDom(doc, attach);
337
337
  const stateObserver = new win.MutationObserver(onStateChange);
338
338
  stateObserver.observe(doc.documentElement, {
339
339
  attributes: true,
@@ -356,7 +356,7 @@ export function installXiaoheiIdleReactions(doc = typeof document === 'undefined
356
356
  clearHeixiuInteraction();
357
357
  clearTimer(idleTailTimer);
358
358
  clearReaction();
359
- mountObserver.disconnect();
359
+ unsubscribeHostDom();
360
360
  stateObserver.disconnect();
361
361
  doc.removeEventListener('pointermove', onPointerMove);
362
362
  doc.removeEventListener('pointerleave', clearPointer);
@@ -0,0 +1,6 @@
1
+ export declare const XIAOHEI_SYLVA_AVATAR_MARKER = "data-xiaohei-avatar-model";
2
+ /** Inject the renderer-sharing 2.5D avatar without editing registered ThreeUI files. */
3
+ export declare function injectXiaoheiSylvaAvatarModel(source: string): string;
4
+ /** Prepare the detached iframe so the avatar exists on its first WebGL boot. */
5
+ export declare function prepareXiaoheiSylvaAvatarFrame(frame: HTMLIFrameElement): boolean;
6
+ //# sourceMappingURL=avatar-model.d.ts.map