Merge remote-tracking branch 'origin/master' into codex/public-work-readmodel-smooth-transition

This commit is contained in:
kdletters
2026-05-26 16:38:38 +08:00
130 changed files with 2966 additions and 511 deletions

View File

@@ -4,8 +4,8 @@ name = "Genarrative"
[setup] [setup]
script = ''' script = '''
cp "$env:CODEX_SOURCE_TREE_PATH\.env.secrets.local" "$env:CODEX_WORKTREE_PATH\.env.secrets.local"
npm install npm install
cp "C:\proj\Genarrative\.env.secrets.local" ".env.secrets.local"
npm run codegraph:init npm run codegraph:init
npm run codegraph:index npm run codegraph:index
''' '''

View File

@@ -0,0 +1,399 @@
# Genarrative陶泥儿项目架构优化计划书
**文档版本**v1.0
**编制日期**2026-05-26
**项目名称**Genarrative陶泥儿
**文档密级**:内部
---
## 一、项目概况
| 维度 | 详情 |
|---|---|
| **项目名** | Genarrative陶泥儿 |
| **项目定位** | AI Native 互动视觉 RPG 平台——支持多种玩法模板的 AI 创作、运行与分享("玩法类型平台" |
| **核心玩法** | 拼图、视觉小说、Match3D、Bark Battle、Big Fish、Jump-Hop、Square Hole、木鱼、教娱等 10+ 种玩法模板 |
| **代码规模** | 前端 ~823 个 TS/TSX 文件,后端 ~1532 个 Rust 文件,属于大型项目 |
### 1.1 计划目的
本计划书基于对 Genarrative 项目当前架构的全面分析,识别架构层面的关键问题,并提出分阶段、可落地的优化方案。旨在:
- 统一前端架构模式,降低团队认知成本和新人上手门槛
- 提升模块内聚性,减少不必要的耦合与依赖
- 建立自动化契约保障机制,降低跨语言同步出错风险
- 优化工程基础设施,提高开发效率和运维可观测性
---
## 二、技术栈总览
| 层级 | 技术选型 | 版本 |
|---|---|---|
| **前端框架** | React + TypeScript + Vite | React 19 / TS 5.8 / Vite 6 |
| **样式** | TailwindCSS | v4 |
| **3D / 动画** | Three.js、Motion、cannon-es | - |
| **后端 HTTP** | Rust + AxumBFF 门面) | Axum 0.8 |
| **游戏状态 DB** | SpacetimeDB实时反应式数据库 | v2.2 |
| **AI / LLM** | LangChain-Rust + LLM Proxy | - |
| **小程序** | 微信小程序(含微信支付) | - |
| **容器化** | Docker ComposeNginx + API Server + OTel Collector | - |
| **运维** | systemd、Nginx、Jenkins CI/CD、k6 压测 | - |
| **可观测性** | OpenTelemetryOTLP → Grafana | - |
---
## 三、当前架构分层图
```
┌──────────────────────────────────────────────────────────────┐
│ 入口层 │
│ index.html → main.tsx → resolveAppRoute() → RouteComponent │
│ (多入口路由:平台主页 / 拼图 / BigFish / Match3D / ...) │
└──────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────┐
│ 前端应用层 (src/) │
│ ┌─────────────┐ ┌──────────────┐ ┌──────────────────────┐│
│ │ components/ │ │ services/ │ │ games/ ││
│ │ *-creation │ │ *-creation │ │ bark-battle/ ││
│ │ *-result │ │ *-runtime │ │ domain/ ││
│ │ *-runtime │ │ *-works │ │ application/ ││
│ │ common/ │ │ storyEngine │ │ infrastructure/ ││
│ │ auth/ │ │ payment │ │ ui/ ││
│ └─────────────┘ └──────────────┘ └──────────────────────┘│
│ ┌─────────────┐ ┌──────────────┐ ┌──────────────────────┐│
│ │ hooks/ │ │ data/ │ │ routing/ ││
│ │ persistence/│ │ functionCat. │ │ config/ editor/ ││
│ └─────────────┘ └──────────────┘ └──────────────────────┘│
└──────────────────────────────────────────────────────────────┘
│ Vite Proxy (/api/*)
┌──────────────────────────────────────────────────────────────┐
│ Rust 后端 (server-rs/) │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ api-server (Axum HTTP / SSE / BFF 门面) │ │
│ └──────────────────────────────────────────────────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌──────────┐ ┌──────────────────┐ ┌──────────────┐ │
│ │ platform │ │ module-* │ │ shared │ │
│ │ -auth │ │ -puzzle │ │ -contracts │ │
│ │ -llm │ │ -visual-novel │ │ -kernel │ │
│ │ -image │ │ -match3d │ │ -logging │ │
│ │ -oss │ │ -bark-battle │ └──────────────┘ │
│ │ -speech │ │ -big-fish ... │ │
│ │ -agent │ │ -runtime │ │
│ └──────────┘ │ -combat/npc │ │
│ └──────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ spacetime-module + spacetime-client → SpacetimeDB │ │
│ └──────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────┐
│ 辅助子系统 │
│ apps/admin-web (React 后台管理) │
│ miniprogram/ (微信小程序) │
│ packages/shared (前后端共享契约/LLM工具) │
│ deploy/ (Docker/Nginx/systemd/OTel) │
│ scripts/ (40+ 构建/部署/检查脚本) │
│ jenkins/ (CI/CD Pipeline) │
└──────────────────────────────────────────────────────────────┘
```
---
## 四、架构亮点
1. **清晰的"玩法模板"平台模式**
每种玩法遵循统一的 `creation → result → runtime` 三段式生命周期,前端 `components/``services/` 均按此模式组织。新增玩法可快速套用模板,极大降低了横向扩展成本。
2. **后端严格的分层约束**
`api-server`(门面)→ `module-*`(领域)→ `spacetime-module`(持久化),`module-*` 不直接依赖 Axum、HTTP、SpacetimeDB table、LLM、文件系统保证了领域纯净性和可测试性。
3. **SpacetimeDB 作为游戏状态核心**
采用反应式实时数据库替代传统 Redis + PostgreSQL 组合,天然适合多人实时游戏状态同步,减少了中间层复杂度和延迟。
4. **前端 DDD 探索**
`src/games/bark-battle/` 采用 `domain / application / infrastructure / ui` 四层 DDD 结构,为复杂玩法的前端架构提供了良好范本。
5. **完善的多入口路由体系**
通过 `resolveAppRoute()` 按 URL path 分发到不同的 lazy-loaded 组件,实现了按需加载和良好的首屏性能。
6. **运维体系完备**
Docker Compose + systemd + Nginx + OpenTelemetry + k6 压测 + Jenkins CI/CD覆盖了构建、部署、监控、压测全链路。
---
## 五、问题诊断与改进方案
### 问题 1前端 services/ 与 components/ 的耦合不统一
**现状**
大部分玩法遵循 `services/` + `components/` 分离模式,但部分玩法运行时直接放在 `components/`services 层职责模糊——有的承担了业务逻辑编排,有的仅作简单 API 调用。
**影响**
- 新人阅读代码时无法预判某个逻辑应位于哪个目录
- 单元测试困难services 与组件耦合的业务逻辑无法独立测试
- 跨玩法复用时需要额外的迁移成本
**改进方案**
1. 制定规范:`services/` 仅负责纯 API 调用和数据转换,不包含业务判断逻辑
2. 业务逻辑统一归到 `hooks/``games/<play-type>/application/`
3. 以 puzzle 玩法为样板,先行重构并形成迁移指南,再推广至其余玩法
4. 在 CI 中增加 ESLint 规则,禁止 `components/` 直接 import `services/` 之外的外部模块
**预期收益**
- 职责边界清晰,降低认知成本约 30%
- services 层可独立单测覆盖率达到 80%+
- 新玩法开发上手时间从 2 天缩短至 0.5 天
---
### 问题 2前端 DDD 与模板模式并存,架构不统一
**现状**
`bark-battle` 采用 DDD 四层结构(`domain/application/infrastructure/ui`),其余玩法散落在 `components/` + `services/` 下,存在两种截然不同的组织范式。
**影响**
- 团队内部对"正确"的代码组织方式缺乏共识
- 代码审查时需要切换判断标准
- DDD 玩法的优势无法在全局范围内发挥
**改进方案**
1. 所有玩法统一迁移到 `src/games/<play-type>/` 下,采用 `domain / application / ui` 三层结构infrastructure 按需保留)
2. 以 puzzle 为样板完成首例迁移,产出迁移 Checklist 和模板生成脚本
3. 新增玩法脚手架直接生成 DDD 结构目录
4. 旧玩法分批次迁移,每批次 2-3 个玩法,在 4 个迭代内完成
**预期收益**
- 架构一致性提升至 100%
- 跨玩法逻辑复用变得可能domain 层可共享)
- 为后续 monorepo 改造打下基础
---
### 问题 3后端 module-* 粒度偏细,存在潜在循环依赖风险
**现状**
后端共 35 个 crate。`module-runtime` 被拆分为 3 个独立 crate`module-combat / npc / inventory` 各自独立。部分紧密协作的模块之间可能存在隐式耦合。
**影响**
- 编译时间增长35 个 crate 独立编译)
- 跨 crate 重构时需要同时修改多处
- 循环依赖风险增加,可能在特定组合下触发编译失败
**改进方案**
1. 评估合并方案:
- `module-runtime-*` 系列合并为单 crate `module-runtime`,内部用 `mod` 做逻辑隔离
- `module-combat / npc / inventory` 评估合并为 `module-combat`npc 和 inventory 作为子模块
2. 保留 trait/interface 抽象层,确保 module 之间不直接依赖具体实现
3. 在 CI 中引入 `cargo-deny` 或自定义脚本,自动检测 module 间的依赖方向是否违反分层约束
4. 目标:将 35 个 crate 精简至 25 个以内
**预期收益**
- 全量编译时间预计缩短 15%-20%
- 循环依赖风险归零
- module 内部重构成本降低
---
### 问题 4根目录 env 文件过多且混乱
**现状**
根目录存在 4 个 env 文件(`.env``.env.example``.env.production` 等),且 `deploy/` 下另有多个 env 文件。配置分散在多处,部分文件之间字段不一致。
**影响**
- 排查配置问题时需要翻阅多个文件
- 新人无法快速确定本地开发需要哪些环境变量
- 部署时可能遗漏或错误覆盖某项配置
**改进方案**
1. 收敛为三层配置体系:
- `.env.example`:包含所有可配置项的说明和默认值(唯一提交到仓库的 env 文件)
- `.env.local`:本地开发覆盖(加入 .gitignore
- `deploy/env/<env-name>.env`:各部署环境专用配置
2. 引入 config crate支持层次覆盖default → local → env-specific启动时自动校验必填字段
3. 在 CI 中加入 env 校验步骤:对比 `.env.example` 与部署环境的 env 文件,标记缺失或多余字段
**预期收益**
- 配置查找时间从分钟级降至秒级
- 部署配置遗漏导致的线上事故减少 90%+
- 新成员本地环境搭建时间从 30 分钟缩短至 10 分钟
---
### 问题 5scripts/ 目录膨胀为"万能工具箱"
**现状**
`scripts/` 目录共 42 个文件,涵盖构建、部署、检查、迁移、生成、压测等,全部平铺在同一层级,缺乏分类。
**影响**
- 难以快速定位所需脚本
- 同类脚本缺乏命名规范
- 新增脚本时不知道放在何处
**改进方案**
1. 按功能域分类重组:
```
scripts/
├── build/ # 构建相关vite、cargo、wasm 等)
├── deploy/ # 部署相关docker、systemd、rsync
├── check/ # 检查/校验lint、format、type-check
├── spacetime/ # SpacetimeDB 相关migration、seed
├── generate/ # 代码生成scaffold、proto、types
└── loadtest/ # 压测脚本k6 配置及辅助)
```
2. 为每个子目录添加 README.md说明各脚本用途和调用方式
3. 将重复逻辑抽取为共享函数库
**预期收益**
- 脚本查找效率提升 60%+
- 降低脚本重复概率
- 便于 CI Pipeline 直接引用标准化路径
---
### 问题 6前端路由系统缺乏统一的"玩法注册"机制
**现状**
`appRoutes.tsx` 中硬编码 `switch-case` 逻辑,每新增一种玩法需手动修改路由文件、入口组件、资源加载等多个位置。
**影响**
- 新增玩法的接入点分散,容易遗漏
- 路由文件随玩法增多持续膨胀
- 无法实现"按需注册"——即使某环境不包含某玩法,路由代码仍然存在
**改进方案**
1. 建立 `PlayTypeRegistry` 模式:每个玩法导出一个注册项对象,包含 `path``lazyComponent``preload` 等字段
2. `resolveAppRoute()` 改为动态聚合所有注册项,替代硬编码 switch-case
3. 支持环境级玩法开关:通过配置控制某环境启用哪些玩法,路由系统自动忽略未启用的
**预期收益**
- 新增玩法零侵入路由系统,只需在玩法目录内添加注册文件
- 路由文件体积与玩法数量解耦
- 灰度发布和 A/B 测试变得可能
---
### 问题 7前端缺少统一的状态管理层
**现状**
前端状态管理依赖 React hooks + props drilling + services 层手动管理。未使用任何状态管理库(如 Zustand、Jotai、Redux
**影响**
- 全局状态(用户认证、会话、通知)通过多层 props 传递,组件耦合度高
- 跨页面状态无法优雅共享
- 状态变更难以追踪和调试
**改进方案**
1. 引入 Zustand轻量、无 boilerplate、TS 友好)管理全局状态:
- `useAuthStore`:认证状态
- `useSessionStore`:当前会话/游戏状态
- `useNotificationStore`:全局通知
2. 玩法内状态继续使用 React hooks + `useReducer`,保持局部自治
3. 全局 store 与玩法内 state 通过事件总线松耦合通信
**预期收益**
- props drilling 层级从 5+ 层降至 1-2 层
- 全局状态可追溯,支持 Redux DevTools 调试
- 跨玩法状态共享(如用户余额、道具)变得自然
---
### 问题 8shared-contracts 的实际复用程度待验证
**现状**
前后端通过 `packages/shared` 共享 DTO 类型定义,但依赖手动同步 TypeScript 类型。可能存在前后端契约不一致但编译期无法检出的情况。
**影响**
- 后端修改 DTO 字段后,前端可能遗漏更新导致运行时错误
- 手动同步耗时且易出错
- Code Review 时难以判断契约一致性
**改进方案**
1. 引入 `ts-rs`:从 Rust 结构体自动生成 TypeScript 类型定义
2. 将生成步骤集成到 CI Pipeline
- 每次 Rust PR 触发 `ts-rs` 重新生成 TS 类型
- 对比生成的类型与仓库中的类型是否一致,不一致则 CI 失败
3. 长期考虑引入 Protobuf / OpenAPI 作为跨语言契约的单一事实来源
**预期收益**
- 前后端契约不一致导致的线上 bug 减少 95%+
- 手动同步工作量归零
- PR Review 时契约一致性问题自动拦截
---
## 六、改进优先级路线图
| 优先级 | 改进项 | 涉及层 | 建议时间 | 预期收益 |
|---|---|---|---|---|
| **P0** | 统一前端 services/hooks/components 职责边界 | 前端 | 第 1-2 周 | 降低认知成本,提升可测试性 |
| **P1** | 建立 PlayType 注册机制 | 前端 | 第 2-3 周 | 新增玩法零侵入路由 |
| **P1** | 评估 module-* 合并方案并执行 | 后端 | 第 3-4 周 | 减少编译时间 15%-20% |
| **P1** | 引入 Zustand 全局状态管理 | 前端 | 第 4-5 周 | 改善状态追踪与跨组件共享 |
| **P2** | 清理 scripts/ 目录结构 | 工程 | 第 5-6 周 | 提高可发现性 |
| **P2** | 前端玩法统一迁移至 DDD 结构 | 前端 | 第 5-8 周 | 架构一致性 100% |
| **P2** | env 配置收敛 | 工程 | 第 6-8 周 | 减少部署配置事故 |
| **P3** | 前后端共享 DTO 自动化ts-rs | 全栈 | 第 6-8 周 | 消除契约不一致风险 |
| **P3** | CI 分层约束检查cargo-deny | 后端 | 第 8-10 周 | 循环依赖归零 |
> **说明**P0 为阻塞项必须最先完成。P1 项可部分并行推进PlayType 注册与 module 合并互不依赖。P2/P3 为优化项,可在日常迭代中穿插推进。
---
## 七、架构健康度评分卡
| 维度 | 评分 | 当前状态 | 目标状态 |
|---|---|---|---|
| **分层清晰度** | ★★★★☆ | 后端分层严格,前端分层存在不一致 | ★★★★★ 前后端均严格分层 |
| **模块化程度** | ★★★★☆ | 后端 35 crate 粒度偏细,前端结构化较好 | ★★★★☆ 后端精简至 25 crate |
| **可扩展性** | ★★★★★ | 玩法模板模式使新增玩法成本低 | ★★★★★ 维持 |
| **代码复用** | ★★★☆☆ | shared 层作用有限services 层有重复 | ★★★★☆ DDD 统一后 domain 可复用 |
| **DevOps 成熟度** | ★★★★★ | Docker + k6 + OTel + Jenkins 覆盖完整 | ★★★★★ 维持 |
| **文档完备性** | ★★★★★ | docs/ 分类清晰,基线文档齐全 | ★★★★★ 维持 |
| **技术债务管控** | ★★★★☆ | 有明确的"历史残留"标记和废弃策略 | ★★★★★ 增加自动化检测 |
**综合评级A-(优秀,存在可优化空间)**
---
## 八、附录:代码规模统计
| 维度 | 数量 |
|---|---|
| **前端 TypeScript/TSX 文件** | ~823 个 |
| **后端 Rust 源文件** | ~1532 个 |
| **后端 Crate 数量** | 35 个 |
| **核心玩法类型** | 10+ 种 |
| **scripts/ 脚本数量** | 42 个 |
| **根目录 env 文件** | 4 个 + deploy 下多个 |
### 模块规模明细(后端)
| Crate | 职责 | 建议 |
|---|---|---|
| `api-server` | Axum HTTP 门面,路由聚合 | 保持 |
| `platform-*` (auth/llm/image/oss/speech/agent) | 平台级跨玩法能力 | 保持 |
| `module-puzzle` | 拼图玩法 | 作为 DDD 迁移样板 |
| `module-visual-novel` | 视觉小说 | 后续迁移 |
| `module-match3d` | Match3D 三消 | 后续迁移 |
| `module-bark-battle` | 犬吠对战 | 已对接前端 DDD |
| `module-big-fish` | Big Fish | 后续迁移 |
| `module-runtime*` (3 crates) | 通用运行时 | **建议合并为单 crate** |
| `module-combat / npc / inventory` | 战斗系统 | **建议合并** |
| `spacetime-module` + `spacetime-client` | SpacetimeDB 接入 | 保持 |
| `shared-contracts / kernel / logging` | 共享基础设施 | 保持 |
---
> **文档结束**
> 本计划书由 Genarrative 架构分析报告衍生,所有改进项均基于对当前项目代码库的实际分析。执行过程中如遇阻力或新发现,应及时更新本计划书并同步相关方。

View File

@@ -16,6 +16,22 @@
--- ---
## 2026-05-25 抓大鹅发现页官方 demo 使用静态资源与本地运行态
- 背景:本轮抓大鹅资源管线已经生成完整 `level-scene`、背景、UI spritesheet、物品 spritesheet 和切片资源,需要放入发现页作为可试玩验证入口,但不应把一次性本地资源包装成后端正式作品。
- 决策:发现页官方抓大鹅 demo 固定 profileId 为 `match3d-demo-20260525`、公开作品号为 `M3-20260525`,资源读取 `public/match3d-demo/undersea-candy-market/` 下的静态文件。公开卡片、作品号搜索和详情页沿用平台公开作品详情链路;启动运行态时用 `createLocalMatch3DRuntimeAdapter`,不调用正式 Match3D runtime 后端、不新增 SpacetimeDB schema、不写正式作品统计。
- 影响范围:`src/data/match3dDemoGalleryCard.ts``src/components/platform-entry/PlatformEntryFlowShellImpl.tsx`、发现页公开卡片、作品号搜索、Match3D 本地 runtime adapter、玩法链路文档。
- 验证方式:搜索 `M3-20260525` 能打开“海底糖果集市”并启动本地抓大鹅运行态;正式 Match3D 公开作品仍走 server runtime adapter。
- 关联文档:`docs/【玩法创作】平台入口与玩法链路-2026-05-15.md`
## 2026-05-25 抓大鹅运行态 HUD 收敛为拼图同款低遮挡样式
- 背景:抓大鹅游玩阶段 UI 需要继续对齐拼图运行态的观感,同时移除右上角设置入口、灰白半透底板和显眼锅壳,让棋盘区域更专注。
- 决策:抓大鹅运行态只保留左上透明返回按钮,右上不再显示设置入口;顶部关卡名和倒计时直接复用拼图同款的铭牌 + 下挂计时牌结构、同色板、同造型和 `media/logo.png` 产品 logo底部备选栏和道具图标保持交互边界但不再显示灰白半透底中央容器图层可以视觉隐藏但棋盘命中边界和既有交互逻辑保留。
- 影响范围:`src/components/match3d-runtime/Match3DRuntimeShell.tsx``src/components/match3d-runtime/Match3DRuntimeShell.test.tsx``src/index.css`、抓大鹅玩法链路文档。
- 验证方式:运行态页面不再渲染“打开抓大鹅设置”,顶部仍显示关卡名和倒计时,底部槽位和道具按钮 class 中不含旧白底视觉;相关测试通过后保持该口径。
- 关联文档:`docs/【玩法创作】平台入口与玩法链路-2026-05-15.md`
## 2026-05-25 平台首页推荐按桌面与移动断点分流 ## 2026-05-25 平台首页推荐按桌面与移动断点分流
- 背景:平台首页的推荐页在桌面与移动端之间原先共用同一套推荐运行态逻辑,容易让桌面和移动两套内容同时启动,也让首页的推荐卡与桌面发现壳互相抢状态。 - 背景:平台首页的推荐页在桌面与移动端之间原先共用同一套推荐运行态逻辑,容易让桌面和移动两套内容同时启动,也让首页的推荐卡与桌面发现壳互相抢状态。

View File

@@ -1512,10 +1512,18 @@
- 验证:`curl.exe -i http://127.0.0.1:8082/api/creation-entry/config` 返回 `200` 且包含 `baby-object-match`;前端草稿页作品架重新渲染。 - 验证:`curl.exe -i http://127.0.0.1:8082/api/creation-entry/config` 返回 `200` 且包含 `baby-object-match`;前端草稿页作品架重新渲染。
- 关联:`server-rs/crates/api-server/src/state.rs``server-rs/crates/api-server/src/creation_entry_config.rs``docs/【开发运维】本地开发验证与生产运维-2026-05-15.md` - 关联:`server-rs/crates/api-server/src/state.rs``server-rs/crates/api-server/src/creation_entry_config.rs``docs/【开发运维】本地开发验证与生产运维-2026-05-15.md`
## 存档选择入口不要只藏在“玩过”弹窗里 ## 抓大鹅物品 spritesheet 偏移先查 alpha 连通域切片是否启用
- 现象:用户有 RPG / 拼图运行态存档,但平台底部 `草稿` Tab 只展示作品架,个人中心只有点击 `玩过` 后才可能看到“可继续”,导致看起来没有存档选择入口 - 现象:抓大鹅物品图集里大多数素材显示不全、被裁碎、位置整体偏移,甚至切出来像拼贴块
- 原因:`/api/profile/save-archives` 已在入口 bootstrap 加载,但前端只把 `saveEntries` 注入 `ProfilePlayedWorksModal`;没有独立的存档入口 - 原因:旧链路只按 `10x10` 固定格线裁切,遇到模型输出的透明图集稍有偏移、跨格或留白不均时就会把主体切坏。现在后端优先按透明 alpha 连通域识别真实素材矩形,再按原图从上到下、从左到右排序;只有识别数量不足时才回退旧网格切法
- 处理:个人中心 `常用功能` 必须保留 `存档` 快捷入口,点击后打开独立存档选择弹窗并复用 `SaveArchiveCard`;恢复仍走 `/api/profile/save-archives/{worldKey}`,拼图存档继续走拼图 resume 分支RPG 走 `handleContinueGame(snapshot)` - 处理:优先检查 `generated_asset_sheets.rs` 的 alpha 连通域切片是否生效,再查 `item_assets.rs` 是否还在透传旧的固定格线语义。不要只改前端显示比例
- 验证:`npm run test -- src/components/rpg-entry/RpgEntryFlowShell.agent.interaction.test.tsx -t "profile page exposes save archive picker"` - 验证:定向测试 `cargo test -p api-server generated_asset_sheet_two_items_per_row --manifest-path server-rs/Cargo.toml -- --nocapture` 应通过,且错位透明样本应按连通域切出完整视图
- 关联:`src/components/rpg-entry/RpgEntryHomeView.tsx``src/components/platform-entry/PlatformEntryFlowShellImpl.tsx``src/components/rpg-entry/useRpgEntryBootstrap.ts``docs/【玩法创作】平台入口与玩法链路-2026-05-15.md` - 关联:`server-rs/crates/api-server/src/generated_asset_sheets.rs``server-rs/crates/api-server/src/match3d/item_assets.rs`
## 个人中心不再保留直达“存档”按钮入口
- 现象2026-05-25 起,移动端“我的”页顶部改为品牌行 + 扫码 / 设置按钮,设置区和次级入口不再提供独立的 `存档` 按钮;用户仍可在“玩过”弹窗里查看可继续存档。
- 原因:产品布局收口后,个人中心只保留设置、扫码、常用功能和条件性次级入口,存档恢复继续以后端 `/api/profile/save-archives` 真相为准,但不再作为页面直达入口。
- 处理:后续如果需要重新暴露存档入口,优先评估是否应回到“玩过”或别的独立弹窗流程,不要默认把存档再塞回常用功能宫格或设置列表。
- 验证:`npm test -- src/components/rpg-entry/RpgEntryHomeView.recharge.test.tsx -t "mobile profile page matches the reference layout sections|profile scan action opens camera scanner instead of recharge panel"`
- 关联:`src/components/rpg-entry/RpgEntryHomeView.tsx``docs/【项目基线】当前产品与工程约束-2026-05-15.md``docs/【玩法创作】平台入口与玩法链路-2026-05-15.md`

View File

@@ -17,6 +17,8 @@
拼图生成页步骤真进度、步骤内假进度和精简展示口径见 [【玩法创作】拼图生成页进度口径-2026-05-23.md](./%E3%80%90%E7%8E%A9%E6%B3%95%E5%88%9B%E4%BD%9C%E3%80%91%E6%8B%BC%E5%9B%BE%E7%94%9F%E6%88%90%E9%A1%B5%E8%BF%9B%E5%BA%A6%E5%8F%A3%E5%BE%84-2026-05-23.md)。 拼图生成页步骤真进度、步骤内假进度和精简展示口径见 [【玩法创作】拼图生成页进度口径-2026-05-23.md](./%E3%80%90%E7%8E%A9%E6%B3%95%E5%88%9B%E4%BD%9C%E3%80%91%E6%8B%BC%E5%9B%BE%E7%94%9F%E6%88%90%E9%A1%B5%E8%BF%9B%E5%BA%A6%E5%8F%A3%E5%BE%84-2026-05-23.md)。
从文字需求生成高一致性美术素材流程抽象出的发明专利交底稿见 [【专利交底】一种极低成本快速生成高质量2D小游戏高一致性美术素材的解决方案-2026-05-25.md](./%E3%80%90%E4%B8%93%E5%88%A9%E4%BA%A4%E5%BA%95%E3%80%91%E4%B8%80%E7%A7%8D%E6%9E%81%E4%BD%8E%E6%88%90%E6%9C%AC%E5%BF%AB%E9%80%9F%E7%94%9F%E6%88%90%E9%AB%98%E8%B4%A8%E9%87%8F2D%E5%B0%8F%E6%B8%B8%E6%88%8F%E9%AB%98%E4%B8%80%E8%87%B4%E6%80%A7%E7%BE%8E%E6%9C%AF%E7%B4%A0%E6%9D%90%E7%9A%84%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88-2026-05-25.md)。
生产部署切换到 systemd + Nginx + SpacetimeDB 自托管的总方案见 [PRODUCTION_DEPLOYMENT_PLAN_2026-05-02.md](./technical/PRODUCTION_DEPLOYMENT_PLAN_2026-05-02.md),该文档也是当前生产 Jenkinsfile 的唯一入口。SpacetimeDB 表结构变更、自动迁移边界和保留旧数据的分阶段迁移流程见 [SPACETIMEDB_SCHEMA_CHANGE_CONSTRAINTS.md](./technical/SPACETIMEDB_SCHEMA_CHANGE_CONSTRAINTS.md)private 表迁移 JSON 导入导出、HTTP 413 分片导入和旧数据库迁移流水线经验见 [SPACETIMEDB_JSON_STRING_MIGRATION_PROCEDURE_2026-04-27.md](./technical/SPACETIMEDB_JSON_STRING_MIGRATION_PROCEDURE_2026-04-27.md) 与 [JENKINS_SPACETIMEDB_DATABASE_MIGRATION_PIPELINES_2026-04-29.md](./technical/JENKINS_SPACETIMEDB_DATABASE_MIGRATION_PIPELINES_2026-04-29.md);后台管理独立前端工程技术方案见 [ADMIN_WEB_CONSOLE_TECHNICAL_SOLUTION_2026-04-30.md](./technical/ADMIN_WEB_CONSOLE_TECHNICAL_SOLUTION_2026-04-30.md)。 生产部署切换到 systemd + Nginx + SpacetimeDB 自托管的总方案见 [PRODUCTION_DEPLOYMENT_PLAN_2026-05-02.md](./technical/PRODUCTION_DEPLOYMENT_PLAN_2026-05-02.md),该文档也是当前生产 Jenkinsfile 的唯一入口。SpacetimeDB 表结构变更、自动迁移边界和保留旧数据的分阶段迁移流程见 [SPACETIMEDB_SCHEMA_CHANGE_CONSTRAINTS.md](./technical/SPACETIMEDB_SCHEMA_CHANGE_CONSTRAINTS.md)private 表迁移 JSON 导入导出、HTTP 413 分片导入和旧数据库迁移流水线经验见 [SPACETIMEDB_JSON_STRING_MIGRATION_PROCEDURE_2026-04-27.md](./technical/SPACETIMEDB_JSON_STRING_MIGRATION_PROCEDURE_2026-04-27.md) 与 [JENKINS_SPACETIMEDB_DATABASE_MIGRATION_PIPELINES_2026-04-29.md](./technical/JENKINS_SPACETIMEDB_DATABASE_MIGRATION_PIPELINES_2026-04-29.md);后台管理独立前端工程技术方案见 [ADMIN_WEB_CONSOLE_TECHNICAL_SOLUTION_2026-04-30.md](./technical/ADMIN_WEB_CONSOLE_TECHNICAL_SOLUTION_2026-04-30.md)。
SpacetimeDB 表结构变更、自动迁移边界和保留旧数据的分阶段迁移流程见 [SPACETIMEDB_SCHEMA_CHANGE_CONSTRAINTS.md](./technical/SPACETIMEDB_SCHEMA_CHANGE_CONSTRAINTS.md)。 SpacetimeDB 表结构变更、自动迁移边界和保留旧数据的分阶段迁移流程见 [SPACETIMEDB_SCHEMA_CHANGE_CONSTRAINTS.md](./technical/SPACETIMEDB_SCHEMA_CHANGE_CONSTRAINTS.md)。

View File

@@ -0,0 +1,184 @@
# 一种极低成本快速生成高质量2D小游戏高一致性美术素材的解决方案
更新时间:`2026-05-25`
> 本文为内部发明专利交底稿,目标是把“文字需求 -> 画面图 -> 透明 spritesheet -> 自动边界检测 -> 元素绑定”这一条高一致性美术素材生成链路抽象为可申请的通用技术方案。
## 摘要
本发明涉及一种极低成本快速生成高质量 2D 小游戏高一致性美术素材的解决方案。该方案接收文字形态的需求描述,调用图片生成模型生成一张用于表达整体视觉关系的游戏画面图;再以所述游戏画面图作为参考,继续调用图片生成模型生成一张透明背景的 spritesheet 图片,所述 spritesheet 图片承载需要随不同设备分辨率自适应调整位置的素材;随后基于自动边界检测算法对所述 spritesheet 图片中的素材进行逐一解析,按照从上到下、从左到右的顺序,将解析出的素材与文字形态需求描述中的画面元素一一对应,并将代码中的元素标识与对应素材绑定。该方案通过单次文字输入驱动画面图生成、基于画面图派生透明 spritesheet、自动边界检测替代人工切图、顺序映射替代手工命名和手工对图从而在较少人工干预和较低重复生成成本下快速得到风格统一、可直接绑定代码的高一致性美术素材。
## 技术领域
本发明属于人工智能图像生成、2D 小游戏美术素材生产、图像分割解析和元素绑定技术领域具体涉及一种根据文字需求描述自动生成游戏画面图、spritesheet 美术素材和元素映射关系的方法及系统。
## 背景技术
现有 2D 小游戏的美术素材生产通常包含以下步骤:先由设计人员撰写文字需求,再由美术人员分别绘制画面图、按钮图、状态图和装饰图,之后由前端或游戏程序员进行切图、命名、排布和代码绑定。该流程存在如下问题:
1. 素材往往分散生成,整体风格不统一。
2. 多分辨率适配时,需要人工调整大量元素位置,维护成本高。
3. 切图和命名依赖人工,容易出现遗漏、错位和绑定错误。
4. 文字需求与最终代码元素之间缺少稳定映射,后续修改代价大。
5. 若每个素材分别生成,会增加生成次数和等待成本。
因此,需要一种能够把文字需求直接转化为成套美术素材,并且能够自动解析、自动映射、自动绑定到代码中的方法。
## 发明内容
### 要解决的技术问题
本发明主要解决以下技术问题:
1. 如何根据文字形态的需求描述快速生成一张完整游戏画面图。
2. 如何基于该画面图进一步生成透明背景的 spritesheet 图片。
3. 如何基于自动边界检测算法逐一解析 spritesheet 中的素材。
4. 如何按照从上到下、从左到右的顺序将素材与文字描述中的画面元素一一对应。
5. 如何将映射结果稳定绑定到代码,减少人工切图和手工配置成本。
### 技术方案
本发明提供一种高一致性美术素材生成方法,包括如下步骤:
```text
文字形态需求描述
-> 游戏画面图生成
-> 透明背景 spritesheet 生成
-> 自动边界检测解析素材
-> 顺序映射文字元素
-> 代码绑定
```
其中,所述文字形态需求描述至少包含画面元素名称、语义说明、布局意图和顺序信息。所述游戏画面图用于表达整体视觉风格和元素关系;所述 spritesheet 图片用于承载需要随不同设备分辨率自适应调整位置的素材;所述自动边界检测算法用于把 spritesheet 中的独立素材一一切分出来;所述顺序映射用于将解析结果与文字描述中的元素一一对应;所述代码绑定用于将元素标识、资源地址、边界框或布局参数写入代码配置或元素表。
### 有益效果
与现有技术相比,本发明至少具有以下效果:
1. 降低人工切图成本。
2. 降低人工命名和代码绑定成本。
3. 提升整体美术素材一致性。
4. 提升多分辨率适配效率。
5. 减少重复生成和重复调整次数。
6. 让文字需求到代码元素的映射更稳定、更可维护。
## 附图说明
图 1 为本发明从文字需求描述到元素绑定的总体流程图。
图 2 为游戏画面图生成与 spritesheet 生成的派生关系示意图。
图 3 为自动边界检测算法解析透明背景 spritesheet 的流程图。
图 4 为素材顺序与文字形态需求描述中的画面元素一一对应的映射关系示意图。
## 具体实施方式
### 一、系统组成
本发明的系统可以包括如下模块:
1. 输入采集模块:用于接收文字形态需求描述。
2. 图像生成模块:用于根据文字形态需求描述生成游戏画面图。
3. 图集生成模块:用于根据游戏画面图生成透明背景 spritesheet 图片。
4. 边界检测模块:用于对 spritesheet 图片执行自动边界检测算法。
5. 顺序映射模块:用于将解析出的素材按照从上到下、从左到右的顺序与文字描述中的画面元素对应。
6. 代码绑定模块:用于将元素标识与对应素材绑定。
### 二、方法步骤
#### S100接收文字形态需求描述
系统接收用户输入的文字形态需求描述。该需求描述可写成一段自然语言,也可写成按元素顺序排列的结构化文本。需求描述中应至少能够识别出画面元素名称、语义含义和布局顺序。
#### S200生成游戏画面图
图像生成模块调用图片生成模型,根据所述文字形态需求描述生成一张完整游戏画面图。所述游戏画面图用于表达整体视觉关系、主次层级和风格基调,为后续 spritesheet 生成提供统一参考。
#### S300生成透明背景 spritesheet 图片
图集生成模块以所述游戏画面图为参考,再次调用图片生成模型,生成一张透明背景的 spritesheet 图片。所述 spritesheet 图片中包含需要随不同设备分辨率自适应调整位置的素材,例如按钮、状态条、提示气泡、装饰元素或其他需要由代码控制位置的元素。
#### S400自动边界检测解析素材
边界检测模块对所述 spritesheet 图片执行自动边界检测算法,对透明背景中的每个独立素材进行逐一解析,输出素材边界框、素材索引和必要的资源属性。所述自动边界检测算法优选采用 alpha 通道连通域检测、边界矩形检测或二者组合;在一个优选实施方式中,可复用拼图场景中已验证的自动边界检测思路,以提高解析稳定性。
#### S500按照顺序映射文字元素
顺序映射模块将解析出的素材按照从上到下、从左到右的顺序进行排列,并与文字形态需求描述中的画面元素内容一一对应。若需求描述中已显式给出元素顺序,则优先按该顺序映射;若仅给出自然语言描述,则可先抽取元素列表,再按布局顺序排序。由此形成元素索引与语义名称之间的稳定映射关系。
#### S600代码绑定
代码绑定模块将所述映射关系写入代码配置、元素表或资源清单中。代码侧只需读取元素标识,即可找到对应素材的资源地址、边界框和布局参数,从而完成美术素材与程序逻辑之间的直接绑定。
#### S700输出美术素材包
系统最终输出至少包括游戏画面图、透明背景 spritesheet 图片、素材映射表和代码绑定结果。由于 spritesheet 图片与游戏画面图来自同一视觉链路,且素材顺序与文字描述顺序一一对应,因此可得到风格统一、可直接绑定、可适配多分辨率的高一致性美术素材包。
### 三、核心机制
1. 文字驱动:一次文字描述即可驱动画面图和 spritesheet 生成。
2. 单图派生spritesheet 以游戏画面图为参考生成,减少风格漂移。
3. 自动解析:边界检测算法替代人工切图。
4. 顺序对应:素材顺序与文字元素顺序一致,减少命名和对图错误。
5. 代码绑定:映射结果可直接进入代码配置或资源表。
### 四、实施例
#### 实施例一:界面型 2D 小游戏素材生成
用户输入“科技实验室界面,顶部标题栏,中部主角色,底部三个操作按钮,右侧状态提示”。系统先生成一张完整游戏画面图,再生成一张透明背景 spritesheet 图片。边界检测模块解析出标题栏、主角色、操作按钮和状态提示等素材,顺序映射模块按从上到下、从左到右的顺序将其与文字描述对应,代码绑定模块将这些元素写入代码配置,最终形成可直接用于界面装配的素材包。
#### 实施例二:需要自适应位置的素材生成
用户输入“横版战斗界面,血条、技能按钮、提示气泡、道具栏”。系统将这些需要随设备分辨率自适应调整位置的元素集中生成到同一张 spritesheet 图片中。运行时,代码根据元素绑定结果对血条、按钮和提示元素进行位置调整,而不改变它们对应的语义关系。
#### 实施例三:代码与元素一一绑定
系统为解析出的每个素材分配唯一元素标识,例如 `top_title_bar``center_character``bottom_actions``right_status_hint`。代码侧通过元素标识直接读取对应素材的边界框和资源路径,从而消除人工对图和人工命名的步骤。
## 权利要求书草案
1. 一种极低成本快速生成高质量 2D 小游戏高一致性美术素材的方法,其特征在于,包括:接收文字形态需求描述;根据所述文字形态需求描述调用图片生成模型生成游戏画面图;以所述游戏画面图为参考图再次调用图片生成模型生成透明背景的 spritesheet 图片;对所述 spritesheet 图片执行自动边界检测算法,逐一解析素材边界;按照从上到下、从左到右的顺序将解析出的素材与所述文字形态需求描述中的画面元素一一对应;将代码中的元素标识与对应素材绑定。
2. 根据权利要求 1 所述的方法,其特征在于,所述文字形态需求描述至少包括画面元素名称、语义说明和布局顺序。
3. 根据权利要求 1 所述的方法,其特征在于,所述游戏画面图用于表达整体视觉风格和元素关系,所述 spritesheet 图片用于承载需要随不同设备分辨率自适应调整位置的素材。
4. 根据权利要求 1 所述的方法,其特征在于,所述 spritesheet 图片具有透明背景,且素材之间通过透明区域分隔。
5. 根据权利要求 1 所述的方法,其特征在于,所述自动边界检测算法包括基于 alpha 通道的连通域检测、边界矩形检测或二者组合。
6. 根据权利要求 5 所述的方法,其特征在于,所述自动边界检测算法复用拼图场景中已验证的素材边界解析思路。
7. 根据权利要求 1 所述的方法,其特征在于,所述从上到下、从左到右的顺序用于建立元素索引与语义名称之间的映射表。
8. 根据权利要求 1 所述的方法,其特征在于,所述代码绑定包括为每一素材写入唯一元素标识,并在代码中通过所述元素标识读取对应素材的资源地址、边界框或布局参数。
9. 根据权利要求 1 所述的方法,其特征在于,所述 spritesheet 图片中的素材包括按钮、状态条、提示元素、装饰元素或其他需要自适应布局的画面元素。
10. 根据权利要求 1 所述的方法,其特征在于,所述游戏画面图与所述 spritesheet 图片由同一视觉链路生成,以保持美术素材的一致性。
11. 根据权利要求 1 所述的方法,其特征在于,所述元素绑定结果用于在不同设备分辨率下动态调整素材位置,而不改变元素语义对应关系。
12. 一种极低成本快速生成高质量 2D 小游戏高一致性美术素材的系统,其特征在于,包括输入采集模块、图像生成模块、图集生成模块、边界检测模块、顺序映射模块和代码绑定模块;所述各模块被配置为执行权利要求 1 至 11 任一项所述的方法。
13. 一种电子设备,包括处理器和存储器,所述存储器中存储有计算机程序,其特征在于,所述计算机程序被所述处理器执行时实现权利要求 1 至 11 任一项所述的方法。
14. 一种计算机可读存储介质,其上存储有计算机程序,其特征在于,所述计算机程序被处理器执行时实现权利要求 1 至 11 任一项所述的方法。
## 可重点保护的创新点
1. 文字需求直接驱动一张游戏画面图。
2. 基于该画面图再生成透明背景 spritesheet。
3. 自动边界检测替代人工切图。
4. 按从上到下、从左到右的顺序把素材与文字元素一一对应。
5. 通过元素标识直接绑定代码与素材,减少人工命名和对图成本。
## 正式申请前建议
1. 检索是否已有“文字生成画面图 + spritesheet 自动解析 + 元素绑定”的相近专利,再确定独立权利要求的保护重心。
2. 将“极低成本”“高质量”等效果性表述尽量放在说明书效果部分,权利要求中改写为“减少人工切图”“减少重复生成”“提高一致性”等技术特征。
3. 避免在权利要求中绑定特定供应商或模型名称;模型名称可保留在实施例中。
4. 如需扩大保护范围可将“2D 小游戏”进一步上位为“交互式图像驱动应用”的美术素材生成方法。
5. 如需增强授权稳定性,可将“文字驱动生成 + 透明 spritesheet + 自动边界检测 + 顺序映射 + 代码绑定”组合为主权利要求的必要技术特征。

View File

@@ -160,7 +160,7 @@ npm run check:server-rs-ddd
- LLM`GENARRATIVE_LLM_*`,创意 Agent 另用 `APIMART_BASE_URL` / `APIMART_API_KEY` - LLM`GENARRATIVE_LLM_*`,创意 Agent 另用 `APIMART_BASE_URL` / `APIMART_API_KEY`
- 图片生成VectorEngine `gpt-image-2` 图片 provider 归属 `platform-image`,密钥只在后端环境变量中;`api-server` 内的 `openai_image_generation.rs` 只是兼容调用面和外部失败审计桥接,不再承载 provider 协议实现。APIMart 只保留给创意 Agent `gpt-5` Responses 文本 / 多模态链路DashScope 只按仍在使用的历史能力单独处理,不作为 GPT-image-2 兜底。 - 图片生成VectorEngine `gpt-image-2` 图片 provider 归属 `platform-image`,密钥只在后端环境变量中;`api-server` 内的 `openai_image_generation.rs` 只是兼容调用面和外部失败审计桥接,不再承载 provider 协议实现。APIMart 只保留给创意 Agent `gpt-5` Responses 文本 / 多模态链路DashScope 只按仍在使用的历史能力单独处理,不作为 GPT-image-2 兜底。
- Match3D 物品 sheet关卡整图完成后走 VectorEngine `/v1/images/edits` multipart `image`,模型为 `gpt-image-2``2K 1:1` 输出 `10*10` spritesheet物品 sheet prompt 固定要求纯绿色绿幕背景,后端上传 OSS 前必须把绿幕扣成透明 PNG并把透明整图写入 `itemSpritesheetImageSrc/itemSpritesheetImageObjectKey`。后端固定从该 sheet 解析并持久化 20 个物品、每个 5 个形态;通用系列素材图集的行列索引按每行 2 个物品计算,必须落在 `1..=10`,难度只决定运行态加载 3 / 9 / 15 / 20 种。 - Match3D 物品 sheet关卡整图完成后走 VectorEngine `/v1/images/edits` multipart `image`,模型为 `gpt-image-2``2K 1:1` 输出 `10*10` spritesheet物品 sheet prompt 固定要求纯绿色绿幕背景,后端上传 OSS 前必须把绿幕扣成透明 PNG并把透明整图写入 `itemSpritesheetImageSrc/itemSpritesheetImageObjectKey`。后端优先按透明 alpha 连通域从该 sheet 识别真实素材矩形并持久化 20 个物品、每个 5 个形态;识别数量不足时才回退 `10*10` 固定网格。通用系列素材图集的行列索引按每行 2 个物品计算,必须落在 `1..=10`,难度只决定运行态加载 3 / 9 / 15 / 20 种。
- Match3D UI spritesheet 和背景派生图:关卡整图作为参考图并发生成 `1K 1:1` UI spritesheet 与 `1K 9:16` 背景图,模型均为 `gpt-image-2`。UI spritesheet prompt 固定要求纯绿色绿幕背景,后端上传 OSS 前必须把绿幕扣成透明 PNG背景图必须合成为全画幅不透明 PNG。 - Match3D UI spritesheet 和背景派生图:关卡整图作为参考图并发生成 `1K 1:1` UI spritesheet 与 `1K 9:16` 背景图,模型均为 `gpt-image-2`。UI spritesheet prompt 固定要求纯绿色绿幕背景,后端上传 OSS 前必须把绿幕扣成透明 PNG背景图必须合成为全画幅不透明 PNG。
- Match3D 1:1 容器 UIVectorEngine `/v1/images/edits` multipart 参考图。该容器参考图是后端生图协议输入,必须通过 `include_bytes!``api-server` 编译进二进制,避免 API 单独发布或运行目录缺少 `public/` 时生成失败。 - Match3D 1:1 容器 UIVectorEngine `/v1/images/edits` multipart 参考图。该容器参考图是后端生图协议输入,必须通过 `include_bytes!``api-server` 编译进二进制,避免 API 单独发布或运行目录缺少 `public/` 时生成失败。
- 敲木鱼敲击物和背景环境图VectorEngine `/v1/images/edits`,模型固定 `gpt-image-2`。敲击物支持 multipart 多参考图第一张固定为后端内嵌默认木鱼图用户上传图只作为新主题参考prompt 必须要求 `1:1` 真实透明 alpha PNG 并禁止黑底、白底、棋盘格和任何实底背景。当前敲击物上传 OSS 前不做服务端抠图后处理避免误伤玉米等主体像素。背景环境图只使用第一步抠图完成后的透明敲击物图作为参考prompt 必须要求中央主体预留区保持干净,中央 40% 区域禁止出现主题主体、主体局部特写、轮廓影子或重复元素,主题元素只能作为外围氛围,且必须显式声明不继承任何绿色底色、绿幕底色或纯绿色画布。 - 敲木鱼敲击物和背景环境图VectorEngine `/v1/images/edits`,模型固定 `gpt-image-2`。敲击物支持 multipart 多参考图第一张固定为后端内嵌默认木鱼图用户上传图只作为新主题参考prompt 必须要求 `1:1` 真实透明 alpha PNG 并禁止黑底、白底、棋盘格和任何实底背景。当前敲击物上传 OSS 前不做服务端抠图后处理避免误伤玉米等主体像素。背景环境图只使用第一步抠图完成后的透明敲击物图作为参考prompt 必须要求中央主体预留区保持干净,中央 40% 区域禁止出现主题主体、主体局部特写、轮廓影子或重复元素,主题元素只能作为外围氛围,且必须显式声明不继承任何绿色底色、绿幕底色或纯绿色画布。

View File

@@ -72,7 +72,7 @@ RPG 从作品架、广场详情或作品号搜索点击“启动”前,入口
RPG 运行态的战斗终局、继续冒险、继续探索和切场景都属于服务端 runtime 快照真相:`module-runtime-story` 必须在终局战斗 action 后调用 post-battle finalization持久写入 `story_continue_adventure``deferredOptions``deferredRuntimeState.storyEngineMemory.currentSceneActState` 和清理后的战斗状态;`idle_travel_next_scene` / `camp_travel_home_scene` 必须由后端写入新的 `currentScenePreset``currentSceneActState``currentEncounter``runtimeStats.scenesTraveled`。前端只播放退场、进场和继续按钮表现,不能用默认 `观察/试探/调息` fallback 或本地动画假装推进剧情。旧 bootstrap 快照可能只有 `connectedSceneIds` / `forwardSceneId` 而没有 `connections`,后端生成战后旅行选项时必须兼容这些字段。 RPG 运行态的战斗终局、继续冒险、继续探索和切场景都属于服务端 runtime 快照真相:`module-runtime-story` 必须在终局战斗 action 后调用 post-battle finalization持久写入 `story_continue_adventure``deferredOptions``deferredRuntimeState.storyEngineMemory.currentSceneActState` 和清理后的战斗状态;`idle_travel_next_scene` / `camp_travel_home_scene` 必须由后端写入新的 `currentScenePreset``currentSceneActState``currentEncounter``runtimeStats.scenesTraveled`。前端只播放退场、进场和继续按钮表现,不能用默认 `观察/试探/调息` fallback 或本地动画假装推进剧情。旧 bootstrap 快照可能只有 `connectedSceneIds` / `forwardSceneId` 而没有 `connections`,后端生成战后旅行选项时必须兼容这些字段。
RPG / 拼图等运行态存档选择入口统一在个人中心 `次级入口 > 存档` 和设置入口区保留为独立弹窗;“玩过”弹窗可以继续合并展示可继续存档,但不能成为唯一入口。移动端“我的”页的五项常用功能宫格只放泥点充值、邀请好友、兑换码、玩家社区、反馈与建议,避免把存档挤入主宫格破坏参考图布局。前端只展示 `/api/profile/save-archives` 返回的列表并在用户选择后调用对应恢复接口,不能本地拼装或筛选正式存档真相。 RPG / 拼图等运行态存档仍以 `/api/profile/save-archives` 的后端列表为真相,恢复动作继续走对应恢复接口,但移动端“我的”页已经不再提供独立的 `次级入口 > 存档` 和设置入口存档按钮;“玩过”弹窗可以继续合并展示可继续存档,个人中心只保留设置、扫码、常用功能和条件性次级入口。移动端“我的”页的五项常用功能宫格只放泥点充值、邀请好友、兑换码、玩家社区、反馈与建议,避免把存档挤入主宫格破坏参考图布局。前端只展示 `/api/profile/save-archives` 返回的列表并在用户选择后调用对应恢复接口,不能本地拼装或筛选正式存档真相。
## 拼图 ## 拼图
@@ -191,8 +191,8 @@ RPG / 拼图等运行态存档选择入口统一在个人中心 `次级入口 >
3. 首次调用 VectorEngine `gpt-image-2`,无参考图,竖屏 `9:16`,生成完整抓大鹅关卡画面并持久化到 `generatedBackgroundAsset.levelSceneImageSrc/levelSceneImageObjectKey`。提示词必须包含用户主题描述、顶部返回 / 标题倒计时 / 设置按钮、中间与主题匹配且贴横向边缘的容器,以及底部“移出 / 凑齐 / 打乱”三个道具按钮。 3. 首次调用 VectorEngine `gpt-image-2`,无参考图,竖屏 `9:16`,生成完整抓大鹅关卡画面并持久化到 `generatedBackgroundAsset.levelSceneImageSrc/levelSceneImageObjectKey`。提示词必须包含用户主题描述、顶部返回 / 标题倒计时 / 设置按钮、中间与主题匹配且贴横向边缘的容器,以及底部“移出 / 凑齐 / 打乱”三个道具按钮。
4. 关卡整图完成后并发发起三次 `gpt-image-2` 编辑请求,三者都以关卡整图作为参考图:`1K``1:1` 的 UI spritesheet 写入 `uiSpritesheetImageSrc/uiSpritesheetImageObjectKey``1K``9:16` 的背景图写入 `imageSrc/imageObjectKey``2K``1:1` 的物品 spritesheet 写入 `itemSpritesheetImageSrc/itemSpritesheetImageObjectKey` 4. 关卡整图完成后并发发起三次 `gpt-image-2` 编辑请求,三者都以关卡整图作为参考图:`1K``1:1` 的 UI spritesheet 写入 `uiSpritesheetImageSrc/uiSpritesheetImageObjectKey``1K``9:16` 的背景图写入 `imageSrc/imageObjectKey``2K``1:1` 的物品 spritesheet 写入 `itemSpritesheetImageSrc/itemSpritesheetImageObjectKey`
5. UI spritesheet 提示词固定要求按从上到下、从左到右整理纯绿色绿幕背景素材:返回按钮、设置按钮、方格素材(不含边框,仅保留一个)、移出按钮、凑齐按钮、打乱按钮;后端上传 OSS 前必须把绿幕扣成透明 PNG。背景图提示词固定要求移除全部 UI 组件和容器内含物,完整保留容器和背景,并补全被 UI 覆盖的背景内容。 5. UI spritesheet 提示词固定要求按从上到下、从左到右整理纯绿色绿幕背景素材:返回按钮、设置按钮、方格素材(不含边框,仅保留一个)、移出按钮、凑齐按钮、打乱按钮;后端上传 OSS 前必须把绿幕扣成透明 PNG。背景图提示词固定要求移除全部 UI 组件和容器内含物,完整保留容器和背景,并补全被 UI 覆盖的背景内容。
6. 物品 spritesheet 固定 `10行*10列`、统一纯绿色绿幕背景,后端上传 OSS 前必须把绿幕扣成透明 PNG素材间距严格均匀分布每一行包含两种物品每种物品五个不同形态物品来自参考图中心容器中的 2D 素材,严禁高相似度物品。新流程每次固定解析并持久化 `20` 种物品,物品信息列表全部展示这 `20` 种;持久化单格映射必须`row = itemIndex / 2 + 1``col = itemIndex % 2 * 5 + viewIndex + 1` 写入通用系列素材图集,不能再用 `row = itemIndex + 1``generatedItemAssets[].imageViews[]` 仍兼容已切好的五视角图,缺失时运行态和编辑器按 spritesheet 自动解析结果回退。 6. 物品 spritesheet 固定 `10行*10列`、统一纯绿色绿幕背景,后端上传 OSS 前必须把绿幕扣成透明 PNG素材间距严格均匀分布每一行包含两种物品每种物品五个不同形态物品来自参考图中心容器中的 2D 素材,严禁高相似度物品。新流程每次解析并持久化 `20` 种物品,物品信息列表全部展示这 `20` 种;后端切 `generatedItemAssets[].imageViews[]` 时优先按透明 alpha 连通域识别真实素材矩形,再按原图从上到下、从左到右排序,每 `5` 个区域组成一个物品的五个形态;只有识别出的区域数量不足时才回退 `10*10` 固定网格。持久化单格映射元数据仍`row = itemIndex / 2 + 1``col = itemIndex % 2 * 5 + viewIndex + 1` 写入通用系列素材图集,不能再用 `row = itemIndex + 1``generatedItemAssets[].imageViews[]` 仍兼容已切好的五视角图,缺失时运行态和编辑器按 spritesheet 自动解析结果回退。
7. 前端和运行态统一使用 alpha 连通域矩形检测解析 spritesheetUI 图按返回、设置、方格、移出、凑齐、打乱顺序映射回原 UI 位置;物品图按检测顺序每 `5` 个区域组成一个物品的五个形态,最多 `20` 个物品。透明背景是解析前提,不能在前端按固定像素坐标写死切片。 7. 前端和运行态统一使用 alpha 连通域矩形检测解析 spritesheetUI 图先把识别出的透明素材矩形按行聚类,再在每一行内按横向 `x` 坐标排序,最后按返回、设置、方格、移出、凑齐、打乱顺序映射回原 UI 位置;不能只按全局 `y` 坐标排序,否则同一行素材上下略有错位时会把方格和底部道具按钮顺序打乱。物品图按检测顺序每 `5` 个区域组成一个物品的五个形态,最多 `20` 个物品。透明背景是解析前提,不能在前端按固定像素坐标写死切片。
8. 文本生成物品名称时必须同时生成 `itemSize`,只允许 `大``中``小`。该字段随 `generatedItemAssets[].itemSize` 持久化并下发;历史缺失字段的素材按 `大` 兼容,模型缺失或非法值按物品名本地推断。 8. 文本生成物品名称时必须同时生成 `itemSize`,只允许 `大``中``小`。该字段随 `generatedItemAssets[].itemSize` 持久化并下发;历史缺失字段的素材按 `大` 兼容,模型缺失或非法值按物品名本地推断。
9. 当前抓大鹅音频生成关闭:入口无 `生成音效`,草稿不生成背景音乐或点击音效,结果页不展示背景音乐 Tab 或点击音效生成入口。历史 `backgroundMusic` / `clickSound` 字段继续兼容传递。 9. 当前抓大鹅音频生成关闭:入口无 `生成音效`,草稿不生成背景音乐或点击音效,结果页不展示背景音乐 Tab 或点击音效生成入口。历史 `backgroundMusic` / `clickSound` 字段继续兼容传递。
10. 背景、UI spritesheet、物品 spritesheet 和历史容器兼容字段的持久化真相仍在 `generatedItemAssets[].backgroundAsset` 与提升后的 `generatedBackgroundAsset`Agent session、work summary/detail、结果页和运行态入口都必须把该字段提升为 `backgroundImageSrc/backgroundImageObjectKey/generatedBackgroundAsset` 读取。草稿编译后的 `draftJson` 自身也必须携带 `generatedItemAssets` 快照HTTP facade 不能只依赖 work detail 回读补齐 UI 资产,外部回读为空时也不得清空草稿内已有的背景 / 图集。平台壳层从作品架、广场、生成完成回调、结果页保存 / 发布 / 试玩回调进入 Match3D profile 时也要先归一化并提升,避免首次试玩、手动试玩、推荐流或公开详情运行态退回默认背景。 10. 背景、UI spritesheet、物品 spritesheet 和历史容器兼容字段的持久化真相仍在 `generatedItemAssets[].backgroundAsset` 与提升后的 `generatedBackgroundAsset`Agent session、work summary/detail、结果页和运行态入口都必须把该字段提升为 `backgroundImageSrc/backgroundImageObjectKey/generatedBackgroundAsset` 读取。草稿编译后的 `draftJson` 自身也必须携带 `generatedItemAssets` 快照HTTP facade 不能只依赖 work detail 回读补齐 UI 资产,外部回读为空时也不得清空草稿内已有的背景 / 图集。平台壳层从作品架、广场、生成完成回调、结果页保存 / 发布 / 试玩回调进入 Match3D profile 时也要先归一化并提升,避免首次试玩、手动试玩、推荐流或公开详情运行态退回默认背景。
@@ -215,12 +215,15 @@ RPG / 拼图等运行态存档选择入口统一在个人中心 `次级入口 >
- 难度只决定本局加载的物品种类数量:轻松 3、标准 9、进阶 15、硬核 20。硬核仍保留 21 次消除和 63 件总物品,运行态按 20 种素材循环复用,不要求生成第 21 种素材。 - 难度只决定本局加载的物品种类数量:轻松 3、标准 9、进阶 15、硬核 20。硬核仍保留 21 次消除和 63 件总物品,运行态按 20 种素材循环复用,不要求生成第 21 种素材。
- 运行态启动前要预加载 `generatedItemAssets[].imageViews[]`、顶层 `generatedBackgroundAsset`、物品挂载 `backgroundAsset` 中的背景、UI spritesheet 和物品 spritesheet首次生成自动试玩、结果页手动试玩、推荐流和公开详情启动都必须传入提升后的 profile。卡片摘要缺图集字段时进入运行态前必须补读 work detail。补读后的 profile 也要再次提升 `generatedItemAssets[].backgroundAsset`,确保背景和图集字段传给 `Match3DRuntimeShell` - 运行态启动前要预加载 `generatedItemAssets[].imageViews[]`、顶层 `generatedBackgroundAsset`、物品挂载 `backgroundAsset` 中的背景、UI spritesheet 和物品 spritesheet首次生成自动试玩、结果页手动试玩、推荐流和公开详情启动都必须传入提升后的 profile。卡片摘要缺图集字段时进入运行态前必须补读 work detail。补读后的 profile 也要再次提升 `generatedItemAssets[].backgroundAsset`,确保背景和图集字段传给 `Match3DRuntimeShell`
- 背景图作为运行态全屏背景,图内已经保留容器;旧 `containerImage*` 只作为历史透明容器兼容字段。若 `containerImage*``uiSpritesheetImage*` 同源,运行态不得把 UI spritesheet 当中心容器图叠到棋盘上。 - 背景图作为运行态全屏背景,图内已经保留容器;旧 `containerImage*` 只作为历史透明容器兼容字段。若 `containerImage*``uiSpritesheetImage*` 同源,运行态不得把 UI spritesheet 当中心容器图叠到棋盘上。
- 抓大鹅运行态 HUD 需贴近拼图顶部信息条的视觉口径:左上只保留透明返回按钮;右上不再暴露设置入口;顶部关卡名和倒计时直接复用拼图同款的铭牌 + 下挂计时牌结构、同色板和同造型,并在牌面左侧挂上 `media/logo.png` 产品 logo下方备选栏和道具图标只保留内容与交互边界不再显示灰白半透底板中央容器图层视觉可隐藏但棋盘命中边界仍保留。
- generated 私有图换签未完成时,局内物品先隐藏等待,不得短暂显示默认积木;同一批资源在重启 run 时保留已解析签名 URL只有资源源列表变化或换签失败后才允许进入兜底视觉。 - generated 私有图换签未完成时,局内物品先隐藏等待,不得短暂显示默认积木;同一批资源在重启 run 时保留已解析签名 URL只有资源源列表变化或换签失败后才允许进入兜底视觉。
- `itemSize` 只缩放生成 2D 图片本体:`大``中``小` 均按相对尺寸缩放,其中 `大` 也比原始图片略小,`中``小` 进一步缩小;不改变后端下发的布局半径、点击半径或三消规则。 - `itemSize` 只缩放生成 2D 图片本体:`大``中``小` 均按相对尺寸缩放,其中 `大` 也比原始图片略小,`中``小` 进一步缩小;不改变后端下发的布局半径、点击半径或三消规则。
- 物品进入底部物品栏时按同类型插入:如果物品栏已有同类物品,新物品插到该类型最后一个物品后面,后续物品整体后移;没有同类时追加到当前末尾。达到三件同类时,在飞入物品栏动画结束后,左侧和右侧同类物品向中间合成,三件一起消失,播放合成音效,不展示星星图标,后面的物品再向前补位。该动效只是前端表现层,后端和本地试玩仍负责权威插入、指定点击类型清除与补位后的槽位快照。 - 物品进入底部物品栏时按同类型插入:如果物品栏已有同类物品,新物品插到该类型最后一个物品后面,后续物品整体后移;没有同类时追加到当前末尾。达到三件同类时,在飞入物品栏动画结束后,左侧和右侧同类物品向中间合成,三件一起消失,播放合成音效,不展示星星图标,后面的物品再向前补位。该动效只是前端表现层,后端和本地试玩仍负责权威插入、指定点击类型清除与补位后的槽位快照。
- 抓大鹅运行态右上角常驻设置入口,直接暴露重新开始按钮;重新开始收口到设置面板内,结算弹层仍保留结果态的再来一局动作。 - 抓大鹅运行态不渲染右上角设置入口,也不在局内直接暴露重新开始按钮;结算弹层仍保留结果态的再来一局动作。
- 高 DPR 移动端 WebGL canvas 必须锁定 CSS 尺寸,避免右下溢出。 - 高 DPR 移动端 WebGL canvas 必须锁定 CSS 尺寸,避免右下溢出。
发现页可挂载官方抓大鹅静态 demo用于验证生图、切图和运行态资源闭环。当前 demo profile 固定为 `match3d-demo-20260525`,公开作品号为 `M3-20260525`,静态资源位于 `public/match3d-demo/undersea-candy-market/`公开卡片、作品号搜索和详情启动都走平台现有公开作品详情不新建页面。demo 运行态使用前端本地 `createLocalMatch3DRuntimeAdapter`,不调用正式 Match3D runtime 后端、不新增 SpacetimeDB schema也不写正式作品统计后续若要把 demo 资源转成正式公开作品,必须改为后端 profile / gallery 投影真相后再接正式 runtime。
## 视觉小说 ## 视觉小说
当前视觉小说只吸收外部 TXT 玩法的创作与运行经验,不迁入外部平台社区、支付、榜单、私有存档或回放。 当前视觉小说只吸收外部 TXT 玩法的创作与运行经验,不迁入外部平台社区、支付、榜单、私有存档或回放。

View File

@@ -93,9 +93,9 @@ server-rs + Axum + SpacetimeDB
7. 主站入口已锁定移动端页面级缩放;单个游戏页面不要再重复实现整页缩放锁定。 7. 主站入口已锁定移动端页面级缩放;单个游戏页面不要再重复实现整页缩放锁定。
8. 图像输入通用 UI 统一走 `src/components/common/CreativeImageInputPanel.tsx`。外层页面持有业务状态组件只承担上传卡、预览、参考图缩略图、AI 重绘开关、错误展示和提交按钮。 8. 图像输入通用 UI 统一走 `src/components/common/CreativeImageInputPanel.tsx`。外层页面持有业务状态组件只承担上传卡、预览、参考图缩略图、AI 重绘开关、错误展示和提交按钮。
9. 发现页 `分类` 子频道的筛选必须打开独立 dialog / drawer / modal至少支持玩法类型过滤与排序切换筛选结果为空时显示空状态不把筛选内容展开在当前列表下方。 9. 发现页 `分类` 子频道的筛选必须打开独立 dialog / drawer / modal至少支持玩法类型过滤与排序切换筛选结果为空时显示空状态不把筛选内容展开在当前列表下方。
10. 移动端“我的”页按参考图顺序组织为顶部头像 / 昵称 / 陶泥号、会员横幅、三张统计卡、每日任务、五项常用功能宫格、设置入口、次级入口和法律信息;`media/profile/` 中的陶泥素材作为该页图形资产。常用功能宫格固定承载泥点充值、邀请好友、兑换码、玩家社区、反馈与建议;存档和填邀请码保留在次级入口带,不挤入五宫格 10. 移动端“我的”页顶部品牌行承载扫码和设置入口,正文按参考图顺序组织为头像 / 昵称 / 陶泥号、会员横幅、三张统计卡、每日任务、五项常用功能宫格、设置入口、可选次级入口和法律信息;`media/profile/` 中的陶泥素材作为该页图形资产。常用功能宫格固定承载泥点充值、邀请好友、兑换码、玩家社区、反馈与建议;页面不再提供独立存档按钮入口,填邀请码仅在新用户可填写窗口内展示为次级入口
11. “我的”页泥点、游戏时长、已玩游戏数量三张统计卡只展示各自标签和值,内容不换行,不在统计区底部展示“更新于”时间,字号维持平台普通 UI 档位;移动端昵称、会员卡、每日任务、常用功能和法律信息也应保持 `10px``14px` 的普通 UI 字号区间,避免展示级字号挤压内容。 11. “我的”页泥点、游戏时长、已玩游戏数量三张统计卡只展示各自标签和值,三个统计 icon 使用小尺寸普通 UI 档位,内容不换行,不在统计区底部展示“更新于”时间;移动端昵称、会员卡、每日任务、常用功能和法律信息也应保持 `10px``14px` 的普通 UI 字号区间,避免展示级字号挤压内容。
12. 移动端“我的”页需要兼容窄屏:头像 / 昵称 / 陶泥号、三张统计卡、每日任务、五项常用功能、次级入口和法律信息都必须能在底部固定 TabBar 上方完整滚动露出,不得与底部 dock、刘海 safe-area 或相邻 UI 元素遮挡重叠。 12. 移动端“我的”页需要兼容窄屏:头像 / 昵称 / 陶泥号、三张统计卡、每日任务、五项常用功能、可选次级入口和法律信息都必须能在底部固定 TabBar 上方完整滚动露出,不得与底部 dock、刘海 safe-area 或相邻 UI 元素遮挡重叠。
13. RPG 等运行态的战斗飘字、血量变化和即时反馈必须在暗色、噪声高的场景背景上保持可读:使用高亮文字、深色描边、强阴影或小面积半透明底,不只依赖红/绿文字本身表达伤害或治疗。 13. RPG 等运行态的战斗飘字、血量变化和即时反馈必须在暗色、噪声高的场景背景上保持可读:使用高亮文字、深色描边、强阴影或小面积半透明底,不只依赖红/绿文字本身表达伤害或治疗。
14. 平台亮色 UI 配色以陶泥儿主视觉为准:暖白 / 米杏底、陶土橙主按钮、深棕正文与浅杏边框;新增界面优先复用 `src/index.css``--platform-*` 主题变量和 `apps/admin-web/src/styles/admin.css` 的同系色值,不再引入粉红、蓝绿等独立主色方案。 14. 平台亮色 UI 配色以陶泥儿主视觉为准:暖白 / 米杏底、陶土橙主按钮、深棕正文与浅杏边框;新增界面优先复用 `src/index.css``--platform-*` 主题变量和 `apps/admin-web/src/styles/admin.css` 的同系色值,不再引入粉红、蓝绿等独立主色方案。

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Some files were not shown because too many files have changed in this diff Show More