@lemoncat7/dsh-theme-xiaohei 0.3.3 → 0.3.4
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 +5 -5
- package/lib/chrome/sidebar.d.ts +1 -1
- package/lib/chrome/sidebar.js +13 -15
- package/lib/chrome/tokens.d.ts +1 -1
- package/lib/chrome/tokens.js +4 -4
- package/lib/client.js +383 -55
- package/lib/metallic-brand-mark.js +2 -2
- package/lib/scene/character-expression.d.ts +4 -0
- package/lib/scene/character-expression.js +15 -0
- package/lib/scene/character-eye-material.d.ts +13 -0
- package/lib/scene/character-eye-material.js +88 -0
- package/lib/scene/character-eye-renderer.d.ts +5 -0
- package/lib/scene/character-eye-renderer.js +80 -0
- package/lib/scene/character-eye-rig.d.ts +20 -0
- package/lib/scene/character-eye-rig.js +35 -0
- package/lib/scene/character-gaze.d.ts +16 -0
- package/lib/scene/character-gaze.js +36 -0
- package/lib/scene/character-motion-clock.d.ts +1 -1
- package/lib/scene/character-motion-clock.js +17 -4
- package/lib/scene/character-motion.js +66 -12
- package/lib/scene/character-rig-renderer.d.ts +3 -2
- package/lib/scene/character-rig-renderer.js +28 -18
- package/lib/scene/character-rig.d.ts +2 -0
- package/lib/scene/character-rig.js +9 -1
- package/lib/sidebar-reveal.js +11 -3
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -1442,12 +1442,10 @@ var XIAOHEI_SIDEBAR_CSS = `
|
|
|
1442
1442
|
* Keep the toggle itself native. Opacity is applied to content, never the shell
|
|
1443
1443
|
* (which also hosts fixed-position settings dialogs). */
|
|
1444
1444
|
@media (prefers-reduced-motion: no-preference) {
|
|
1445
|
-
#root [data-
|
|
1446
|
-
#root [data-slot='sidebar'] > div[data-xiaohei-sidebar-reveal]:not([class*='_collapsed']) > div:first-child > button:first-child {
|
|
1445
|
+
#root [data-xiaohei-sidebar-reveal] [data-xiaohei-sidebar-brand] {
|
|
1447
1446
|
transition: opacity 100ms ease-out;
|
|
1448
1447
|
}
|
|
1449
|
-
#root [data-
|
|
1450
|
-
#root [data-slot='sidebar'] > div[data-xiaohei-sidebar-reveal='waiting']:not([class*='_collapsed']) > div:first-child > button:first-child {
|
|
1448
|
+
#root [data-xiaohei-sidebar-reveal='waiting'] [data-xiaohei-sidebar-brand] {
|
|
1451
1449
|
opacity: 0 !important;
|
|
1452
1450
|
visibility: hidden;
|
|
1453
1451
|
transition: none;
|
|
@@ -1596,9 +1594,9 @@ html[data-xiaohei-sidebar-resizing] #dsh-theme-xiaohei\\/sidebar-glass {
|
|
|
1596
1594
|
}
|
|
1597
1595
|
|
|
1598
1596
|
/* Keep native rail/wide geometry and one consistent control material. */
|
|
1599
|
-
#root [data-slot='sidebar']
|
|
1600
|
-
#root [data-slot='sidebar'] > div:
|
|
1601
|
-
#root [data-slot='sidebar'] > div:
|
|
1597
|
+
#root [data-slot='sidebar'] button:is([aria-label='Collapse sidebar'], [aria-label='\u6536\u8D77\u4FA7\u8FB9\u680F']),
|
|
1598
|
+
#root [data-slot='sidebar'] > div:has(button:is([aria-label='Collapse sidebar'], [aria-label='\u6536\u8D77\u4FA7\u8FB9\u680F'])) > button[aria-label='\u65B0\u5EFA\u4F1A\u8BDD'],
|
|
1599
|
+
#root [data-slot='sidebar'] > div:has(button:is([aria-label='Collapse sidebar'], [aria-label='\u6536\u8D77\u4FA7\u8FB9\u680F'])) > button[aria-label='New session'] {
|
|
1602
1600
|
color: var(--xiaohei-sidebar-emphasis);
|
|
1603
1601
|
transition:
|
|
1604
1602
|
background-color var(--xiaohei-motion-fast) ease,
|
|
@@ -1606,12 +1604,12 @@ html[data-xiaohei-sidebar-resizing] #dsh-theme-xiaohei\\/sidebar-glass {
|
|
|
1606
1604
|
transform var(--xiaohei-motion-fast) var(--xiaohei-motion-curve);
|
|
1607
1605
|
}
|
|
1608
1606
|
|
|
1609
|
-
#root [data-slot='sidebar']
|
|
1607
|
+
#root [data-slot='sidebar'] button:is([aria-label='Collapse sidebar'], [aria-label='\u6536\u8D77\u4FA7\u8FB9\u680F']):hover {
|
|
1610
1608
|
background: var(--xiaohei-sidebar-hover);
|
|
1611
1609
|
}
|
|
1612
1610
|
|
|
1613
|
-
#root [data-slot='sidebar'] > div:
|
|
1614
|
-
#root [data-slot='sidebar'] > div:
|
|
1611
|
+
#root [data-slot='sidebar'] > div:has(button:is([aria-label='Collapse sidebar'], [aria-label='\u6536\u8D77\u4FA7\u8FB9\u680F'])) > button[aria-label='\u65B0\u5EFA\u4F1A\u8BDD'],
|
|
1612
|
+
#root [data-slot='sidebar'] > div:has(button:is([aria-label='Collapse sidebar'], [aria-label='\u6536\u8D77\u4FA7\u8FB9\u680F'])) > button[aria-label='New session'] {
|
|
1615
1613
|
border: 1px solid var(--xiaohei-sidebar-control-edge);
|
|
1616
1614
|
border-radius: var(--xiaohei-radius-control);
|
|
1617
1615
|
background: var(--xiaohei-sidebar-control);
|
|
@@ -1622,14 +1620,14 @@ html[data-xiaohei-sidebar-resizing] #dsh-theme-xiaohei\\/sidebar-glass {
|
|
|
1622
1620
|
text-align: start;
|
|
1623
1621
|
}
|
|
1624
1622
|
|
|
1625
|
-
#root [data-slot='sidebar'] > div:
|
|
1626
|
-
#root [data-slot='sidebar'] > div:
|
|
1623
|
+
#root [data-slot='sidebar'] > div:has(button:is([aria-label='Collapse sidebar'], [aria-label='\u6536\u8D77\u4FA7\u8FB9\u680F'])) > button[aria-label='\u65B0\u5EFA\u4F1A\u8BDD']:hover,
|
|
1624
|
+
#root [data-slot='sidebar'] > div:has(button:is([aria-label='Collapse sidebar'], [aria-label='\u6536\u8D77\u4FA7\u8FB9\u680F'])) > button[aria-label='New session']:hover {
|
|
1627
1625
|
border-color: var(--xiaohei-sidebar-control-edge-hover);
|
|
1628
1626
|
background: var(--xiaohei-sidebar-hover);
|
|
1629
1627
|
}
|
|
1630
1628
|
|
|
1631
1629
|
/* The footer uses a divider instead of another framed card. */
|
|
1632
|
-
#root [data-slot='sidebar'] > div:
|
|
1630
|
+
#root [data-slot='sidebar'] > div:has(button:is([aria-label='Collapse sidebar'], [aria-label='\u6536\u8D77\u4FA7\u8FB9\u680F']))
|
|
1633
1631
|
> :has(> div > [data-slot='sidebar.footer.action']) {
|
|
1634
1632
|
box-sizing: border-box;
|
|
1635
1633
|
gap: 2px;
|
|
@@ -1702,8 +1700,8 @@ html[data-xiaohei-sidebar-resizing] #dsh-theme-xiaohei\\/sidebar-glass {
|
|
|
1702
1700
|
backdrop-filter: none;
|
|
1703
1701
|
}
|
|
1704
1702
|
|
|
1705
|
-
#root [data-slot='sidebar'] > div:
|
|
1706
|
-
#root [data-slot='sidebar'] > div:
|
|
1703
|
+
#root [data-slot='sidebar'] > div:has(button:is([aria-label='Collapse sidebar'], [aria-label='\u6536\u8D77\u4FA7\u8FB9\u680F'])) > button[aria-label='\u65B0\u5EFA\u4F1A\u8BDD'],
|
|
1704
|
+
#root [data-slot='sidebar'] > div:has(button:is([aria-label='Collapse sidebar'], [aria-label='\u6536\u8D77\u4FA7\u8FB9\u680F'])) > button[aria-label='New session'] {
|
|
1707
1705
|
border-color: ButtonText;
|
|
1708
1706
|
}
|
|
1709
1707
|
|
|
@@ -1727,13 +1725,13 @@ html {
|
|
|
1727
1725
|
--xiaohei-sidebar-emphasis: #E1E6E7;
|
|
1728
1726
|
--xiaohei-sidebar-icon: rgb(220 227 229 / 70%);
|
|
1729
1727
|
--xiaohei-sidebar-hover: rgb(231 238 240 / 6.5%);
|
|
1730
|
-
--xiaohei-sidebar-glass-fill: rgb(18 22 25 /
|
|
1728
|
+
--xiaohei-sidebar-glass-fill: rgb(18 22 25 / 25%);
|
|
1731
1729
|
--xiaohei-sidebar-glass-solid: #1B2023;
|
|
1732
1730
|
--xiaohei-sidebar-glass-edge: rgb(255 255 255 / 8%);
|
|
1733
1731
|
--xiaohei-sidebar-glass-highlight: rgb(255 255 255 / 13%);
|
|
1734
1732
|
--xiaohei-sidebar-glass-refraction: rgb(255 255 255 / 18%);
|
|
1735
1733
|
--xiaohei-sidebar-glass-saturation: 102%;
|
|
1736
|
-
--xiaohei-sidebar-glass-blur:
|
|
1734
|
+
--xiaohei-sidebar-glass-blur: 12px;
|
|
1737
1735
|
--xiaohei-sidebar-glass-radius: 18px;
|
|
1738
1736
|
--xiaohei-sidebar-control: rgb(231 238 240 / 7%);
|
|
1739
1737
|
--xiaohei-sidebar-control-edge: rgb(231 238 240 / 8%);
|
|
@@ -1841,13 +1839,13 @@ html[data-xiaohei-appearance='light'] {
|
|
|
1841
1839
|
--xiaohei-sidebar-emphasis: #3F454C;
|
|
1842
1840
|
--xiaohei-sidebar-icon: rgb(48 54 61 / 68%);
|
|
1843
1841
|
--xiaohei-sidebar-hover: rgb(48 54 61 / 6%);
|
|
1844
|
-
--xiaohei-sidebar-glass-fill: rgb(247 245 242 /
|
|
1842
|
+
--xiaohei-sidebar-glass-fill: rgb(247 245 242 / 30%);
|
|
1845
1843
|
--xiaohei-sidebar-glass-solid: #EDF1F3;
|
|
1846
1844
|
--xiaohei-sidebar-glass-edge: rgb(37 45 51 / 9%);
|
|
1847
1845
|
--xiaohei-sidebar-glass-highlight: rgb(255 255 255 / 64%);
|
|
1848
1846
|
--xiaohei-sidebar-glass-refraction: rgb(255 255 255 / 18%);
|
|
1849
1847
|
--xiaohei-sidebar-glass-saturation: 102%;
|
|
1850
|
-
--xiaohei-sidebar-glass-blur:
|
|
1848
|
+
--xiaohei-sidebar-glass-blur: 12px;
|
|
1851
1849
|
--xiaohei-sidebar-control: rgb(255 255 255 / 30%);
|
|
1852
1850
|
--xiaohei-sidebar-control-edge: rgb(46 51 58 / 8%);
|
|
1853
1851
|
--xiaohei-sidebar-control-edge-hover: rgb(46 51 58 / 13%);
|
|
@@ -3421,7 +3419,13 @@ function createSidebarReveal(doc) {
|
|
|
3421
3419
|
let observer;
|
|
3422
3420
|
let phase = "", width = 0, waiting = false;
|
|
3423
3421
|
const attribute = "data-xiaohei-sidebar-reveal";
|
|
3424
|
-
const readPhase = () =>
|
|
3422
|
+
const readPhase = () => {
|
|
3423
|
+
const state = shell?.closest("[data-sidebar-collapsed]")?.getAttribute("data-sidebar-collapsed");
|
|
3424
|
+
if (state === "true") return "rail";
|
|
3425
|
+
if (state === "false") return "wide";
|
|
3426
|
+
if (shell?.querySelector("button[aria-label='Collapse sidebar'], button[aria-label='\u6536\u8D77\u4FA7\u8FB9\u680F']")) return "wide";
|
|
3427
|
+
return "rail";
|
|
3428
|
+
};
|
|
3425
3429
|
const apply3 = () => {
|
|
3426
3430
|
if (!shell) return;
|
|
3427
3431
|
const target = Number.parseFloat(shell.style.width);
|
|
@@ -3447,7 +3451,7 @@ function createSidebarReveal(doc) {
|
|
|
3447
3451
|
phase = readPhase();
|
|
3448
3452
|
if (!shell) return;
|
|
3449
3453
|
observer = new doc.defaultView.MutationObserver(changed);
|
|
3450
|
-
observer.observe(
|
|
3454
|
+
observer.observe(column, { subtree: true, childList: true, attributes: true, attributeFilter: ["data-sidebar-collapsed", "aria-label", "style"] });
|
|
3451
3455
|
apply3();
|
|
3452
3456
|
},
|
|
3453
3457
|
resize(nextWidth) {
|
|
@@ -3719,8 +3723,9 @@ var CHARACTER_MOTION = { "peek": { "light": { "layers": { "ear0": { "box": [17.5
|
|
|
3719
3723
|
|
|
3720
3724
|
// src/scene/character-motion-clock.ts
|
|
3721
3725
|
function createCharacterMotionClock(clock, changed, random = Math.random) {
|
|
3722
|
-
let timer, disposed = false,
|
|
3726
|
+
let timer, disposed = false, active = "";
|
|
3723
3727
|
let clips;
|
|
3728
|
+
let blinksSinceEar = 0, nextEar = 0;
|
|
3724
3729
|
const clear = () => {
|
|
3725
3730
|
if (timer !== void 0) clock.clearTimeout(timer);
|
|
3726
3731
|
timer = void 0;
|
|
@@ -3745,7 +3750,7 @@ function createCharacterMotionClock(clock, changed, random = Math.random) {
|
|
|
3745
3750
|
rest();
|
|
3746
3751
|
return;
|
|
3747
3752
|
}
|
|
3748
|
-
timer = clock.setTimeout(step, 1e3 /
|
|
3753
|
+
timer = clock.setTimeout(step, 1e3 / 60);
|
|
3749
3754
|
};
|
|
3750
3755
|
step();
|
|
3751
3756
|
}
|
|
@@ -3753,7 +3758,11 @@ function createCharacterMotionClock(clock, changed, random = Math.random) {
|
|
|
3753
3758
|
timer = void 0;
|
|
3754
3759
|
if (!clips || disposed) return;
|
|
3755
3760
|
const gestures = Object.keys(clips).filter((name) => name !== "blink" && name !== "attention");
|
|
3756
|
-
|
|
3761
|
+
const ears = gestures.filter((name) => name.startsWith("ear"));
|
|
3762
|
+
const action = ears.length && blinksSinceEar >= 2 ? ears[nextEar++ % ears.length] : random() < 0.72 && clips.blink || !gestures.length ? "blink" : gestures[Math.floor(random() * gestures.length)];
|
|
3763
|
+
if (action.startsWith("ear")) blinksSinceEar = 0;
|
|
3764
|
+
else blinksSinceEar++;
|
|
3765
|
+
play(action);
|
|
3757
3766
|
}
|
|
3758
3767
|
return {
|
|
3759
3768
|
setClips(next) {
|
|
@@ -3761,6 +3770,8 @@ function createCharacterMotionClock(clock, changed, random = Math.random) {
|
|
|
3761
3770
|
clear();
|
|
3762
3771
|
clips = next;
|
|
3763
3772
|
active = "";
|
|
3773
|
+
blinksSinceEar = 0;
|
|
3774
|
+
nextEar = 0;
|
|
3764
3775
|
changed(void 0, 0);
|
|
3765
3776
|
if (clips) timer = clock.setTimeout(start, 1200 + random() * 800);
|
|
3766
3777
|
},
|
|
@@ -3776,6 +3787,206 @@ function createCharacterMotionClock(clock, changed, random = Math.random) {
|
|
|
3776
3787
|
};
|
|
3777
3788
|
}
|
|
3778
3789
|
|
|
3790
|
+
// src/scene/character-expression.ts
|
|
3791
|
+
var smooth = (t) => {
|
|
3792
|
+
const x = Math.max(0, Math.min(1, t));
|
|
3793
|
+
return x * x * (3 - 2 * x);
|
|
3794
|
+
};
|
|
3795
|
+
function blinkClosure(progress) {
|
|
3796
|
+
if (progress <= 0 || progress >= 1) return 0;
|
|
3797
|
+
if (progress < 0.3) return smooth(progress / 0.3);
|
|
3798
|
+
if (progress < 0.4) return 1;
|
|
3799
|
+
return 1 - smooth((progress - 0.4) / 0.6);
|
|
3800
|
+
}
|
|
3801
|
+
function attentionBlink(progress) {
|
|
3802
|
+
return blinkClosure((progress - 0.12) / 0.16);
|
|
3803
|
+
}
|
|
3804
|
+
|
|
3805
|
+
// src/scene/character-eye-rig.ts
|
|
3806
|
+
var EYE_RIGS = {
|
|
3807
|
+
seated: [
|
|
3808
|
+
{ left: [285, 223], right: [326, 224], upper: [302, 188], lower: [310, 276], iris: [309, 230, 13, 20, 0], skin: [315, 258] },
|
|
3809
|
+
{ left: [373, 221], right: [421, 226], upper: [387, 186], lower: [393, 277], iris: [393, 228, 15, 22, 0], skin: [391, 261] }
|
|
3810
|
+
],
|
|
3811
|
+
peek: [
|
|
3812
|
+
{ left: [80, 214], right: [119, 221], upper: [103, 186], lower: [91, 267], iris: [102, 225, 14, 20, 0.25], skin: [110, 253] },
|
|
3813
|
+
{ left: [171, 252], right: [210, 265], upper: [195, 221], lower: [175, 300], iris: [186, 260, 15, 20, 0.4], skin: [186, 288] }
|
|
3814
|
+
],
|
|
3815
|
+
chin: [
|
|
3816
|
+
{ left: [252, 252], right: [290, 247], upper: [266, 223], lower: [287, 297], iris: [278, 258, 14, 19, -0.3], skin: [291, 285] },
|
|
3817
|
+
{ left: [339, 234], right: [387, 227], upper: [358, 196], lower: [365, 280], iris: [361, 235, 15, 21, -0.25], skin: [367, 269] }
|
|
3818
|
+
],
|
|
3819
|
+
halfpeek: [
|
|
3820
|
+
{ left: [89, 390], right: [159, 395], upper: [116, 337], lower: [110, 471], iris: [116, 401, 23, 30, 0.22], skin: [117, 445] }
|
|
3821
|
+
]
|
|
3822
|
+
};
|
|
3823
|
+
function clampGaze(x, y) {
|
|
3824
|
+
if (!Number.isFinite(x) || !Number.isFinite(y)) return [0, 0];
|
|
3825
|
+
const length = Math.max(1, Math.hypot(x, y));
|
|
3826
|
+
return [x / length, y / length];
|
|
3827
|
+
}
|
|
3828
|
+
function eyelidControls(eye2, closure) {
|
|
3829
|
+
const t = Math.max(0, Math.min(1, closure));
|
|
3830
|
+
const cornerY = (eye2.left[1] + eye2.right[1]) / 2;
|
|
3831
|
+
const drop = (eye2.lower[1] - cornerY) * 0.24;
|
|
3832
|
+
const middle = [(eye2.left[0] + eye2.right[0]) / 2, cornerY + drop + (eye2.right[0] - eye2.left[0]) * 0.18];
|
|
3833
|
+
const lerp2 = (p) => [p[0] + (middle[0] - p[0]) * t, p[1] + (middle[1] - p[1]) * t];
|
|
3834
|
+
return { upper: lerp2(eye2.upper), lower: lerp2(eye2.lower), left: [eye2.left[0], eye2.left[1] + drop * t], right: [eye2.right[0], eye2.right[1] + drop * t] };
|
|
3835
|
+
}
|
|
3836
|
+
|
|
3837
|
+
// src/scene/character-eye-material.ts
|
|
3838
|
+
function lidY(eye2, control, x) {
|
|
3839
|
+
let low = 0, high = 1;
|
|
3840
|
+
for (let i = 0; i < 14; i++) {
|
|
3841
|
+
const t2 = (low + high) / 2, s2 = 1 - t2;
|
|
3842
|
+
if (s2 * s2 * eye2.left[0] + 2 * s2 * t2 * control[0] + t2 * t2 * eye2.right[0] < x) low = t2;
|
|
3843
|
+
else high = t2;
|
|
3844
|
+
}
|
|
3845
|
+
const t = (low + high) / 2, s = 1 - t;
|
|
3846
|
+
return s * s * eye2.left[1] + 2 * s * t * control[1] + t * t * eye2.right[1];
|
|
3847
|
+
}
|
|
3848
|
+
function prepareEyeMaterial(doc, source, eye2) {
|
|
3849
|
+
const left = Math.floor(eye2.left[0] - 9), right = Math.ceil(eye2.right[0] + 9);
|
|
3850
|
+
const top = Math.floor(Math.min(eye2.upper[1], eye2.left[1], eye2.right[1]) - 5);
|
|
3851
|
+
const bottom = Math.ceil(Math.max(eye2.lower[1], eye2.left[1], eye2.right[1]) + 5);
|
|
3852
|
+
const width = right - left, height = bottom - top;
|
|
3853
|
+
const canvas = () => {
|
|
3854
|
+
const c = doc.createElement("canvas");
|
|
3855
|
+
c.width = width;
|
|
3856
|
+
c.height = height;
|
|
3857
|
+
return c;
|
|
3858
|
+
};
|
|
3859
|
+
const ink = canvas(), skin = canvas(), mask = canvas();
|
|
3860
|
+
const ic = ink.getContext("2d"), sc = skin.getContext("2d"), mc = mask.getContext("2d");
|
|
3861
|
+
const pixels = source.getImageData(0, 0, source.canvas.width, source.canvas.height);
|
|
3862
|
+
const pixel = (x, y) => {
|
|
3863
|
+
const offset = (Math.max(0, Math.min(pixels.height - 1, Math.round(y / 2))) * pixels.width + Math.max(0, Math.min(pixels.width - 1, Math.round(x / 2)))) * 4;
|
|
3864
|
+
return [pixels.data[offset], pixels.data[offset + 1], pixels.data[offset + 2]];
|
|
3865
|
+
};
|
|
3866
|
+
const ref = pixel(...eye2.skin), output = ic.createImageData(width, height), plate = sc.createImageData(width, height);
|
|
3867
|
+
const isSkin = (c) => c.every((v, i) => Math.abs(v - ref[i]) < 25);
|
|
3868
|
+
const skinAt = (x, y, c) => {
|
|
3869
|
+
if (isSkin(c)) return c;
|
|
3870
|
+
const sum = [ref[0] * 0.05, ref[1] * 0.05, ref[2] * 0.05];
|
|
3871
|
+
let weight = 0.05;
|
|
3872
|
+
for (const radius of [6, 12, 20, 30]) for (let i = 0; i < 8; i++) {
|
|
3873
|
+
const p = pixel(x + Math.cos(i * Math.PI / 4) * radius, y + Math.sin(i * Math.PI / 4) * radius);
|
|
3874
|
+
if (!isSkin(p)) continue;
|
|
3875
|
+
const w = 1 / radius;
|
|
3876
|
+
weight += w;
|
|
3877
|
+
for (let k = 0; k < 3; k++) sum[k] += p[k] * w;
|
|
3878
|
+
}
|
|
3879
|
+
return sum.map((v) => Math.round(v / weight));
|
|
3880
|
+
};
|
|
3881
|
+
for (let x = 0; x < width; x++) {
|
|
3882
|
+
const ax = left + x, upper = lidY(eye2, eye2.upper, ax);
|
|
3883
|
+
for (let y = 0; y < height; y++) {
|
|
3884
|
+
const ay = top + y, c = pixel(ax, ay), index = (y * width + x) * 4;
|
|
3885
|
+
const darkness = 1 - (c[0] + c[1] + c[2]) / Math.max(1, ref[0] + ref[1] + ref[2]);
|
|
3886
|
+
const green = c[1] > c[0] * 1.15 && c[1] > c[2] * 1.12;
|
|
3887
|
+
const inBand = ay >= upper - 12 && ay <= upper + 3;
|
|
3888
|
+
const alpha = inBand && !green ? Math.max(0, Math.min(1, (darkness - 0.3) / 0.35)) : 0;
|
|
3889
|
+
output.data.set([...c, Math.round(alpha * 255)], index);
|
|
3890
|
+
plate.data.set([...skinAt(ax, ay, c), 255], index);
|
|
3891
|
+
}
|
|
3892
|
+
}
|
|
3893
|
+
ic.putImageData(output, 0, 0);
|
|
3894
|
+
sc.putImageData(plate, 0, 0);
|
|
3895
|
+
const inkMask = mc.createImageData(width, height);
|
|
3896
|
+
for (let i = 0; i < output.data.length; i += 4) inkMask.data[i + 3] = output.data[i + 3] > 4 ? 255 : 0;
|
|
3897
|
+
mc.putImageData(inkMask, 0, 0);
|
|
3898
|
+
const expanded = canvas(), ec = expanded.getContext("2d");
|
|
3899
|
+
for (const [dx, dy] of [[0, 0], [-1, 0], [1, 0], [0, -1], [0, 1]]) ec.drawImage(mask, dx, dy);
|
|
3900
|
+
mc.drawImage(expanded, 0, 0);
|
|
3901
|
+
mc.translate(-left, -top);
|
|
3902
|
+
mc.beginPath();
|
|
3903
|
+
mc.moveTo(eye2.left[0] - 7, eye2.left[1]);
|
|
3904
|
+
mc.quadraticCurveTo(eye2.upper[0], eye2.upper[1] - 4, eye2.right[0] + 7, eye2.right[1]);
|
|
3905
|
+
mc.quadraticCurveTo(eye2.lower[0], eye2.lower[1] + 20, eye2.left[0] - 7, eye2.left[1]);
|
|
3906
|
+
mc.closePath();
|
|
3907
|
+
mc.fill();
|
|
3908
|
+
sc.globalCompositeOperation = "destination-in";
|
|
3909
|
+
sc.filter = "blur(0.65px)";
|
|
3910
|
+
sc.drawImage(mask, 0, 0);
|
|
3911
|
+
sc.filter = "none";
|
|
3912
|
+
return { ink, skin, left, top, width, height };
|
|
3913
|
+
}
|
|
3914
|
+
|
|
3915
|
+
// src/scene/character-eye-renderer.ts
|
|
3916
|
+
function createEyeRenderer(ctx, body, eyes) {
|
|
3917
|
+
const doc = ctx.canvas.ownerDocument;
|
|
3918
|
+
const source = doc.createElement("canvas");
|
|
3919
|
+
source.width = body.width;
|
|
3920
|
+
source.height = body.height;
|
|
3921
|
+
const sample = source.getContext("2d", { willReadFrequently: true });
|
|
3922
|
+
sample.drawImage(body, 0, 0);
|
|
3923
|
+
const color = (p) => {
|
|
3924
|
+
const data = sample.getImageData(Math.round(p[0] / 2), Math.round(p[1] / 2), 1, 1).data;
|
|
3925
|
+
return [data[0], data[1], data[2]];
|
|
3926
|
+
};
|
|
3927
|
+
const rgb = (c) => `rgb(${c.map((v) => Math.round(v)).join(" ")})`;
|
|
3928
|
+
const prepared = eyes.map((eye2) => {
|
|
3929
|
+
const [cx, cy, rx, ry, angle] = eye2.iris;
|
|
3930
|
+
const iris = doc.createElement("canvas");
|
|
3931
|
+
iris.width = Math.ceil(rx * 2 + 4);
|
|
3932
|
+
iris.height = Math.ceil(ry * 2 + 4);
|
|
3933
|
+
const ic = iris.getContext("2d");
|
|
3934
|
+
ic.translate(iris.width / 2, iris.height / 2);
|
|
3935
|
+
ic.rotate(angle);
|
|
3936
|
+
ic.beginPath();
|
|
3937
|
+
ic.ellipse(0, 0, rx, ry, 0, 0, Math.PI * 2);
|
|
3938
|
+
ic.clip();
|
|
3939
|
+
ic.rotate(-angle);
|
|
3940
|
+
ic.drawImage(body, 0, 0, body.width, body.height, -cx, -cy, body.width * 2, body.height * 2);
|
|
3941
|
+
return { eye: eye2, iris, skin: color(eye2.skin), material: prepareEyeMaterial(doc, sample, eye2) };
|
|
3942
|
+
});
|
|
3943
|
+
function aperture(eye2, closure) {
|
|
3944
|
+
const { upper, lower, left, right } = eyelidControls(eye2, closure);
|
|
3945
|
+
ctx.beginPath();
|
|
3946
|
+
ctx.moveTo(...left);
|
|
3947
|
+
ctx.quadraticCurveTo(...upper, ...right);
|
|
3948
|
+
ctx.quadraticCurveTo(...lower, ...left);
|
|
3949
|
+
ctx.closePath();
|
|
3950
|
+
}
|
|
3951
|
+
return (gaze, closure) => {
|
|
3952
|
+
const [gx, gy] = clampGaze(...gaze);
|
|
3953
|
+
ctx.save();
|
|
3954
|
+
ctx.scale(0.5, 0.5);
|
|
3955
|
+
for (const { eye: eye2, iris, skin, material } of prepared) {
|
|
3956
|
+
const [cx, cy, rx, ry] = eye2.iris;
|
|
3957
|
+
ctx.save();
|
|
3958
|
+
ctx.drawImage(material.skin, material.left, material.top);
|
|
3959
|
+
ctx.save();
|
|
3960
|
+
aperture(eye2, 0);
|
|
3961
|
+
ctx.clip();
|
|
3962
|
+
if (closure < 0.999) {
|
|
3963
|
+
ctx.save();
|
|
3964
|
+
aperture(eye2, closure);
|
|
3965
|
+
ctx.clip();
|
|
3966
|
+
const shade = ctx.createLinearGradient(0, cy - ry, 0, cy + ry);
|
|
3967
|
+
const brightness = (skin[0] + skin[1] + skin[2]) / 765;
|
|
3968
|
+
const white = brightness > 0.65 ? [255, 253, 241] : [166, 185, 193];
|
|
3969
|
+
shade.addColorStop(0, rgb(white.map((c) => c * 0.83)));
|
|
3970
|
+
shade.addColorStop(0.5, rgb(white));
|
|
3971
|
+
ctx.fillStyle = shade;
|
|
3972
|
+
ctx.fillRect(cx - 70, cy - 70, 140, 140);
|
|
3973
|
+
const dx = gx * rx * 0.26, dy = gy * ry * 0.13;
|
|
3974
|
+
ctx.drawImage(iris, cx - iris.width / 2 + dx, cy - iris.height / 2 + dy);
|
|
3975
|
+
ctx.restore();
|
|
3976
|
+
}
|
|
3977
|
+
ctx.restore();
|
|
3978
|
+
const lids = eyelidControls(eye2, closure);
|
|
3979
|
+
for (let x = 0; x < material.width; x++) {
|
|
3980
|
+
const ax = material.left + x;
|
|
3981
|
+
const dy = lidY({ ...eye2, left: lids.left, right: lids.right }, lids.upper, ax) - lidY(eye2, eye2.upper, ax);
|
|
3982
|
+
ctx.drawImage(material.ink, x, 0, 1, material.height, ax, material.top + dy, 1, material.height);
|
|
3983
|
+
}
|
|
3984
|
+
ctx.restore();
|
|
3985
|
+
}
|
|
3986
|
+
ctx.restore();
|
|
3987
|
+
};
|
|
3988
|
+
}
|
|
3989
|
+
|
|
3779
3990
|
// src/scene/character-rig.ts
|
|
3780
3991
|
var TAIL_JOINTS = [
|
|
3781
3992
|
[284, 328],
|
|
@@ -3786,6 +3997,12 @@ var TAIL_JOINTS = [
|
|
|
3786
3997
|
[307, 448],
|
|
3787
3998
|
[319, 464]
|
|
3788
3999
|
];
|
|
4000
|
+
function earOffset(y, top, root, angle) {
|
|
4001
|
+
const span = Math.max(1, root - top);
|
|
4002
|
+
const weight = Math.max(0, Math.min(1, (root - y) / span));
|
|
4003
|
+
if (weight === 0) return 0;
|
|
4004
|
+
return Math.sin(angle) * Math.min(20, span * 0.55) * weight * weight;
|
|
4005
|
+
}
|
|
3789
4006
|
function solveBones(rest, angles) {
|
|
3790
4007
|
return rest.reduce((out, p, i) => {
|
|
3791
4008
|
const parent = out[i - 1];
|
|
@@ -3826,11 +4043,13 @@ function skinVertex(v, joints, rest = TAIL_JOINTS) {
|
|
|
3826
4043
|
function rigAngles(progress, count, tail) {
|
|
3827
4044
|
const t = Math.max(0, Math.min(1, progress));
|
|
3828
4045
|
const envelope = Math.sin(Math.PI * t) ** 2;
|
|
3829
|
-
return Array.from({ length: count }, (_, i) => envelope * (tail ? i ? 0.12 : 0 : 0.
|
|
4046
|
+
return Array.from({ length: count }, (_, i) => envelope * (tail ? i ? 0.12 : 0 : 0.32) * Math.sin(t * Math.PI * (tail ? 3 : 4) - i * (tail ? 0.65 : 1.1)));
|
|
3830
4047
|
}
|
|
3831
4048
|
|
|
3832
4049
|
// src/scene/character-rig-renderer.ts
|
|
3833
|
-
function createRigRenderer(ctx, rig, images) {
|
|
4050
|
+
function createRigRenderer(ctx, rig, images, eyes = []) {
|
|
4051
|
+
const body = images.get(rig.layers.body.src);
|
|
4052
|
+
const drawEyes = body ? createEyeRenderer(ctx, body, eyes) : void 0;
|
|
3834
4053
|
const tail = rig.layers.tail;
|
|
3835
4054
|
const vertices = [], triangles = [];
|
|
3836
4055
|
if (tail) {
|
|
@@ -3884,24 +4103,67 @@ function createRigRenderer(ctx, rig, images) {
|
|
|
3884
4103
|
ctx.restore();
|
|
3885
4104
|
}
|
|
3886
4105
|
}
|
|
3887
|
-
return (action, progress) => {
|
|
4106
|
+
return (action, progress, gaze = [0, 0]) => {
|
|
3888
4107
|
ctx.clearRect(0, 0, rig.size[0], rig.size[1]);
|
|
3889
|
-
const
|
|
3890
|
-
rig.ears.
|
|
3891
|
-
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
4108
|
+
const earProgress = action === "attention" ? Math.max(0, Math.min(1, (progress - 0.03) / 0.65)) : progress;
|
|
4109
|
+
const ears = rigAngles(earProgress, rig.ears.length, false);
|
|
4110
|
+
rig.ears.forEach(([, root], i) => {
|
|
4111
|
+
const part = rig.layers["ear" + i], image = part && images.get(part.src);
|
|
4112
|
+
if (!part || !image) return;
|
|
4113
|
+
const angle = action === "attention" || action === "ear" + i ? ears[i] : 0;
|
|
4114
|
+
if (Math.abs(angle) < 1e-8) {
|
|
4115
|
+
layer("ear" + i);
|
|
4116
|
+
return;
|
|
4117
|
+
}
|
|
4118
|
+
const [x, top, right, bottom] = part.box;
|
|
4119
|
+
for (let row = 0; row < image.height; row++) {
|
|
4120
|
+
const y = top + row * (bottom - top) / image.height;
|
|
4121
|
+
ctx.drawImage(image, 0, row, image.width, 1, x + earOffset(y, top, root, angle), y, right - x, (bottom - top) / image.height);
|
|
4122
|
+
}
|
|
3897
4123
|
});
|
|
3898
4124
|
layer("body");
|
|
3899
|
-
drawTail(action === "
|
|
3900
|
-
|
|
3901
|
-
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
|
|
4125
|
+
drawTail(action === "attention" ? Math.max(0, Math.min(1, (progress - 0.22) / 0.78)) : action === "tail" ? progress : 0);
|
|
4126
|
+
const closure = action === "blink" ? blinkClosure(progress) : action === "attention" ? attentionBlink(progress) : 0;
|
|
4127
|
+
drawEyes?.(gaze, closure);
|
|
4128
|
+
};
|
|
4129
|
+
}
|
|
4130
|
+
|
|
4131
|
+
// src/scene/character-gaze.ts
|
|
4132
|
+
function createCharacterGaze(clock, changed) {
|
|
4133
|
+
let value = [0, 0], target = [0, 0], frame, last = 0, disposed = false;
|
|
4134
|
+
function step(now) {
|
|
4135
|
+
frame = void 0;
|
|
4136
|
+
if (disposed) return;
|
|
4137
|
+
const dt = Math.min(64, Math.max(0, now - last));
|
|
4138
|
+
last = now;
|
|
4139
|
+
const amount = 1 - Math.exp(-dt / 95);
|
|
4140
|
+
value = [value[0] + (target[0] - value[0]) * amount, value[1] + (target[1] - value[1]) * amount];
|
|
4141
|
+
const settled = Math.hypot(value[0] - target[0], value[1] - target[1]) < 1e-3;
|
|
4142
|
+
if (settled) value = target;
|
|
4143
|
+
changed(value);
|
|
4144
|
+
if (!settled) frame = clock.requestAnimationFrame(step);
|
|
4145
|
+
}
|
|
4146
|
+
function stop() {
|
|
4147
|
+
if (frame !== void 0) clock.cancelAnimationFrame(frame);
|
|
4148
|
+
frame = void 0;
|
|
4149
|
+
}
|
|
4150
|
+
return {
|
|
4151
|
+
target(x, y) {
|
|
4152
|
+
if (disposed) return;
|
|
4153
|
+
target = clampGaze(x, y);
|
|
4154
|
+
if (frame === void 0 && Math.hypot(value[0] - target[0], value[1] - target[1]) >= 1e-3) {
|
|
4155
|
+
last = clock.performance.now();
|
|
4156
|
+
frame = clock.requestAnimationFrame(step);
|
|
4157
|
+
}
|
|
4158
|
+
},
|
|
4159
|
+
reset() {
|
|
4160
|
+
stop();
|
|
4161
|
+
target = value = [0, 0];
|
|
4162
|
+
changed(value);
|
|
4163
|
+
},
|
|
4164
|
+
dispose() {
|
|
4165
|
+
disposed = true;
|
|
4166
|
+
stop();
|
|
3905
4167
|
}
|
|
3906
4168
|
};
|
|
3907
4169
|
}
|
|
@@ -3913,6 +4175,23 @@ function createCharacterMotion(doc) {
|
|
|
3913
4175
|
let disposed = false, part, rig;
|
|
3914
4176
|
let canvas, render;
|
|
3915
4177
|
let pose2 = "", appearance = "", revision = 0, nearby = false, lastPointer = 0;
|
|
4178
|
+
let attentionTimer, lastAttention = -Infinity;
|
|
4179
|
+
let gazePoint = [0, 0], activeAction, activeProgress = 0;
|
|
4180
|
+
let bounds;
|
|
4181
|
+
const paint = () => {
|
|
4182
|
+
if (render && part) {
|
|
4183
|
+
render(activeAction, activeProgress, gazePoint);
|
|
4184
|
+
part.dataset.motion = activeAction ?? "rig-rest";
|
|
4185
|
+
}
|
|
4186
|
+
};
|
|
4187
|
+
const gaze = createCharacterGaze(win, (point) => {
|
|
4188
|
+
gazePoint = point;
|
|
4189
|
+
paint();
|
|
4190
|
+
});
|
|
4191
|
+
const cancelAttention = () => {
|
|
4192
|
+
if (attentionTimer !== void 0) win.clearTimeout(attentionTimer);
|
|
4193
|
+
attentionTimer = void 0;
|
|
4194
|
+
};
|
|
3916
4195
|
function decode(src) {
|
|
3917
4196
|
if (loading.has(src)) return loading.get(src);
|
|
3918
4197
|
if (images.has(src)) return Promise.resolve();
|
|
@@ -3927,8 +4206,9 @@ function createCharacterMotion(doc) {
|
|
|
3927
4206
|
}
|
|
3928
4207
|
const clock = createCharacterMotionClock(win, (action, progress) => {
|
|
3929
4208
|
if (!canvas || !part || !render) return;
|
|
3930
|
-
|
|
3931
|
-
|
|
4209
|
+
activeAction = action;
|
|
4210
|
+
activeProgress = progress;
|
|
4211
|
+
paint();
|
|
3932
4212
|
});
|
|
3933
4213
|
function update() {
|
|
3934
4214
|
if (disposed) return;
|
|
@@ -3936,8 +4216,13 @@ function createCharacterMotion(doc) {
|
|
|
3936
4216
|
const moving = doc.documentElement.hasAttribute("data-xiaohei-sidebar-resizing");
|
|
3937
4217
|
const next = !doc.hidden && !reduced.matches && !moving && part ? CHARACTER_MOTION[pose2]?.[mode] : void 0;
|
|
3938
4218
|
if (next === rig && appearance === mode) return;
|
|
3939
|
-
|
|
4219
|
+
cancelAttention();
|
|
3940
4220
|
render = void 0;
|
|
4221
|
+
clock.setClips(void 0);
|
|
4222
|
+
gaze.reset();
|
|
4223
|
+
bounds = void 0;
|
|
4224
|
+
activeAction = void 0;
|
|
4225
|
+
activeProgress = 0;
|
|
3941
4226
|
const current = ++revision;
|
|
3942
4227
|
canvas?.remove();
|
|
3943
4228
|
canvas = void 0;
|
|
@@ -3959,9 +4244,9 @@ function createCharacterMotion(doc) {
|
|
|
3959
4244
|
return;
|
|
3960
4245
|
}
|
|
3961
4246
|
currentPart.append(canvas);
|
|
3962
|
-
render = createRigRenderer(ctx, next, images);
|
|
4247
|
+
render = createRigRenderer(ctx, next, images, EYE_RIGS[pose2]);
|
|
3963
4248
|
clock.setClips({
|
|
3964
|
-
blink: { duration:
|
|
4249
|
+
blink: { duration: 280 },
|
|
3965
4250
|
...Object.fromEntries(next.ears.map((_, i) => ["ear" + i, { duration: 1050 }])),
|
|
3966
4251
|
...next.layers.tail ? { tail: { duration: 2400 } } : {},
|
|
3967
4252
|
attention: { duration: 2400 }
|
|
@@ -3971,14 +4256,48 @@ function createCharacterMotion(doc) {
|
|
|
3971
4256
|
const pointer = (event) => {
|
|
3972
4257
|
if (!part || !render || event.pointerType !== "mouse") return;
|
|
3973
4258
|
const now = win.performance.now();
|
|
3974
|
-
if (now - lastPointer
|
|
3975
|
-
|
|
3976
|
-
|
|
4259
|
+
if (!bounds || now - lastPointer >= 100) {
|
|
4260
|
+
bounds = part.getBoundingClientRect();
|
|
4261
|
+
lastPointer = now;
|
|
4262
|
+
}
|
|
4263
|
+
const rect = bounds, eyes = EYE_RIGS[pose2];
|
|
4264
|
+
if (rig && eyes?.length) {
|
|
4265
|
+
const scale = Math.min(rect.width / rig.size[0], rect.height / rig.size[1]);
|
|
4266
|
+
const eyeX = eyes.reduce((sum, eye2) => sum + eye2.iris[0], 0) / eyes.length / 2;
|
|
4267
|
+
const eyeY = eyes.reduce((sum, eye2) => sum + eye2.iris[1], 0) / eyes.length / 2;
|
|
4268
|
+
const cx = rect.left + eyeX * scale;
|
|
4269
|
+
const cy = rect.top + (rect.height - rig.size[1] * scale) / 2 + eyeY * scale;
|
|
4270
|
+
gaze.target((event.clientX - cx) / Math.max(220, win.innerWidth * 0.32), (event.clientY - cy) / Math.max(180, win.innerHeight * 0.32));
|
|
4271
|
+
}
|
|
3977
4272
|
const near = event.clientX >= rect.left - 70 && event.clientX <= rect.right + 70 && event.clientY >= rect.top - 50 && event.clientY <= rect.bottom + 50;
|
|
3978
|
-
if (near
|
|
4273
|
+
if (!near) cancelAttention();
|
|
4274
|
+
if (near && !nearby && now - lastAttention > 6e3) {
|
|
4275
|
+
const current = revision;
|
|
4276
|
+
attentionTimer = win.setTimeout(() => {
|
|
4277
|
+
attentionTimer = void 0;
|
|
4278
|
+
if (!disposed && nearby && current === revision) {
|
|
4279
|
+
lastAttention = win.performance.now();
|
|
4280
|
+
clock.attention();
|
|
4281
|
+
}
|
|
4282
|
+
}, 180);
|
|
4283
|
+
}
|
|
3979
4284
|
nearby = near;
|
|
3980
4285
|
};
|
|
3981
4286
|
reduced.addEventListener("change", update);
|
|
4287
|
+
const neutral = () => {
|
|
4288
|
+
gaze.target(0, 0);
|
|
4289
|
+
nearby = false;
|
|
4290
|
+
cancelAttention();
|
|
4291
|
+
};
|
|
4292
|
+
const leave = (event) => {
|
|
4293
|
+
if (!event.relatedTarget) neutral();
|
|
4294
|
+
};
|
|
4295
|
+
const resize = () => {
|
|
4296
|
+
bounds = void 0;
|
|
4297
|
+
};
|
|
4298
|
+
doc.addEventListener("pointerout", leave);
|
|
4299
|
+
win.addEventListener("blur", neutral);
|
|
4300
|
+
win.addEventListener("resize", resize);
|
|
3982
4301
|
doc.addEventListener("visibilitychange", update);
|
|
3983
4302
|
doc.addEventListener("pointermove", pointer, { passive: true });
|
|
3984
4303
|
const observer = new win.MutationObserver(update);
|
|
@@ -3986,9 +4305,12 @@ function createCharacterMotion(doc) {
|
|
|
3986
4305
|
return {
|
|
3987
4306
|
setPose(nextPart, nextPose) {
|
|
3988
4307
|
if (nextPart !== part || pose2 !== nextPose) {
|
|
4308
|
+
cancelAttention();
|
|
3989
4309
|
revision++;
|
|
3990
|
-
clock.setClips(void 0);
|
|
3991
4310
|
render = void 0;
|
|
4311
|
+
clock.setClips(void 0);
|
|
4312
|
+
gaze.reset();
|
|
4313
|
+
bounds = void 0;
|
|
3992
4314
|
canvas?.remove();
|
|
3993
4315
|
canvas = void 0;
|
|
3994
4316
|
rig = void 0;
|
|
@@ -4000,8 +4322,10 @@ function createCharacterMotion(doc) {
|
|
|
4000
4322
|
},
|
|
4001
4323
|
dispose() {
|
|
4002
4324
|
disposed = true;
|
|
4325
|
+
cancelAttention();
|
|
4003
4326
|
revision++;
|
|
4004
4327
|
clock.dispose();
|
|
4328
|
+
gaze.dispose();
|
|
4005
4329
|
canvas?.remove();
|
|
4006
4330
|
render = void 0;
|
|
4007
4331
|
images.clear();
|
|
@@ -4011,6 +4335,9 @@ function createCharacterMotion(doc) {
|
|
|
4011
4335
|
observer.disconnect();
|
|
4012
4336
|
doc.removeEventListener("visibilitychange", update);
|
|
4013
4337
|
doc.removeEventListener("pointermove", pointer);
|
|
4338
|
+
doc.removeEventListener("pointerout", leave);
|
|
4339
|
+
win.removeEventListener("blur", neutral);
|
|
4340
|
+
win.removeEventListener("resize", resize);
|
|
4014
4341
|
}
|
|
4015
4342
|
};
|
|
4016
4343
|
}
|
|
@@ -5862,7 +6189,7 @@ var HEIXIU_FACE = {
|
|
|
5862
6189
|
var HEIXIU_FOOT = Math.max(...HEIXIU_PROFILE.map((r, i) => r * Math.sin(i / HEIXIU_PROFILE.length * Math.PI * 2))) * 100;
|
|
5863
6190
|
var HEIXIU_REST = { x: 0, y: 0, sx: 1, sy: 1, roll: 0, lid: 1, cheer: 0 };
|
|
5864
6191
|
var HEIXIU_REACTIONS = ["greet", "hop", "wiggle"];
|
|
5865
|
-
var
|
|
6192
|
+
var smooth2 = (x) => {
|
|
5866
6193
|
const k = Math.max(0, Math.min(1, x));
|
|
5867
6194
|
return k * k * (3 - 2 * k);
|
|
5868
6195
|
};
|
|
@@ -5898,7 +6225,7 @@ var HeixiuReactions = class {
|
|
|
5898
6225
|
this.aim(0, time);
|
|
5899
6226
|
}
|
|
5900
6227
|
aim(direction, time) {
|
|
5901
|
-
this.hover = this.hoverFrom + (this.hoverTo - this.hoverFrom) *
|
|
6228
|
+
this.hover = this.hoverFrom + (this.hoverTo - this.hoverFrom) * smooth2((time - this.hoverAt) / 0.28);
|
|
5902
6229
|
this.hoverFrom = this.hover;
|
|
5903
6230
|
this.hoverTo = Math.max(-1, Math.min(1, direction));
|
|
5904
6231
|
this.hoverAt = time;
|
|
@@ -5954,7 +6281,7 @@ var HeixiuReactions = class {
|
|
|
5954
6281
|
}
|
|
5955
6282
|
sample(time) {
|
|
5956
6283
|
const out = this.track(time);
|
|
5957
|
-
this.hover = this.hoverFrom + (this.hoverTo - this.hoverFrom) *
|
|
6284
|
+
this.hover = this.hoverFrom + (this.hoverTo - this.hoverFrom) * smooth2((time - this.hoverAt) / 0.28);
|
|
5958
6285
|
out.roll += this.hover * 5;
|
|
5959
6286
|
out.x += this.hover * 4;
|
|
5960
6287
|
return out;
|
|
@@ -7247,6 +7574,7 @@ function XiaoheiMetallicBrandMark({ size, className }) {
|
|
|
7247
7574
|
{
|
|
7248
7575
|
className: className === void 0 ? "xiaohei-brand-mark" : `${className} xiaohei-brand-mark`,
|
|
7249
7576
|
"data-brand-context": context,
|
|
7577
|
+
"data-xiaohei-sidebar-brand": context === "sidebar" ? "" : void 0,
|
|
7250
7578
|
"data-metallic-ready": ready || snapshot !== void 0 ? "true" : "false",
|
|
7251
7579
|
style: geometry,
|
|
7252
7580
|
"aria-hidden": "true",
|
|
@@ -7258,7 +7586,7 @@ function XiaoheiMetallicBrandMark({ size, className }) {
|
|
|
7258
7586
|
);
|
|
7259
7587
|
}
|
|
7260
7588
|
function XiaoheiBrandName() {
|
|
7261
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "xiaohei-brand-name", children: "\u7F57\u5C0F\u9ED1 \xB7 \u5996\u7075\u4F1A\u9986" });
|
|
7589
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "xiaohei-brand-name", "data-xiaohei-sidebar-brand": "", children: "\u7F57\u5C0F\u9ED1 \xB7 \u5996\u7075\u4F1A\u9986" });
|
|
7262
7590
|
}
|
|
7263
7591
|
|
|
7264
7592
|
// src/plugin.ts
|