diff --git a/blog/hami-core-adopted-by-nvidia-kai-scheduler/index.md b/blog/hami-core-adopted-by-nvidia-kai-scheduler/index.md
index 0079bcf90..b2699cae6 100644
--- a/blog/hami-core-adopted-by-nvidia-kai-scheduler/index.md
+++ b/blog/hami-core-adopted-by-nvidia-kai-scheduler/index.md
@@ -68,12 +68,10 @@ graph TD
POD --> SCHED --> INJECT --> WEBHOOK --> CONTAINER --> ENFORCE
DAEMON -. "loads libvgpu.so" .-> CONTAINER
- style SCHED fill:#d9f99d,stroke:#4f7d00,stroke-width:2px,color:#1f2937
- style INJECT fill:#d9f99d,stroke:#4f7d00,stroke-width:2px,color:#1f2937
- style WEBHOOK fill:#dbeafe,stroke:#1a5fb4,stroke-width:2px,color:#1f2937
- style DAEMON fill:#dbeafe,stroke:#1a5fb4,stroke-width:2px,color:#1f2937
- style CONTAINER fill:#fef3c7,stroke:#b45309,stroke-width:2px,color:#1f2937
- style ENFORCE fill:#dcfce7,stroke:#0b6b3c,stroke-width:2px,color:#1f2937
+ class SCHED,INJECT kai
+ class WEBHOOK,DAEMON info
+ class CONTAINER run
+ class ENFORCE ok
```
The workflow has four phases:
@@ -93,8 +91,8 @@ graph TD
B2 --> B3["Cannot oversubscribe
hard isolation"]
A3 ~~~ B1
- style A3 fill:#fee2e2,stroke:#b3261e,stroke-width:2px,color:#1f2937
- style B3 fill:#dcfce7,stroke:#0b6b3c,stroke-width:2px,color:#1f2937
+ class A3 bad
+ class B3 ok
```
### Deploy
@@ -200,8 +198,8 @@ graph TD
HAMI --> Kueue
HAMI --> Koordinator
- style HAMI fill:#dbeafe,stroke:#1a5fb4,stroke-width:2px,color:#1f2937
- style KAI fill:#d9f99d,stroke:#4f7d00,stroke-width:2px,color:#1f2937
+ class HAMI info
+ class KAI accent
```
### It creates real value for users
diff --git a/blog/kai-scheduler-hami-gpu-memory-hard-isolation/index.md b/blog/kai-scheduler-hami-gpu-memory-hard-isolation/index.md
index 62b1b04f3..766cd8828 100644
--- a/blog/kai-scheduler-hami-gpu-memory-hard-isolation/index.md
+++ b/blog/kai-scheduler-hami-gpu-memory-hard-isolation/index.md
@@ -41,12 +41,10 @@ graph TD
LIB -. "provides libvgpu.so" .-> RUN
RUN -. "writes node-local cache" .-> MON
- style KAI fill:#d9f99d,stroke:#4f7d00,stroke-width:2px,color:#1f2937
- style WEBHOOK fill:#dbeafe,stroke:#1a5fb4,stroke-width:2px,color:#1f2937
- style LIB fill:#dbeafe,stroke:#1a5fb4,stroke-width:2px,color:#1f2937
- style RUN fill:#fef3c7,stroke:#b45309,stroke-width:2px,color:#1f2937
- style ENF fill:#dcfce7,stroke:#0b6b3c,stroke-width:2px,color:#1f2937
- style MON fill:#dbeafe,stroke:#1a5fb4,stroke-width:2px,color:#1f2937
+ class KAI accent
+ class WEBHOOK,LIB,MON info
+ class RUN run
+ class ENF ok
```
`CUDA_DEVICE_MEMORY_LIMIT` is the contract between scheduling and enforcement. KAI does not need to know how CUDA calls are intercepted, and HAMi-core does not need to know how the quota was calculated. KAI retains its own scheduling logic; it integrates with HAMi-core rather than replacing its scheduler with the full HAMi platform.
diff --git a/blog/volcano-ascend-vnpu-soft-slicing/index.md b/blog/volcano-ascend-vnpu-soft-slicing/index.md
index e786b57b2..961eadf03 100644
--- a/blog/volcano-ascend-vnpu-soft-slicing/index.md
+++ b/blog/volcano-ascend-vnpu-soft-slicing/index.md
@@ -124,10 +124,10 @@ graph TD
VOL --> SCHD --> HOOK --> ENF
HOOK -. "shared-memory accounting" .-> MON
- style VOL fill:#d9f99d,stroke:#4f7d00,stroke-width:2px,color:#1f2937
- style HOOK fill:#fef3c7,stroke:#b45309,stroke-width:2px,color:#1f2937
- style ENF fill:#dcfce7,stroke:#0b6b3c,stroke-width:2px,color:#1f2937
- style MON fill:#dbeafe,stroke:#1a5fb4,stroke-width:2px,color:#1f2937
+ class VOL accent
+ class HOOK run
+ class ENF ok
+ class MON info
```
The Pod contract is minimal: `schedulerName: volcano`, `runtimeClassName: ascend`, the annotation `huawei.com/vnpu-mode: hami-core`, and limits on the two extended resources. Without the annotation, the Pod falls back to the template-based path and can stay Pending on a soft-slicing node.
diff --git a/docusaurus.config.js b/docusaurus.config.js
index 11f4414e3..0fe3227aa 100644
--- a/docusaurus.config.js
+++ b/docusaurus.config.js
@@ -290,6 +290,9 @@ module.exports = {
defaultMode: "dark",
respectPrefersColorScheme: false,
},
+ mermaid: {
+ theme: { light: "default", dark: "dark" },
+ },
announcementBar,
navbar: {
title: "HAMi",
diff --git a/i18n/zh/docusaurus-plugin-content-blog/hami-core-adopted-by-nvidia-kai-scheduler/index.md b/i18n/zh/docusaurus-plugin-content-blog/hami-core-adopted-by-nvidia-kai-scheduler/index.md
index da06580dc..b9d026f46 100644
--- a/i18n/zh/docusaurus-plugin-content-blog/hami-core-adopted-by-nvidia-kai-scheduler/index.md
+++ b/i18n/zh/docusaurus-plugin-content-blog/hami-core-adopted-by-nvidia-kai-scheduler/index.md
@@ -67,12 +67,10 @@ graph TD
POD --> SCHED --> INJECT --> WEBHOOK --> CONTAINER --> ENFORCE
DAEMON -. "加载 libvgpu.so" .-> CONTAINER
- style SCHED fill:#d9f99d,stroke:#4f7d00,stroke-width:2px,color:#1f2937
- style INJECT fill:#d9f99d,stroke:#4f7d00,stroke-width:2px,color:#1f2937
- style WEBHOOK fill:#dbeafe,stroke:#1a5fb4,stroke-width:2px,color:#1f2937
- style DAEMON fill:#dbeafe,stroke:#1a5fb4,stroke-width:2px,color:#1f2937
- style CONTAINER fill:#fef3c7,stroke:#b45309,stroke-width:2px,color:#1f2937
- style ENFORCE fill:#dcfce7,stroke:#0b6b3c,stroke-width:2px,color:#1f2937
+ class SCHED,INJECT kai
+ class WEBHOOK,DAEMON info
+ class CONTAINER run
+ class ENFORCE ok
```
工作流程分为四个阶段:
@@ -92,8 +90,8 @@ graph TD
B2 --> B3["无法超额
硬隔离"]
A3 ~~~ B1
- style A3 fill:#fee2e2,stroke:#b3261e,stroke-width:2px,color:#1f2937
- style B3 fill:#dcfce7,stroke:#0b6b3c,stroke-width:2px,color:#1f2937
+ class A3 bad
+ class B3 ok
```
### 部署方式
@@ -199,8 +197,8 @@ graph TD
HAMI --> Kueue
HAMI --> Koordinator
- style HAMI fill:#dbeafe,stroke:#1a5fb4,stroke-width:2px,color:#1f2937
- style KAI fill:#d9f99d,stroke:#4f7d00,stroke-width:2px,color:#1f2937
+ class HAMI info
+ class KAI accent
```
### 为用户创造实际价值
diff --git a/i18n/zh/docusaurus-plugin-content-blog/kai-scheduler-hami-gpu-memory-hard-isolation/index.md b/i18n/zh/docusaurus-plugin-content-blog/kai-scheduler-hami-gpu-memory-hard-isolation/index.md
index 35d4ec23e..8d53815b6 100644
--- a/i18n/zh/docusaurus-plugin-content-blog/kai-scheduler-hami-gpu-memory-hard-isolation/index.md
+++ b/i18n/zh/docusaurus-plugin-content-blog/kai-scheduler-hami-gpu-memory-hard-isolation/index.md
@@ -41,12 +41,10 @@ graph TD
LIB -. "提供 libvgpu.so" .-> RUN
RUN -. "写入节点本地缓存" .-> MON
- style KAI fill:#d9f99d,stroke:#4f7d00,stroke-width:2px,color:#1f2937
- style WEBHOOK fill:#dbeafe,stroke:#1a5fb4,stroke-width:2px,color:#1f2937
- style LIB fill:#dbeafe,stroke:#1a5fb4,stroke-width:2px,color:#1f2937
- style RUN fill:#fef3c7,stroke:#b45309,stroke-width:2px,color:#1f2937
- style ENF fill:#dcfce7,stroke:#0b6b3c,stroke-width:2px,color:#1f2937
- style MON fill:#dbeafe,stroke:#1a5fb4,stroke-width:2px,color:#1f2937
+ class KAI accent
+ class WEBHOOK,LIB,MON info
+ class RUN run
+ class ENF ok
```
`CUDA_DEVICE_MEMORY_LIMIT` 是调度层与隔离层之间的契约。KAI 不需要知道 CUDA 调用如何被拦截,HAMi-core 也不需要知道配额如何计算。KAI 保留自己的调度逻辑;它集成的是 HAMi-core,而不是用完整的 HAMi 平台替换自身调度器。
diff --git a/i18n/zh/docusaurus-plugin-content-blog/volcano-ascend-vnpu-soft-slicing/index.md b/i18n/zh/docusaurus-plugin-content-blog/volcano-ascend-vnpu-soft-slicing/index.md
index 9e191ff25..11c88b99c 100644
--- a/i18n/zh/docusaurus-plugin-content-blog/volcano-ascend-vnpu-soft-slicing/index.md
+++ b/i18n/zh/docusaurus-plugin-content-blog/volcano-ascend-vnpu-soft-slicing/index.md
@@ -124,10 +124,10 @@ graph TD
VOL --> SCHD --> HOOK --> ENF
HOOK -. "共享内存记账" .-> MON
- style VOL fill:#d9f99d,stroke:#4f7d00,stroke-width:2px,color:#1f2937
- style HOOK fill:#fef3c7,stroke:#b45309,stroke-width:2px,color:#1f2937
- style ENF fill:#dcfce7,stroke:#0b6b3c,stroke-width:2px,color:#1f2937
- style MON fill:#dbeafe,stroke:#1a5fb4,stroke-width:2px,color:#1f2937
+ class VOL accent
+ class HOOK run
+ class ENF ok
+ class MON info
```
Pod 侧的契约很简洁:`schedulerName: volcano`、`runtimeClassName: ascend`、注解 `huawei.com/vnpu-mode: hami-core`,以及对两个扩展资源的 limits。少了这个注解,Pod 会退回模板路径,在纯软切分节点上可能一直 Pending。
diff --git a/src/css/custom.css b/src/css/custom.css
index d1a1ad269..1406a7c5d 100644
--- a/src/css/custom.css
+++ b/src/css/custom.css
@@ -145,6 +145,23 @@
rgba(241, 246, 250, 0.95)
);
--hami-diagram-outcome-bg: rgba(255, 255, 255, 0.62);
+
+ /* mermaid class roles: accent, info, run, ok, bad */
+ --hami-mermaid-accent-fill: #d9f99d;
+ --hami-mermaid-accent-stroke: #4f7d00;
+ --hami-mermaid-accent-text: #1f2937;
+ --hami-mermaid-info-fill: #dbeafe;
+ --hami-mermaid-info-stroke: #1a5fb4;
+ --hami-mermaid-info-text: #1f2937;
+ --hami-mermaid-run-fill: #fef3c7;
+ --hami-mermaid-run-stroke: #b45309;
+ --hami-mermaid-run-text: #1f2937;
+ --hami-mermaid-ok-fill: #dcfce7;
+ --hami-mermaid-ok-stroke: #0b6b3c;
+ --hami-mermaid-ok-text: #1f2937;
+ --hami-mermaid-bad-fill: #fee2e2;
+ --hami-mermaid-bad-stroke: #b3261e;
+ --hami-mermaid-bad-text: #1f2937;
}
:root[data-theme="dark"] {
@@ -247,6 +264,22 @@
);
--hami-diagram-outcome-bg: rgba(255, 255, 255, 0.04);
+ --hami-mermaid-accent-fill: #365314;
+ --hami-mermaid-accent-stroke: #a3e635;
+ --hami-mermaid-accent-text: #ecfccb;
+ --hami-mermaid-info-fill: #1e3a5f;
+ --hami-mermaid-info-stroke: #60a5fa;
+ --hami-mermaid-info-text: #dbeafe;
+ --hami-mermaid-run-fill: #78350f;
+ --hami-mermaid-run-stroke: #fbbf24;
+ --hami-mermaid-run-text: #fef3c7;
+ --hami-mermaid-ok-fill: #14532d;
+ --hami-mermaid-ok-stroke: #4ade80;
+ --hami-mermaid-ok-text: #dcfce7;
+ --hami-mermaid-bad-fill: #7f1d1d;
+ --hami-mermaid-bad-stroke: #f87171;
+ --hami-mermaid-bad-text: #fee2e2;
+
--ifm-navbar-search-input-icon: url("data:image/svg+xml;utf8,");
}
@@ -408,17 +441,17 @@ body.hami-lightbox-open {
align-items: center;
justify-content: center;
overflow: hidden;
- background: #ffffff;
+ background: var(--ifm-background-color);
border-radius: 12px;
box-shadow: 0 18px 48px rgba(0, 0, 0, 0.45);
padding: 16px;
cursor: zoom-out;
}
-/* Mermaid renders a dark-theme variant in dark mode (light text, dark
- fills), so the zoom card must follow the color mode or contrast breaks. */
-html[data-theme="dark"] .hami-lightbox__svg {
- background: var(--ifm-background-surface-color);
+.hami-lightbox__svg .docusaurus-mermaid-container {
+ width: 100%;
+ height: 100%;
+ cursor: zoom-out;
}
.docusaurus-mermaid-container {
@@ -426,6 +459,78 @@ html[data-theme="dark"] .hami-lightbox__svg {
text-align: center;
}
+.docusaurus-mermaid-container svg {
+ background: transparent !important;
+}
+
+/* mermaid leaves subgraph titles / edge labels dark even on the dark theme */
+.docusaurus-mermaid-container .cluster-label,
+.docusaurus-mermaid-container .cluster-label span,
+.docusaurus-mermaid-container .cluster span,
+.docusaurus-mermaid-container .edgeLabel,
+.docusaurus-mermaid-container .edgeLabel span,
+.docusaurus-mermaid-container .edgeLabel p {
+ color: var(--ifm-font-color-base) !important;
+}
+
+.docusaurus-mermaid-container .cluster-label text,
+.docusaurus-mermaid-container .edgeLabel text {
+ fill: var(--ifm-font-color-base) !important;
+}
+
+.docusaurus-mermaid-container .edgeLabel,
+.docusaurus-mermaid-container .edgeLabel p,
+.docusaurus-mermaid-container .labelBkg {
+ background-color: var(--ifm-background-color) !important;
+}
+
+.docusaurus-mermaid-container .edgeLabel rect {
+ background-color: var(--ifm-background-color) !important;
+ fill: var(--ifm-background-color) !important;
+}
+
+.docusaurus-mermaid-container .accent {
+ --hami-mermaid-node-fill: var(--hami-mermaid-accent-fill);
+ --hami-mermaid-node-stroke: var(--hami-mermaid-accent-stroke);
+ --hami-mermaid-node-text: var(--hami-mermaid-accent-text);
+}
+
+.docusaurus-mermaid-container .info {
+ --hami-mermaid-node-fill: var(--hami-mermaid-info-fill);
+ --hami-mermaid-node-stroke: var(--hami-mermaid-info-stroke);
+ --hami-mermaid-node-text: var(--hami-mermaid-info-text);
+}
+
+.docusaurus-mermaid-container .run {
+ --hami-mermaid-node-fill: var(--hami-mermaid-run-fill);
+ --hami-mermaid-node-stroke: var(--hami-mermaid-run-stroke);
+ --hami-mermaid-node-text: var(--hami-mermaid-run-text);
+}
+
+.docusaurus-mermaid-container .ok {
+ --hami-mermaid-node-fill: var(--hami-mermaid-ok-fill);
+ --hami-mermaid-node-stroke: var(--hami-mermaid-ok-stroke);
+ --hami-mermaid-node-text: var(--hami-mermaid-ok-text);
+}
+
+.docusaurus-mermaid-container .bad {
+ --hami-mermaid-node-fill: var(--hami-mermaid-bad-fill);
+ --hami-mermaid-node-stroke: var(--hami-mermaid-bad-stroke);
+ --hami-mermaid-node-text: var(--hami-mermaid-bad-text);
+}
+
+.docusaurus-mermaid-container
+ :is(.accent, .info, .run, .ok, .bad)
+ > :is(rect, polygon, circle, ellipse, path) {
+ fill: var(--hami-mermaid-node-fill) !important;
+ stroke: var(--hami-mermaid-node-stroke) !important;
+ stroke-width: 2px !important;
+}
+
+.docusaurus-mermaid-container :is(.accent, .info, .run, .ok, .bad) :is(.nodeLabel, span) {
+ color: var(--hami-mermaid-node-text) !important;
+}
+
.mermaid-figure {
margin: 0 0 1.5rem;
text-align: center;
diff --git a/src/theme/utils/useImageLightbox.js b/src/theme/utils/useImageLightbox.js
index 46646c155..e72d05eef 100644
--- a/src/theme/utils/useImageLightbox.js
+++ b/src/theme/utils/useImageLightbox.js
@@ -116,13 +116,21 @@ function ensureLightbox() {
const clone = svg.cloneNode(true);
// Mermaid caps the inline SVG at its rendered size; lift the cap and let
// it scale to fit the lightbox box in both dimensions (the viewBox keeps
- // the aspect ratio), so the whole diagram is visible without scrolling.
+ // the aspect ratio), so the whole diagram is always visible without scrolling.
clone.style.maxWidth = "none";
clone.style.width = "100%";
clone.style.height = "100%";
clone.removeAttribute("height");
clone.removeAttribute("width");
- svgHost.replaceChildren(clone);
+
+ // Node colors are CSS under .docusaurus-mermaid-container. Keep the clone
+ // in that same host so the zoomed view matches the page.
+ const wrap = document.createElement("div");
+ const source = svg.closest(MERMAID_CONTAINER);
+ wrap.className = source?.className || "docusaurus-mermaid-container";
+ wrap.appendChild(clone);
+
+ svgHost.replaceChildren(wrap);
svgHost.hidden = false;
lightboxImage.hidden = true;
lightboxImage.removeAttribute("src");