# XCEngine API Documentation Skill ## 目标 本规范用于维护 `XCEngine` 的唯一正式 API 文档树,并约束后续所有模块级重构的工作方式。 硬性要求: 1. `docs/api/XCEngine/**` 必须与 `engine/include/XCEngine/**` 保持平行。 2. canonical API 文档只保留一套;迁移完成后必须删除旧目录与旧入口。 3. 每个 public header 对应一个独立文档目录,每个类型页都使用 `{TypeName}/{TypeName}.md`。 4. 方法页优先使用源码中的原始函数名;不要改成 kebab-case、全小写或其它再命名形式。 5. API 文档必须以源码、实现、测试和真实调用点为依据,禁止只根据名字猜测行为。 ## Canonical 目录结构 ```text docs/api/ ├── main.md ├── XCEngine/ │ ├── XCEngine.md │ ├── Debug/ │ │ ├── Debug.md │ │ ├── Logger/ │ │ │ ├── Logger.md │ │ │ ├── Get.md │ │ │ ├── Initialize.md │ │ │ └── Log.md │ │ └── RenderDocCapture/ │ │ ├── RenderDocCapture.md │ │ └── BeginCapture.md │ └── ... ├── _guides/ │ └── Debug/ └── _meta/ ``` 说明: - `docs/api/XCEngine/**` 是唯一 canonical API 树。 - `docs/api/_guides/**` 用于概念、教程、设计理念和工作流说明,不是第二套 API 树。 - `README.md` 不用于 canonical 模块索引页;模块索引页统一使用 `{DirName}.md`。 ## 强制命名规则 ### 1. 目录索引页 - 根索引页:`docs/api/XCEngine/XCEngine.md` - 模块索引页:`docs/api/XCEngine/{ModuleName}/{ModuleName}.md` - 子模块索引页:`docs/api/XCEngine/{ModuleName}/{SubmoduleName}/{SubmoduleName}.md` 示例: - `docs/api/XCEngine/Debug/Debug.md` - `docs/api/XCEngine/Core/Core.md` - `docs/api/XCEngine/RHI/D3D12/D3D12.md` ### 2. 类型目录 - 每个 public header 对应一个独立文件夹。 - 文件夹名必须与 header stem 或主要类型名一致。 - 保留源码中的大小写,不做风格改写。 示例: - `docs/api/XCEngine/Debug/Logger/` - `docs/api/XCEngine/Core/Asset/ResourceManager/` - `docs/api/XCEngine/RHI/D3D12/D3D12Device/` ### 3. 类型总览页 - 固定为 `{TypeName}/{TypeName}.md` - 不允许把类型总览页直接平铺在模块目录中 ### 4. 方法详情页 - 方法页放在所属类型目录内。 - 文件名优先使用原函数名。 - 重载共享同一页,在页内按签名分节说明。 示例: - `Get.md` - `Initialize.md` - `SetCaptureFilePath.md` - `LoadSceneAsync.md` ### 5. 特殊命名 - 构造函数:`Constructor.md` - 析构函数:`Destructor.md` - 运算符使用可读的 PascalCase 名称 建议映射: - `operator=` -> `OperatorAssign.md` - `operator+=` -> `OperatorPlusAssign.md` - `operator[]` -> `OperatorSubscript.md` - `operator()` -> `OperatorCall.md` ## 写作前的取证流程 在编写任何 API 页之前,必须完成下面的最小取证: 1. 阅读对应 public header。 2. 阅读对应 `.cpp` 或内联实现。 3. 搜索测试、示例和真实调用点。 4. 确认生命周期、线程语义、所有权、失败路径和平台限制。 至少回答以下问题后才能落文: - 这个类型解决什么问题,边界在哪里? - 调用前需要什么前置条件? - 调用失败时返回什么,或者会静默失败? - 谁拥有对象,谁负责释放资源? - 多线程下哪些调用安全,哪些只能在初始化阶段使用? - 当前实现是不是完整的?有没有空实现、占位实现或只做轻量封装? 禁止行为: - 只根据 `Get`、`Create`、`Set` 之类的前缀写模板句。 - 把“设计意图”当成“当前实现行为”来写。 - 把测试里假设成立的场景,误写成通用保证。 ## 契约分层规则 文档必须明确区分下面三层信息: ### 1. 接口契约 来自 public header,属于使用者可以依赖的 API 形状。 例如: - 函数签名 - 参数和返回值 - 可见的数据结构 - 明确暴露的枚举值和宏 ### 2. 当前实现行为 来自 `.cpp`、内联实现、测试和调用点,描述当前版本的真实行为。 例如: - 是否自动初始化 - 是否加锁 - 是否会写日志、刷新文件、拉起窗口焦点 - 是否只是 no-op 或 stub 这一层必须使用明确表述,例如: - “当前实现中……” - “按 `engine/src/...` 的实现……” - “当前版本会……” ### 3. 合理推断 只在确实有必要时使用,而且必须标明是推断。 例如: - “从 API 形状看,设计上显然是为后续 Chrome Trace 导出预留扩展点。” 如果不能证明,就不要写。 ## 页面职责 ### 1. 模块页 / 子模块页 负责: - 说明模块职责、边界和典型使用场景 - 列出子目录与 public headers - 给出与相邻模块的关系 - 链接相关 guide 页 不负责: - 展开所有方法细节 - 重复 header 全量声明 ### 2. 类型页 必须包含: - 命名空间 - 类型分类 - 头文件 - 角色概述 - 生命周期 - 线程语义 - 所有权 / 资源管理方式 - 当前实现限制 - 与相关方法页、guide 页的跳转 如果类型是枚举或结构体,还应补充: - 字段或枚举值说明 - 值之间的语义关系 - 典型使用方式 ### 3. 方法页 必须包含: - 准确签名 - 调用目的 - 前置条件 - 参数说明 - 返回值说明 - 副作用 - 线程语义 - 失败路径或 no-op 条件 - 最小可信示例 方法页不能只写“获取对象”“设置状态”这种空描述。 ## 内容深度要求 ### 1. 解释“是什么” 说明类型或方法的职责,而不是简单复述名字。 ### 2. 解释“怎么用” 给出最小可运行或最小可信的使用顺序,让用户知道放在初始化、运行时还是销毁阶段。 ### 3. 解释“为什么这样设计” 结合引擎架构解释: - 为什么做成 singleton、service、interface、sink、builder、handle - 这样做的收益是什么 - 有哪些代价或约束 ### 4. 解释“当前实现做到哪一步” 商业级 API 文档不能假装所有接口都同样成熟。 对于未完成能力,必须明确说明: - 当前是占位接口 - 当前只有基础实现 - 当前只覆盖某个平台 / 某条后端路径 ## 教程与概念页规范 当某个模块仅靠 API 页不足以让用户理解时,应增加 `_guides` 页。 适合写 guide 的内容: - 前置知识 - 架构设计理念 - 推荐工作流 - 和 Unity / Unreal / RenderDoc 等常见工具的概念对照 - 最佳实践与反模式 guide 页不是第二套 API 参考,它们负责回答: - 为什么要这样组织模块 - 用户第一次接触时该从哪里开始 - 这套 API 与常见引擎的对应关系是什么 guide 页应尽量包含: - 问题背景 - 设计目标 - 推荐流程 - 优点与代价 - 与现有 API 页的链接 ## Unity 风格的解释性要求 当模块涉及常见引擎概念时,可以增加 Unity 对照,但必须克制且准确。 推荐写法: - “可以把 `Logger` 理解为比 Unity Console 更底层的日志分发中心。” - “当前 `Profiler` 只覆盖轻量 CPU 埋点,不等同于 Unity Profiler 的完整时间线分析。” - “`RenderDocCapture` 更接近引擎内置的 RenderDoc 工作流桥接,而不是 Unity Frame Debugger 的替代品。” 禁止写法: - “和 Unity 完全一样” - “等价于某商业引擎的完整系统” ## 页面模板 ### 1. 模块页模板 ```markdown # {DirName} **命名空间**: `{Namespace}` **类型**: `module` / `submodule` / `module-root` **描述**: {一句话说明当前目录职责} ## 概述 {解释职责边界、典型场景和相邻模块关系} ## 设计要点 - {要点 1} - {要点 2} ## 头文件 - [TypeA](TypeA/TypeA.md) - `TypeA.h` - [TypeB](TypeB/TypeB.md) - `TypeB.h` ## 相关指南 - [GuideA](../../_guides/.../GuideA.md) ``` ### 2. 类型页模板 ```markdown # {TypeName} **命名空间**: `{Namespace}` **类型**: `class` / `class (abstract)` / `class (singleton)` / `struct` / `enum class` **头文件**: `XCEngine/.../{Header}.h` **描述**: {一句话说明} ## 概述 {说明角色、状态、边界、典型使用方式} ## 生命周期 - {初始化与销毁方式} ## 线程语义 - {线程安全说明} ## 公开成员 | 成员 | 说明 | |------|------| | [Initialize](Initialize.md) | {说明} | | [Shutdown](Shutdown.md) | {说明} | ``` ### 3. 方法页模板 ```markdown # {TypeName}::{MethodName} {一句话说明方法职责} ```cpp {完整签名} ``` ## 行为说明 {说明前置条件、后置状态、副作用和当前实现细节} ## 参数 - `param` - {描述} ## 返回值 - `{Type}` - {描述} ## 线程语义 - {线程安全、只建议初始化阶段调用、或必须同线程配对等} ## 示例 ```cpp {最小可信示例} ``` ``` ## 验收清单 - `docs/api/XCEngine/**` 与 `engine/include/XCEngine/**` 目录平行 - canonical 树下没有模块级 `README.md` - 每个 public header 都有对应类型目录 - 每个类型总览页都位于 `{TypeName}/{TypeName}.md` - 方法页使用原函数名或规范化运算符名 - 所有链接都指向真实存在的 `.md` 页面 - 文档中明确区分接口契约、当前实现和合理推断 - 重要模块拥有必要的 guide 页 - 重要限制、stub、平台条件和线程语义都已写清