@lemoncat7/dsh-theme-xiaohei 0.3.0-alpha.22 → 0.3.1
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 +37 -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/frames.d.ts +1 -1
- package/lib/chrome/frames.js +14 -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 +118 -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 +5864 -4447
- 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-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 +309 -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-poses.d.ts +26 -0
- package/lib/scene/character-poses.js +11 -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 +43 -0
- package/lib/scene/wallpaper-character.d.ts +4 -0
- package/lib/scene/wallpaper-character.js +195 -0
- package/lib/scene.d.ts +7 -13
- package/lib/scene.js +7 -1023
- package/lib/sidebar-glass.js +88 -35
- package/lib/sidebar-heixiu-roaming.js +5 -5
- 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,17 @@
|
|
|
1
|
+
export type CharacterIdlePose = 'seated' | 'chin' | 'doze';
|
|
2
|
+
export declare const CHARACTER_CHIN_DELAY = 30000;
|
|
3
|
+
export declare const CHARACTER_DOZE_DELAY = 180000;
|
|
4
|
+
interface IdleClock {
|
|
5
|
+
now(): number;
|
|
6
|
+
setTimeout(callback: () => void, delay: number): number;
|
|
7
|
+
clearTimeout(handle: number): void;
|
|
8
|
+
}
|
|
9
|
+
/** One pending deadline, no polling, no model/session state or persisted user data. */
|
|
10
|
+
export declare function createCharacterIdleController(clock: IdleClock, changed: (pose: CharacterIdlePose) => void): {
|
|
11
|
+
readonly pose: CharacterIdlePose;
|
|
12
|
+
activity(): void;
|
|
13
|
+
setPaused(value: boolean): void;
|
|
14
|
+
dispose(): void;
|
|
15
|
+
};
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=character-idle.d.ts.map
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
export const CHARACTER_CHIN_DELAY = 30_000;
|
|
2
|
+
export const CHARACTER_DOZE_DELAY = 180_000;
|
|
3
|
+
/** One pending deadline, no polling, no model/session state or persisted user data. */
|
|
4
|
+
export function createCharacterIdleController(clock, changed) {
|
|
5
|
+
let pose = 'seated';
|
|
6
|
+
let lastActivity = clock.now();
|
|
7
|
+
let timer;
|
|
8
|
+
let paused = true;
|
|
9
|
+
let disposed = false;
|
|
10
|
+
const clear = () => {
|
|
11
|
+
if (timer !== undefined)
|
|
12
|
+
clock.clearTimeout(timer);
|
|
13
|
+
timer = undefined;
|
|
14
|
+
};
|
|
15
|
+
const update = (next) => {
|
|
16
|
+
if (next !== pose) {
|
|
17
|
+
pose = next;
|
|
18
|
+
changed(next);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
const schedule = () => {
|
|
22
|
+
clear();
|
|
23
|
+
if (paused || disposed || pose === 'doze')
|
|
24
|
+
return;
|
|
25
|
+
const deadline = pose === 'seated' ? CHARACTER_CHIN_DELAY : CHARACTER_DOZE_DELAY;
|
|
26
|
+
timer = clock.setTimeout(tick, Math.max(1, lastActivity + deadline - clock.now()));
|
|
27
|
+
};
|
|
28
|
+
function tick() {
|
|
29
|
+
timer = undefined;
|
|
30
|
+
if (paused || disposed)
|
|
31
|
+
return;
|
|
32
|
+
const elapsed = clock.now() - lastActivity;
|
|
33
|
+
update(elapsed >= CHARACTER_DOZE_DELAY ? 'doze' : elapsed >= CHARACTER_CHIN_DELAY ? 'chin' : 'seated');
|
|
34
|
+
schedule();
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
get pose() { return pose; },
|
|
38
|
+
activity() {
|
|
39
|
+
if (paused || disposed)
|
|
40
|
+
return;
|
|
41
|
+
const now = clock.now();
|
|
42
|
+
// Pointer events can fire at 120 Hz. Update a timestamp at most once per
|
|
43
|
+
// second; never reset a timeout on each pointer movement or keystroke.
|
|
44
|
+
if (pose === 'seated' && now - lastActivity < 1000)
|
|
45
|
+
return;
|
|
46
|
+
lastActivity = now;
|
|
47
|
+
if (pose !== 'seated') {
|
|
48
|
+
update('seated');
|
|
49
|
+
schedule();
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
setPaused(value) {
|
|
53
|
+
if (disposed || value === paused)
|
|
54
|
+
return;
|
|
55
|
+
paused = value;
|
|
56
|
+
clear();
|
|
57
|
+
lastActivity = clock.now();
|
|
58
|
+
update('seated');
|
|
59
|
+
if (!paused)
|
|
60
|
+
schedule();
|
|
61
|
+
},
|
|
62
|
+
dispose() { disposed = true; clear(); },
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=character-idle.js.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/** Pure placement policy: decoration may only occupy space outside message bounds. */
|
|
2
|
+
export interface CharacterRect {
|
|
3
|
+
left: number;
|
|
4
|
+
top: number;
|
|
5
|
+
right: number;
|
|
6
|
+
bottom: number;
|
|
7
|
+
}
|
|
8
|
+
export interface CharacterLayoutInput {
|
|
9
|
+
sidebar: CharacterRect;
|
|
10
|
+
scroll: CharacterRect;
|
|
11
|
+
flow: CharacterRect;
|
|
12
|
+
viewportWidth: number;
|
|
13
|
+
viewportHeight: number;
|
|
14
|
+
controls: CharacterRect[];
|
|
15
|
+
}
|
|
16
|
+
export interface CharacterPlacement {
|
|
17
|
+
pose: 'seated' | 'peek' | 'halfpeek' | 'hidden';
|
|
18
|
+
left: number;
|
|
19
|
+
top: number;
|
|
20
|
+
width: number;
|
|
21
|
+
height: number;
|
|
22
|
+
}
|
|
23
|
+
export declare function resolveCharacterPlacement(input: CharacterLayoutInput): CharacterPlacement;
|
|
24
|
+
//# sourceMappingURL=character-layout.d.ts.map
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
const hidden = { pose: 'hidden', left: 0, top: 0, width: 0, height: 0 };
|
|
2
|
+
const SEATED_RATIO = 0.71;
|
|
3
|
+
const PEEK_RATIO = 0.63;
|
|
4
|
+
const HALF_PEEK_RATIO = 0.44;
|
|
5
|
+
export function resolveCharacterPlacement(input) {
|
|
6
|
+
const { sidebar, scroll, flow, viewportWidth, viewportHeight, controls } = input;
|
|
7
|
+
// Wallpaper belongs to the viewport, not the welcome/composer dock. Reserve
|
|
8
|
+
// the same top/bottom chrome space before and after the first message.
|
|
9
|
+
const bottom = Math.min(sidebar.bottom, viewportHeight) - 148;
|
|
10
|
+
const top = Math.max(sidebar.top + 24, 96);
|
|
11
|
+
if (bottom - top < 130 || sidebar.right > flow.left)
|
|
12
|
+
return hidden;
|
|
13
|
+
const rightStart = flow.right + 56;
|
|
14
|
+
const seatedWidth = Math.min(250, scroll.right - rightStart - 20, (bottom - top) * SEATED_RATIO, 340 * SEATED_RATIO);
|
|
15
|
+
if (seatedWidth >= 190) {
|
|
16
|
+
const height = seatedWidth / SEATED_RATIO;
|
|
17
|
+
return { pose: 'seated', left: scroll.right - seatedWidth - 16,
|
|
18
|
+
top: top + (bottom - top - height) * 0.6, width: seatedWidth, height };
|
|
19
|
+
}
|
|
20
|
+
const avatarInset = viewportWidth > 760 ? 52 : 0;
|
|
21
|
+
const freeGap = flow.left - avatarInset - sidebar.right;
|
|
22
|
+
if (freeGap >= 66) {
|
|
23
|
+
const width = Math.min(104, freeGap - 12, (bottom - top) * PEEK_RATIO);
|
|
24
|
+
const height = width / PEEK_RATIO;
|
|
25
|
+
return { pose: 'peek', left: sidebar.right - 6,
|
|
26
|
+
top: top + Math.min(160, (bottom - top - height) * 0.5), width, height };
|
|
27
|
+
}
|
|
28
|
+
// A collapsed rail has a large blank region between navigation and Settings.
|
|
29
|
+
// Use that region only after excluding every real interactive control.
|
|
30
|
+
if (sidebar.right - sidebar.left > 100)
|
|
31
|
+
return hidden;
|
|
32
|
+
const left = sidebar.left + 7;
|
|
33
|
+
const width = Math.min(60, flow.left - avatarInset - left - 10);
|
|
34
|
+
if (width < 40)
|
|
35
|
+
return hidden;
|
|
36
|
+
const height = width / HALF_PEEK_RATIO;
|
|
37
|
+
const blocked = controls.filter(r => r.right > left && r.left < left + width)
|
|
38
|
+
.map(r => ({ start: Math.max(top, r.top - 12), end: Math.min(bottom, r.bottom + 12) }))
|
|
39
|
+
.filter(r => r.end > r.start).sort((a, b) => a.start - b.start);
|
|
40
|
+
let cursor = top;
|
|
41
|
+
let best = { start: top, end: top };
|
|
42
|
+
for (const block of [...blocked, { start: bottom, end: bottom }]) {
|
|
43
|
+
if (block.start - cursor > best.end - best.start)
|
|
44
|
+
best = { start: cursor, end: block.start };
|
|
45
|
+
cursor = Math.max(cursor, block.end);
|
|
46
|
+
}
|
|
47
|
+
if (best.end - best.start < height + 12)
|
|
48
|
+
return hidden;
|
|
49
|
+
return { pose: 'halfpeek', left, top: best.start + (best.end - best.start - height) * 0.45, width, height };
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=character-layout.js.map
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** Shared catalog: runtime preloading and CSS must always use the same assets. */
|
|
2
|
+
export declare const CHARACTER_POSES: {
|
|
3
|
+
readonly seated: {
|
|
4
|
+
readonly light: string;
|
|
5
|
+
readonly dark: string;
|
|
6
|
+
};
|
|
7
|
+
readonly chin: {
|
|
8
|
+
readonly light: string;
|
|
9
|
+
readonly dark: string;
|
|
10
|
+
};
|
|
11
|
+
readonly doze: {
|
|
12
|
+
readonly light: string;
|
|
13
|
+
readonly dark: string;
|
|
14
|
+
};
|
|
15
|
+
readonly peek: {
|
|
16
|
+
readonly light: string;
|
|
17
|
+
readonly dark: string;
|
|
18
|
+
};
|
|
19
|
+
readonly halfpeek: {
|
|
20
|
+
readonly light: string;
|
|
21
|
+
readonly dark: string;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
export type CharacterPose = keyof typeof CHARACTER_POSES;
|
|
25
|
+
export declare const CHARACTER_POSE_NAMES: CharacterPose[];
|
|
26
|
+
//# sourceMappingURL=character-poses.d.ts.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { XIAOHEI_SEATED_LIGHT, XIAOHEI_SEATED_DARK, XIAOHEI_PEEK_LIGHT, XIAOHEI_PEEK_DARK, XIAOHEI_CHIN_LIGHT, XIAOHEI_CHIN_DARK, XIAOHEI_DOZE_LIGHT, XIAOHEI_DOZE_DARK, XIAOHEI_HALFPEEK_LIGHT, XIAOHEI_HALFPEEK_DARK, } from '../generated-backgrounds.js';
|
|
2
|
+
/** Shared catalog: runtime preloading and CSS must always use the same assets. */
|
|
3
|
+
export const CHARACTER_POSES = {
|
|
4
|
+
seated: { light: XIAOHEI_SEATED_LIGHT, dark: XIAOHEI_SEATED_DARK },
|
|
5
|
+
chin: { light: XIAOHEI_CHIN_LIGHT, dark: XIAOHEI_CHIN_DARK },
|
|
6
|
+
doze: { light: XIAOHEI_DOZE_LIGHT, dark: XIAOHEI_DOZE_DARK },
|
|
7
|
+
peek: { light: XIAOHEI_PEEK_LIGHT, dark: XIAOHEI_PEEK_DARK },
|
|
8
|
+
halfpeek: { light: XIAOHEI_HALFPEEK_LIGHT, dark: XIAOHEI_HALFPEEK_DARK },
|
|
9
|
+
};
|
|
10
|
+
export const CHARACTER_POSE_NAMES = Object.keys(CHARACTER_POSES);
|
|
11
|
+
//# sourceMappingURL=character-poses.js.map
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
/** Session feedback runs on an inner plane so ambient drifting stays untouched. */
|
|
2
|
-
export declare const XIAOHEI_HEIXIU_FEEDBACK_CSS = "\n.xiaohei-scene__heixiu-body {\n position: absolute;\n inset: 0;\n display: block;\n transform: translate3d(0, 0, 0);\n opacity: 1;\n}\n\nhtml[data-xiaohei-state='
|
|
2
|
+
export declare const XIAOHEI_HEIXIU_FEEDBACK_CSS = "\n.xiaohei-scene__heixiu-body {\n position: absolute;\n inset: 0;\n display: block;\n transform: translate3d(0, 0, 0);\n opacity: 1;\n}\n\nhtml[data-xiaohei-state='complete'] .xiaohei-scene__heixiu--mascot .xiaohei-scene__heixiu-body,\nhtml[data-xiaohei-state='complete'] .xiaohei-scene__heixiu--sidebar .xiaohei-scene__heixiu-body {\n animation: xiaohei-heixiu-feedback-complete 760ms cubic-bezier(0.16, 1, 0.3, 1) both;\n}\n\nhtml[data-xiaohei-state='complete'] .xiaohei-scene__heixiu--sidebar .xiaohei-scene__heixiu-body {\n animation-delay: 140ms;\n}\n\nhtml[data-xiaohei-state='error'] .xiaohei-scene__heixiu .xiaohei-scene__heixiu-body {\n animation: xiaohei-heixiu-feedback-error 880ms cubic-bezier(0.22, 0.72, 0.24, 1) both;\n}\n\nhtml[data-xiaohei-state='complete'] .xiaohei-scene__heixiu .xiaohei-scene__heixiu-open,\nhtml[data-xiaohei-state='error'] .xiaohei-scene__heixiu .xiaohei-scene__heixiu-open {\n animation: xiaohei-heixiu-feedback-eyes-open 620ms step-end both;\n}\n\nhtml[data-xiaohei-state='complete'] .xiaohei-scene__heixiu .xiaohei-scene__heixiu-blink,\nhtml[data-xiaohei-state='error'] .xiaohei-scene__heixiu .xiaohei-scene__heixiu-blink {\n animation: xiaohei-heixiu-feedback-eyes-blink 620ms step-end both;\n}\n\n@keyframes xiaohei-heixiu-feedback-complete {\n 0%, 100% { transform: translate3d(0, 0, 0); opacity: 1; }\n 38% { transform: translate3d(0, -0.42rem, 0); opacity: 1; }\n 68% { transform: translate3d(0, -0.12rem, 0); opacity: 0.96; }\n}\n\n@keyframes xiaohei-heixiu-feedback-error {\n 0%, 100% { transform: translate3d(0, 0, 0); opacity: 1; }\n 30% { transform: translate3d(0, 0.2rem, 0); opacity: 0.52; }\n 62% { transform: translate3d(0, 0.08rem, 0); opacity: 0.72; }\n}\n\n@keyframes xiaohei-heixiu-feedback-eyes-open {\n 0%, 24%, 48%, 100% { opacity: 1; }\n 25%, 47% { opacity: 0; }\n}\n\n@keyframes xiaohei-heixiu-feedback-eyes-blink {\n 0%, 24%, 48%, 100% { opacity: 0; }\n 25%, 47% { opacity: 1; }\n}\n\n@media (prefers-reduced-motion: reduce) {\n html[data-xiaohei-state] .xiaohei-scene__heixiu .xiaohei-scene__heixiu-body,\n html[data-xiaohei-state] .xiaohei-scene__heixiu .xiaohei-scene__heixiu-open,\n html[data-xiaohei-state] .xiaohei-scene__heixiu .xiaohei-scene__heixiu-blink {\n animation: none;\n }\n}\n";
|
|
3
3
|
//# sourceMappingURL=heixiu-feedback.d.ts.map
|
|
@@ -8,20 +8,11 @@ export const XIAOHEI_HEIXIU_FEEDBACK_CSS = `
|
|
|
8
8
|
opacity: 1;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
html[data-xiaohei-state='thinking'] .xiaohei-scene__heixiu--composer .xiaohei-scene__heixiu-body {
|
|
12
|
-
animation: xiaohei-heixiu-feedback-send 620ms cubic-bezier(0.22, 0.72, 0.24, 1) both;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
11
|
html[data-xiaohei-state='complete'] .xiaohei-scene__heixiu--mascot .xiaohei-scene__heixiu-body,
|
|
16
|
-
html[data-xiaohei-state='complete'] .xiaohei-scene__heixiu--composer .xiaohei-scene__heixiu-body,
|
|
17
12
|
html[data-xiaohei-state='complete'] .xiaohei-scene__heixiu--sidebar .xiaohei-scene__heixiu-body {
|
|
18
13
|
animation: xiaohei-heixiu-feedback-complete 760ms cubic-bezier(0.16, 1, 0.3, 1) both;
|
|
19
14
|
}
|
|
20
15
|
|
|
21
|
-
html[data-xiaohei-state='complete'] .xiaohei-scene__heixiu--composer .xiaohei-scene__heixiu-body {
|
|
22
|
-
animation-delay: 70ms;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
16
|
html[data-xiaohei-state='complete'] .xiaohei-scene__heixiu--sidebar .xiaohei-scene__heixiu-body {
|
|
26
17
|
animation-delay: 140ms;
|
|
27
18
|
}
|
|
@@ -30,24 +21,16 @@ html[data-xiaohei-state='error'] .xiaohei-scene__heixiu .xiaohei-scene__heixiu-b
|
|
|
30
21
|
animation: xiaohei-heixiu-feedback-error 880ms cubic-bezier(0.22, 0.72, 0.24, 1) both;
|
|
31
22
|
}
|
|
32
23
|
|
|
33
|
-
html[data-xiaohei-state='thinking'] .xiaohei-scene__heixiu--composer .xiaohei-scene__heixiu-open,
|
|
34
24
|
html[data-xiaohei-state='complete'] .xiaohei-scene__heixiu .xiaohei-scene__heixiu-open,
|
|
35
25
|
html[data-xiaohei-state='error'] .xiaohei-scene__heixiu .xiaohei-scene__heixiu-open {
|
|
36
26
|
animation: xiaohei-heixiu-feedback-eyes-open 620ms step-end both;
|
|
37
27
|
}
|
|
38
28
|
|
|
39
|
-
html[data-xiaohei-state='thinking'] .xiaohei-scene__heixiu--composer .xiaohei-scene__heixiu-blink,
|
|
40
29
|
html[data-xiaohei-state='complete'] .xiaohei-scene__heixiu .xiaohei-scene__heixiu-blink,
|
|
41
30
|
html[data-xiaohei-state='error'] .xiaohei-scene__heixiu .xiaohei-scene__heixiu-blink {
|
|
42
31
|
animation: xiaohei-heixiu-feedback-eyes-blink 620ms step-end both;
|
|
43
32
|
}
|
|
44
33
|
|
|
45
|
-
@keyframes xiaohei-heixiu-feedback-send {
|
|
46
|
-
0%, 100% { transform: translate3d(0, 0, 0); opacity: 1; }
|
|
47
|
-
34% { transform: translate3d(0, -0.28rem, 0); opacity: 1; }
|
|
48
|
-
68% { transform: translate3d(0, 0.08rem, 0); opacity: 0.94; }
|
|
49
|
-
}
|
|
50
|
-
|
|
51
34
|
@keyframes xiaohei-heixiu-feedback-complete {
|
|
52
35
|
0%, 100% { transform: translate3d(0, 0, 0); opacity: 1; }
|
|
53
36
|
38% { transform: translate3d(0, -0.42rem, 0); opacity: 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
|