docs(readme): redesign project landing page

Add project-native hero and runtime flow visuals with responsive SVG layouts and decorative motion.

Expand setup, integration, architecture, contribution, and licensing guidance for current releases.
This commit is contained in:
DrSmoothl
2026-07-14 21:29:34 +08:00
parent f9d251d1fa
commit be05d47dd4
3 changed files with 417 additions and 35 deletions
+127 -35
View File
@@ -1,61 +1,153 @@
<h1 align="center">
<img src=".github/logo.svg" width="100%" alt="SnowLuma" />
</h1>
<p align="center">
<i>Next Remote Protocol Framework.</i>
<img src="./assets/readme/hero.svg" width="100%" alt="SnowLuma 将 QQ 原生会话桥接到 OneBot、WebUI 与自动化工具" />
</p>
<p align="center">
<a href="https://github.com/SnowLuma/SnowLuma/releases"><img alt="Release" src="https://img.shields.io/github/v/release/SnowLuma/SnowLuma?label=release&style=flat-square"></a>
<a href="https://github.com/SnowLuma/SnowLuma/actions"><img alt="Build" src="https://img.shields.io/github/actions/workflow/status/SnowLuma/SnowLuma/release.yml?branch=main&style=flat-square&label=build"></a>
<a href="https://www.npmjs.com/package/@snowluma/sdk"><img alt="NPM" src="https://img.shields.io/npm/v/%40snowluma%2Fsdk?style=flat-square&label=sdk&color=cb3837"></a>
<a href="https://github.com/SnowLuma/SnowLuma/stargazers"><img alt="Stars" src="https://img.shields.io/github/stars/SnowLuma/SnowLuma?style=flat-square"></a>
<a href="https://github.com/SnowLuma/SnowLuma/releases"><img alt="最新版本" src="https://img.shields.io/github/v/release/SnowLuma/SnowLuma?label=release&style=flat-square"></a>
<a href="https://github.com/SnowLuma/SnowLuma/actions"><img alt="构建状态" src="https://img.shields.io/github/actions/workflow/status/SnowLuma/SnowLuma/release.yml?branch=main&style=flat-square&label=build"></a>
<a href="https://www.npmjs.com/package/@snowluma/sdk"><img alt="SnowLuma SDK 版本" src="https://img.shields.io/npm/v/%40snowluma%2Fsdk?style=flat-square&label=sdk&color=287fb8"></a>
<a href="https://www.npmjs.com/package/@snowluma/mcp"><img alt="SnowLuma MCP 版本" src="https://img.shields.io/npm/v/%40snowluma%2Fmcp?style=flat-square&label=mcp&color=7658c7"></a>
<a href="https://github.com/SnowLuma/SnowLuma/stargazers"><img alt="GitHub Stars" src="https://img.shields.io/github/stars/SnowLuma/SnowLuma?style=flat-square"></a>
</p>
<p align="center">
<a href="https://github.com/SnowLuma/SnowLuma/releases">Releases</a> ·
<a href="https://github.com/SnowLuma/SnowLuma/issues">Issues</a> ·
<a href="https://qm.qq.com/q/g3UMLpWALe">QQ 群</a> ·
<a href="https://t.me/napcatqq">Telegram</a>
<a href="#快速开始">快速开始</a> ·
<a href="#运行链路">运行链路</a> ·
<a href="./docs/onebot-actions.md">动作参考</a> ·
<a href="./packages/sdk/README.md">SDK</a> ·
<a href="./packages/mcp/README.md">MCP</a> ·
<a href="https://github.com/SnowLuma/SnowLuma/issues">问题反馈</a>
</p>
---
SnowLuma 是面向 QQ 客户端的 TypeScript 互操作运行时。它把 QQ 原生会话转换为 [OneBot v11](https://github.com/botuniverse/onebot-11) 动作与事件,并通过 WebSocket、HTTP、WebUI、SDK 和 MCP 提供统一入口;每个账号拥有独立会话,适合机器人开发、自动化与协议研究。
SnowLuma 是一个基于 TypeScript 的协议转换框架,旨在为 QQ 客户端提供 [OneBot v11](https://github.com/botuniverse/onebot-11) 标准接口,支持 WebSocket/HTTP 适配、多账号并行及 WebUI 管理。
> ⚠️ **免责声明**:SnowLuma 是独立的第三方互操作项目,**与腾讯 / QQ 无任何隶属或授权关系**。本项目**仅供学习与技术研究**,请遵守《QQ 用户协议》及适用法律;软件按"现状"提供、不附带任何担保,使用风险自负。详见 [`EULA.md`](EULA.md)。
> [!CAUTION]
> **使用边界**:SnowLuma 是独立的第三方互操作项目,**与腾讯 / QQ 无任何隶属或授权关系**。本项目仅供学习与技术研究,请遵守《QQ 用户协议》及适用法律;软件按“现状”提供、不附带任何担保,使用风险自负。详见 [`EULA.md`](EULA.md)。
>
> ⚠️ **Disclaimer**: SnowLuma is an independent, third-party interoperability project with **no affiliation with or endorsement by Tencent / QQ**, provided **for study and research only**, "as is" without warranty. Comply with the QQ User Agreement and applicable law; use at your own risk. See [`EULA.md`](EULA.md).
> **Disclaimer**: SnowLuma is an independent third-party interoperability project with no affiliation with or endorsement by Tencent / QQ. It is provided for study and research only, “as is” and without warranty. See [`EULA.md`](EULA.md).
## 特性
## 运行链路
- **OneBot v11 兼容**:支持文本、音视频、Markdown、JSON 等消息格式。
- **高性能架构**:TypeScript 全栈,基于 pnpm monorepo 管理,核心逻辑分离。
- **现代化管理**:内置 WebUI 面板,支持实时日志、密码热更、多账号管理。
- **多适配器支持**:WebSocket (Server/Client)、HTTP (Server/Post)。
- **数据持久化**:使用 SQLite 存储好友、群组等关系数据。
<p align="center">
<img src="./assets/readme/runtime-map.svg" width="100%" alt="QQ 会话经过协议桥接与 OneBot 标准化后连接到 WebSocket、HTTP、WebUI、SDK 和 MCP" />
</p>
SnowLuma 将会话接入、协议解析、身份映射、OneBot 转换和网络适配拆成清晰边界。多个 QQ 账号可以并行运行,同时保持独立状态、日志与连接配置。
## 核心能力
| 场景 | SnowLuma 提供 |
| --- | --- |
| OneBot 接入 | OneBot v11 动作与事件,支持 WebSocket 服务端 / 客户端及 HTTP 服务端 / 上报 |
| 消息与媒体 | 文本、图片、语音、视频、文件、回复、提及、转发及 JSON / XML 卡片等常见消息元素 |
| 多账号运行 | 每个 QQ 账号独立维护会话、身份映射、消息存储与网络适配器 |
| WebUI 管理 | 账号状态、实时日志、连接配置、动作调试、密码管理与可定制总览 |
| 开发者工具 | 提供 [`@snowluma/sdk`](packages/sdk/README.md) 与 [`@snowluma/mcp`](packages/mcp/README.md) |
| 可观察错误 | 关键解析与执行失败会留下明确上下文,不以静默丢弃掩盖问题 |
## 快速开始
1. 从 [Releases](https://github.com/SnowLuma/SnowLuma/releases) 下载最新发布包并解压。
2. 运行 `./launcher.bat` (Windows) 或 `./launcher.sh` (Linux)。
3. 访问 `http://localhost:5099` (初始账号 `admin`,密码见控制台输出)。
### 1. 选择发行包
无人值守部署可同时设置 `SNOWLUMA_ACCEPT_EULA=1` 与 `SNOWLUMA_ACCEPT_PRIVACY=1` 完成协议确认。两项必须同时设置;移除任意变量后会恢复按当前协议版本检查 WebUI 同意记录。设置这些变量即表示您已阅读并同意 [`EULA.md`](EULA.md) 与 [`PRIVACY.md`](PRIVACY.md)。
前往 [Releases](https://github.com/SnowLuma/SnowLuma/releases) 下载与你的平台匹配的版本:
## 许可 / License
| 平台 | 完整版(内置 Node.js,推荐) | Lite(需要 Node.js 22+) |
| --- | --- | --- |
| Windows x64 | `SnowLuma-vX.Y.Z-win-x64.zip` | `SnowLuma-vX.Y.Z-win-x64-lite.zip` |
| Linux x64 | `SnowLuma-vX.Y.Z-linux-x64.tar.gz` | `SnowLuma-vX.Y.Z-linux-x64-lite.tar.gz` |
| Linux arm64 | `SnowLuma-vX.Y.Z-linux-arm64.tar.gz` | `SnowLuma-vX.Y.Z-linux-arm64-lite.tar.gz` |
SnowLuma 采用 **源码可见非商业许可(SnowLuma Source-Available Non-Commercial License)**,见 [`LICENSE`](LICENSE)。**这不是 OSI 开源许可**:源码公开供查看、学习与非商业自托管,但**禁止任何商业使用**(出售、转售、付费托管 / 代搭 / 代运营等),公开发布修改版须事先书面授权。随附的原生附加组件(`snowluma-*.node` 等)为专有组件,不在本许可范围内。二进制发行包另受 [`EULA.md`](EULA.md) 约束;商业授权请联系 motricseven@foxmail.com。参与贡献请阅读 [`CONTRIBUTING.md`](CONTRIBUTING.md)。
完整版适合直接解压运行;Lite 版只移除了内置 Node.js,其余运行时依赖与 WebUI 静态资源保持一致。
SnowLuma is under a **source-available, non-commercial** license (see [`LICENSE`](LICENSE)) — **NOT** an OSI open-source license. The source is published for study and non-commercial self-hosting; **commercial use is prohibited** without prior written permission, and the bundled native addon (`snowluma-*.node`) is proprietary and not covered by this license.
### 2. 启动 SnowLuma
Windows 运行 `launcher.bat`。Linux 在解压目录执行:
```bash
chmod +x launcher.sh
./launcher.sh
```
### 3. 打开 WebUI
浏览器访问 [`http://localhost:5099`](http://localhost:5099)。初始账号为 `admin`,随机密码会显示在启动日志中;登录后即可接入已启动的 QQ 进程并配置 OneBot 连接。
<details>
<summary><strong>无人值守部署:通过环境变量确认协议</strong></summary>
同时设置以下两个变量可跳过 WebUI 的协议确认页面:
```bash
SNOWLUMA_ACCEPT_EULA=1
SNOWLUMA_ACCEPT_PRIVACY=1
```
两项必须同时设置,且环境变量确认不会写入持久化同意记录。设置变量即表示运营者已阅读并同意 [`EULA.md`](EULA.md) 与 [`PRIVACY.md`](PRIVACY.md)。
</details>
## 选择接入方式
| 入口 | 适合场景 | 参考 |
| --- | --- | --- |
| WebSocket / HTTP | 对接现有 OneBot 机器人框架 | [OneBot 动作参考](docs/onebot-actions.md) |
| TypeScript SDK | 编写类型安全的客户端与消息逻辑 | [`packages/sdk`](packages/sdk/README.md) |
| MCP | 让支持 MCP 的工具查询或调用 SnowLuma 动作 | [`packages/mcp`](packages/mcp/README.md) |
| WebUI | 管理运行状态、日志、账号与连接 | 启动后访问 `http://localhost:5099` |
## 开发与贡献
本地开发需要 Node.js 22+ 与项目锁定版本的 pnpm。所有日常开发基于 `dev` 分支:
```bash
git clone https://github.com/SnowLuma/SnowLuma.git
cd SnowLuma
git checkout dev
pnpm install
pnpm typecheck
pnpm test
```
- 先读 [`CONTEXT.md`](CONTEXT.md) 了解模块边界与项目词汇。
- 提交代码前阅读 [`CONTRIBUTING.md`](CONTRIBUTING.md) 与 [`CODE_OF_CONDUCT.md`](CODE_OF_CONDUCT.md)。
- 开发方向与已完成事项见 [`RoadMap.md`](RoadMap.md)。
<details>
<summary><strong>主要目录</strong></summary>
| 路径 | 作用 |
| --- | --- |
| `packages/protocol` | QQ 协议定义、数据包解析、消息推送与 OIDB 服务 |
| `packages/onebot` | OneBot 动作执行、事件转换与网络适配 |
| `packages/core` | 运行时编排、QQ 会话桥接与 WebUI 服务端 |
| `packages/webui` | React 管理界面 |
| `packages/sdk` | 对外发布的 TypeScript SDK |
| `packages/mcp` | 面向 MCP 客户端的动作目录与执行入口 |
</details>
## 使用边界与许可
> [!IMPORTANT]
> SnowLuma 使用 **源码可见非商业许可**,**不是 OSI 开源许可**。源码可用于查看、学习、非商业自托管及私下修改;任何商业使用,以及公开发布修改版或衍生版,均需事先取得书面授权。
- 完整条款见 [`LICENSE`](LICENSE)。
- 随附的原生附加组件为专有组件,不在源码许可范围内。
- 二进制发行包另受 [`EULA.md`](EULA.md) 与 [`PRIVACY.md`](PRIVACY.md) 约束。
- 商业授权请联系 `motricseven@foxmail.com`。
SnowLuma is source-available for study and non-commercial self-hosting, but it is **not OSI open source**. Commercial use and public distribution of modified or derivative versions require prior written permission. Bundled native components are proprietary and excluded from the source license.
## 社区与支持
- [提交问题](https://github.com/SnowLuma/SnowLuma/issues)
- [QQ 群](https://qm.qq.com/q/g3UMLpWALe)
- [Telegram](https://t.me/napcatqq)
## 鸣谢
参考了 [LagrangeV2](https://github.com/LagrangeDev/LagrangeV2) 的协议定义与 [NapCatQQ](https://github.com/NapNeko/NapCatQQ) 的实现思路。
---
项目参考了 [LagrangeV2](https://github.com/LagrangeDev/LagrangeV2) 的协议定义与 [NapCatQQ](https://github.com/NapNeko/NapCatQQ) 的实现思路。
<p align="center">
<a href="https://github.com/SnowLuma/SnowLuma/graphs/contributors"><img src="https://contrib.rocks/image?repo=SnowLuma/SnowLuma" /></a>
<a href="https://github.com/SnowLuma/SnowLuma/graphs/contributors"><img src="https://contrib.rocks/image?repo=SnowLuma/SnowLuma" alt="SnowLuma 贡献者" /></a>
</p>
+150
View File
@@ -0,0 +1,150 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="400" viewBox="0 0 1200 400" role="img" aria-labelledby="hero-title hero-desc">
<title id="hero-title">SnowLuma — QQ 到 OneBot 的现代协议桥</title>
<desc id="hero-desc">SnowLuma 将多个 QQ 原生会话经过协议、桥接与 OneBot 三层处理,连接到 WebSocket、HTTP、WebUI、SDK 与 MCP。</desc>
<defs>
<linearGradient id="hero-bg" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" stop-color="#08111f"/>
<stop offset="0.58" stop-color="#101b31"/>
<stop offset="1" stop-color="#17223d"/>
</linearGradient>
<linearGradient id="brand-line" x1="0" y1="0" x2="1" y2="0">
<stop offset="0" stop-color="#75d2ff"/>
<stop offset="0.55" stop-color="#bba7ff"/>
<stop offset="1" stop-color="#f4bfd9"/>
</linearGradient>
<linearGradient id="bridge-fill" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" stop-color="#192c4e"/>
<stop offset="1" stop-color="#2a2550"/>
</linearGradient>
<filter id="soft-glow" x="-40%" y="-40%" width="180%" height="180%">
<feGaussianBlur stdDeviation="16"/>
</filter>
<style>
.sans { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif; }
.mono { font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace; }
.hero-star { animation: hero-star-float 4s ease-in-out infinite; }
.hero-star-main { transform-origin: 16px 14px; }
.hero-star-secondary { transform-origin: 38px 38px; animation-delay: 0.5s; }
@keyframes hero-star-float {
0% { transform: translateY(0) rotate(0deg); opacity: 0.9; }
50% { transform: translateY(-8px) rotate(10deg); opacity: 1; }
100% { transform: translateY(0) rotate(0deg); opacity: 0.9; }
}
@media (prefers-reduced-motion: reduce) { .hero-star { animation: none; } }
</style>
</defs>
<rect width="1200" height="400" rx="28" fill="url(#hero-bg)"/>
<circle cx="1112" cy="28" r="138" fill="#63c9f6" opacity="0.08" filter="url(#soft-glow)"/>
<circle cx="705" cy="392" r="120" fill="#b59cff" opacity="0.06" filter="url(#soft-glow)"/>
<g aria-hidden="true" fill="none" stroke-linecap="round">
<path d="M694 28H1154" stroke="#5f7192" stroke-opacity="0.28"/>
<path d="M694 372H1154" stroke="#5f7192" stroke-opacity="0.2"/>
<path d="M708 14V386" stroke="#5f7192" stroke-opacity="0.16"/>
<path d="M1140 14V386" stroke="#5f7192" stroke-opacity="0.16"/>
</g>
<g id="title-block" transform="translate(64 54)">
<text class="mono" x="0" y="0" fill="#8da1c0" font-size="14" letter-spacing="2.2">QQ INTEROPERABILITY · ONEBOT V11 · MULTI-ACCOUNT</text>
<text class="sans" x="0" y="92" font-size="74" font-weight="760" letter-spacing="-3">
<tspan fill="#f7fbff">Snow</tspan><tspan fill="#82d7ff">Luma</tspan>
</text>
<rect x="2" y="110" width="148" height="5" rx="2.5" fill="url(#brand-line)"/>
<text class="sans" x="0" y="162" fill="#dce7f7" font-size="27" font-weight="590">把 QQ 原生会话,稳定地桥接到</text>
<text class="sans" x="0" y="199" fill="#dce7f7" font-size="27" font-weight="590">OneBot、WebUI 与自动化工具。</text>
<text class="sans" x="0" y="244" fill="#92a6c5" font-size="16">一个运行时,管理多账号、动作调用、事件分发与实时状态。</text>
<g transform="translate(0 274)">
<rect width="128" height="34" rx="17" fill="#172942" stroke="#315173"/>
<circle cx="18" cy="17" r="4" fill="#75d2ff"/>
<text class="mono" x="31" y="22" fill="#b9dfff" font-size="13">Windows x64</text>
<g transform="translate(140 0)">
<rect width="174" height="34" rx="17" fill="#211f41" stroke="#4d4777"/>
<circle cx="18" cy="17" r="4" fill="#bba7ff"/>
<text class="mono" x="31" y="22" fill="#d8cdfd" font-size="13">Linux x64 / arm64</text>
</g>
<g transform="translate(326 0)">
<rect width="120" height="34" rx="17" fill="#302037" stroke="#68435c"/>
<circle cx="18" cy="17" r="4" fill="#f4bfd9"/>
<text class="mono" x="31" y="22" fill="#f7d7e6" font-size="13">TypeScript</text>
</g>
</g>
</g>
<g id="project-proof" transform="translate(734 58)">
<text class="mono" x="0" y="0" fill="#8398b8" font-size="13" letter-spacing="1.8">LIVE SESSION ROUTING</text>
<g transform="translate(0 24)">
<g>
<rect width="116" height="45" rx="12" fill="#12253d" stroke="#2d5274"/>
<circle cx="19" cy="17" r="5" fill="#74d2ff"/>
<text class="mono" x="31" y="21" fill="#c7e9fb" font-size="12">QQ · 01</text>
<text class="mono" x="16" y="36" fill="#7189a9" font-size="10">ONLINE</text>
</g>
<g transform="translate(132 0)">
<rect width="116" height="45" rx="12" fill="#1b2342" stroke="#4a4c78"/>
<circle cx="19" cy="17" r="5" fill="#bba7ff"/>
<text class="mono" x="31" y="21" fill="#ddd4ff" font-size="12">QQ · 02</text>
<text class="mono" x="16" y="36" fill="#8186ad" font-size="10">ONLINE</text>
</g>
<g transform="translate(264 0)">
<rect width="116" height="45" rx="12" fill="#292039" stroke="#67445d"/>
<circle cx="19" cy="17" r="5" fill="#f4bfd9"/>
<text class="mono" x="31" y="21" fill="#f8dbea" font-size="12">QQ · N</text>
<text class="mono" x="16" y="36" fill="#a17f95" font-size="10">READY</text>
</g>
</g>
<g aria-hidden="true" fill="none" stroke="url(#brand-line)" stroke-width="2" stroke-linecap="round" opacity="0.85">
<path d="M58 69V90C58 102 78 104 94 104H190"/>
<path d="M190 69V104"/>
<path d="M322 69V90C322 102 302 104 286 104H190"/>
</g>
<g transform="translate(0 104)">
<rect x="12" y="16" width="356" height="88" rx="18" fill="#0d1729" stroke="#263853" opacity="0.72"/>
<rect x="6" y="8" width="368" height="88" rx="18" fill="#111f35" stroke="#364865" opacity="0.88"/>
<rect width="380" height="88" rx="18" fill="url(#bridge-fill)" stroke="#6684ae" stroke-opacity="0.74"/>
<text class="mono" x="22" y="25" fill="#90a6c6" font-size="11" letter-spacing="1.4">SNOWLUMA RUNTIME</text>
<text class="sans" x="22" y="53" fill="#f4f8ff" font-size="20" font-weight="680">Protocol → Bridge → OneBot</text>
<text class="sans" x="22" y="74" fill="#93a8c7" font-size="13">独立会话 · 类型化动作 · 可追踪事件</text>
<g transform="translate(326 13)" aria-hidden="true">
<path class="hero-star hero-star-main" d="M16 0L19.5 10.5L30 14L19.5 17.5L16 28L12.5 17.5L2 14L12.5 10.5Z" fill="#c8b7ff"/>
<path class="hero-star hero-star-secondary" d="M38 30L40 36L46 38L40 40L38 46L36 40L30 38L36 36Z" fill="#f2c2da" opacity="0.9"/>
</g>
</g>
<g aria-hidden="true" fill="none" stroke="#6881a4" stroke-width="1.5" stroke-linecap="round">
<path d="M58 208V224"/>
<path d="M190 208V224"/>
<path d="M322 208V224"/>
</g>
<g transform="translate(0 224)">
<g>
<rect width="116" height="68" rx="15" fill="#10253b" stroke="#315d7c"/>
<text class="sans" x="58" y="29" fill="#bfe8fb" text-anchor="middle" font-size="15" font-weight="650">OneBot v11</text>
<text class="mono" x="58" y="50" fill="#6685a3" text-anchor="middle" font-size="10">ACTIONS · EVENTS</text>
</g>
<g transform="translate(132 0)">
<rect width="116" height="68" rx="15" fill="#201f42" stroke="#504d7a"/>
<text class="sans" x="58" y="29" fill="#ded5ff" text-anchor="middle" font-size="15" font-weight="650">WebUI</text>
<text class="mono" x="58" y="50" fill="#8483ad" text-anchor="middle" font-size="10">STATUS · LOGS</text>
</g>
<g transform="translate(264 0)">
<rect width="116" height="68" rx="15" fill="#2a2038" stroke="#65455e"/>
<text class="sans" x="58" y="29" fill="#f6d6e6" text-anchor="middle" font-size="15" font-weight="650">SDK / MCP</text>
<text class="mono" x="58" y="50" fill="#9d7e93" text-anchor="middle" font-size="10">TOOLS · STREAMS</text>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.0 KiB

+140
View File
@@ -0,0 +1,140 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="440" viewBox="0 0 1200 440" role="img" aria-labelledby="map-title map-desc">
<title id="map-title">SnowLuma 运行链路</title>
<desc id="map-desc">QQ 进程接入后,数据经过协议桥接、OneBot 标准化,再分发到 WebSocket、HTTP、WebUI、SDK 与 MCP。</desc>
<defs>
<linearGradient id="map-rule" x1="0" y1="0" x2="1" y2="0">
<stop offset="0" stop-color="#54bde9"/>
<stop offset="0.55" stop-color="#9e88ef"/>
<stop offset="1" stop-color="#e4a8c6"/>
</linearGradient>
<linearGradient id="consumer-border" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" stop-color="#54bde9"/>
<stop offset="0.5" stop-color="#9e88ef"/>
<stop offset="1" stop-color="#e4a8c6"/>
</linearGradient>
<linearGradient id="consumer-flow" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" stop-color="#a5e7ff"/>
<stop offset="0.5" stop-color="#d1c5ff"/>
<stop offset="1" stop-color="#ffd4e8"/>
</linearGradient>
<style>
.sans { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif; }
.mono { font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace; }
@media (prefers-reduced-motion: reduce) { .consumer-flow { display: none; } }
</style>
</defs>
<rect width="1200" height="440" rx="28" fill="#f6f9fd"/>
<rect x="0.75" y="0.75" width="1198.5" height="438.5" rx="27.25" fill="none" stroke="#cbd8e8" stroke-width="1.5"/>
<g transform="translate(54 42)">
<text class="mono" x="0" y="0" fill="#6e819b" font-size="13" letter-spacing="2">RUNTIME MAP · FROM SESSION TO CONSUMER</text>
<text class="sans" x="0" y="45" fill="#14223a" font-size="34" font-weight="720">一条事件如何穿过 SnowLuma</text>
<text class="sans" x="0" y="75" fill="#63758e" font-size="16">每层只承担一种职责,多个 QQ 账号各自拥有独立、可追踪的会话链路。</text>
</g>
<g id="connection-labels" class="mono" fill="#7c8ca2" font-size="10" letter-spacing="1.5" text-anchor="middle">
<text x="305" y="210">PIPE</text>
<text x="577" y="210">MAP</text>
<text x="849" y="210">OUT</text>
</g>
<g aria-hidden="true" fill="none" stroke="url(#map-rule)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M284 225H316L309 218M316 225L309 232"/>
<path d="M556 225H588L581 218M588 225L581 232"/>
<path d="M828 225H860L853 218M860 225L853 232"/>
</g>
<g id="stage-session" transform="translate(54 138)">
<rect width="230" height="218" rx="20" fill="#ffffff" stroke="#c9d8e8" stroke-width="1.5"/>
<path d="M20 0H210" fill="none" stroke="#54bde9" stroke-width="4" stroke-linecap="round"/>
<text class="mono" x="20" y="32" fill="#5582a0" font-size="11" letter-spacing="1.4">01 · 会话接入</text>
<g transform="translate(20 48)">
<rect width="190" height="54" rx="13" fill="#edf8fd" stroke="#afd9eb"/>
<circle cx="25" cy="19" r="5" fill="#47b7e6"/>
<circle cx="25" cy="35" r="5" fill="#92d8f3"/>
<text class="mono" x="42" y="23" fill="#315a77" font-size="11">QQ · ACCOUNT 01</text>
<text class="mono" x="42" y="39" fill="#6d92a8" font-size="11">QQ · ACCOUNT 02</text>
</g>
<text class="sans" x="115" y="132" fill="#15243a" font-size="20" font-weight="680" text-anchor="middle">多个 QQ 进程</text>
<text class="sans" x="115" y="158" fill="#687c95" font-size="14" text-anchor="middle">独立接入、独立登录状态</text>
<text class="sans" x="115" y="181" fill="#687c95" font-size="14" text-anchor="middle">每个账号单独路由</text>
</g>
<g id="stage-bridge" transform="translate(326 138)">
<rect width="230" height="218" rx="20" fill="#ffffff" stroke="#d0c9ed" stroke-width="1.5"/>
<path d="M20 0H210" fill="none" stroke="#9e88ef" stroke-width="4" stroke-linecap="round"/>
<text class="mono" x="20" y="32" fill="#7163aa" font-size="11" letter-spacing="1.4">02 · 协议桥接</text>
<g transform="translate(20 42)">
<rect x="10" y="14" width="170" height="48" rx="12" fill="#f2effd" stroke="#cfc5f2"/>
<rect x="5" y="7" width="180" height="48" rx="12" fill="#eeeafd" stroke="#c3b7ee"/>
<rect width="190" height="48" rx="12" fill="#e9e3fb" stroke="#b6a7e9"/>
<text class="mono" x="95" y="21" fill="#544584" text-anchor="middle" font-size="11">PACKET → EVENT</text>
<text class="mono" x="95" y="37" fill="#77699c" text-anchor="middle" font-size="10">PROTOCOL · BRIDGE</text>
</g>
<text class="sans" x="115" y="132" fill="#15243a" font-size="20" font-weight="680" text-anchor="middle">解析与身份映射</text>
<text class="sans" x="115" y="158" fill="#687c95" font-size="14" text-anchor="middle">协议数据转换为内部事件</text>
<text class="sans" x="115" y="181" fill="#687c95" font-size="14" text-anchor="middle">异常路径保留可观察信息</text>
</g>
<g id="stage-onebot" transform="translate(598 138)">
<rect width="230" height="218" rx="20" fill="#ffffff" stroke="#d9c8e1" stroke-width="1.5"/>
<path d="M20 0H210" fill="none" stroke="#cf9bc0" stroke-width="4" stroke-linecap="round"/>
<text class="mono" x="20" y="32" fill="#916382" font-size="11" letter-spacing="1.4">03 · 标准化</text>
<g transform="translate(20 49)">
<rect width="190" height="55" rx="13" fill="#faeff6" stroke="#e6bfd5"/>
<text class="sans" x="95" y="25" fill="#753e62" text-anchor="middle" font-size="17" font-weight="700">OneBot v11</text>
<text class="mono" x="95" y="42" fill="#a37792" text-anchor="middle" font-size="10">ACTIONS ↔ EVENTS</text>
</g>
<text class="sans" x="115" y="132" fill="#15243a" font-size="20" font-weight="680" text-anchor="middle">统一动作与事件</text>
<text class="sans" x="115" y="158" fill="#687c95" font-size="14" text-anchor="middle">参数校验、动作执行</text>
<text class="sans" x="115" y="181" fill="#687c95" font-size="14" text-anchor="middle">事件转换与消息存储</text>
</g>
<g id="stage-consumers" transform="translate(870 138)">
<rect x="2" y="2" width="272" height="214" rx="18" fill="#101a2d" stroke="url(#consumer-border)" stroke-width="4"/>
<rect class="consumer-flow" x="2" y="2" width="272" height="214" rx="18" fill="none" stroke="url(#consumer-flow)" stroke-width="5" stroke-linecap="round" stroke-dasharray="108 838" aria-hidden="true">
<animate attributeName="stroke-dashoffset" from="0" to="-946" dur="4.8s" repeatCount="indefinite"/>
</rect>
<text class="mono" x="20" y="32" fill="#91a5c2" font-size="11" letter-spacing="1.4">04 · 消费端</text>
<text class="sans" x="20" y="65" fill="#f2f7ff" font-size="20" font-weight="680">按场景自由组合</text>
<g class="mono" font-size="11" text-anchor="middle">
<g transform="translate(20 84)">
<rect width="70" height="32" rx="10" fill="#17304a" stroke="#315b7a"/>
<text x="35" y="21" fill="#bce8fb">WS</text>
</g>
<g transform="translate(102 84)">
<rect width="70" height="32" rx="10" fill="#242244" stroke="#514e7c"/>
<text x="35" y="21" fill="#ddd5ff">HTTP</text>
</g>
<g transform="translate(184 84)">
<rect width="70" height="32" rx="10" fill="#34233c" stroke="#67465e"/>
<text x="35" y="21" fill="#f6d9e7">WebUI</text>
</g>
<g transform="translate(20 128)">
<rect width="111" height="32" rx="10" fill="#182a43" stroke="#334f70"/>
<text x="55.5" y="21" fill="#c4def5">SDK</text>
</g>
<g transform="translate(143 128)">
<rect width="111" height="32" rx="10" fill="#2b2447" stroke="#554d7e"/>
<text x="55.5" y="21" fill="#dfd7ff">MCP</text>
</g>
</g>
<text class="sans" x="20" y="190" fill="#8196b5" font-size="13">多个适配器可同时启用</text>
</g>
<g transform="translate(54 392)">
<rect width="1092" height="1" fill="#d4dfeb"/>
<circle cx="5" cy="24" r="4" fill="#54bde9"/>
<text class="sans" x="18" y="29" fill="#60738c" font-size="14">一次接入,统一管理运行状态、日志、连接与动作调用。</text>
<text class="mono" x="1092" y="29" fill="#8191a6" text-anchor="end" font-size="11">SNOWLUMA / RUNTIME MAP</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.2 KiB