@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.
- package/README.md +39 -17
- package/THIRD_PARTY_NOTICES.md +41 -0
- package/lib/appearance.js +26 -10
- package/lib/blink.js +3 -3
- package/lib/bloub-heixiu/ambient.d.ts +3 -0
- package/lib/bloub-heixiu/ambient.js +12 -0
- package/lib/bloub-heixiu/character.d.ts +33 -0
- package/lib/bloub-heixiu/character.js +124 -0
- package/lib/bloub-heixiu/effects.d.ts +4 -0
- package/lib/bloub-heixiu/effects.js +91 -0
- package/lib/bloub-heixiu/flight.d.ts +15 -0
- package/lib/bloub-heixiu/flight.js +66 -0
- package/lib/bloub-heixiu/follow.d.ts +13 -0
- package/lib/bloub-heixiu/follow.js +23 -0
- package/lib/bloub-heixiu/layout.d.ts +18 -0
- package/lib/bloub-heixiu/layout.js +12 -0
- package/lib/bloub-heixiu/renderer.d.ts +16 -0
- package/lib/bloub-heixiu/renderer.js +94 -0
- package/lib/bloub-heixiu/runtime.d.ts +6 -0
- package/lib/bloub-heixiu/runtime.js +395 -0
- package/lib/bloub-heixiu/signals.d.ts +17 -0
- package/lib/bloub-heixiu/signals.js +53 -0
- package/lib/bloub-heixiu/styles.d.ts +2 -0
- package/lib/bloub-heixiu/styles.js +98 -0
- package/lib/chrome/accessibility.d.ts +1 -1
- package/lib/chrome/accessibility.js +5 -13
- package/lib/chrome/composer-avatar.d.ts +10 -0
- package/lib/chrome/composer-avatar.js +599 -0
- package/lib/chrome/composer-send-heixiu.d.ts +3 -0
- package/lib/chrome/composer-send-heixiu.js +143 -0
- package/lib/chrome/composer.d.ts +2 -2
- package/lib/chrome/composer.js +84 -95
- package/lib/chrome/controls.d.ts +8 -0
- package/lib/chrome/controls.js +348 -0
- package/lib/chrome/conversation-messages.d.ts +1 -1
- package/lib/chrome/conversation-messages.js +207 -9
- package/lib/chrome/conversation.d.ts +1 -1
- package/lib/chrome/conversation.js +6 -0
- package/lib/chrome/identity.js +4 -18
- package/lib/chrome/portal.d.ts +1 -1
- package/lib/chrome/portal.js +1 -1
- package/lib/chrome/sidebar.d.ts +1 -1
- package/lib/chrome/sidebar.js +134 -153
- package/lib/chrome/tokens.d.ts +1 -1
- package/lib/chrome/tokens.js +121 -68
- package/lib/chrome/workspace.d.ts +2 -2
- package/lib/chrome/workspace.js +35 -254
- package/lib/chrome.js +4 -0
- package/lib/client.d.ts +5 -12
- package/lib/client.js +6262 -4455
- package/lib/composer-avatar.d.ts +18 -0
- package/lib/composer-avatar.js +441 -0
- package/lib/composer-send-heixiu.d.ts +8 -0
- package/lib/composer-send-heixiu.js +133 -0
- package/lib/gaze.js +3 -3
- package/lib/generated-backgrounds.d.ts +14 -0
- package/lib/generated-backgrounds.js +14 -0
- package/lib/generated-character-motion.d.ts +4 -0
- package/lib/generated-character-motion.js +2 -0
- package/lib/generated-identity.d.ts +1 -0
- package/lib/generated-identity.js +1 -0
- package/lib/generated-keyart.d.ts +18 -3
- package/lib/generated-keyart.js +18 -3
- package/lib/host-contract.d.ts +9 -0
- package/lib/host-contract.js +13 -0
- package/lib/host-dom.d.ts +11 -0
- package/lib/host-dom.js +60 -0
- package/lib/loading-heixiu.js +3 -3
- package/lib/metallic-brand-mark.d.ts +10 -0
- package/lib/metallic-brand-mark.js +323 -0
- package/lib/plugin.d.ts +1 -1
- package/lib/plugin.js +31 -16
- package/lib/portal.js +11 -10
- package/lib/reactions.js +3 -3
- package/lib/scene/avatar-model.d.ts +6 -0
- package/lib/scene/avatar-model.js +646 -0
- package/lib/scene/avatar-motion.d.ts +3 -0
- package/lib/scene/avatar-motion.js +799 -0
- package/lib/scene/character-idle.d.ts +17 -0
- package/lib/scene/character-idle.js +65 -0
- package/lib/scene/character-layout.d.ts +24 -0
- package/lib/scene/character-layout.js +51 -0
- package/lib/scene/character-motion-clock.d.ts +18 -0
- package/lib/scene/character-motion-clock.js +57 -0
- package/lib/scene/character-motion-types.d.ts +12 -0
- package/lib/scene/character-motion-types.js +2 -0
- package/lib/scene/character-motion.d.ts +6 -0
- package/lib/scene/character-motion.js +126 -0
- package/lib/scene/character-poses.d.ts +26 -0
- package/lib/scene/character-poses.js +11 -0
- package/lib/scene/character-rig-renderer.d.ts +4 -0
- package/lib/scene/character-rig-renderer.js +85 -0
- package/lib/scene/character-rig.d.ts +20 -0
- package/lib/scene/character-rig.js +53 -0
- package/lib/scene/heixiu-feedback.d.ts +1 -1
- package/lib/scene/heixiu-feedback.js +0 -17
- package/lib/scene/pointer-bridge.d.ts +21 -0
- package/lib/scene/pointer-bridge.js +155 -0
- package/lib/scene/runtime.d.ts +12 -0
- package/lib/scene/runtime.js +87 -0
- package/lib/scene/styles.d.ts +7 -0
- package/lib/scene/styles.js +75 -0
- package/lib/scene/sylva-performance.d.ts +11 -0
- package/lib/scene/sylva-performance.js +58 -0
- package/lib/scene/wallpaper-character-styles.d.ts +3 -0
- package/lib/scene/wallpaper-character-styles.js +53 -0
- package/lib/scene/wallpaper-character.d.ts +4 -0
- package/lib/scene/wallpaper-character.js +213 -0
- package/lib/scene.d.ts +7 -13
- package/lib/scene.js +7 -1023
- package/lib/sidebar-glass.js +99 -36
- package/lib/sidebar-heixiu-roaming.js +5 -5
- package/lib/sidebar-reveal.d.ts +8 -0
- package/lib/sidebar-reveal.js +51 -0
- package/lib/state.d.ts +14 -2
- package/lib/state.js +12 -4
- package/lib/theme.js +2 -2
- package/lib/vendor/bloub/decor.d.ts +114 -0
- package/lib/vendor/bloub/decor.js +198 -0
- package/lib/vendor/bloub/engine.d.ts +213 -0
- package/lib/vendor/bloub/engine.js +452 -0
- package/lib/vendor/bloub/expressions.d.ts +35 -0
- package/lib/vendor/bloub/expressions.js +143 -0
- package/lib/vendor/bloub/eyefit.d.ts +75 -0
- package/lib/vendor/bloub/eyefit.js +393 -0
- package/lib/vendor/bloub/face.d.ts +63 -0
- package/lib/vendor/bloub/face.js +106 -0
- package/lib/vendor/bloub/math.d.ts +22 -0
- package/lib/vendor/bloub/math.js +36 -0
- package/lib/vendor/bloub/profiles.d.ts +8 -0
- package/lib/vendor/bloub/profiles.js +20 -0
- package/lib/vendor/bloub/repere.d.ts +30 -0
- package/lib/vendor/bloub/repere.js +32 -0
- package/lib/vendor/bloub/shape.d.ts +80 -0
- package/lib/vendor/bloub/shape.js +268 -0
- package/lib/vendor/bloub/skins.d.ts +36 -0
- package/lib/vendor/bloub/skins.js +74 -0
- package/lib/vendor/bloub/states.d.ts +87 -0
- package/lib/vendor/bloub/states.js +468 -0
- package/package.json +23 -6
- package/lib/appearance.d.ts.map +0 -1
- package/lib/appearance.js.map +0 -1
- package/lib/blink.d.ts.map +0 -1
- package/lib/blink.js.map +0 -1
- package/lib/boot-appearance.d.ts.map +0 -1
- package/lib/boot-appearance.js.map +0 -1
- package/lib/boot-loader.d.ts.map +0 -1
- package/lib/boot-loader.js.map +0 -1
- package/lib/chrome/accessibility.d.ts.map +0 -1
- package/lib/chrome/accessibility.js.map +0 -1
- package/lib/chrome/blink.d.ts.map +0 -1
- package/lib/chrome/blink.js.map +0 -1
- package/lib/chrome/composer.d.ts.map +0 -1
- package/lib/chrome/composer.js.map +0 -1
- package/lib/chrome/conversation-messages.d.ts.map +0 -1
- package/lib/chrome/conversation-messages.js.map +0 -1
- package/lib/chrome/conversation.d.ts.map +0 -1
- package/lib/chrome/conversation.js.map +0 -1
- package/lib/chrome/frames.d.ts.map +0 -1
- package/lib/chrome/frames.js.map +0 -1
- package/lib/chrome/gaze.d.ts.map +0 -1
- package/lib/chrome/gaze.js.map +0 -1
- package/lib/chrome/identity.d.ts.map +0 -1
- package/lib/chrome/identity.js.map +0 -1
- package/lib/chrome/overlays.d.ts.map +0 -1
- package/lib/chrome/overlays.js.map +0 -1
- package/lib/chrome/portal.d.ts.map +0 -1
- package/lib/chrome/portal.js.map +0 -1
- package/lib/chrome/reactions.d.ts.map +0 -1
- package/lib/chrome/reactions.js.map +0 -1
- package/lib/chrome/sidebar.d.ts.map +0 -1
- package/lib/chrome/sidebar.js.map +0 -1
- package/lib/chrome/tokens.d.ts.map +0 -1
- package/lib/chrome/tokens.js.map +0 -1
- package/lib/chrome/workspace.d.ts.map +0 -1
- package/lib/chrome/workspace.js.map +0 -1
- package/lib/chrome.d.ts.map +0 -1
- package/lib/chrome.js.map +0 -1
- package/lib/client.d.ts.map +0 -1
- package/lib/client.js.map +0 -7
- package/lib/gaze.d.ts.map +0 -1
- package/lib/gaze.js.map +0 -1
- package/lib/generated-identity.d.ts.map +0 -1
- package/lib/generated-identity.js.map +0 -1
- package/lib/generated-keyart.d.ts.map +0 -1
- package/lib/generated-keyart.js.map +0 -1
- package/lib/generated-loading-assets.d.ts.map +0 -1
- package/lib/generated-loading-assets.js.map +0 -1
- package/lib/generated-sidebar-assets.d.ts +0 -4
- package/lib/generated-sidebar-assets.d.ts.map +0 -1
- package/lib/generated-sidebar-assets.js +0 -4
- package/lib/generated-sidebar-assets.js.map +0 -1
- package/lib/heixiu-interactions.d.ts.map +0 -1
- package/lib/heixiu-interactions.js.map +0 -1
- package/lib/index.d.ts.map +0 -1
- package/lib/index.js.map +0 -1
- package/lib/loading-heixiu.d.ts.map +0 -1
- package/lib/loading-heixiu.js.map +0 -1
- package/lib/plugin.d.ts.map +0 -1
- package/lib/plugin.js.map +0 -1
- package/lib/portal.d.ts.map +0 -1
- package/lib/portal.js.map +0 -1
- package/lib/reactions.d.ts.map +0 -1
- package/lib/reactions.js.map +0 -1
- package/lib/scene/heixiu-feedback.d.ts.map +0 -1
- package/lib/scene/heixiu-feedback.js.map +0 -1
- package/lib/scene/heixiu-interactions.d.ts.map +0 -1
- package/lib/scene/heixiu-interactions.js.map +0 -1
- package/lib/scene/state-transitions.d.ts.map +0 -1
- package/lib/scene/state-transitions.js.map +0 -1
- package/lib/scene.d.ts.map +0 -1
- package/lib/scene.js.map +0 -1
- package/lib/sidebar-glass.d.ts.map +0 -1
- package/lib/sidebar-glass.js.map +0 -1
- package/lib/sidebar-heixiu-escape.d.ts.map +0 -1
- package/lib/sidebar-heixiu-escape.js.map +0 -1
- package/lib/sidebar-heixiu-roaming.d.ts.map +0 -1
- package/lib/sidebar-heixiu-roaming.js.map +0 -1
- package/lib/state.d.ts.map +0 -1
- package/lib/state.js.map +0 -1
- package/lib/theme.d.ts.map +0 -1
- package/lib/theme.js.map +0 -1
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export declare const XIAOHEI_SYLVA_POINTER_CHANNEL = "dsh-theme-xiaohei/sylva-pointer-v1";
|
|
2
|
+
export declare const XIAOHEI_SYLVA_POINTER_ACK_CHANNEL = "dsh-theme-xiaohei/sylva-pointer-ack-v1";
|
|
3
|
+
export declare const XIAOHEI_SYLVA_POINTER_MARKER = "data-xiaohei-pointer-bridge";
|
|
4
|
+
export type XiaoheiSylvaPointerMessage = {
|
|
5
|
+
channel: typeof XIAOHEI_SYLVA_POINTER_CHANNEL;
|
|
6
|
+
event: 'move' | 'leave';
|
|
7
|
+
x?: number;
|
|
8
|
+
y?: number;
|
|
9
|
+
pointerType?: string;
|
|
10
|
+
};
|
|
11
|
+
type FrameBounds = Pick<DOMRectReadOnly, 'left' | 'top' | 'width' | 'height'>;
|
|
12
|
+
/** Translate a host-page pointer into the isolated scene viewport. */
|
|
13
|
+
export declare function resolveXiaoheiSylvaPointer(clientX: number, clientY: number, bounds: FrameBounds): Pick<XiaoheiSylvaPointerMessage, 'event' | 'x' | 'y'>;
|
|
14
|
+
/** Add the receiver to a derived srcDoc without changing the registered ThreeUI source. */
|
|
15
|
+
export declare function injectXiaoheiSylvaPointerBridge(source: string): string;
|
|
16
|
+
/** Prepare a frame before it is connected, so WebGL boots exactly once. */
|
|
17
|
+
export declare function prepareXiaoheiSylvaPointerFrame(frame: HTMLIFrameElement): boolean;
|
|
18
|
+
/** Install a movement-only bridge. It never forwards clicks or presses. */
|
|
19
|
+
export declare function installXiaoheiSylvaPointerBridge(host: HTMLElement, prepareSceneFrame?: (frame: HTMLIFrameElement) => void): () => void;
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=pointer-bridge.d.ts.map
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
export const XIAOHEI_SYLVA_POINTER_CHANNEL = 'dsh-theme-xiaohei/sylva-pointer-v1';
|
|
2
|
+
export const XIAOHEI_SYLVA_POINTER_ACK_CHANNEL = 'dsh-theme-xiaohei/sylva-pointer-ack-v1';
|
|
3
|
+
export const XIAOHEI_SYLVA_POINTER_MARKER = 'data-xiaohei-pointer-bridge';
|
|
4
|
+
/** Translate a host-page pointer into the isolated scene viewport. */
|
|
5
|
+
export function resolveXiaoheiSylvaPointer(clientX, clientY, bounds) {
|
|
6
|
+
const x = clientX - bounds.left;
|
|
7
|
+
const y = clientY - bounds.top;
|
|
8
|
+
if (bounds.width <= 0 || bounds.height <= 0 || x < 0 || y < 0 || x > bounds.width || y > bounds.height) {
|
|
9
|
+
return { event: 'leave' };
|
|
10
|
+
}
|
|
11
|
+
return { event: 'move', x, y };
|
|
12
|
+
}
|
|
13
|
+
const RECEIVER = `
|
|
14
|
+
/* ${XIAOHEI_SYLVA_POINTER_MARKER}="true" — host pointer coordinates enter
|
|
15
|
+
the authored scene here, while actions remain owned by DSH. */
|
|
16
|
+
var XIAOHEI_POINTER_CHANNEL = ${JSON.stringify(XIAOHEI_SYLVA_POINTER_CHANNEL)};
|
|
17
|
+
var XIAOHEI_POINTER_ACK_CHANNEL = ${JSON.stringify(XIAOHEI_SYLVA_POINTER_ACK_CHANNEL)};
|
|
18
|
+
function xiaoheiAcknowledgePointer(eventName) {
|
|
19
|
+
parent.postMessage({
|
|
20
|
+
channel: XIAOHEI_POINTER_ACK_CHANNEL,
|
|
21
|
+
event: eventName,
|
|
22
|
+
pointerX: pointer.x,
|
|
23
|
+
pointerY: pointer.y,
|
|
24
|
+
ndcX: ndc.x,
|
|
25
|
+
ndcY: ndc.y,
|
|
26
|
+
reducedMotion: REDUCED
|
|
27
|
+
}, '*');
|
|
28
|
+
}
|
|
29
|
+
window.addEventListener('message', function (message) {
|
|
30
|
+
if (message.source !== parent) return;
|
|
31
|
+
var data = message.data;
|
|
32
|
+
if (!data || data.channel !== XIAOHEI_POINTER_CHANNEL) return;
|
|
33
|
+
if (data.event === 'leave') {
|
|
34
|
+
pointer.x = pointer.y = 0;
|
|
35
|
+
ndc.x = 10;
|
|
36
|
+
xiaoheiAcknowledgePointer('leave');
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
if (data.event !== 'move' || !Number.isFinite(data.x) || !Number.isFinite(data.y)) return;
|
|
40
|
+
pointer.x = (data.x / window.innerWidth) * 2 - 1;
|
|
41
|
+
pointer.y = (data.y / window.innerHeight) * 2 - 1;
|
|
42
|
+
var xiaoheiHeroRect = hero.getBoundingClientRect();
|
|
43
|
+
ndc.x = ((data.x - xiaoheiHeroRect.left) / xiaoheiHeroRect.width) * 2 - 1;
|
|
44
|
+
ndc.y = -((data.y - xiaoheiHeroRect.top) / xiaoheiHeroRect.height) * 2 + 1;
|
|
45
|
+
/* Reduced motion keeps ambient animation still, but direct manipulation
|
|
46
|
+
must remain responsive. Render only the pointer-driven moss response. */
|
|
47
|
+
if (REDUCED && renderer && camera && typeof updateMouse === 'function') {
|
|
48
|
+
var xiaoheiReduced = REDUCED;
|
|
49
|
+
REDUCED = false;
|
|
50
|
+
updateMouse(0.016);
|
|
51
|
+
renderer.render(scene, camera);
|
|
52
|
+
REDUCED = xiaoheiReduced;
|
|
53
|
+
}
|
|
54
|
+
xiaoheiAcknowledgePointer('move');
|
|
55
|
+
});
|
|
56
|
+
`;
|
|
57
|
+
/** Add the receiver to a derived srcDoc without changing the registered ThreeUI source. */
|
|
58
|
+
export function injectXiaoheiSylvaPointerBridge(source) {
|
|
59
|
+
if (source.includes(`${XIAOHEI_SYLVA_POINTER_MARKER}="true"`))
|
|
60
|
+
return source;
|
|
61
|
+
const runtimeEnd = source.lastIndexOf('\n})();\n</script>');
|
|
62
|
+
if (runtimeEnd < 0)
|
|
63
|
+
return source;
|
|
64
|
+
return `${source.slice(0, runtimeEnd)}${RECEIVER}${source.slice(runtimeEnd)}`;
|
|
65
|
+
}
|
|
66
|
+
/** Prepare a frame before it is connected, so WebGL boots exactly once. */
|
|
67
|
+
export function prepareXiaoheiSylvaPointerFrame(frame) {
|
|
68
|
+
const source = frame.getAttribute('srcdoc');
|
|
69
|
+
if (source === null)
|
|
70
|
+
return false;
|
|
71
|
+
const bridgedSource = injectXiaoheiSylvaPointerBridge(source);
|
|
72
|
+
if (bridgedSource === source && !source.includes(`${XIAOHEI_SYLVA_POINTER_MARKER}="true"`))
|
|
73
|
+
return false;
|
|
74
|
+
frame.dataset.xiaoheiPointerBridge = 'true';
|
|
75
|
+
if (bridgedSource !== source)
|
|
76
|
+
frame.setAttribute('srcdoc', bridgedSource);
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
/** Install a movement-only bridge. It never forwards clicks or presses. */
|
|
80
|
+
export function installXiaoheiSylvaPointerBridge(host, prepareSceneFrame = () => { }) {
|
|
81
|
+
const win = host.ownerDocument.defaultView;
|
|
82
|
+
if (win === null)
|
|
83
|
+
return () => { };
|
|
84
|
+
let frame = null;
|
|
85
|
+
let lastFrameWindow = null;
|
|
86
|
+
const prepareFrame = () => {
|
|
87
|
+
const nextFrame = host.querySelector('iframe');
|
|
88
|
+
if (!(nextFrame instanceof win.HTMLIFrameElement))
|
|
89
|
+
return;
|
|
90
|
+
frame = nextFrame;
|
|
91
|
+
lastFrameWindow = nextFrame.contentWindow;
|
|
92
|
+
prepareSceneFrame(frame);
|
|
93
|
+
prepareXiaoheiSylvaPointerFrame(frame);
|
|
94
|
+
};
|
|
95
|
+
const post = (message) => {
|
|
96
|
+
frame?.contentWindow?.postMessage({ channel: XIAOHEI_SYLVA_POINTER_CHANNEL, ...message }, '*');
|
|
97
|
+
};
|
|
98
|
+
const onPointerMove = (event) => {
|
|
99
|
+
if (event.pointerType === 'touch' || frame === null)
|
|
100
|
+
return;
|
|
101
|
+
const point = resolveXiaoheiSylvaPointer(event.clientX, event.clientY, frame.getBoundingClientRect());
|
|
102
|
+
post({ ...point, pointerType: event.pointerType || 'mouse' });
|
|
103
|
+
};
|
|
104
|
+
const onPointerDown = (event) => {
|
|
105
|
+
if (event.pointerType !== 'touch' || frame === null)
|
|
106
|
+
return;
|
|
107
|
+
const point = resolveXiaoheiSylvaPointer(event.clientX, event.clientY, frame.getBoundingClientRect());
|
|
108
|
+
post({ ...point, pointerType: 'touch' });
|
|
109
|
+
};
|
|
110
|
+
const onPointerEnd = (event) => {
|
|
111
|
+
if (event.pointerType === 'touch')
|
|
112
|
+
post({ event: 'leave', pointerType: 'touch' });
|
|
113
|
+
};
|
|
114
|
+
const onPointerLeave = (event) => {
|
|
115
|
+
post({ event: 'leave', pointerType: event.pointerType || 'mouse' });
|
|
116
|
+
};
|
|
117
|
+
const onBlur = () => post({ event: 'leave', pointerType: 'mouse' });
|
|
118
|
+
const onMessage = (event) => {
|
|
119
|
+
if (event.source !== lastFrameWindow)
|
|
120
|
+
return;
|
|
121
|
+
const data = event.data;
|
|
122
|
+
if (data === null || data.channel !== XIAOHEI_SYLVA_POINTER_ACK_CHANNEL || frame === null)
|
|
123
|
+
return;
|
|
124
|
+
frame.dataset.xiaoheiPointerState = data.event === 'move' ? 'active' : 'idle';
|
|
125
|
+
frame.dataset.xiaoheiPointerX = String(data.pointerX ?? '');
|
|
126
|
+
frame.dataset.xiaoheiPointerY = String(data.pointerY ?? '');
|
|
127
|
+
frame.dataset.xiaoheiPointerReducedMotion = String(data.reducedMotion === true);
|
|
128
|
+
};
|
|
129
|
+
const observer = new win.MutationObserver(prepareFrame);
|
|
130
|
+
observer.observe(host, {
|
|
131
|
+
childList: true,
|
|
132
|
+
subtree: true,
|
|
133
|
+
attributes: true,
|
|
134
|
+
attributeFilter: ['srcdoc'],
|
|
135
|
+
});
|
|
136
|
+
prepareFrame();
|
|
137
|
+
win.addEventListener('pointermove', onPointerMove, { passive: true, capture: true });
|
|
138
|
+
win.addEventListener('pointerdown', onPointerDown, { passive: true, capture: true });
|
|
139
|
+
win.addEventListener('pointerup', onPointerEnd, { passive: true, capture: true });
|
|
140
|
+
win.addEventListener('pointercancel', onPointerEnd, { passive: true, capture: true });
|
|
141
|
+
win.addEventListener('pointerleave', onPointerLeave, { capture: true });
|
|
142
|
+
win.addEventListener('blur', onBlur);
|
|
143
|
+
win.addEventListener('message', onMessage);
|
|
144
|
+
return () => {
|
|
145
|
+
observer.disconnect();
|
|
146
|
+
win.removeEventListener('pointermove', onPointerMove, { capture: true });
|
|
147
|
+
win.removeEventListener('pointerdown', onPointerDown, { capture: true });
|
|
148
|
+
win.removeEventListener('pointerup', onPointerEnd, { capture: true });
|
|
149
|
+
win.removeEventListener('pointercancel', onPointerEnd, { capture: true });
|
|
150
|
+
win.removeEventListener('pointerleave', onPointerLeave, { capture: true });
|
|
151
|
+
win.removeEventListener('blur', onBlur);
|
|
152
|
+
win.removeEventListener('message', onMessage);
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=pointer-bridge.js.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
type XiaoheiWorldRenderer = (host: HTMLElement) => () => void;
|
|
2
|
+
/** Register the browser-only world renderer without coupling shared scene code to raw assets. */
|
|
3
|
+
export declare function configureXiaoheiWorldRenderer(renderer: XiaoheiWorldRenderer): () => void;
|
|
4
|
+
/** Number of top-level decorative parts installed into the ambient layer. */
|
|
5
|
+
export declare const XIAOHEI_SCENE_PART_COUNT: 1;
|
|
6
|
+
/**
|
|
7
|
+
* Install the static wallpaper after plugin boot becomes idle. Appearance is
|
|
8
|
+
* CSS-driven; no image load handlers or per-frame character animation.
|
|
9
|
+
*/
|
|
10
|
+
export declare function installXiaoheiScene(doc?: Document | undefined): () => void;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=runtime.d.ts.map
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { XIAOHEI_SCENE_CSS, XIAOHEI_SCENE_LAYER_ID, XIAOHEI_SCENE_STYLE_ID, XIAOHEI_SCENE_WORLD_CLASS, } from './styles.js';
|
|
2
|
+
let worldRenderer;
|
|
3
|
+
/** Register the browser-only world renderer without coupling shared scene code to raw assets. */
|
|
4
|
+
export function configureXiaoheiWorldRenderer(renderer) {
|
|
5
|
+
worldRenderer = renderer;
|
|
6
|
+
return () => {
|
|
7
|
+
if (worldRenderer === renderer)
|
|
8
|
+
worldRenderer = undefined;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
const PARTS = [
|
|
12
|
+
XIAOHEI_SCENE_WORLD_CLASS,
|
|
13
|
+
];
|
|
14
|
+
/** Number of top-level decorative parts installed into the ambient layer. */
|
|
15
|
+
export const XIAOHEI_SCENE_PART_COUNT = PARTS.length;
|
|
16
|
+
/**
|
|
17
|
+
* Install the static wallpaper after plugin boot becomes idle. Appearance is
|
|
18
|
+
* CSS-driven; no image load handlers or per-frame character animation.
|
|
19
|
+
*/
|
|
20
|
+
export function installXiaoheiScene(doc = typeof document === 'undefined' ? undefined : document) {
|
|
21
|
+
if (doc === undefined)
|
|
22
|
+
return () => { };
|
|
23
|
+
let disposed = false;
|
|
24
|
+
let removeMountedScene = () => { };
|
|
25
|
+
let removeWorld = () => { };
|
|
26
|
+
const mount = () => {
|
|
27
|
+
if (disposed)
|
|
28
|
+
return;
|
|
29
|
+
removeWorld();
|
|
30
|
+
removeWorld = () => { };
|
|
31
|
+
doc.getElementById(XIAOHEI_SCENE_STYLE_ID)?.remove();
|
|
32
|
+
doc.getElementById(XIAOHEI_SCENE_LAYER_ID)?.remove();
|
|
33
|
+
const style = doc.createElement('style');
|
|
34
|
+
style.id = XIAOHEI_SCENE_STYLE_ID;
|
|
35
|
+
style.textContent = XIAOHEI_SCENE_CSS;
|
|
36
|
+
doc.head.append(style);
|
|
37
|
+
const layer = doc.createElement('div');
|
|
38
|
+
layer.id = XIAOHEI_SCENE_LAYER_ID;
|
|
39
|
+
layer.setAttribute('aria-hidden', 'true');
|
|
40
|
+
layer.setAttribute('data-xiaohei-scene', '');
|
|
41
|
+
let worldHost;
|
|
42
|
+
for (const className of PARTS) {
|
|
43
|
+
if (className === XIAOHEI_SCENE_WORLD_CLASS) {
|
|
44
|
+
worldHost = createWorldBackground(doc);
|
|
45
|
+
layer.append(worldHost);
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
const part = doc.createElement('span');
|
|
49
|
+
part.className = className;
|
|
50
|
+
layer.append(part);
|
|
51
|
+
}
|
|
52
|
+
doc.body.prepend(layer);
|
|
53
|
+
if (worldHost !== undefined && worldRenderer !== undefined) {
|
|
54
|
+
removeWorld = worldRenderer(worldHost);
|
|
55
|
+
}
|
|
56
|
+
removeMountedScene = () => {
|
|
57
|
+
removeWorld();
|
|
58
|
+
removeWorld = () => { };
|
|
59
|
+
layer.remove();
|
|
60
|
+
style.remove();
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
const win = doc.defaultView;
|
|
64
|
+
let cancelSchedule = () => { };
|
|
65
|
+
if (win !== null && typeof win.requestIdleCallback === 'function') {
|
|
66
|
+
const idleId = win.requestIdleCallback(mount, { timeout: 800 });
|
|
67
|
+
cancelSchedule = () => win.cancelIdleCallback(idleId);
|
|
68
|
+
}
|
|
69
|
+
else if (win !== null) {
|
|
70
|
+
const timeoutId = win.setTimeout(mount, 0);
|
|
71
|
+
cancelSchedule = () => win.clearTimeout(timeoutId);
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
mount();
|
|
75
|
+
}
|
|
76
|
+
return () => {
|
|
77
|
+
disposed = true;
|
|
78
|
+
cancelSchedule();
|
|
79
|
+
removeMountedScene();
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
function createWorldBackground(doc) {
|
|
83
|
+
const world = doc.createElement('div');
|
|
84
|
+
world.className = XIAOHEI_SCENE_WORLD_CLASS;
|
|
85
|
+
return world;
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=runtime.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Stable scene and material ids, shared with lifecycle and browser checks. */
|
|
2
|
+
export declare const XIAOHEI_SCENE_STYLE_ID = "dsh-theme-xiaohei/scene-style";
|
|
3
|
+
export declare const XIAOHEI_SCENE_LAYER_ID = "dsh-theme-xiaohei/scene-layer";
|
|
4
|
+
export declare const XIAOHEI_SCENE_WORLD_CLASS = "xiaohei-scene__world";
|
|
5
|
+
/** Static paired wallpapers; no per-frame effects or session-state dependency. */
|
|
6
|
+
export declare const XIAOHEI_SCENE_CSS: string;
|
|
7
|
+
//# sourceMappingURL=styles.d.ts.map
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { XIAOHEI_WALLPAPER_LIGHT, XIAOHEI_WALLPAPER_DARK, } from '../generated-backgrounds.js';
|
|
2
|
+
import { XIAOHEI_WALLPAPER_CHARACTER_CSS } from './wallpaper-character-styles.js';
|
|
3
|
+
/** Stable scene and material ids, shared with lifecycle and browser checks. */
|
|
4
|
+
export const XIAOHEI_SCENE_STYLE_ID = 'dsh-theme-xiaohei/scene-style';
|
|
5
|
+
export const XIAOHEI_SCENE_LAYER_ID = 'dsh-theme-xiaohei/scene-layer';
|
|
6
|
+
export const XIAOHEI_SCENE_WORLD_CLASS = 'xiaohei-scene__world';
|
|
7
|
+
/** Static paired wallpapers; no per-frame effects or session-state dependency. */
|
|
8
|
+
export const XIAOHEI_SCENE_CSS = `
|
|
9
|
+
body {
|
|
10
|
+
background: #151C26;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
html[data-xiaohei-appearance='light'] body {
|
|
14
|
+
background: #D4D5D5;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
#root {
|
|
18
|
+
position: relative;
|
|
19
|
+
z-index: 1;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
[id='${XIAOHEI_SCENE_LAYER_ID}'] {
|
|
23
|
+
position: fixed;
|
|
24
|
+
inset: 0;
|
|
25
|
+
/* The decorative canvas uses the large viewport, not the keyboard-reduced
|
|
26
|
+
* visual viewport. The host UI is still free to resize above it. */
|
|
27
|
+
height: 100vh;
|
|
28
|
+
height: 100lvh;
|
|
29
|
+
container: xiaohei-wallpaper / size;
|
|
30
|
+
z-index: 0;
|
|
31
|
+
overflow: hidden;
|
|
32
|
+
contain: strict;
|
|
33
|
+
isolation: isolate;
|
|
34
|
+
pointer-events: none;
|
|
35
|
+
user-select: none;
|
|
36
|
+
background: #151C26;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
html[data-xiaohei-appearance='light'] [id='${XIAOHEI_SCENE_LAYER_ID}'] {
|
|
40
|
+
background: #D4D5D5;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.${XIAOHEI_SCENE_WORLD_CLASS} {
|
|
44
|
+
--xiaohei-wallpaper-wide: url("${XIAOHEI_WALLPAPER_DARK}");
|
|
45
|
+
position: absolute;
|
|
46
|
+
inset: 0;
|
|
47
|
+
display: block;
|
|
48
|
+
overflow: hidden;
|
|
49
|
+
pointer-events: none;
|
|
50
|
+
background-image: var(--xiaohei-wallpaper-wide);
|
|
51
|
+
background-size: cover;
|
|
52
|
+
background-position: right center;
|
|
53
|
+
background-repeat: no-repeat;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
html[data-xiaohei-appearance='light'] .${XIAOHEI_SCENE_WORLD_CLASS} {
|
|
57
|
+
--xiaohei-wallpaper-wide: url("${XIAOHEI_WALLPAPER_LIGHT}");
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/* The atmosphere contains no character; responsive poses are placed separately
|
|
61
|
+
* against measured free space, never by cropping a portrait into messages. */
|
|
62
|
+
${XIAOHEI_WALLPAPER_CHARACTER_CSS}
|
|
63
|
+
|
|
64
|
+
.${XIAOHEI_SCENE_WORLD_CLASS} > * {
|
|
65
|
+
width: 100%;
|
|
66
|
+
height: 100%;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
@media (forced-colors: active), print {
|
|
70
|
+
[id='${XIAOHEI_SCENE_LAYER_ID}'] {
|
|
71
|
+
display: none;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
`;
|
|
75
|
+
//# sourceMappingURL=styles.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare const XIAOHEI_SYLVA_PERFORMANCE_MARKER = "data-xiaohei-performance-profile";
|
|
2
|
+
/**
|
|
3
|
+
* Apply a conservative runtime profile to the registered ThreeUI source.
|
|
4
|
+
*
|
|
5
|
+
* The registered source remains byte-for-byte untouched on disk. The profile
|
|
6
|
+
* only changes the iframe source snapshot before its first navigation, keeping
|
|
7
|
+
* upstream source verification useful while avoiding the scene's most costly
|
|
8
|
+
* defaults on long-running DSH sessions.
|
|
9
|
+
*/
|
|
10
|
+
export declare function injectXiaoheiSylvaPerformanceProfile(source: string): string;
|
|
11
|
+
//# sourceMappingURL=sylva-performance.d.ts.map
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
export const XIAOHEI_SYLVA_PERFORMANCE_MARKER = 'data-xiaohei-performance-profile';
|
|
2
|
+
/**
|
|
3
|
+
* Apply a conservative runtime profile to the registered ThreeUI source.
|
|
4
|
+
*
|
|
5
|
+
* The registered source remains byte-for-byte untouched on disk. The profile
|
|
6
|
+
* only changes the iframe source snapshot before its first navigation, keeping
|
|
7
|
+
* upstream source verification useful while avoiding the scene's most costly
|
|
8
|
+
* defaults on long-running DSH sessions.
|
|
9
|
+
*/
|
|
10
|
+
export function injectXiaoheiSylvaPerformanceProfile(source) {
|
|
11
|
+
if (source.includes(`${XIAOHEI_SYLVA_PERFORMANCE_MARKER}="balanced-v1"`))
|
|
12
|
+
return source;
|
|
13
|
+
const replacements = [
|
|
14
|
+
[
|
|
15
|
+
'var BLADES_NEAR = small ? 70000 : 190000;',
|
|
16
|
+
'var BLADES_NEAR = small ? 48000 : 105000;',
|
|
17
|
+
],
|
|
18
|
+
[
|
|
19
|
+
'var BLADES_FAR = small ? 20000 : 60000;',
|
|
20
|
+
'var BLADES_FAR = small ? 12000 : 28000;',
|
|
21
|
+
],
|
|
22
|
+
[
|
|
23
|
+
'renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, small ? 1.6 : 2));',
|
|
24
|
+
'renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, small ? 1.25 : 1.4));',
|
|
25
|
+
],
|
|
26
|
+
[
|
|
27
|
+
'if (!small) bf = buildButterfly(nearGroup, nearLimbs, nearGroup.userData.uni);',
|
|
28
|
+
'bf = null; /* butterfly disabled by the Xiaohei long-session profile */',
|
|
29
|
+
],
|
|
30
|
+
[
|
|
31
|
+
'if (renderer && clock) renderFrame();',
|
|
32
|
+
`if (renderer && clock) {
|
|
33
|
+
var xiaoheiWorldElapsed = now - xiaoheiWorldLastFrame;
|
|
34
|
+
if (xiaoheiWorldElapsed >= xiaoheiWorldFrameInterval) {
|
|
35
|
+
xiaoheiWorldLastFrame = now - (xiaoheiWorldElapsed % xiaoheiWorldFrameInterval);
|
|
36
|
+
renderFrame();
|
|
37
|
+
}
|
|
38
|
+
}`,
|
|
39
|
+
],
|
|
40
|
+
];
|
|
41
|
+
let profiled = source;
|
|
42
|
+
for (const [authored, optimized] of replacements) {
|
|
43
|
+
if (!profiled.includes(authored))
|
|
44
|
+
return source;
|
|
45
|
+
profiled = profiled.replace(authored, optimized);
|
|
46
|
+
}
|
|
47
|
+
const runtimeEnd = profiled.lastIndexOf('\n})();\n</script>');
|
|
48
|
+
if (runtimeEnd < 0)
|
|
49
|
+
return source;
|
|
50
|
+
const marker = `
|
|
51
|
+
/* ${XIAOHEI_SYLVA_PERFORMANCE_MARKER}="balanced-v1" */
|
|
52
|
+
var xiaoheiWorldLastFrame = 0;
|
|
53
|
+
var xiaoheiWorldFrameInterval = 1000 / (
|
|
54
|
+
NARROW.matches || (window.innerWidth * window.innerHeight) < 620000 ? 30 : 45
|
|
55
|
+
);`;
|
|
56
|
+
return `${profiled.slice(0, runtimeEnd)}${marker}${profiled.slice(runtimeEnd)}`;
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=sylva-performance.js.map
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { CHARACTER_POSES, CHARACTER_POSE_NAMES } from './character-poses.js';
|
|
2
|
+
/** Complete raster poses remain crisp; only entry/exit opacity and transform move. */
|
|
3
|
+
export const XIAOHEI_WALLPAPER_CHARACTER_CSS = `
|
|
4
|
+
.xiaohei-wallpaper-character {
|
|
5
|
+
${CHARACTER_POSE_NAMES.map(pose => `--xiaohei-${pose}-art: url("${CHARACTER_POSES[pose].dark}");`).join('\n ')}
|
|
6
|
+
position: absolute;
|
|
7
|
+
inset: 0;
|
|
8
|
+
pointer-events: none;
|
|
9
|
+
user-select: none;
|
|
10
|
+
}
|
|
11
|
+
html[data-xiaohei-sidebar-resizing] .xiaohei-wallpaper-character {
|
|
12
|
+
visibility: hidden;
|
|
13
|
+
}
|
|
14
|
+
html[data-xiaohei-appearance='light'] .xiaohei-wallpaper-character {
|
|
15
|
+
${CHARACTER_POSE_NAMES.map(pose => `--xiaohei-${pose}-art: url("${CHARACTER_POSES[pose].light}");`).join('\n ')}
|
|
16
|
+
}
|
|
17
|
+
.xiaohei-wallpaper-character > span {
|
|
18
|
+
position: absolute;
|
|
19
|
+
display: block;
|
|
20
|
+
background-size: contain;
|
|
21
|
+
background-position: left center;
|
|
22
|
+
background-repeat: no-repeat;
|
|
23
|
+
pointer-events: none;
|
|
24
|
+
opacity: 0;
|
|
25
|
+
transition: opacity 220ms ease, transform 220ms cubic-bezier(.2,.8,.2,1);
|
|
26
|
+
}
|
|
27
|
+
.xiaohei-wallpaper-character .xiaohei-character-motion {
|
|
28
|
+
position: absolute; inset: 0; width: 100%; height: 100%;
|
|
29
|
+
object-fit: contain; object-position: left center; pointer-events: none;
|
|
30
|
+
}
|
|
31
|
+
.xiaohei-wallpaper-character > span[data-motion]:not([data-motion='rest']) {
|
|
32
|
+
background-image: none;
|
|
33
|
+
}
|
|
34
|
+
${CHARACTER_POSE_NAMES.map(pose => `
|
|
35
|
+
.xiaohei-wallpaper-character__${pose}[data-ready] {
|
|
36
|
+
background-image: var(--xiaohei-${pose}-art);
|
|
37
|
+
}`).join('\n')}
|
|
38
|
+
.xiaohei-wallpaper-character__peek,
|
|
39
|
+
.xiaohei-wallpaper-character__halfpeek {
|
|
40
|
+
transform: translateX(4px);
|
|
41
|
+
}
|
|
42
|
+
${CHARACTER_POSE_NAMES.map(pose => `.xiaohei-wallpaper-character[data-pose='${pose}'] > .xiaohei-wallpaper-character__${pose}`).join(',\n')} {
|
|
43
|
+
opacity: 1;
|
|
44
|
+
transform: none;
|
|
45
|
+
}
|
|
46
|
+
.xiaohei-wallpaper-character[data-pose='hidden'] > span {
|
|
47
|
+
transition: none;
|
|
48
|
+
}
|
|
49
|
+
@media (prefers-reduced-motion: reduce) {
|
|
50
|
+
.xiaohei-wallpaper-character > span { transition: none; transform: none; }
|
|
51
|
+
}
|
|
52
|
+
`;
|
|
53
|
+
//# sourceMappingURL=wallpaper-character-styles.js.map
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare const XIAOHEI_WALLPAPER_CHARACTER_ID = "dsh-theme-xiaohei/wallpaper-character";
|
|
2
|
+
/** Places the layered character only when the host geometry is settled. */
|
|
3
|
+
export declare function installXiaoheiWallpaperCharacter(doc?: Document | undefined): () => void;
|
|
4
|
+
//# sourceMappingURL=wallpaper-character.d.ts.map
|