Merge branch 'master' into codex/frontend-error-dialogs
# Conflicts: # .hermes/shared-memory/decision-log.md # server-rs/crates/api-server/src/generated_asset_sheets.rs
This commit is contained in:
92
docs/technical/【后端架构】统一公开作品ReadModel设计-2026-05-26.md
Normal file
92
docs/technical/【后端架构】统一公开作品ReadModel设计-2026-05-26.md
Normal file
@@ -0,0 +1,92 @@
|
||||
# 统一公开作品 ReadModel 设计
|
||||
|
||||
更新时间:`2026-05-26`
|
||||
|
||||
## 背景
|
||||
|
||||
各玩法原本各自维护 `*_gallery_card_view` / `*_gallery_view` / `custom_world_gallery_entry` 等公开投影。它们继续保留为 source view 和兼容路径,但公开列表与公开详情的主读模型需要跨玩法统一,避免 `api-server` 在 HTTP 热路径里为每个玩法各写一套拼装逻辑。
|
||||
|
||||
## 统一契约
|
||||
|
||||
公开列表主读模型:
|
||||
|
||||
- `public_work_gallery_entry`
|
||||
|
||||
公开详情摘要主读模型:
|
||||
|
||||
- `public_work_detail_entry`
|
||||
|
||||
统一字段只保留公开层契约所需内容:
|
||||
|
||||
- `source_type`
|
||||
- `work_id`
|
||||
- `profile_id`
|
||||
- `source_session_id`
|
||||
- `public_work_code`
|
||||
- `owner_user_id`
|
||||
- `author_display_name`
|
||||
- `world_name`
|
||||
- `subtitle`
|
||||
- `summary_text`
|
||||
- `cover_image_src`
|
||||
- `cover_asset_id`
|
||||
- `theme_tags`
|
||||
- `play_count`
|
||||
- `remix_count`
|
||||
- `like_count`
|
||||
- `published_at_micros`
|
||||
- `updated_at_micros`
|
||||
- `sort_time_micros`
|
||||
- `detail_payload_json`
|
||||
|
||||
其中 `detail_payload_json` 只承载平台详情页展示扩展,不承载正式 runtime 配置、玩法规则或草稿真相。
|
||||
|
||||
## 来源与兼容
|
||||
|
||||
统一 public view 由现有玩法 source view 组装:
|
||||
|
||||
- `puzzle_gallery_card_view`
|
||||
- `puzzle_gallery_view`
|
||||
- `custom_world_gallery_entry`
|
||||
- `jump_hop_gallery_card_view`
|
||||
- `jump_hop_gallery_view`
|
||||
- `wooden_fish_gallery_card_view`
|
||||
- `wooden_fish_gallery_view`
|
||||
- `match_3_d_gallery_view`
|
||||
- `square_hole_gallery_view`
|
||||
- `visual_novel_gallery_view`
|
||||
- `big_fish_gallery_view`
|
||||
- `bark_battle_gallery_view`
|
||||
|
||||
规则是:
|
||||
|
||||
- 旧 view 保留,不删除。
|
||||
- 旧 view 退到底层 source / 兼容职责。
|
||||
- 新 `public_work_*` view 是 `api-server` 公开列表 / 详情的统一主读模型。
|
||||
- 旧 `/api/runtime/<play>/gallery` 响应 shape 保持兼容,由 BFF mapper 把统一 cache 再映射回当前 DTO。
|
||||
- 旧详情 / runtime / 点赞 / 游玩 / Remix 仍走玩法专用路径。
|
||||
|
||||
## 订阅与路由
|
||||
|
||||
`spacetime-client` 当前长期订阅:
|
||||
|
||||
- `SELECT * FROM public_work_gallery_entry`
|
||||
- `SELECT * FROM public_work_detail_entry`
|
||||
- `SELECT * FROM public_work_play_daily_stat`
|
||||
- 各玩法 source view 作为兼容缓存和旧路径支撑
|
||||
|
||||
`api-server` 当前新增统一公开路由:
|
||||
|
||||
- `GET /api/public-works`
|
||||
- `GET /api/public-works/{publicWorkCode}`
|
||||
|
||||
旧 route 继续保留,由 BFF 从统一 cache 映射回旧 DTO 形状。
|
||||
|
||||
## 验证
|
||||
|
||||
- `npm run spacetime:generate`
|
||||
- `npm run check:spacetime-schema`
|
||||
- `cargo check -p spacetime-client --manifest-path server-rs/Cargo.toml`
|
||||
- `cargo check -p api-server --manifest-path server-rs/Cargo.toml`
|
||||
- `npm run typecheck`
|
||||
- `npm run check:encoding`
|
||||
@@ -131,7 +131,7 @@ npm run check:server-rs-ddd
|
||||
3. 删除字段、改名、重排字段、改类型或修改字段属性前,必须先询问用户并确认迁移计划。
|
||||
4. Vec 字段不要直接写无法 const 求值的 default;需要默认空集合时优先使用 `Option<Vec<T>>` 加 `#[default(None::<Vec<T>>)]`,业务层归一为空数组。
|
||||
5. 运行态读表必须按已声明索引访问。只要 table 上存在覆盖查询前缀的 `#[index(...)]` 或主键 / unique accessor,列表、详情、快照组装和计数都先用对应 accessor `.filter(...)` / `.find(...)`,再在内存中处理索引无法覆盖的残余条件;不得用 `.iter().filter(...)` 扫整表替代现成索引。
|
||||
6. 面向公开列表的只读投影优先做成 public view / public 读模型表,并由 `api-server` 的 `spacetime-client` 长期订阅后读本地 cache。短期不把作品列表整体交给浏览器前端直接订阅;不要让 HTTP 列表接口每次请求都调用 procedure 重新组装全量列表。需要请求时间窗口的轻量统计可订阅公开统计表后在 `api-server` 本地聚合,需要写入副作用的详情、点赞、游玩记录仍可走 procedure / reducer。中期如要让前端可选直连订阅,只能新增或统一稳定的专用 public read model,例如 `public_work_gallery_entry`,并保持字段、排序键、公开权限和降级语义由后端投影定义;前端不得直接订阅 `puzzle_work_profile`、`custom_world_profile` 等领域源表,也不得自己做 join、聚合或权限逻辑。首屏、排序、字段归一、权限降级和 HTTP fallback 仍由 `api-server` BFF 维持。
|
||||
6. 面向公开列表的只读投影优先做成 public view / public 读模型表,并由 `api-server` 的 `spacetime-client` 长期订阅后读本地 cache。跨玩法公开作品统一主读模型是 `public_work_gallery_entry` 和 `public_work_detail_entry`;各玩法既有 `*_gallery_card_view` / `*_gallery_view` / `custom_world_gallery_entry` 保留为 source view 和兼容路径。短期不把作品列表整体交给浏览器前端直接订阅;不要让 HTTP 列表接口每次请求都调用 procedure 重新组装全量列表。需要请求时间窗口的轻量统计可订阅 `public_work_play_daily_stat` 后在 `api-server` 本地聚合,需要写入副作用的详情、点赞、游玩记录仍走玩法 procedure / reducer。前端不得直接订阅 `puzzle_work_profile`、`custom_world_profile` 等领域源表,也不得自己做 join、聚合或权限逻辑。首屏、排序、字段归一、权限降级和 HTTP fallback 由 `api-server` BFF 维持。
|
||||
7. 多列索引按 SpacetimeDB 绑定生成的元组参数直接传入,例如 `.filter((source_type, profile_id, played_day))`;前缀查询只传前缀元组,例如 `.filter((scope_kind, scope_id.as_str()))`。不要为了绕过类型问题退回整表遍历。
|
||||
8. procedure result 必须返回 typed snapshot / typed value。`spacetime-client` mapper 不得再通过 `row_json/session_json/work_json/items_json/run_json/event_json/feedback_json: Option<String>` 做跨层 JSON 字符串传输,也不得在 mapper 里反序列化旧 `*JsonRecord` 兼容结构。业务内部持久化字段如 `profile_payload_json`、`levels_json` 等不属于 procedure result 载荷例外,仍按各自表契约处理。
|
||||
9. 修改后运行:
|
||||
@@ -160,7 +160,7 @@ npm run check:server-rs-ddd
|
||||
|
||||
- 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 兜底。
|
||||
- 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 1:1 容器 UI:VectorEngine `/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% 区域禁止出现主题主体、主体局部特写、轮廓影子或重复元素,主题元素只能作为外围氛围,且必须显式声明不继承任何绿色底色、绿幕底色或纯绿色画布。
|
||||
@@ -304,7 +304,7 @@ npm run check:server-rs-ddd
|
||||
- Rust view:`big_fish_gallery_view`
|
||||
- 返回类型:`Vec<BigFishWorkSummarySnapshot>`
|
||||
- 源码:`server-rs/crates/spacetime-module/src/big_fish/session.rs`
|
||||
- 说明:大鱼吃小鱼公开广场列表投影,只从 `Published` creation session 组装公开卡片字段;`api-server` 的 `spacetime-client` 长期订阅 `SELECT * FROM big_fish_gallery_view` 与 `SELECT * FROM public_work_play_daily_stat WHERE source_type = 'big-fish'` 后,从本地 cache 构造 `/api/runtime/big-fish/gallery` 响应。公开列表不再每个 HTTP 请求调用 `list_big_fish_works` procedure;个人作品列表、详情、点赞、游玩记录和 Remix 仍按原有 procedure / reducer 路径处理。
|
||||
- 说明:大鱼吃小鱼公开 source 投影,只从 `Published` creation session 组装公开卡片字段;统一公开列表 / 详情主路径通过 `public_work_gallery_entry` / `public_work_detail_entry` 消费该 view 并映射成跨玩法契约。玩法旧 gallery 路径保留兼容 shape;个人作品列表、详情、点赞、游玩记录和 Remix 仍按原有 procedure / reducer 路径处理。
|
||||
|
||||
### `chapter_progression`
|
||||
|
||||
@@ -350,7 +350,7 @@ npm run check:server-rs-ddd
|
||||
|
||||
- Rust 结构体:`CustomWorldGalleryEntry`
|
||||
- 源码:`server-rs/crates/spacetime-module/src/custom_world.rs`
|
||||
- 作用:自定义世界公开作品列表读模型。`api-server` 的 `spacetime-client` 长期订阅 `SELECT * FROM custom_world_gallery_entry` 与 `SELECT * FROM public_work_play_daily_stat WHERE source_type = 'custom-world'`,`/api/runtime/custom-world-gallery` 从本地 cache 排序并聚合 `recentPlayCount7d`,不再每个 HTTP 请求调用 `list_custom_world_gallery_entries` procedure。旧 procedure 只用于兼容旧库缺少 gallery 读模型行时的一次性同步兜底。
|
||||
- 作用:自定义世界公开 source 读模型。统一公开列表 / 详情主路径通过 `public_work_gallery_entry` / `public_work_detail_entry` 消费该投影并映射成跨玩法契约;`/api/runtime/custom-world-gallery` 保留旧 HTTP shape,并从统一 public cache 映射回旧 DTO。旧 procedure 只用于兼容旧库缺少 gallery 读模型行时的一次性同步兜底。
|
||||
|
||||
### `custom_world_profile`
|
||||
|
||||
@@ -402,14 +402,14 @@ npm run check:server-rs-ddd
|
||||
- Rust view:`jump_hop_gallery_card_view`
|
||||
- 返回类型:`Vec<JumpHopGalleryCardViewRow>`
|
||||
- 源码:`server-rs/crates/spacetime-module/src/jump_hop.rs`
|
||||
- 说明:跳一跳公开广场列表卡片投影,只暴露 `publication_status = Published` 的作品卡片字段;`api-server` 的 `spacetime-client` 长期订阅 `SELECT * FROM jump_hop_gallery_card_view` 后,从本地 cache 构造跳一跳公开列表响应。个人作品列表、详情、发布和运行态仍按 procedure 路径处理。
|
||||
- 说明:跳一跳公开列表 source 投影,只暴露 `publication_status = Published` 的作品卡片字段;统一公开列表主路径通过 `public_work_gallery_entry` 消费该 view 并映射成跨玩法契约。个人作品列表、详情、发布和运行态仍按 procedure 路径处理。
|
||||
|
||||
### SpacetimeDB view:`jump_hop_gallery_view`
|
||||
|
||||
- Rust view:`jump_hop_gallery_view`
|
||||
- 返回类型:`Vec<JumpHopGalleryViewRow>`
|
||||
- 源码:`server-rs/crates/spacetime-module/src/jump_hop.rs`
|
||||
- 说明:跳一跳公开详情兼容投影,包含作品、路径和素材字段;公开列表主路径优先使用 `jump_hop_gallery_card_view`。
|
||||
- 说明:跳一跳公开详情兼容投影,包含作品、路径和素材字段;统一公开详情主路径通过 `public_work_detail_entry` 消费该 view,只保留平台详情页展示摘要。
|
||||
|
||||
### `wooden_fish_agent_session`
|
||||
|
||||
@@ -437,14 +437,14 @@ npm run check:server-rs-ddd
|
||||
- Rust view:`wooden_fish_gallery_card_view`
|
||||
- 返回类型:`Vec<WoodenFishGalleryCardViewRow>`
|
||||
- 源码:`server-rs/crates/spacetime-module/src/wooden_fish.rs`
|
||||
- 说明:敲木鱼公开广场列表卡片投影,只暴露 `publication_status = published` 的作品卡片字段;`api-server` 的 `spacetime-client` 长期订阅 `SELECT * FROM wooden_fish_gallery_card_view` 后,从本地 cache 构造敲木鱼公开列表响应。个人作品列表、详情、发布和运行态仍按 procedure 路径处理。
|
||||
- 说明:敲木鱼公开列表 source 投影,只暴露 `publication_status = published` 的作品卡片字段;统一公开列表主路径通过 `public_work_gallery_entry` 消费该 view 并映射成跨玩法契约。个人作品列表、详情、发布和运行态仍按 procedure 路径处理。
|
||||
|
||||
### SpacetimeDB view:`wooden_fish_gallery_view`
|
||||
|
||||
- Rust view:`wooden_fish_gallery_view`
|
||||
- 返回类型:`Vec<WoodenFishGalleryViewRow>`
|
||||
- 源码:`server-rs/crates/spacetime-module/src/wooden_fish.rs`
|
||||
- 说明:敲木鱼公开详情兼容投影,包含敲击物图案、背景环境图、主题返回按钮图、敲击音效和飘字配置;公开列表主路径优先使用 `wooden_fish_gallery_card_view`。
|
||||
- 说明:敲木鱼公开详情兼容投影,包含敲击物图案、背景环境图、主题返回按钮图、敲击音效和飘字配置;统一公开详情主路径通过 `public_work_detail_entry` 消费该 view,只保留平台详情页展示摘要。
|
||||
|
||||
### `match3d_agent_message`
|
||||
|
||||
@@ -471,7 +471,7 @@ npm run check:server-rs-ddd
|
||||
- Rust view:`match3d_gallery_view`
|
||||
- 返回类型:`Vec<Match3DGalleryViewRow>`
|
||||
- 源码:`server-rs/crates/spacetime-module/src/match3d.rs`
|
||||
- 说明:抓大鹅公开广场列表投影,只暴露 `publication_status = published` 的作品卡片字段;`api-server` 的 `spacetime-client` 长期订阅 `SELECT * FROM match_3_d_gallery_view` 与 `SELECT * FROM public_work_play_daily_stat WHERE source_type = 'match3d'` 后,从本地 cache 构造 `/api/runtime/match3d/gallery` 响应。公开列表不再每个 HTTP 请求调用 `list_match3d_works` procedure;个人作品列表、详情、发布、点赞、游玩记录和 Remix 仍按原有 procedure / reducer 路径处理。
|
||||
- 说明:抓大鹅公开 source 投影,只暴露 `publication_status = published` 的作品卡片字段;统一公开列表 / 详情主路径通过 `public_work_gallery_entry` / `public_work_detail_entry` 消费该 view 并映射成跨玩法契约。个人作品列表、详情、发布、点赞、游玩记录和 Remix 仍按原有 procedure / reducer 路径处理。
|
||||
|
||||
### `npc_state`
|
||||
|
||||
@@ -604,14 +604,14 @@ npm run check:server-rs-ddd
|
||||
- Rust view:`puzzle_gallery_view`
|
||||
- 返回类型:`Vec<PuzzleWorkProfile>`
|
||||
- 源码:`server-rs/crates/spacetime-module/src/puzzle.rs`
|
||||
- 说明:拼图广场公开详情兼容投影,只暴露 `publication_status = Published` 的作品,但返回完整 `PuzzleWorkProfile`,包含 levels / anchor_pack 等详情级字段;公开列表主路径不再订阅该 view。
|
||||
- 说明:拼图广场公开详情 source / 兼容投影,只暴露 `publication_status = Published` 的作品,但返回完整 `PuzzleWorkProfile`,包含 levels / anchor_pack 等详情级字段;统一公开详情主路径通过 `public_work_detail_entry` 消费该 view,只保留平台详情页展示摘要。
|
||||
|
||||
### SpacetimeDB view:`puzzle_gallery_card_view`
|
||||
|
||||
- Rust view:`puzzle_gallery_card_view`
|
||||
- 返回类型:`Vec<PuzzleGalleryCardViewRow>`
|
||||
- 源码:`server-rs/crates/spacetime-module/src/puzzle.rs`
|
||||
- 说明:拼图广场公开列表卡片投影,只暴露前端列表卡片需要的公开字段,不携带 levels / anchor_pack 等详情级载荷;`api-server` 的 `spacetime-client` 长期订阅 `SELECT * FROM puzzle_gallery_card_view` 与 `SELECT * FROM public_work_play_daily_stat WHERE source_type = 'puzzle'` 后,从本地 cache 构造 `/api/runtime/puzzle/gallery` 响应,并在本地按当前请求时间聚合 `recentPlayCount7d`,不再每个 HTTP 请求调用 `list_puzzle_gallery` procedure。
|
||||
- 说明:拼图公开列表 source 投影,只暴露前端列表卡片需要的公开字段,不携带 levels / anchor_pack 等详情级载荷;统一公开列表主路径通过 `public_work_gallery_entry` 消费该 view,`/api/runtime/puzzle/gallery` 保留旧 HTTP shape,并从统一 public cache 映射回 `PuzzleGalleryResponse`。
|
||||
|
||||
### 拼图公开列表 HTTP 窗口缓存
|
||||
|
||||
@@ -624,26 +624,31 @@ npm run check:server-rs-ddd
|
||||
|
||||
`spacetime-client` 建立每个池连接时会等待下列订阅初始同步:
|
||||
|
||||
- `SELECT * FROM public_work_gallery_entry`
|
||||
- `SELECT * FROM public_work_detail_entry`
|
||||
- `SELECT * FROM bark_battle_gallery_view`
|
||||
- `SELECT * FROM puzzle_gallery_card_view`
|
||||
- `SELECT * FROM jump_hop_gallery_card_view`
|
||||
- `SELECT * FROM wooden_fish_gallery_card_view`
|
||||
- `SELECT * FROM custom_world_gallery_entry`
|
||||
- `SELECT * FROM match_3_d_gallery_view`
|
||||
- `SELECT * FROM square_hole_gallery_view`
|
||||
- `SELECT * FROM visual_novel_gallery_view`
|
||||
- `SELECT * FROM big_fish_gallery_view`
|
||||
- `SELECT * FROM jump_hop_gallery_card_view`
|
||||
|
||||
下列订阅用于统计或配置缓存,订阅失败不会让公开列表连接整体不可用,调用方保留兼容兜底:
|
||||
|
||||
- `SELECT * FROM public_work_play_daily_stat WHERE source_type = 'puzzle'`
|
||||
- `SELECT * FROM public_work_play_daily_stat WHERE source_type = 'jump-hop'`
|
||||
- `SELECT * FROM public_work_play_daily_stat WHERE source_type = 'wooden-fish'`
|
||||
- `SELECT * FROM public_work_play_daily_stat WHERE source_type = 'custom-world'`
|
||||
- `SELECT * FROM public_work_play_daily_stat WHERE source_type = 'match3d'`
|
||||
- `SELECT * FROM public_work_play_daily_stat WHERE source_type = 'square-hole'`
|
||||
- `SELECT * FROM public_work_play_daily_stat WHERE source_type = 'visual-novel'`
|
||||
- `SELECT * FROM public_work_play_daily_stat WHERE source_type = 'big-fish'`
|
||||
- `SELECT * FROM public_work_play_daily_stat WHERE source_type = 'bark-battle'`
|
||||
- `SELECT * FROM creation_entry_config`
|
||||
- `SELECT * FROM creation_entry_type_config`
|
||||
- `SELECT * FROM asset_object`
|
||||
|
||||
拼图、自定义世界、抓大鹅、方洞挑战、视觉小说和大鱼吃小鱼的公开列表 HTTP 路由都从订阅 cache 读取公开 read model / view。各玩法的个人作品列表、详情、发布、点赞、游玩记录、Remix 和其它需要鉴权或写入副作用的路径继续走 procedure / reducer;不要为了公开列表性能把这些 owner-specific 或 mutation 语义混进 public view。
|
||||
跨玩法公开作品列表 / 详情主读模型是 `public_work_gallery_entry` 与 `public_work_detail_entry`。拼图、自定义世界等旧玩法公开列表 HTTP 路由保留原响应 shape,由 BFF mapper 从统一 public cache 映射回当前 DTO;旧 `*_gallery_card_view` / `*_gallery_view` / `custom_world_gallery_entry` 继续作为 source view 和兼容缓存。各玩法的个人作品列表、详情、发布、点赞、游玩记录、Remix 和其它需要鉴权或写入副作用的路径继续走 procedure / reducer;不要为了公开列表性能把这些 owner-specific 或 mutation 语义混进 public view。
|
||||
|
||||
`GET /api/creation-entry/config` 和入口熔断优先从订阅 cache 读取创作入口配置;cache 缺失时使用最近一次成功读取的内存快照,再兜底调用 `get_creation_entry_config` procedure 完成空库种子或旧库兼容。
|
||||
入口配置快照包含 start card、类型弹窗、活动横幅和入口类型列表;入口类型列表新增 `category_id`、`category_label`、`category_sort_order` 后,后台 upsert、`shared-contracts`、`module-runtime` 和 `spacetime-client` binding 必须同步,旧迁移 JSON 通过 `migration.rs` 默认值兼容。
|
||||
@@ -652,7 +657,7 @@ RPG 创作入口的配置 ID 是 `rpg`,当前 `visible=true`、`open=true`;
|
||||
|
||||
结构化创作和 RPG 的 LLM JSON 链路默认不启用 Responses `web_search`;只有在明确需要联网增强时,才通过 `GENARRATIVE_RPG_LLM_WEB_SEARCH_ENABLED` 或 `GENARRATIVE_CREATION_AGENT_LLM_WEB_SEARCH_ENABLED` 显式打开。否则未开通工具的上游会先吐自然语言再返回 `ToolNotOpen`,这类失败要按上游工具不可用处理,不要误判成模型返回结果解析失败。
|
||||
|
||||
未来可选:若发现页、推荐流和各玩法广场需要统一给浏览器前端直接订阅公开作品列表,只新增 / 统一专用 public read model,例如 `public_work_gallery_entry`。该 read model 必须是后端投影后的公开作品卡片契约,覆盖作品类型、公开作品号、标题、摘要、封面、作者展示名、排序键、公开统计和入口开关后的可见性,不暴露玩法领域源表 row shape。前端可选择订阅这个稳定投影来减少 HTTP 拉取,但不能订阅 `puzzle_work_profile`、`custom_world_profile` 等源表后自行拼装列表;BFF 仍保留首屏、SEO / 分享、旧客户端、订阅失败和灰度期间的 HTTP fallback。
|
||||
统一公开作品 BFF 路由是 `GET /api/public-works` 与 `GET /api/public-works/{publicWorkCode}`,响应契约由 `shared-contracts::public_work` 和 `packages/shared/src/contracts/publicWork.ts` 共同维护。前端首期仍走 BFF HTTP,不直接订阅 SpacetimeDB;后续若允许浏览器直连订阅,也只能订阅 `public_work_gallery_entry` / `public_work_detail_entry` 这类稳定公开 read model,不能订阅 `puzzle_work_profile`、`custom_world_profile` 等源表后自行拼装列表。设计细节见 `docs/technical/【后端架构】统一公开作品ReadModel设计-2026-05-26.md`。
|
||||
|
||||
### `quest_log`
|
||||
|
||||
@@ -704,7 +709,7 @@ RPG 创作入口的配置 ID 是 `rpg`,当前 `visible=true`、`open=true`;
|
||||
- Rust view:`square_hole_gallery_view`
|
||||
- 返回类型:`Vec<SquareHoleGalleryViewRow>`
|
||||
- 源码:`server-rs/crates/spacetime-module/src/square_hole.rs`
|
||||
- 说明:方洞挑战公开广场列表投影,只暴露 `publication_status = published` 的作品卡片字段;`api-server` 的 `spacetime-client` 长期订阅 `SELECT * FROM square_hole_gallery_view` 与 `SELECT * FROM public_work_play_daily_stat WHERE source_type = 'square-hole'` 后,从本地 cache 构造 `/api/runtime/square-hole/gallery` 响应。公开列表不再每个 HTTP 请求调用 `list_square_hole_works` procedure;个人作品列表、详情、发布、点赞、游玩记录和 Remix 仍按原有 procedure / reducer 路径处理。
|
||||
- 说明:方洞挑战公开 source 投影,只暴露 `publication_status = published` 的作品卡片字段;统一公开列表 / 详情主路径通过 `public_work_gallery_entry` / `public_work_detail_entry` 消费该 view 并映射成跨玩法契约。个人作品列表、详情、发布、点赞、游玩记录和 Remix 仍按原有 procedure / reducer 路径处理。
|
||||
|
||||
### `story_event`
|
||||
|
||||
@@ -779,4 +784,4 @@ RPG 创作入口的配置 ID 是 `rpg`,当前 `visible=true`、`open=true`;
|
||||
- Rust view:`visual_novel_gallery_view`
|
||||
- 返回类型:`Vec<VisualNovelGalleryViewRow>`
|
||||
- 源码:`server-rs/crates/spacetime-module/src/visual_novel.rs`
|
||||
- 说明:视觉小说公开广场列表投影,只暴露 `publication_status = published` 的作品卡片字段,不把完整 `draft` 暴露给公开列表订阅;`api-server` 的 `spacetime-client` 长期订阅 `SELECT * FROM visual_novel_gallery_view` 与 `SELECT * FROM public_work_play_daily_stat WHERE source_type = 'visual-novel'` 后,从本地 cache 构造 `/api/runtime/visual-novel/gallery` 响应。公开列表不再每个 HTTP 请求调用 `list_visual_novel_works` procedure;个人历史、详情、运行态和发布仍按原有 procedure / reducer 路径处理。
|
||||
- 说明:视觉小说公开 source 投影,只暴露 `publication_status = published` 的作品卡片字段,不把完整 `draft` 暴露给公开列表订阅;统一公开列表 / 详情主路径通过 `public_work_gallery_entry` / `public_work_detail_entry` 消费该 view 并映射成跨玩法契约。个人历史、详情、运行态和发布仍按原有 procedure / reducer 路径处理。
|
||||
|
||||
@@ -46,7 +46,8 @@
|
||||
4. 生成中作品在整卡上加等待遮罩,但不移除作品基础信息。
|
||||
5. 生成中状态不能只存在前端内存 notice。后端作品摘要必须下发可恢复的 `generationStatus`;前端刷新或退出产品后,作品架优先用摘要状态恢复等待遮罩,本轮内存 notice 只作为即时反馈。
|
||||
6. 点击 `generationStatus=generating` 的草稿卡必须恢复对应玩法的生成进度页,不能进入空白结果页或普通工作区;恢复生成页的 `startedAtMs` 使用进入生成页的当前时间,作品摘要 `updatedAt` 只用于排序和摘要展示,不参与假进度起算。
|
||||
7. 私有 generated 图片必须通过 `ResolvedAssetImage` / `/api/assets/read-url` 换签读取。
|
||||
7. 从草稿 Tab 作品架打开草稿工作区、生成页或结果页时,返回按钮必须回到草稿 Tab 的同一作品架语境;从创作 Tab 新建或直接进入创作链路时才回到创作 Tab。平台壳层需要显式记录本次创作流的返回来源,不能让结果页返回动作固定跳到创作入口。
|
||||
8. 私有 generated 图片必须通过 `ResolvedAssetImage` / `/api/assets/read-url` 换签读取。
|
||||
|
||||
发现 Tab、创作 Tab 与草稿 Tab 的页面根内容区不再套 `platform-page-stage` 外层全局卡片壳,让列表、筛选和玩法卡获得更宽的横向空间;推荐页和我的页仍按各自页面设计保留原有全局卡片口径。移动端“我的”页仍按顶部头像 / 昵称 / 陶泥号、会员横幅、三张统计卡、每日任务、五项常用功能宫格、设置入口和法律信息组织,不保留旧的底部“填邀请码”次级入口;每日任务卡必须读取 `/api/profile/tasks` 的当前任务摘要并在领取后同步刷新卡片进度。字号必须维持平台普通 UI 档位,不能因为窄屏把卡片标题、功能 label 或法律信息撑成展示级字号;最后一屏内容必须能在底部 dock 上方完整滚动露出,不得被固定底部导航遮挡。
|
||||
|
||||
@@ -93,7 +94,8 @@ RPG / 拼图等运行态存档仍以 `/api/profile/save-archives` 的后端列
|
||||
- 支持画面描述生图、多参考图生图、上传或历史生成主图后 AI 重绘、上传或历史生成主图后不重绘;主链要求浏览器先经 `/api/assets/direct-upload-tickets` 直传 OSS 并确认 `asset_object`,创作 action 只提交 `referenceImageAssetObjectId(s)`,由后端校验 owner / bucket / kind / MIME / size 后签发 OSS 只读 URL 并下载为 VectorEngine `/v1/images/edits` 的 multipart `image` part。本地上传 Data URL 与历史 `/generated-*` 图片路径仅保留为旧草稿、旧入口或未迁移客户端的兼容输入;关闭 AI 重绘时,后端统一解析为首关或当前关卡正式图后再持久化,不调用第一段拼图首图生成。
|
||||
- 草稿生成会先持久化 `generationStatus=generating` 的作品摘要,生成完成并回写关卡拼图画面、关卡画面参考图、UI spritesheet 和关卡背景图后再变为 `ready`;当前不自动生成背景音乐。生成页步骤推进必须跟随后端 session `progressPercent` 的真实里程碑:`88` 表示草稿编译完成并进入出图步骤,`94` 表示生成图已保存并进入 UI / 背景步骤,`96` 表示正式图与 UI 背景已确认并进入写入步骤,最终 action 成功或发布才进入完成态;每个步骤内部可以按实际等待时间使用假进度平滑推进,总进度按 `0-88`、`88-94`、`94-96`、`96-98` 的真实里程碑区间平滑推进。任一同步 action 回包到达时立即以真实完成/失败结果冻结进度。
|
||||
- 作品架拼图草稿的“生成中”遮罩只表示初始草稿还没有可查看结果;只要作品摘要、首关封面或任一关卡候选图已经可用,后续 UI 背景重生成和追加关卡生图都必须作为结果页局部生成态处理,不能阻止打开草稿结果页。
|
||||
- 拼图草稿编译是长耗时 action,前端 action 请求默认等待 `1_800_000ms`(30 分钟)且不自动重试。每次 `gpt-image-2` 调用的预期用时按 90 秒计算,但 `生成拼图首图` 单独按 4 分钟展示;完整 AI 重绘路径为 `编译首关草稿` 8 秒、`生成关卡名称` 10 秒、`生成拼图首图` 4 分钟、`生成关卡画面` 90 秒、`生成UI与背景` 90 秒、`写入正式草稿` 10 秒,合计约 448 秒。上传图且关闭 AI 重绘时必须跳过 `生成拼图首图`,直接进入 `生成关卡画面` 和 `生成UI与背景`,合计约 208 秒。生成页恢复时必须使用进入生成页的当前时间作为原始 `startedAtMs`;失败/完成态用 `finishedAtMs` 冻结耗时。未收到对应后端里程碑前,后续步骤保持待处理;即使当前步骤预计时长耗尽,也只能让当前步骤内部进度停在 `98%` 内,不能自动完成当前步骤或跳到后续步骤。生成页每个步骤只展示标题和进度,不展示步骤详细描述。
|
||||
- 拼图草稿编译是长耗时 action,前端 action 请求默认等待 `1_800_000ms`(30 分钟)且不自动重试。每次图片生成调用的预期用时按 90 秒计算,但 `生成拼图首图` 单独按 4 分钟展示;完整 AI 重绘路径为 `编译首关草稿` 8 秒、`生成关卡名称` 10 秒、`生成拼图首图` 4 分钟、`生成关卡画面` 90 秒、`生成UI与背景` 90 秒、`写入正式草稿` 10 秒,合计约 448 秒。上传图且关闭 AI 重绘时必须跳过 `生成拼图首图`,直接进入 `生成关卡画面` 和 `生成UI与背景`,合计约 208 秒。生成页恢复时必须使用进入生成页的当前时间作为原始 `startedAtMs`;失败/完成态用 `finishedAtMs` 冻结耗时。未收到对应后端里程碑前,后续步骤保持待处理;即使当前步骤预计时长耗尽,也只能让当前步骤内部进度停在 `98%` 内,不能自动完成当前步骤或跳到后续步骤。生成页每个步骤只展示标题和进度,不展示步骤详细描述。
|
||||
- 前端创作、结果页、生成页和错误提示不展示 GPT / Gemini 等具体模型名称;如需在内部保留模型路由,UI 只使用“标准模式”“创意模式”等产品化名称。
|
||||
- 若浏览器锁屏、息屏或网络切换导致 compile 请求失败,前端在标记失败前必须先复读 `getPuzzleAgentSession(sessionId)`;只有最新 session 仍缺 `draft.coverImageSrc`、首关 `coverImageSrc` 或候选图时才展示失败,复读到已生成草稿时按成功收尾、刷新作品架并继续自动试玩/结果页链路。
|
||||
- 拼图参考图 AI 重绘走 VectorEngine `/v1/images/edits`;无参考图时走 `/v1/images/generations`。两者模型都使用 `gpt-image-2`,参考图由后端作为 multipart `image` part 传入编辑接口。
|
||||
- 每次新建关卡生成或重新生成关卡图都必须由 `api-server` 串起当前关卡资产包:AI 重绘开启时第一段沿用草稿生成第一关的拼图主图提示词配置和模型 / 尺寸 / 参考图规则生成 `coverImageSrc/coverAssetId` 作为关卡拼图画面和结果页预览图,提示词来源同样按显式画面描述、关卡画面描述、草稿摘要顺序回退,且固定要求输出画面比例为 `1:1`;上传图且关闭 AI 重绘时跳过这一段,把上传图或历史图持久化为 `sourceType=uploaded` 的正式候选。随后用正式候选图作为参考,`9:16` 生成完整拼图游戏关卡画面并写入 `levelSceneImageSrc/levelSceneImageObjectKey`,提示词必须要求道具按钮上不要显示次数标注,且返回按钮和设置按钮旁禁止标注文字;UI spritesheet 与关卡纯背景在关卡画面完成后并发生成,spritesheet 用 `1:1`、`1k` 先生成纯绿色绿幕背景图,后端上传 OSS 前必须把绿幕扣成透明 PNG,再写入 `uiSpritesheetImageSrc/uiSpritesheetImageObjectKey`,按钮顺序固定为返回、设置、下一关、提示、原图、冻结,按钮素材自身保留对应中文文字,返回和设置按钮不得额外生成白色外圈、白底圆环或浮雕外框;纯背景用 `9:16`、`1k` 写入 `levelBackgroundImageSrc/levelBackgroundImageObjectKey`,提示词必须包含“禁止在背景中出现人像或和拼图画面中主体一致的内容”。运行态不直接使用第二段完整关卡画面,但必须持久化它用于追踪和后续再生成。结果页局部关卡生成进度按 AI 重绘开启约 270 秒、关闭 AI 重绘约 180 秒展示。
|
||||
@@ -111,6 +113,7 @@ RPG / 拼图等运行态存档仍以 `/api/profile/save-archives` 的后端列
|
||||
- 拼图运行态顶部关卡信息采用游戏化铭牌样式:橘棕横向关卡名牌承载 `第 N 关` 和关卡名,左侧固定使用 `media/logo.png` 卡通形象;倒计时作为下挂米白小牌独立显示,紧贴铭牌但不遮挡棋盘。该样式只改变运行态 HUD 视觉,不改变计时、暂停、失败同步或关卡推进规则。
|
||||
- 拼图运行态进行中关卡的 `elapsedMs` 仍是结算字段,设置面板的“当前用时”必须按 `startedAtMs`、暂停累计和冻结累计实时派生;不要直接把进行中的 `currentLevel.elapsedMs` 当作展示值。
|
||||
- 推荐页嵌入拼图运行态时,通关结算弹层必须挂到页面级 fixed 浮层,不能留在推荐卡片视觉区内的 absolute 覆盖层;推荐页滑动卡片和运行态视口都使用 `overflow: hidden`,半屏内容区会裁剪排行榜、下一关按钮和相似作品卡。
|
||||
- 推荐页嵌入拼图运行态时,“下一关”应优先切到相似作品;如果当前推荐候选为空,才回退到同作品下一关,避免匿名推荐流在多关卡作品上持续停留在同一作品内。下一关请求 pending 期间必须保留当前 `PuzzleRuntimeShell` 和棋盘,不得把推荐卡整体切回 `加载中...` 占位态;局部同步状态由拼图运行态自己的 busy 表现承接。后端返回的新关卡属于其它作品时,前端必须同步 `selectedPuzzleDetail`、推荐页 `puzzleGalleryEntries` 缓存和 `activeRecommendEntryKey`,让底部作品信息、分享 / 点赞 / 改造和下一次“下一个”基准都指向新作品。
|
||||
- 推荐页里的拼图作品如果从运行态进入“改造”结果页,返回平台后要清掉推荐嵌入态的 `activeRecommendEntryKey` / `activeRecommendRuntimeKind` / `isStartingRecommendEntry`,再重新按推荐页自动启动逻辑进入作品,不能复用已经被清空的旧 `puzzleRun`。
|
||||
- 拼图运行态允许前端低延迟交互表现,但通关、排行榜、奖励和作品状态仍以后端确认为准。
|
||||
|
||||
@@ -194,8 +197,8 @@ RPG / 拼图等运行态存档仍以 `/api/profile/save-archives` 的后端列
|
||||
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`。
|
||||
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 自动解析结果回退。
|
||||
7. 前端和运行态统一使用 alpha 连通域矩形检测解析 spritesheet:UI 图按返回、设置、方格、移出、凑齐、打乱顺序映射回原 UI 位置;物品图按检测顺序每 `5` 个区域组成一个物品的五个形态,最多 `20` 个物品。透明背景是解析前提,不能在前端按固定像素坐标写死切片。
|
||||
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 连通域矩形检测解析 spritesheet:UI 图先把识别出的透明素材矩形按行聚类,再在每一行内按横向 `x` 坐标排序,最后按返回、设置、方格、移出、凑齐、打乱顺序映射回原 UI 位置;不能只按全局 `y` 坐标排序,否则同一行素材上下略有错位时会把方格和底部道具按钮顺序打乱。物品图按检测顺序每 `5` 个区域组成一个物品的五个形态,最多 `20` 个物品。透明背景是解析前提,不能在前端按固定像素坐标写死切片。
|
||||
8. 文本生成物品名称时必须同时生成 `itemSize`,只允许 `大`、`中`、`小`。该字段随 `generatedItemAssets[].itemSize` 持久化并下发;历史缺失字段的素材按 `大` 兼容,模型缺失或非法值按物品名本地推断。
|
||||
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 时也要先归一化并提升,避免首次试玩、手动试玩、推荐流或公开详情运行态退回默认背景。
|
||||
@@ -218,12 +221,15 @@ RPG / 拼图等运行态存档仍以 `/api/profile/save-archives` 的后端列
|
||||
- 难度只决定本局加载的物品种类数量:轻松 3、标准 9、进阶 15、硬核 20。硬核仍保留 21 次消除和 63 件总物品,运行态按 20 种素材循环复用,不要求生成第 21 种素材。
|
||||
- 运行态启动前要预加载 `generatedItemAssets[].imageViews[]`、顶层 `generatedBackgroundAsset`、物品挂载 `backgroundAsset` 中的背景、UI spritesheet 和物品 spritesheet;首次生成自动试玩、结果页手动试玩、推荐流和公开详情启动都必须传入提升后的 profile。卡片摘要缺图集字段时,进入运行态前必须补读 work detail。补读后的 profile 也要再次提升 `generatedItemAssets[].backgroundAsset`,确保背景和图集字段传给 `Match3DRuntimeShell`。
|
||||
- 背景图作为运行态全屏背景,图内已经保留容器;旧 `containerImage*` 只作为历史透明容器兼容字段。若 `containerImage*` 与 `uiSpritesheetImage*` 同源,运行态不得把 UI spritesheet 当中心容器图叠到棋盘上。
|
||||
- 抓大鹅运行态 HUD 需贴近拼图顶部信息条的视觉口径:左上只保留透明返回按钮;右上不再暴露设置入口;顶部关卡名和倒计时直接复用拼图同款的铭牌 + 下挂计时牌结构、同色板和同造型,并在牌面左侧挂上 `media/logo.png` 产品 logo;下方备选栏和道具图标只保留内容与交互边界,不再显示灰白半透底板;中央容器图层视觉可隐藏,但棋盘命中边界仍保留。
|
||||
- generated 私有图换签未完成时,局内物品先隐藏等待,不得短暂显示默认积木;同一批资源在重启 run 时保留已解析签名 URL,只有资源源列表变化或换签失败后才允许进入兜底视觉。
|
||||
- `itemSize` 只缩放生成 2D 图片本体:`大`、`中`、`小` 均按相对尺寸缩放,其中 `大` 也比原始图片略小,`中` 和 `小` 进一步缩小;不改变后端下发的布局半径、点击半径或三消规则。
|
||||
- 物品进入底部物品栏时按同类型插入:如果物品栏已有同类物品,新物品插到该类型最后一个物品后面,后续物品整体后移;没有同类时追加到当前末尾。达到三件同类时,在飞入物品栏动画结束后,左侧和右侧同类物品向中间合成,三件一起消失,播放合成音效,不展示星星图标,后面的物品再向前补位。该动效只是前端表现层,后端和本地试玩仍负责权威插入、指定点击类型清除与补位后的槽位快照。
|
||||
- 抓大鹅运行态右上角常驻设置入口,不直接暴露重新开始按钮;重新开始收口到设置面板内,结算弹层仍保留结果态的再来一局动作。
|
||||
- 抓大鹅运行态不渲染右上角设置入口,也不在局内直接暴露重新开始按钮;结算弹层仍保留结果态的再来一局动作。
|
||||
- 高 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 玩法的创作与运行经验,不迁入外部平台社区、支付、榜单、私有存档或回放。
|
||||
|
||||
Reference in New Issue
Block a user