# AnyImage 开发约定 ## 总则 - 说明性内容(提交说明、文档、注释、Mermaid 等)以中文为主,专有名词和约定俗成的表达可使用英文 - 动手前先读 `docs/index.md`;程序边界、调用流程和模块职责见 `docs/internals/index.md` 与 `docs/internals/architecture.md` - 修改代码、依赖或执行方式后,同步更新 `README.md` 与对应主题文档,保持文档、测试和实现一致 - 优先选择依赖少、直接、易验证的实现;保留工作区中与当前任务无关的已有改动 ## 内部实现文档 - [内部实现总览](docs/internals/index.md):内部实现文档的统一入口 - [程序架构](docs/internals/architecture.md):进程边界、职责与调用主链 - [Operator 实现索引](docs/internals/operators/index.md):源码功能与实现页的对应关系 修改完整工作流时同步更新对应实现页。`operators/common/` 不单独建立页面,共享边界写入程序架构。 ## 模块与目录边界 - 目录结构应能直接表达业务模块和职责;优先按用户可理解的功能或稳定能力组织,不按模糊的数据类型、临时步骤或界面摆放机械分组 - 一个模块只承担一个可描述的职责。功能出现多个相对独立的交互、算法或构建阶段时再建立子目录,并让同一抽象层的实现并列 - 公共层来自已经存在的复用,不来自对未来的猜测。没有真实共享消费者的代码留在所属模块;抽取后只暴露消费者需要的最小接口 - 模块边界优先服从运行进程、依赖方向、数据所有权和生命周期。只在一侧处理的数据不为形式上的“共享”跨越边界;确因加载机制产生的例外应在架构文档中说明 - 编排层只组合步骤和定义公开协议,原子能力放在所属领域模块。编排模块之间不互相导入实现,共享逻辑应下沉 - 公开任务与界面入口不要求一一对应;边界由可复用计算、输入输出协议和失败语义决定。名称必须描述实际动作与产物,不暗示未承担的职责 - 没有生产消费者的入口、兼容层和辅助协议应删除,不为测试便利单独保留 - 移动或拆分模块时同步更新注册、导入、打包、测试和文档,不留下旧路径转发层 ## 常见命令 优先在项目根目录使用 Git Bash;Windows 路径在 Bash 命令中使用正斜杠。 ```bash # 安装或同步开发依赖 uv sync # 运行全部测试 uv run pytest # 运行插件注册、Manifest 与打包相关的快速测试 uv run pytest tests/test_addon.py tests/test_manifest.py tests/test_pack.py -v # 构建 Windows、macOS、Linux 扩展包到 dist/ uv run python pack.py # 本地 BlendJob wheel 内容变化后刷新锁文件 uv lock --refresh ``` 资产脚本必须由 Blender 执行;具体入口与验证范围见 [节点资产](docs/internals/node-assets.md),不要用普通 Python 解释器运行。 `tools/` 中的脚本按维护对象分组,并统一使用能够区分“构建”和“验证”等动作的命名。每个脚本都应有明确入口、文档或测试消费者;没有实际用途的脚本应删除。 ## 命名规范 - 变量、函数、Docstring 使用英文;同一概念在代码和文档中使用统一表达 - 函数的动作前缀应表达产物边界:`generate_*` 表示 AI 生成,`build_*` 只在内存中构建值或几何,`create_*` 表示创建 Blender Image、Mesh、Material、Object 等真实数据 - 名称应说明业务职责,并与用户概念、公开协议和界面术语保持一致;不要使用脱离上下文后无法判断用途的宽泛名称 - 文件和目录名应表达稳定的业务分类和模块职责,不直接沿用函数名,也不按临时执行步骤命名;集合层使用复数,单项分类使用单数,同一层级保持一致 - Python 类使用大驼峰,不添加项目名前缀。Operator 使用动宾结构,如 `ConvertToDepthPlane`、`RemoveImageBackground`;Menu、Panel、AddonPreferences、PropertyGroup 分别使用实际类型后缀,如 `AnyImageImageMenu`、`ServerPanel`、`AnyImagePreferences`、`AnyImageSettings` - `bl_idname` 与挂载到公共 Blender RNA 类型的 Property 使用 `anyimage` 项目前缀:Operator 如 `anyimage.convert_to_depth_plane`,Menu 如 `ANYIMAGE_MT_image_context`,Panel 如 `ANYIMAGE_PT_server`,公共 Property 如 `Scene.anyimage_settings` - Operator 自身 Property 不加项目前缀,使用业务名称,如 `input_path`、`process_res`、`resolution_level` - 扩展包名使用 Manifest 中的真实名称、版本和平台,例如 `AnyImage.v0.11.2.windows-x64.zip`;节点组名称沿用资产中的 `O DA3 Depth Plane`、`O MoGe2 Surface` 等既有名称 - 常量应表达领域约束、共享数值或稳定映射,不为字面量增加没有额外语义的同名别名;需要类型约束时使用集中映射或 Enum - 同一发布单元的版本只保留一个事实来源。只有存在独立兼容周期和实际消费者时,才引入额外版本或迁移状态 ## 代码规范 - 避免不必要的嵌套,优先使用提前返回和小而明确的函数 - 只为特殊、非常规或存在兼容性原因的实现写注释,不复述代码本身 - 删除功能时同时删除无效参数、分支、测试和文档,不保留没有实际消费者的兼容层 - Blender 侧不载入 AI 依赖:UI、Operator 和结果导入放在 `src/anyimage/` 或 `src/anyimage/operators/`,模型下载、ONNX 推理和输出放在 `src/anyimage/server/` - 扩展级设置及其读取入口统一放在 `preferences.py`;使用 `addon_preferences()` 读取,不把 Blender Add-on Preferences 的定位、默认值或路径解析放进专门管理 BlendJob 的 `runtime.py` - Job 参数使用可序列化的普通字典;Blender 数据只能在主线程的 Operator 响应阶段读写 - 新增或修改 Blender 类型时同步检查 `src/anyimage/__init__.py` 的注册与逆序注销,并补充对应测试 - 依赖版本、wheel 或 Manifest 改变时同步检查 `pyproject.toml`、`uv.lock`、`blender_manifest.toml` 和打包测试 ## 执行流程与复用 - 按数据依赖安排步骤:先完成会改变后续输入或分析范围的处理,再执行依赖该结果的计算 - 对相同输入和参数的昂贵确定性计算只执行一次,从同一中间结果派生多个产物 - 实现路径由当前功能的输入范围和质量要求决定,不为无实际用途的全局兼容选项增加分支 - 名称、参数和进度文案应反映当前阶段的真实职责,并明确跨进程流程中每一侧负责的最终操作 - 临时资源的创建与清理由同一所有者管理;共享输入解析和生命周期逻辑,不在各消费者中重复实现 ## 清理、测试与重构验证 - 删除前先用 `rg` 查找生产调用方、注册入口、测试、文档和打包清单。只有注册或测试、没有真实功能消费者的入口视为孤立代码,应连同协议一起删除 - 测试应保护当前功能、公开协议、关键算法和已发生过的回归;不要为了保留旧文件结构、无消费者兼容层或实现细节而写测试 - 删除功能时删除对应测试;移动原子能力时把测试迁到新的职责模块。测试名称也要使用当前业务术语,不能继续出现已废弃的模块名或 Job ID - 打包测试应验证最终产物包含必要文件且不包含已删除结构;文件移动后同步更新 - 结构重构完成后至少执行旧名称与旧路径搜索、差异检查、完整测试和文档构建;涉及 Blender 注册、运行时行为或节点资产时,再使用目标 Blender 验证 - 不混用开发环境、独立运行环境和 Blender 自带 Python;每类验证使用项目声明的对应解释器 - 重构应减少模块、分支、协议和重复计算的数量。新抽象只有在职责稳定或存在真实复用时才成立 ## Blender 节点图规范 - 不修改节点的 `name`,也不使用 `label` 覆盖节点标题;保留 Blender 为节点类型生成的默认名称和外观,避免读图时无法判断节点原型。用途应通过节点类型、参数、空间布局和必要的少量注释表达 - 节点图优先依靠清晰的空间层次表达流程,不用五颜六色的 Frame 做分类;仅在重复区、模拟区等确有包裹语义时少量使用 Frame,并保持配色克制 - 避免跨越大段节点图的连线;来自 Group Input 的参数可按使用区域放置多个 Group Input,并隐藏未连接的 sockets - 主处理链尽量保持为一根从左到右连续可见的几何主线,辅助字段和控制分支放在主线上下两侧,就近汇入消费者 - 避免交错连线、节点重叠和不必要的回折;新增或重建节点组时检查节点坐标唯一性和主要连线方向 - Repeat、Simulation、For Each Geometry Element 等具有输入/输出“头尾”的成对结构,应先确定完整包裹范围,再放置内部节点,保证头尾顺序、配对关系和区域边界一眼可辨 - 作为修改器使用的 Geometry Nodes,除确实需要动态字段或其他结构的接口外,输入 socket 的 structure_type 应设为 SINGLE - 为接口 socket 设置符合业务含义的 `subtype`;例如表示 Blender 场景实际长度的浮点输入使用 `DISTANCE`,明确限制为 `0–1` 的比例使用 `FACTOR`,以 `0–100` 表示的百分比使用 `PERCENTAGE`,角度使用对应 subtype。无上限倍率等不符合范围语义的数值保留普通 Float,不为显示形式强套 subtype - 调整节点接口或布局后,应补充或更新 Blender 验证,检查 socket 顺序与结构、节点不重叠、Group Input 未使用输出已隐藏,以及几何主线可正常求值 ## 文档与 Markdown 规范 - `README.md` 面向用户;实现原理放入 `docs/` 对应主题,不在 README 堆叠内部细节 - 不使用 `---` 分隔线;一级标题只在文档开头使用一次 - Mermaid 节点 ID 使用英文字符,节点显示文本可以使用中文 - 文档描述当前已实现行为;限制、默认值、命令和文件名必须能从代码或测试中验证